From b10f32672946ad638a430cc4289029b7acf8e979 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 18 Aug 2019 21:09:20 +0200 Subject: ath10k: Check if station exists before forwarding tx airtime report It looks like the FW on QCA9984 already reports the tx airtimes before the station is added to the peer entry. The peer entry is created in ath10k_peer_map_event() just with the vdev_id and the ethaddr, but not with a station entry, this is added later in ath10k_peer_create() in callbacks from mac80211. When there is no sta added to the peer entry, this function fails because it calls ieee80211_sta_register_airtime() with NULL. This was reported in OpenWrt some time ago: https://bugs.openwrt.org/index.php?do=details&task_id=2414 This commit should fix this crash: [ 75.991714] Unable to handle kernel paging request at virtual address fffff9e8 [ 75.991756] pgd = c0204000 [ 75.997955] [fffff9e8] *pgd=5fdfd861, *pte=00000000, *ppte=00000000 [ 76.000537] Internal error: Oops: 37 [#1] SMP ARM [ 76.006686] Modules linked in: pppoe ppp_async ath10k_pci ath10k_core ath pptp pppox ppp_mppe ppp_generic mac80211 iptable_nat ipt_REJECT ipt_MASQUERADE cfg80211 xt_time xt_tcpudp xt_tcpmss xt_statistic xt_state xt_recent xt_nat xt_multiport xt_mark xt_mac xt_limit xt_length xt_hl xt_helper xt_esp xt_ecn xt_dscp xt_conntrack xt_connmark xt_connlimit xt_connbytes xt_comment xt_TCPMSS xt_REDIRECT xt_LOG xt_HL xt_FLOWOFFLOAD xt_DSCP xt_CT xt_CLASSIFY usbserial slhc nf_reject_ipv4 nf_nat_redirect nf_nat_masquerade_ipv4 nf_conntrack_ipv4 nf_nat_ipv4 nf_log_ipv4 nf_flow_table_hw nf_flow_table nf_defrag_ipv4 nf_conntrack_rtcache nf_conntrack_netlink iptable_raw iptable_mangle iptable_filter ipt_ah ipt_ECN ip_tables crc_ccitt compat chaoskey fuse sch_cake sch_tbf sch_ingress sch_htb sch_hfsc em_u32 cls_u32 [ 76.059974] cls_tcindex cls_route cls_matchall cls_fw cls_flow cls_basic act_skbedit act_mirred ledtrig_usbport xt_set ip_set_list_set ip_set_hash_netportnet ip_set_hash_netport ip_set_hash_netnet ip_set_hash_netiface ip_set_hash_net ip_set_hash_mac ip_set_hash_ipportnet ip_set_hash_ipportip ip_set_hash_ipport ip_set_hash_ipmark ip_set_hash_ip ip_set_bitmap_port ip_set_bitmap_ipmac ip_set_bitmap_ip ip_set nfnetlink ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6t_NPT ip6t_MASQUERADE nf_nat_masquerade_ipv6 nf_nat nf_conntrack nf_log_ipv6 nf_log_common ip6table_mangle ip6table_filter ip6_tables ip6t_REJECT x_tables nf_reject_ipv6 msdos ip_gre gre ifb sit tunnel4 ip_tunnel tun vfat fat hfsplus cifs nls_utf8 nls_iso8859_15 nls_iso8859_1 nls_cp850 nls_cp437 nls_cp1250 sha1_generic md5 md4 [ 76.130634] usb_storage leds_gpio xhci_plat_hcd xhci_pci xhci_hcd dwc3 dwc3_of_simple ohci_platform ohci_hcd phy_qcom_dwc3 ahci ehci_platform sd_mod ahci_platform libahci_platform libahci libata scsi_mod ehci_hcd gpio_button_hotplug ext4 mbcache jbd2 exfat crc32c_generic [ 76.154772] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.132 #0 [ 76.177001] Hardware name: Generic DT based system [ 76.182990] task: c0b06d80 task.stack: c0b00000 [ 76.187832] PC is at ieee80211_sta_register_airtime+0x24/0x148 [mac80211] [ 76.192211] LR is at ath10k_htt_t2h_msg_handler+0x678/0x10f4 [ath10k_core] [ 76.199052] pc : [] lr : [] psr: a0000113 [ 76.205820] sp : c0b01d54 ip : 00000002 fp : bf869c0c [ 76.211981] r10: 0000003c r9 : dbdca138 r8 : 00060002 [ 76.217192] r7 : 00000000 r6 : dabe1150 r5 : 00000000 r4 : dbdc95c0 [ 76.222401] r3 : 00000000 r2 : 00060002 r1 : 00000000 r0 : 00000000 [ 76.229003] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 76.235509] Control: 10c5787d Table: 5c94006a DAC: 00000051 [ 76.242716] Process swapper/0 (pid: 0, stack limit = 0xc0b00210) [ 76.248446] Stack: (0xc0b01d54 to 0xc0b02000) [ 76.254532] 1d40: dbdc95c0 00000000 dabe1150 [ 76.258808] 1d60: 00000001 dabe1150 dbdca138 0000003c bf869c0c bf83e8b0 00000002 c0314b10 [ 76.266969] 1d80: dbdc9c70 00000001 00000001 dabe114c 00010000 00000000 dbdcd724 bf88f3d8 [ 76.275126] 1da0: c0310d28 db393c00 dbdc95c0 00000000 c0b01dd0 c07fb4c4 dbdcd724 00000001 [ 76.283286] 1dc0: 00000022 bf88b09c db393c00 00000022 c0b01dd0 c0b01dd0 00000000 dbdcc5c0 [ 76.291445] 1de0: bf88f04c dbdcd654 dbdcd71c dbdc95c0 00000014 dbdcd724 dbdcc5c0 00000005 [ 76.299605] 1e00: 0004b400 bf85c360 00000000 bf87101c c0b01e24 00000006 00000000 dbdc95c0 [ 76.307764] 1e20: 00000001 00000040 0000012c c0b01e80 1cf51000 bf85c448 dbdcd440 dbdc95c0 [ 76.315925] 1e40: dbdca440 ffffa880 00000040 bf88cb68 dbdcd440 00000001 00000040 ffffa880 [ 76.324084] 1e60: c0b02d00 c06d72e0 dd990080 c0a3f080 c0b255dc c0b047e4 c090afac c090e80c [ 76.332244] 1e80: c0b01e80 c0b01e80 c0b01e88 c0b01e88 dd4cc200 00000000 00000003 c0b0208c [ 76.340405] 1ea0: c0b02080 40000003 ffffe000 00000100 c0b02080 c03015c8 00000000 00000001 [ 76.348564] 1ec0: dd408000 c0a38210 c0b2c7c0 0000000a ffffa880 c0b02d00 c07fb764 00200102 [ 76.356723] 1ee0: dd4cc268 c0a3e414 00000000 00000000 00000001 dd408000 de803000 00000000 [ 76.364883] 1f00: 00000000 c03247cc c0a3e414 c0368f1c c0b03f60 c0b153cc de80200c de802000 [ 76.373042] 1f20: c0b01f48 c0301488 c0308630 60000013 ffffffff c0b01f7c 00000000 c0b00000 [ 76.381204] 1f40: 00000000 c030c08c 00000001 00000000 00000000 c0315180 ffffe000 c0b03cc0 [ 76.389363] 1f60: c0b03c70 00000000 00000000 c0a2da28 00000000 00000000 c0b01f90 c0b01f98 [ 76.397522] 1f80: c030862c c0308630 60000013 ffffffff 00000051 00000000 ffffe000 c035dd18 [ 76.405681] 1fa0: 000000bf c0b03c40 00000000 c0b2c000 dddfce80 c035e060 c0b2c040 c0a00cf4 [ 76.413842] 1fc0: ffffffff ffffffff 00000000 c0a0067c c0a2da28 00000000 00000000 c0b2c1d4 [ 76.422001] 1fe0: c0b03c5c c0a2da24 c0b07ee0 4220406a 512f04d0 4220807c 00000000 00000000 [ 76.430335] [] (ieee80211_sta_register_airtime [mac80211]) from [<00000002>] (0x2) [ 76.438314] Code: e1cd81f0 e1a08002 e1cda1f8 e58de020 (e5102618) [ 76.446965] ---[ end trace 227a38ade964d642 ]--- Fixes: bb31b7cb106c ("ath10k: report tx airtime provided by fw") Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 53f1095de8ff..9f0e7b4943ec 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2726,7 +2726,7 @@ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, spin_lock_bh(&ar->data_lock); peer = ath10k_peer_find_by_id(ar, peer_id); - if (!peer) { + if (!peer || !peer->sta) { spin_unlock_bh(&ar->data_lock); rcu_read_unlock(); continue; -- cgit v1.2.3-59-g8ed1b From 7165ef890a4c44cf16db66b82fd78448f4bde6ba Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 24 Jul 2019 23:31:08 -0700 Subject: ath10k: Fix HOST capability QMI incompatibility The introduction of 768ec4c012ac ("ath10k: update HOST capability QMI message") served the purpose of supporting the new and extended HOST capability QMI message. But while the new message adds a slew of optional members it changes the data type of the "daemon_support" member, which means that older versions of the firmware will fail to decode the incoming request message. There is no way to detect this breakage from Linux and there's no way to recover from sending the wrong message (i.e. we can't just try one format and then fallback to the other), so a quirk is introduced in DeviceTree to indicate to the driver that the firmware requires the 8bit version of this message. Cc: stable@vger.kernel.org Fixes: 768ec4c012ac ("ath10k: update HOST capability qmi message") Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Signed-off-by: Kalle Valo --- .../bindings/net/wireless/qcom,ath10k.txt | 6 ++++++ drivers/net/wireless/ath/ath10k/qmi.c | 13 ++++++++++--- drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c | 22 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h | 1 + drivers/net/wireless/ath/ath10k/snoc.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/snoc.h | 1 + 6 files changed, 51 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt index ae661e65354e..f9499b20d840 100644 --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt @@ -81,6 +81,12 @@ Optional properties: Definition: Name of external front end module used. Some valid FEM names for example: "microsemi-lx5586", "sky85703-11" and "sky85803" etc. +- qcom,snoc-host-cap-8bit-quirk: + Usage: Optional + Value type: + Definition: Quirk specifying that the firmware expects the 8bit version + of the host capability QMI request + Example (to supply PCI based wifi block details): diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 3b63b6257c43..545ac1f06997 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -581,22 +581,29 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi) { struct wlfw_host_cap_resp_msg_v01 resp = {}; struct wlfw_host_cap_req_msg_v01 req = {}; + struct qmi_elem_info *req_ei; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int ret; req.daemon_support_valid = 1; req.daemon_support = 0; - ret = qmi_txn_init(&qmi->qmi_hdl, &txn, - wlfw_host_cap_resp_msg_v01_ei, &resp); + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei, + &resp); if (ret < 0) goto out; + if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags)) + req_ei = wlfw_host_cap_8bit_req_msg_v01_ei; + else + req_ei = wlfw_host_cap_req_msg_v01_ei; + ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn, QMI_WLFW_HOST_CAP_REQ_V01, WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN, - wlfw_host_cap_req_msg_v01_ei, &req); + req_ei, &req); if (ret < 0) { qmi_txn_cancel(&txn); ath10k_err(ar, "failed to send host capability request: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c index 1fe05c6218c3..86fcf4e1de5f 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c @@ -1988,6 +1988,28 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = { {} }; +struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + daemon_support), + }, + {} +}; + struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h index bca1186e1560..4d107e1364a8 100644 --- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h +++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h @@ -575,6 +575,7 @@ struct wlfw_host_cap_req_msg_v01 { #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[]; +extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[]; struct wlfw_host_cap_resp_msg_v01 { struct qmi_response_type_v01 resp; diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index b491361e6ed4..fc15a0037f0e 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1261,6 +1261,15 @@ out: return ret; } +static void ath10k_snoc_quirks_init(struct ath10k *ar) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + struct device *dev = &ar_snoc->dev->dev; + + if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk")) + set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags); +} + int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1678,6 +1687,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev) ar->ce_priv = &ar_snoc->ce; msa_size = drv_data->msa_size; + ath10k_snoc_quirks_init(ar); + ret = ath10k_snoc_resource_init(ar); if (ret) { ath10k_warn(ar, "failed to initialize resource: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index d62f53501fbb..9db823e46314 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -63,6 +63,7 @@ enum ath10k_snoc_flags { ATH10K_SNOC_FLAG_REGISTERED, ATH10K_SNOC_FLAG_UNREGISTERING, ATH10K_SNOC_FLAG_RECOVERY, + ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, }; struct ath10k_snoc { -- cgit v1.2.3-59-g8ed1b From b003e7f1974eaaefcca12be56dff592481052864 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 25 Jul 2019 10:47:53 -0700 Subject: ath10k: snoc: skip regulator operations The regulator operations is trying to set a voltage to a fixed value, by giving some wiggle room. But some board designs specifies regulator voltages outside this limited range. One such example is the Lenovo Yoga C630, with vdd-3.3-ch0 in particular specified at 3.1V. But consumers with fixed voltage requirements should just rely on the board configuration to provide the power at the required level, so this code should be removed. Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 27 ++++++--------------------- drivers/net/wireless/ath/ath10k/snoc.h | 2 -- 2 files changed, 6 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index fc15a0037f0e..3d93ab09a298 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -37,10 +37,10 @@ static char *const ce_name[] = { }; static struct ath10k_vreg_info vreg_cfg[] = { - {NULL, "vdd-0.8-cx-mx", 800000, 850000, 0, 0, false}, - {NULL, "vdd-1.8-xo", 1800000, 1850000, 0, 0, false}, - {NULL, "vdd-1.3-rfa", 1300000, 1350000, 0, 0, false}, - {NULL, "vdd-3.3-ch0", 3300000, 3350000, 0, 0, false}, + {NULL, "vdd-0.8-cx-mx", 0, 0, false}, + {NULL, "vdd-1.8-xo", 0, 0, false}, + {NULL, "vdd-1.3-rfa", 0, 0, false}, + {NULL, "vdd-3.3-ch0", 0, 0, false}, }; static struct ath10k_clk_info clk_cfg[] = { @@ -1377,9 +1377,8 @@ static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, done: ath10k_dbg(ar, ATH10K_DBG_SNOC, - "snog vreg %s min_v %u max_v %u load_ua %u settle_delay %lu\n", - vreg_info->name, vreg_info->min_v, vreg_info->max_v, - vreg_info->load_ua, vreg_info->settle_delay); + "snog vreg %s load_ua %u settle_delay %lu\n", + vreg_info->name, vreg_info->load_ua, vreg_info->settle_delay); return 0; } @@ -1420,15 +1419,6 @@ static int __ath10k_snoc_vreg_on(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n", vreg_info->name); - ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v, - vreg_info->max_v); - if (ret) { - ath10k_err(ar, - "failed to set regulator %s voltage-min: %d voltage-max: %d\n", - vreg_info->name, vreg_info->min_v, vreg_info->max_v); - return ret; - } - if (vreg_info->load_ua) { ret = regulator_set_load(vreg_info->reg, vreg_info->load_ua); if (ret < 0) { @@ -1453,7 +1443,6 @@ static int __ath10k_snoc_vreg_on(struct ath10k *ar, err_enable: regulator_set_load(vreg_info->reg, 0); err_set_load: - regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); return ret; } @@ -1475,10 +1464,6 @@ static int __ath10k_snoc_vreg_off(struct ath10k *ar, if (ret < 0) ath10k_err(ar, "failed to set load %s\n", vreg_info->name); - ret = regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v); - if (ret) - ath10k_err(ar, "failed to set voltage %s\n", vreg_info->name); - return ret; } diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 9db823e46314..1bf7bd4ef2a3 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -45,8 +45,6 @@ struct ath10k_snoc_ce_irq { struct ath10k_vreg_info { struct regulator *reg; const char *name; - u32 min_v; - u32 max_v; u32 load_ua; unsigned long settle_delay; bool required; -- cgit v1.2.3-59-g8ed1b From c56c7f24d7f88cac9aa9a30fe96adfec96c024bb Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 25 Jul 2019 10:47:54 -0700 Subject: ath10k: Use standard regulator bulk API in snoc The regulator_get_optional() exists for cases where the driver needs do behave differently depending on some regulator supply being present or not, as we don't use this we can use the standard regulator_get() and rely on its handling of unspecified regulators. While the driver currently doesn't specify any loads the regulator framework was updated last year to only account for load of enabled regulators, so should the need appear it's better to apply load numbers during initialization that dynamically. With this the regulator wrappers have been reduced the become identical to the standard bulk API provided by the regulator framework, so use these instead of rolling our own. Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 184 +++++---------------------------- drivers/net/wireless/ath/ath10k/snoc.h | 13 +-- 2 files changed, 27 insertions(+), 170 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 3d93ab09a298..1c9ff7e53e2f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -36,11 +36,11 @@ static char *const ce_name[] = { "WLAN_CE_11", }; -static struct ath10k_vreg_info vreg_cfg[] = { - {NULL, "vdd-0.8-cx-mx", 0, 0, false}, - {NULL, "vdd-1.8-xo", 0, 0, false}, - {NULL, "vdd-1.3-rfa", 0, 0, false}, - {NULL, "vdd-3.3-ch0", 0, 0, false}, +static const char * const ath10k_regulators[] = { + "vdd-0.8-cx-mx", + "vdd-1.8-xo", + "vdd-1.3-rfa", + "vdd-3.3-ch0", }; static struct ath10k_clk_info clk_cfg[] = { @@ -1346,43 +1346,6 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } -static int ath10k_get_vreg_info(struct ath10k *ar, struct device *dev, - struct ath10k_vreg_info *vreg_info) -{ - struct regulator *reg; - int ret = 0; - - reg = devm_regulator_get_optional(dev, vreg_info->name); - - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - - if (ret == -EPROBE_DEFER) { - ath10k_err(ar, "EPROBE_DEFER for regulator: %s\n", - vreg_info->name); - return ret; - } - if (vreg_info->required) { - ath10k_err(ar, "Regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - return ret; - } - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "Optional regulator %s doesn't exist: %d\n", - vreg_info->name, ret); - goto done; - } - - vreg_info->reg = reg; - -done: - ath10k_dbg(ar, ATH10K_DBG_SNOC, - "snog vreg %s load_ua %u settle_delay %lu\n", - vreg_info->name, vreg_info->load_ua, vreg_info->settle_delay); - - return 0; -} - static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, struct ath10k_clk_info *clk_info) { @@ -1411,114 +1374,6 @@ static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, return ret; } -static int __ath10k_snoc_vreg_on(struct ath10k *ar, - struct ath10k_vreg_info *vreg_info) -{ - int ret; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being enabled\n", - vreg_info->name); - - if (vreg_info->load_ua) { - ret = regulator_set_load(vreg_info->reg, vreg_info->load_ua); - if (ret < 0) { - ath10k_err(ar, "failed to set regulator %s load: %d\n", - vreg_info->name, vreg_info->load_ua); - goto err_set_load; - } - } - - ret = regulator_enable(vreg_info->reg); - if (ret) { - ath10k_err(ar, "failed to enable regulator %s\n", - vreg_info->name); - goto err_enable; - } - - if (vreg_info->settle_delay) - udelay(vreg_info->settle_delay); - - return 0; - -err_enable: - regulator_set_load(vreg_info->reg, 0); -err_set_load: - - return ret; -} - -static int __ath10k_snoc_vreg_off(struct ath10k *ar, - struct ath10k_vreg_info *vreg_info) -{ - int ret; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc regulator %s being disabled\n", - vreg_info->name); - - ret = regulator_disable(vreg_info->reg); - if (ret) - ath10k_err(ar, "failed to disable regulator %s\n", - vreg_info->name); - - ret = regulator_set_load(vreg_info->reg, 0); - if (ret < 0) - ath10k_err(ar, "failed to set load %s\n", vreg_info->name); - - return ret; -} - -static int ath10k_snoc_vreg_on(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_vreg_info *vreg_info; - int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - ret = __ath10k_snoc_vreg_on(ar, vreg_info); - if (ret) - goto err_reg_config; - } - - return 0; - -err_reg_config: - for (i = i - 1; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - __ath10k_snoc_vreg_off(ar, vreg_info); - } - - return ret; -} - -static int ath10k_snoc_vreg_off(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_vreg_info *vreg_info; - int ret = 0; - int i; - - for (i = ARRAY_SIZE(vreg_cfg) - 1; i >= 0; i--) { - vreg_info = &ar_snoc->vreg[i]; - - if (!vreg_info->reg) - continue; - - ret = __ath10k_snoc_vreg_off(ar, vreg_info); - } - - return ret; -} - static int ath10k_snoc_clk_init(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1591,11 +1446,12 @@ static int ath10k_snoc_clk_deinit(struct ath10k *ar) static int ath10k_hw_power_on(struct ath10k *ar) { + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); int ret; ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n"); - ret = ath10k_snoc_vreg_on(ar); + ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs); if (ret) return ret; @@ -1606,21 +1462,19 @@ static int ath10k_hw_power_on(struct ath10k *ar) return ret; vreg_off: - ath10k_snoc_vreg_off(ar); + regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); return ret; } static int ath10k_hw_power_off(struct ath10k *ar) { - int ret; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); ath10k_snoc_clk_deinit(ar); - ret = ath10k_snoc_vreg_off(ar); - - return ret; + return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); } static const struct of_device_id ath10k_snoc_dt_match[] = { @@ -1691,12 +1545,20 @@ static int ath10k_snoc_probe(struct platform_device *pdev) goto err_release_resource; } - ar_snoc->vreg = vreg_cfg; - for (i = 0; i < ARRAY_SIZE(vreg_cfg); i++) { - ret = ath10k_get_vreg_info(ar, dev, &ar_snoc->vreg[i]); - if (ret) - goto err_free_irq; + ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators); + ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs, + sizeof(*ar_snoc->vregs), GFP_KERNEL); + if (!ar_snoc->vregs) { + ret = -ENOMEM; + goto err_free_irq; } + for (i = 0; i < ar_snoc->num_vregs; i++) + ar_snoc->vregs[i].supply = ath10k_regulators[i]; + + ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs, + ar_snoc->vregs); + if (ret < 0) + goto err_free_irq; ar_snoc->clk = clk_cfg; for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 1bf7bd4ef2a3..3965ddf66d74 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -42,14 +42,6 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; -struct ath10k_vreg_info { - struct regulator *reg; - const char *name; - u32 load_ua; - unsigned long settle_delay; - bool required; -}; - struct ath10k_clk_info { struct clk *handle; const char *name; @@ -64,6 +56,8 @@ enum ath10k_snoc_flags { ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, }; +struct regulator_bulk_data; + struct ath10k_snoc { struct platform_device *dev; struct ath10k *ar; @@ -75,7 +69,8 @@ struct ath10k_snoc { struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX]; struct ath10k_ce ce; struct timer_list rx_post_retry; - struct ath10k_vreg_info *vreg; + struct regulator_bulk_data *vregs; + size_t num_vregs; struct ath10k_clk_info *clk; struct ath10k_qmi *qmi; unsigned long flags; -- cgit v1.2.3-59-g8ed1b From f93bcf0ce6a144174292716f9a79330567a778b6 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 25 Jul 2019 10:47:55 -0700 Subject: ath10k: Use standard bulk clock API in snoc No frequency is currently specified for the single clock defined in the snoc driver, so the clock wrappers reimplements the standard bulk API provided by the clock framework. Change to this. The single clock defined is marked as optional so this version of the get API is used, but might need to be reconsidered in the future. Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 125 +++++---------------------------- drivers/net/wireless/ath/ath10k/snoc.h | 11 +-- 2 files changed, 21 insertions(+), 115 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 1c9ff7e53e2f..80ce68c0f75e 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -43,8 +43,8 @@ static const char * const ath10k_regulators[] = { "vdd-3.3-ch0", }; -static struct ath10k_clk_info clk_cfg[] = { - {NULL, "cxo_ref_clk_pin", 0, false}, +static const char * const ath10k_clocks[] = { + "cxo_ref_clk_pin", }; static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state); @@ -1346,104 +1346,6 @@ static void ath10k_snoc_release_resource(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } -static int ath10k_get_clk_info(struct ath10k *ar, struct device *dev, - struct ath10k_clk_info *clk_info) -{ - struct clk *handle; - int ret = 0; - - handle = devm_clk_get(dev, clk_info->name); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - if (clk_info->required) { - ath10k_err(ar, "snoc clock %s isn't available: %d\n", - clk_info->name, ret); - return ret; - } - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc ignoring clock %s: %d\n", - clk_info->name, - ret); - return 0; - } - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s freq %u\n", - clk_info->name, clk_info->freq); - - clk_info->handle = handle; - - return ret; -} - -static int ath10k_snoc_clk_init(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_clk_info *clk_info; - int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being enabled\n", - clk_info->name); - - if (clk_info->freq) { - ret = clk_set_rate(clk_info->handle, clk_info->freq); - - if (ret) { - ath10k_err(ar, "failed to set clock %s freq %u\n", - clk_info->name, clk_info->freq); - goto err_clock_config; - } - } - - ret = clk_prepare_enable(clk_info->handle); - if (ret) { - ath10k_err(ar, "failed to enable clock %s\n", - clk_info->name); - goto err_clock_config; - } - } - - return 0; - -err_clock_config: - for (i = i - 1; i >= 0; i--) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - clk_disable_unprepare(clk_info->handle); - } - - return ret; -} - -static int ath10k_snoc_clk_deinit(struct ath10k *ar) -{ - struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); - struct ath10k_clk_info *clk_info; - int i; - - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - clk_info = &ar_snoc->clk[i]; - - if (!clk_info->handle) - continue; - - ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc clock %s being disabled\n", - clk_info->name); - - clk_disable_unprepare(clk_info->handle); - } - - return 0; -} - static int ath10k_hw_power_on(struct ath10k *ar) { struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); @@ -1455,7 +1357,7 @@ static int ath10k_hw_power_on(struct ath10k *ar) if (ret) return ret; - ret = ath10k_snoc_clk_init(ar); + ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks); if (ret) goto vreg_off; @@ -1472,7 +1374,7 @@ static int ath10k_hw_power_off(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n"); - ath10k_snoc_clk_deinit(ar); + clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks); return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); } @@ -1560,13 +1462,22 @@ static int ath10k_snoc_probe(struct platform_device *pdev) if (ret < 0) goto err_free_irq; - ar_snoc->clk = clk_cfg; - for (i = 0; i < ARRAY_SIZE(clk_cfg); i++) { - ret = ath10k_get_clk_info(ar, dev, &ar_snoc->clk[i]); - if (ret) - goto err_free_irq; + ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks); + ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks, + sizeof(*ar_snoc->clks), GFP_KERNEL); + if (!ar_snoc->clks) { + ret = -ENOMEM; + goto err_free_irq; } + for (i = 0; i < ar_snoc->num_clks; i++) + ar_snoc->clks[i].id = ath10k_clocks[i]; + + ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks, + ar_snoc->clks); + if (ret) + goto err_free_irq; + ret = ath10k_hw_power_on(ar); if (ret) { ath10k_err(ar, "failed to power on device: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index 3965ddf66d74..d2449a3b4a8f 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -42,13 +42,6 @@ struct ath10k_snoc_ce_irq { u32 irq_line; }; -struct ath10k_clk_info { - struct clk *handle; - const char *name; - u32 freq; - bool required; -}; - enum ath10k_snoc_flags { ATH10K_SNOC_FLAG_REGISTERED, ATH10K_SNOC_FLAG_UNREGISTERING, @@ -56,6 +49,7 @@ enum ath10k_snoc_flags { ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, }; +struct clk_bulk_data; struct regulator_bulk_data; struct ath10k_snoc { @@ -71,7 +65,8 @@ struct ath10k_snoc { struct timer_list rx_post_retry; struct regulator_bulk_data *vregs; size_t num_vregs; - struct ath10k_clk_info *clk; + struct clk_bulk_data *clks; + size_t num_clks; struct ath10k_qmi *qmi; unsigned long flags; }; -- cgit v1.2.3-59-g8ed1b From 0227ff3656f2c68b44002de0a17cec56cbdac631 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 3 Jul 2019 16:19:49 +0200 Subject: ath10k: avoid leaving .bss_info_changed prematurely ath10k_bss_info_changed() handles various events from the upper layers. It parses the changed bitfield and then configures the driver/firmware accordingly. Each detected event is handled in a separate scope which is independent of each other - but in the same function. The commit f279294e9ee2 ("ath10k: add support for configuring management packet rate") changed this behavior by returning from this function prematurely when some precondition was not fulfilled. All new event handlers added after the BSS_CHANGED_BASIC_RATES event handler would then also be skipped. Signed-off-by: Sven Eckelmann Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 62 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a6d21856b7e7..ba167f4356cf 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5635,6 +5635,37 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static void ath10k_recalculate_mgmt_rate(struct ath10k *ar, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *def) +{ + struct ath10k_vif *arvif = (void *)vif->drv_priv; + const struct ieee80211_supported_band *sband; + u8 basic_rate_idx; + int hw_rate_code; + u32 vdev_param; + u16 bitrate; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + sband = ar->hw->wiphy->bands[def->chan->band]; + basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; + bitrate = sband->bitrates[basic_rate_idx].bitrate; + + hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); + if (hw_rate_code < 0) { + ath10k_warn(ar, "bitrate not supported %d\n", bitrate); + return; + } + + vdev_param = ar->wmi.vdev_param->mgmt_rate; + ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, + hw_rate_code); + if (ret) + ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); +} + static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -5645,10 +5676,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, struct cfg80211_chan_def def; u32 vdev_param, pdev_param, slottime, preamble; u16 bitrate, hw_value; - u8 rate, basic_rate_idx, rateidx; - int ret = 0, hw_rate_code, mcast_rate; + u8 rate, rateidx; + int ret = 0, mcast_rate; enum nl80211_band band; - const struct ieee80211_supported_band *sband; mutex_lock(&ar->conf_mutex); @@ -5872,29 +5902,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->vdev_id, ret); } - if (changed & BSS_CHANGED_BASIC_RATES) { - if (ath10k_mac_vif_chan(vif, &def)) { - mutex_unlock(&ar->conf_mutex); - return; - } - - sband = ar->hw->wiphy->bands[def.chan->band]; - basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; - bitrate = sband->bitrates[basic_rate_idx].bitrate; - - hw_rate_code = ath10k_mac_get_rate_hw_value(bitrate); - if (hw_rate_code < 0) { - ath10k_warn(ar, "bitrate not supported %d\n", bitrate); - mutex_unlock(&ar->conf_mutex); - return; - } - - vdev_param = ar->wmi.vdev_param->mgmt_rate; - ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, - hw_rate_code); - if (ret) - ath10k_warn(ar, "failed to set mgmt tx rate %d\n", ret); - } + if (changed & BSS_CHANGED_BASIC_RATES && + !ath10k_mac_vif_chan(arvif->vif, &def)) + ath10k_recalculate_mgmt_rate(ar, vif, &def); mutex_unlock(&ar->conf_mutex); } -- cgit v1.2.3-59-g8ed1b From 7921ae0919078292bfa88adb812ad7cfb621f977 Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Thu, 18 Jul 2019 22:30:32 +0200 Subject: ath10k: Use ARRAY_SIZE fix coccinelle warning, use ARRAY_SIZE Signed-off-by: Vasyl Gomonovych Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 80ce68c0f75e..13ee97edf6df 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -976,8 +976,7 @@ static int ath10k_snoc_wlan_enable(struct ath10k *ar, sizeof(struct ath10k_svc_pipe_cfg); cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *) &target_service_to_ce_map_wlan; - cfg.num_shadow_reg_cfg = sizeof(target_shadow_reg_cfg_map) / - sizeof(struct ath10k_shadow_reg_cfg); + cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map); cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *) &target_shadow_reg_cfg_map; -- cgit v1.2.3-59-g8ed1b From 9c44bf4c12550f1c3c1be0671e559477e70ab350 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Sun, 28 Jul 2019 11:11:58 +0200 Subject: ath10k: use ath10k_pci_soc_ functions for all warm_reset instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use ath10k_pci_soc_read32 / ath10k_pci_soc_write32 functions for the rest of warm_reset functions. Until now these have been used only for ath10k_pci_warm_reset_si0, but since they already exist it makes sense to simplify code a bit. Runtime tested with QCA9862. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a0b4d265c6eb..bc3dc79de01a 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2567,35 +2567,31 @@ static void ath10k_pci_warm_reset_cpu(struct ath10k *ar) ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); } static void ath10k_pci_warm_reset_ce(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); + val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CE_RST_MASK); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CE_RST_MASK); msleep(10); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val & ~SOC_RESET_CONTROL_CE_RST_MASK); + ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_CE_RST_MASK); } static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_LF_TIMER_CONTROL0_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + - SOC_LF_TIMER_CONTROL0_ADDRESS, - val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); + val = ath10k_pci_soc_read32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS); + ath10k_pci_soc_write32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS, + val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); } static int ath10k_pci_warm_reset(struct ath10k *ar) -- cgit v1.2.3-59-g8ed1b From c41305993ff5a399775da54232b30ff2d6c9576e Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 31 Jul 2019 17:12:20 +0530 Subject: ath10k: revalidate the msa region coming from firmware driver sends QMI_WLFW_MSA_INFO_REQ_V01 QMI request to firmware and in response expects range of addresses and size to be mapped. Add condition to check whether addresses in response falls under valid range otherwise return failure. Testing: Tested on WCN3990 HW Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/qmi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 545ac1f06997..44ad009f8e2e 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -111,6 +111,7 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) struct wlfw_msa_info_resp_msg_v01 resp = {}; struct wlfw_msa_info_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + phys_addr_t max_mapped_addr; struct qmi_txn txn; int ret; int i; @@ -150,8 +151,20 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) goto out; } + max_mapped_addr = qmi->msa_pa + qmi->msa_mem_size; qmi->nr_mem_region = resp.mem_region_info_len; for (i = 0; i < resp.mem_region_info_len; i++) { + if (resp.mem_region_info[i].size > qmi->msa_mem_size || + resp.mem_region_info[i].region_addr > max_mapped_addr || + resp.mem_region_info[i].region_addr < qmi->msa_pa || + resp.mem_region_info[i].size + + resp.mem_region_info[i].region_addr > max_mapped_addr) { + ath10k_err(ar, "received out of range memory region address 0x%llx with size 0x%x, aborting\n", + resp.mem_region_info[i].region_addr, + resp.mem_region_info[i].size); + ret = -EINVAL; + goto fail_unwind; + } qmi->mem_region[i].addr = resp.mem_region_info[i].region_addr; qmi->mem_region[i].size = resp.mem_region_info[i].size; qmi->mem_region[i].secure = resp.mem_region_info[i].secure_flag; @@ -165,6 +178,8 @@ static int ath10k_qmi_msa_mem_info_send_sync_msg(struct ath10k_qmi *qmi) ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa mem info request completed\n"); return 0; +fail_unwind: + memset(&qmi->mem_region[0], 0, sizeof(qmi->mem_region[0]) * i); out: return ret; } -- cgit v1.2.3-59-g8ed1b From 334f5b61a6f29834e881923b98d1e27e5ce9620d Mon Sep 17 00:00:00 2001 From: Wenwen Wang Date: Thu, 15 Aug 2019 16:04:31 -0500 Subject: ath10k: add cleanup in ath10k_sta_state() If 'sta->tdls' is false, no cleanup is executed, leading to memory/resource leaks, e.g., 'arsta->tx_stats'. To fix this issue, perform cleanup before go to the 'exit' label. Signed-off-by: Wenwen Wang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ba167f4356cf..578d1c06ed87 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6559,8 +6559,12 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); - if (!sta->tdls) + if (!sta->tdls) { + ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); + ath10k_mac_dec_num_stations(arvif, sta); + kfree(arsta->tx_stats); goto exit; + } ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, WMI_TDLS_ENABLE_ACTIVE); -- cgit v1.2.3-59-g8ed1b From 1340cc631bd00431e2f174525c971f119df9efa1 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Thu, 29 Aug 2019 10:45:12 +0800 Subject: ath10k: fix latency issue for QCA988x Bad latency is found on QCA988x, the issue was introduced by commit 4504f0e5b571 ("ath10k: sdio: workaround firmware UART pin configuration bug"). If uart_pin_workaround is false, this change will set uart pin even if uart_print is false. Tested HW: QCA9880 Tested FW: 10.2.4-1.0-00037 Fixes: 4504f0e5b571 ("ath10k: sdio: workaround firmware UART pin configuration bug") Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index dc45d16e8d21..383d4fa555a8 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2118,12 +2118,15 @@ static int ath10k_init_uart(struct ath10k *ar) return ret; } - if (!uart_print && ar->hw_params.uart_pin_workaround) { - ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, - ar->hw_params.uart_pin); - if (ret) { - ath10k_warn(ar, "failed to set UART TX pin: %d", ret); - return ret; + if (!uart_print) { + if (ar->hw_params.uart_pin_workaround) { + ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, + ar->hw_params.uart_pin); + if (ret) { + ath10k_warn(ar, "failed to set UART TX pin: %d", + ret); + return ret; + } } return 0; -- cgit v1.2.3-59-g8ed1b From 09764659003d9e208b8f558d164c8f5005b43ab7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 13 Sep 2019 08:43:39 +0100 Subject: ath10k: fix spelling mistake "eanble" -> "enable" There is a spelling mistake in a ath10k_warn warning message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 578d1c06ed87..f7a318e7198d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7433,7 +7433,7 @@ static bool ath10k_mac_set_vht_bitrate_mask_fixup(struct ath10k *ar, err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, WMI_PEER_PARAM_FIXED_RATE, rate); if (err) - ath10k_warn(ar, "failed to eanble STA %pM peer fixed rate: %d\n", + ath10k_warn(ar, "failed to enable STA %pM peer fixed rate: %d\n", sta->addr, err); return true; -- cgit v1.2.3-59-g8ed1b From 75f545e8574419a0f034e5a0b8b39fb8b8e88271 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 18 Sep 2019 16:27:35 +0300 Subject: ath10k: Add xo calibration support for wifi rf clock PMIC XO is the clock source for wifi rf clock in integrated wifi chipset ex: WCN3990. Due to board layout errors XO frequency drifts can cause wifi rf clock inaccuracy. XO calibration test tree in Factory Test Mode is used to find the best frequency offset(for example +/-2KHz )by programming XO trim register. This ensure system clock stays within required 20 ppm WLAN rf clock. Retrieve the xo trim offset via system firmware (e.g., device tree), especially in the case where the device doesn't have a useful EEPROM on which to store the calibrated XO offset (e.g., for integrated Wifi). Calibrated XO offset is sent to fw, which compensate the clock drift by programing the XO trim register. Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/qmi.c | 12 ++++++++++++ drivers/net/wireless/ath/ath10k/snoc.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/snoc.h | 2 ++ 3 files changed, 25 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 44ad009f8e2e..59e15c946db8 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -306,10 +306,16 @@ static int ath10k_qmi_send_cal_report_req(struct ath10k_qmi *qmi) struct wlfw_cal_report_resp_msg_v01 resp = {}; struct wlfw_cal_report_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int i, j = 0; int ret; + if (ar_snoc->xo_cal_supported) { + req.xo_cal_data_valid = 1; + req.xo_cal_data = ar_snoc->xo_cal_data; + } + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_cal_report_resp_msg_v01_ei, &resp); if (ret < 0) @@ -693,6 +699,7 @@ ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) struct wlfw_ind_register_resp_msg_v01 resp = {}; struct wlfw_ind_register_req_msg_v01 req = {}; struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct qmi_txn txn; int ret; @@ -703,6 +710,11 @@ ath10k_qmi_ind_register_send_sync_msg(struct ath10k_qmi *qmi) req.msa_ready_enable_valid = 1; req.msa_ready_enable = 1; + if (ar_snoc->xo_cal_supported) { + req.xo_cal_enable_valid = 1; + req.xo_cal_enable = 1; + } + ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_ind_register_resp_msg_v01_ei, &resp); if (ret < 0) diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 13ee97edf6df..c8c92906a178 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include "ce.h" @@ -1256,6 +1257,16 @@ static int ath10k_snoc_resource_init(struct ath10k *ar) ar_snoc->ce_irqs[i].irq_line = res->start; } + ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data", + &ar_snoc->xo_cal_data); + ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret); + if (ret == 0) { + ar_snoc->xo_cal_supported = true; + ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n", + ar_snoc->xo_cal_data); + } + ret = 0; + out: return ret; } diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index d2449a3b4a8f..bc2b925b1d5a 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -69,6 +69,8 @@ struct ath10k_snoc { size_t num_clks; struct ath10k_qmi *qmi; unsigned long flags; + bool xo_cal_supported; + u32 xo_cal_data; }; static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) -- cgit v1.2.3-59-g8ed1b From 3f14b73c38431a6a1ed24de568e18ed89b7082e2 Mon Sep 17 00:00:00 2001 From: Govind Singh Date: Wed, 18 Sep 2019 16:27:49 +0300 Subject: ath10k: Enable MSA region dump support for WCN3990 MSA memory region caries the hw descriptors information. Dump MSA region in core dump as this is very helpful in debugging hw issues. Testing: Tested on WCN3990 HW Tested FW: WLAN.HL.3.1-00959-QCAHLSWMTPLZ-1 Signed-off-by: Govind Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/coredump.c | 21 ++++++++++ drivers/net/wireless/ath/ath10k/coredump.h | 1 + drivers/net/wireless/ath/ath10k/qmi.c | 4 ++ drivers/net/wireless/ath/ath10k/snoc.c | 66 ++++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/snoc.h | 1 + 5 files changed, 93 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index b6d2932383cf..de0926c61ee7 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -951,6 +951,19 @@ static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = { }, }; +static const struct ath10k_mem_region wcn399x_hw10_mem_regions[] = { + { + /* MSA region start is not fixed, hence it is assigned at runtime */ + .type = ATH10K_MEM_REGION_TYPE_MSA, + .len = 0x100000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, @@ -1048,6 +1061,14 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca4019_hw10_mem_regions), }, }, + { + .hw_id = WCN3990_HW_1_0_DEV_VERSION, + .hw_rev = ATH10K_HW_WCN3990, + .region_table = { + .regions = wcn399x_hw10_mem_regions, + .size = ARRAY_SIZE(wcn399x_hw10_mem_regions), + }, + }, }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 09de41922f97..8bf03e8c1d3a 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -115,6 +115,7 @@ enum ath10k_mem_region_type { ATH10K_MEM_REGION_TYPE_IRAM2 = 5, ATH10K_MEM_REGION_TYPE_IOSRAM = 6, ATH10K_MEM_REGION_TYPE_IOREG = 7, + ATH10K_MEM_REGION_TYPE_MSA = 8, }; /* Define a section of the region which should be copied. As not all parts diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 59e15c946db8..fbc2e4ffc12b 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -829,9 +829,13 @@ ath10k_qmi_driver_event_post(struct ath10k_qmi *qmi, static void ath10k_qmi_event_server_exit(struct ath10k_qmi *qmi) { struct ath10k *ar = qmi->ar; + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); ath10k_qmi_remove_msa_permission(qmi); ath10k_core_free_board_files(ar); + if (!test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags)) + ath10k_snoc_fw_crashed_dump(ar); + ath10k_snoc_fw_indication(ar, ATH10K_QMI_EVENT_FW_DOWN_IND); ath10k_dbg(ar, ATH10K_DBG_QMI, "wifi fw qmi service disconnected\n"); } diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index c8c92906a178..cd22c8654aa9 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -13,6 +13,7 @@ #include #include "ce.h" +#include "coredump.h" #include "debug.h" #include "hif.h" #include "htc.h" @@ -1389,6 +1390,71 @@ static int ath10k_hw_power_off(struct ath10k *ar) return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs); } +static void ath10k_msa_dump_memory(struct ath10k *ar, + struct ath10k_fw_crash_data *crash_data) +{ + struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); + const struct ath10k_hw_mem_layout *mem_layout; + const struct ath10k_mem_region *current_region; + struct ath10k_dump_ram_data_hdr *hdr; + size_t buf_len; + u8 *buf; + + if (!crash_data && !crash_data->ramdump_buf) + return; + + mem_layout = ath10k_coredump_get_mem_layout(ar); + if (!mem_layout) + return; + + current_region = &mem_layout->region_table.regions[0]; + + buf = crash_data->ramdump_buf; + buf_len = crash_data->ramdump_buf_len; + memset(buf, 0, buf_len); + + /* Reserve space for the header. */ + hdr = (void *)buf; + buf += sizeof(*hdr); + buf_len -= sizeof(*hdr); + + hdr->region_type = cpu_to_le32(current_region->type); + hdr->start = cpu_to_le32((unsigned long)ar_snoc->qmi->msa_va); + hdr->length = cpu_to_le32(ar_snoc->qmi->msa_mem_size); + + if (current_region->len < ar_snoc->qmi->msa_mem_size) { + memcpy(buf, ar_snoc->qmi->msa_va, current_region->len); + ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n", + current_region->len, ar_snoc->qmi->msa_mem_size); + } else { + memcpy(buf, ar_snoc->qmi->msa_va, ar_snoc->qmi->msa_mem_size); + } +} + +void ath10k_snoc_fw_crashed_dump(struct ath10k *ar) +{ + struct ath10k_fw_crash_data *crash_data; + char guid[UUID_STRING_LEN + 1]; + + mutex_lock(&ar->dump_mutex); + + spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; + spin_unlock_bh(&ar->data_lock); + + crash_data = ath10k_coredump_new(ar); + + if (crash_data) + scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); + else + scnprintf(guid, sizeof(guid), "n/a"); + + ath10k_err(ar, "firmware crashed! (guid %s)\n", guid); + ath10k_print_driver_info(ar); + ath10k_msa_dump_memory(ar, crash_data); + mutex_unlock(&ar->dump_mutex); +} + static const struct of_device_id ath10k_snoc_dt_match[] = { { .compatible = "qcom,wcn3990-wifi", .data = &drv_priv, diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h index bc2b925b1d5a..c05df45a3945 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.h +++ b/drivers/net/wireless/ath/ath10k/snoc.h @@ -79,5 +79,6 @@ static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar) } int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type); +void ath10k_snoc_fw_crashed_dump(struct ath10k *ar); #endif /* _SNOC_H_ */ -- cgit v1.2.3-59-g8ed1b From c0e33fe6fb0fe392ebfab14127d210679c413192 Mon Sep 17 00:00:00 2001 From: Rakesh Pillai Date: Tue, 19 Feb 2019 11:39:36 +0530 Subject: ath10k: Add peer param map for tlv and non-tlv The peer param id for PEER_PARAM_USE_FIXED_PWR is different for tlv and non-tlv firmware. This causes incorrect peer param to be set by the driver to the firmware(tlv/non-tlv). Create seperate peer param map for tlv and non-tlv firmware and attach the peer param id based on the firmware type during the init. Tested HW: WCN3990 Tested FW: WLAN.HL.3.1-00784-QCAHLSWMTPLZ-1 Signed-off-by: Rakesh Pillai Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/debugfs_sta.c | 2 +- drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++-------- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 19 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 19 +++++++++++++++++++ 7 files changed, 84 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 4d7db07db6ba..c96d1a17fd00 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -169,6 +169,7 @@ struct ath10k_wmi { struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; + struct wmi_peer_param_map *peer_param; const struct wmi_ops *ops; const struct wmi_peer_flags_map *peer_flags; diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 42931a669b02..367539f2c370 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -430,7 +430,7 @@ ath10k_dbg_sta_write_peer_debug_trigger(struct file *file, } ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr, - WMI_PEER_DEBUG, peer_debug_trigger); + ar->wmi.peer_param->debug, peer_debug_trigger); if (ret) { ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index f7a318e7198d..02ca34b6f1aa 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2773,7 +2773,7 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, return -EINVAL; return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr, - WMI_PEER_SMPS_STATE, + ar->wmi.peer_param->smps_state, ath10k_smps_map[smps]); } @@ -2930,7 +2930,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, * poked with peer param command. */ ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid, - WMI_PEER_DUMMY_VAR, 1); + ar->wmi.peer_param->dummy_var, 1); if (ret) { ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n", arvif->bssid, arvif->vdev_id, ret); @@ -6249,7 +6249,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (sta && sta->tdls) ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_AUTHORIZE, 1); + ar->wmi.peer_param->authorize, 1); exit: mutex_unlock(&ar->conf_mutex); @@ -6340,7 +6340,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, bw, mode); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_PHYMODE, mode); + ar->wmi.peer_param->phymode, mode); if (err) { ath10k_warn(ar, "failed to update STA %pM peer phymode %d: %d\n", sta->addr, mode, err); @@ -6348,7 +6348,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) } err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_CHAN_WIDTH, bw); + ar->wmi.peer_param->chan_width, bw); if (err) ath10k_warn(ar, "failed to update STA %pM peer bw %d: %d\n", sta->addr, bw, err); @@ -6359,7 +6359,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, nss); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_NSS, nss); + ar->wmi.peer_param->nss, nss); if (err) ath10k_warn(ar, "failed to update STA %pM nss %d: %d\n", sta->addr, nss, err); @@ -6370,7 +6370,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps); err = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_SMPS_STATE, smps); + ar->wmi.peer_param->smps_state, smps); if (err) ath10k_warn(ar, "failed to update STA %pM smps %d: %d\n", sta->addr, smps, err); @@ -6444,7 +6444,7 @@ static int ath10k_sta_set_txpwr(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, - WMI_PEER_USE_FIXED_PWR, txpwr); + ar->wmi.peer_param->use_fixed_power, txpwr); if (ret) { ath10k_warn(ar, "failed to set tx power for station ret: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 4d5d10c01064..0ca8f9cb4f68 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -4206,6 +4206,24 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; +static struct wmi_peer_param_map wmi_tlv_peer_param_map = { + .smps_state = WMI_TLV_PEER_SMPS_STATE, + .ampdu = WMI_TLV_PEER_AMPDU, + .authorize = WMI_TLV_PEER_AUTHORIZE, + .chan_width = WMI_TLV_PEER_CHAN_WIDTH, + .nss = WMI_TLV_PEER_NSS, + .use_4addr = WMI_TLV_PEER_USE_4ADDR, + .membership = WMI_TLV_PEER_MEMBERSHIP, + .user_pos = WMI_TLV_PEER_USERPOS, + .crit_proto_hint_enabled = WMI_TLV_PEER_CRIT_PROTO_HINT_ENABLED, + .tx_fail_cnt_thr = WMI_TLV_PEER_TX_FAIL_CNT_THR, + .set_hw_retry_cts2s = WMI_TLV_PEER_SET_HW_RETRY_CTS2S, + .ibss_atim_win_len = WMI_TLV_PEER_IBSS_ATIM_WINDOW_LENGTH, + .phymode = WMI_TLV_PEER_PHYMODE, + .use_fixed_power = WMI_TLV_PEER_USE_FIXED_PWR, + .dummy_var = WMI_TLV_PEER_DUMMY_VAR, +}; + static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD, .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD, @@ -4394,6 +4412,7 @@ void ath10k_wmi_tlv_attach(struct ath10k *ar) ar->wmi.cmd = &wmi_tlv_cmd_map; ar->wmi.vdev_param = &wmi_tlv_vdev_param_map; ar->wmi.pdev_param = &wmi_tlv_pdev_param_map; + ar->wmi.peer_param = &wmi_tlv_peer_param_map; ar->wmi.ops = &wmi_tlv_ops; ar->wmi.peer_flags = &wmi_tlv_peer_flags_map; } diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 649b229a41e9..0b7cb011cb19 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -528,6 +528,24 @@ enum wmi_tlv_vdev_param { WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, }; +enum wmi_tlv_peer_param { + WMI_TLV_PEER_SMPS_STATE = 0x1, /* see %wmi_peer_smps_state */ + WMI_TLV_PEER_AMPDU = 0x2, + WMI_TLV_PEER_AUTHORIZE = 0x3, + WMI_TLV_PEER_CHAN_WIDTH = 0x4, + WMI_TLV_PEER_NSS = 0x5, + WMI_TLV_PEER_USE_4ADDR = 0x6, + WMI_TLV_PEER_MEMBERSHIP = 0x7, + WMI_TLV_PEER_USERPOS = 0x8, + WMI_TLV_PEER_CRIT_PROTO_HINT_ENABLED = 0x9, + WMI_TLV_PEER_TX_FAIL_CNT_THR = 0xa, + WMI_TLV_PEER_SET_HW_RETRY_CTS2S = 0xb, + WMI_TLV_PEER_IBSS_ATIM_WINDOW_LENGTH = 0xc, + WMI_TLV_PEER_PHYMODE = 0xd, + WMI_TLV_PEER_USE_FIXED_PWR = 0xe, + WMI_TLV_PEER_DUMMY_VAR = 0xff, +}; + enum wmi_tlv_peer_flags { WMI_TLV_PEER_AUTH = 0x00000001, WMI_TLV_PEER_QOS = 0x00000002, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 4f707c6394bb..1ec609d359dd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -742,6 +742,19 @@ static struct wmi_cmd_map wmi_10_4_cmd_map = { .radar_found_cmdid = WMI_10_4_RADAR_FOUND_CMDID, }; +static struct wmi_peer_param_map wmi_peer_param_map = { + .smps_state = WMI_PEER_SMPS_STATE, + .ampdu = WMI_PEER_AMPDU, + .authorize = WMI_PEER_AUTHORIZE, + .chan_width = WMI_PEER_CHAN_WIDTH, + .nss = WMI_PEER_NSS, + .use_4addr = WMI_PEER_USE_4ADDR, + .use_fixed_power = WMI_PEER_USE_FIXED_PWR, + .debug = WMI_PEER_DEBUG, + .phymode = WMI_PEER_PHYMODE, + .dummy_var = WMI_PEER_DUMMY_VAR, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -9332,6 +9345,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9340,6 +9354,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_2_4_ops; ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map; ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9348,6 +9363,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_2_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10_2_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9356,6 +9372,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_1_ops; ar->wmi.vdev_param = &wmi_10x_vdev_param_map; ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_10x_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; @@ -9364,6 +9381,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_ops; ar->wmi.vdev_param = &wmi_vdev_param_map; ar->wmi.pdev_param = &wmi_pdev_param_map; + ar->wmi.peer_param = &wmi_peer_param_map; ar->wmi.peer_flags = &wmi_peer_flags_map; ar->wmi_key_cipher = wmi_key_cipher_suites; break; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index e80dbe7e8f4c..fc95c0c460ac 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5071,6 +5071,25 @@ enum wmi_rate_preamble { /* Value to disable fixed rate setting */ #define WMI_FIXED_RATE_NONE (0xff) +struct wmi_peer_param_map { + u32 smps_state; + u32 ampdu; + u32 authorize; + u32 chan_width; + u32 nss; + u32 use_4addr; + u32 membership; + u32 use_fixed_power; + u32 user_pos; + u32 crit_proto_hint_enabled; + u32 tx_fail_cnt_thr; + u32 set_hw_retry_cts2s; + u32 ibss_atim_win_len; + u32 debug; + u32 phymode; + u32 dummy_var; +}; + struct wmi_vdev_param_map { u32 rts_threshold; u32 fragmentation_threshold; -- cgit v1.2.3-59-g8ed1b From 40f4ef5e92326ab127bdeb6f024855c8c91de608 Mon Sep 17 00:00:00 2001 From: Surabhi Vishnoi Date: Mon, 25 Feb 2019 18:18:46 +0530 Subject: ath10k: Add support to provide higher range mem chunks in wmi init command With the current implementation of wmi init command, there is no provision for the host driver to provide mem chunks addresses with more than 32-bit, to the firmware. WCN3990 is a 35-bit target and can accept mem chunks addresses which are above 32-bit. If firmware supports address range more than 32 bit, it advertises the support by setting the WMI_SERVICE_EXTEND_ADDRESS service. Based on this service fill the upper bits of paddr while providing the mem chunks in the wmi init command. Tested HW: WCN3990 Tested FW: WLAN.HL.3.1-00784-QCAHLSWMTPLZ-1 Signed-off-by: Surabhi Vishnoi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 11 +++++++++-- drivers/net/wireless/ath/ath10k/wmi-tlv.h | 23 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 2 ++ 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 0ca8f9cb4f68..363fd0bd1e2d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1649,8 +1649,9 @@ ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id, static void ath10k_wmi_tlv_put_host_mem_chunks(struct ath10k *ar, void *host_mem_chunks) { - struct host_memory_chunk *chunk; + struct host_memory_chunk_tlv *chunk; struct wmi_tlv *tlv; + dma_addr_t paddr; int i; __le16 tlv_len, tlv_tag; @@ -1666,6 +1667,12 @@ ath10k_wmi_tlv_put_host_mem_chunks(struct ath10k *ar, void *host_mem_chunks) chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len); chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + if (test_bit(WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, + ar->wmi.svc_map)) { + paddr = ar->wmi.mem_chunks[i].paddr; + chunk->ptr_high = __cpu_to_le32(upper_32_bits(paddr)); + } + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi-tlv chunk %d len %d, addr 0x%llx, id 0x%x\n", i, @@ -1689,7 +1696,7 @@ static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar) void *ptr; chunks_len = ar->wmi.num_mem_chunks * - (sizeof(struct host_memory_chunk) + sizeof(*tlv)); + (sizeof(struct host_memory_chunk_tlv) + sizeof(*tlv)); len = (sizeof(*tlv) + sizeof(*cmd)) + (sizeof(*tlv) + sizeof(*cfg)) + (sizeof(*tlv) + chunks_len); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 0b7cb011cb19..5a85f2eedfe0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1427,6 +1427,11 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WLAN_HPCS_PULSE = 172, WMI_TLV_SERVICE_PER_VDEV_CHAINMASK_CONFIG_SUPPORT = 173, WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI = 174, + WMI_TLV_SERVICE_NAN_DISABLE_SUPPORT = 175, + WMI_TLV_SERVICE_HTT_H2T_NO_HTC_HDR_LEN_IN_MSG_LEN = 176, + WMI_TLV_SERVICE_COEX_SUPPORT_UNEQUAL_ISOLATION = 177, + WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT = 178, + WMI_TLV_SERVICE_SUPPORT_EXTEND_ADDRESS = 179, WMI_TLV_MAX_EXT_SERVICE = 256, }; @@ -1606,6 +1611,9 @@ wmi_tlv_svc_map_ext(const __le32 *in, unsigned long *out, size_t len) WMI_TLV_MAX_SERVICE); SVCMAP(WMI_TLV_SERVICE_TX_DATA_MGMT_ACK_RSSI, WMI_SERVICE_TX_DATA_ACK_RSSI, WMI_TLV_MAX_SERVICE); + SVCMAP(WMI_TLV_SERVICE_SUPPORT_EXTEND_ADDRESS, + WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, + WMI_TLV_MAX_SERVICE); } #undef SVCMAP @@ -1761,6 +1769,21 @@ struct wmi_tlv_resource_config { __le32 host_capab; } __packed; +/* structure describing host memory chunk. */ +struct host_memory_chunk_tlv { + /* id of the request that is passed up in service ready */ + __le32 req_id; + + /* the physical address the memory chunk */ + __le32 ptr; + + /* size of the chunk */ + __le32 size; + + /* the upper 32 bit address valid only for more than 32 bit target */ + __le32 ptr_high; +} __packed; + struct wmi_tlv_init_cmd { struct wmi_tlv_abi_version abi; __le32 num_host_mem_chunks; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index fc95c0c460ac..bdeebc5b84b4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -202,6 +202,7 @@ enum wmi_service { WMI_SERVICE_REPORT_AIRTIME, WMI_SERVICE_SYNC_DELETE_CMDS, WMI_SERVICE_TX_PWR_PER_PEER, + WMI_SERVICE_SUPPORT_EXTEND_ADDRESS, /* Remember to add the new value to wmi_service_name()! */ @@ -496,6 +497,7 @@ static inline char *wmi_service_name(enum wmi_service service_id) SVCSTR(WMI_SERVICE_REPORT_AIRTIME); SVCSTR(WMI_SERVICE_SYNC_DELETE_CMDS); SVCSTR(WMI_SERVICE_TX_PWR_PER_PEER); + SVCSTR(WMI_SERVICE_SUPPORT_EXTEND_ADDRESS); case WMI_SERVICE_MAX: return NULL; -- cgit v1.2.3-59-g8ed1b From 8da96730331dab78e7194c5af48efbcf90264d02 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 15 Mar 2019 00:19:03 -0500 Subject: ath10k: fix missing checks for bmi reads and writes ath10k_bmi_write32 and ath10k_bmi_read32 can fail. The fix checks their statuses to avoid potential undefined behaviors. Signed-off-by: Kangjie Lu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 41 ++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 383d4fa555a8..3d91a4025cfc 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -677,13 +677,22 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) complete(&ar->target_suspend); } -static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) +static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) { + int ret; u32 param = 0; - ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); - ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); - ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); + if (ret) + return ret; + + ret = ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); + if (ret) + return ret; + + ret = ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + if (ret) + return ret; /* Data transfer is not initiated, when reduced Tx completion * is used for SDIO. disable it until fixed @@ -700,14 +709,23 @@ static void ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) else param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET; - ath10k_bmi_write32(ar, hi_acs_flags, param); + ret = ath10k_bmi_write32(ar, hi_acs_flags, param); + if (ret) + return ret; /* Explicitly set fwlog prints to zero as target may turn it on * based on scratch registers. */ - ath10k_bmi_read32(ar, hi_option_flag, ¶m); + ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m); + if (ret) + return ret; + param |= HI_OPTION_DISABLE_DBGLOG; - ath10k_bmi_write32(ar, hi_option_flag, param); + ret = ath10k_bmi_write32(ar, hi_option_flag, param); + if (ret) + return ret; + + return 0; } static int ath10k_init_configure_target(struct ath10k *ar) @@ -2565,8 +2583,13 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err; - if (ar->hif.bus == ATH10K_BUS_SDIO) - ath10k_init_sdio(ar, mode); + if (ar->hif.bus == ATH10K_BUS_SDIO) { + status = ath10k_init_sdio(ar, mode); + if (status) { + ath10k_err(ar, "failed to init SDIO: %d\n", status); + goto err; + } + } } ar->htc.htc_ops.target_send_suspend_complete = -- cgit v1.2.3-59-g8ed1b From 80ce8ca7a6473730a6847046651aab81cdb96898 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 2 Jul 2019 13:39:04 +0100 Subject: ath: fix various spelling mistakes There are a bunch of spelling mistakes in two ath drivers, fix these. Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 +- drivers/net/wireless/ath/ath10k/qmi.c | 4 ++-- drivers/net/wireless/ath/wil6210/wmi.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 3d91a4025cfc..36c62d66c19e 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -2810,7 +2810,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, status = ath10k_hif_set_target_log_mode(ar, fw_diag_log); if (status && status != -EOPNOTSUPP) { - ath10k_warn(ar, "set traget log mode faileds: %d\n", status); + ath10k_warn(ar, "set target log mode failed: %d\n", status); goto err_hif_stop; } diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index fbc2e4ffc12b..637f83ef65f8 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -671,7 +671,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) wlfw_ini_req_msg_v01_ei, &req); if (ret < 0) { qmi_txn_cancel(&txn); - ath10k_err(ar, "fail to send fw log reqest: %d\n", ret); + ath10k_err(ar, "failed to send fw log request: %d\n", ret); goto out; } @@ -680,7 +680,7 @@ int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode) goto out; if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { - ath10k_err(ar, "fw log request rejectedr: %d\n", + ath10k_err(ar, "fw log request rejected: %d\n", resp.resp.error); ret = -EINVAL; goto out; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 153b84447e40..daf16bc01bb3 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -2715,7 +2715,7 @@ int wmi_get_all_temperatures(struct wil6210_priv *wil, return rc; if (reply.evt.status == WMI_FW_STATUS_FAILURE) { - wil_err(wil, "Failed geting TEMP_SENSE_ALL\n"); + wil_err(wil, "Failed getting TEMP_SENSE_ALL\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 5d7e4b4935e435d7e7be9f7746d4cff31a5cb94a Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Wed, 24 Jul 2019 19:27:20 +0800 Subject: ath: Use dev_get_drvdata where possible Instead of using to_pci_dev + pci_get_drvdata, use dev_get_drvdata to make code simpler. Signed-off-by: Chuhong Yuan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/pci.c | 3 +-- drivers/net/wireless/ath/ath9k/pci.c | 5 ++--- drivers/net/wireless/ath/wil6210/pcie_bus.c | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index c6156cc38940..e1378e203611 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -301,8 +301,7 @@ ath5k_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM_SLEEP static int ath5k_pci_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(dev); struct ath5k_hw *ah = hw->priv; ath5k_led_off(ah); diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 92b2dd396436..f3461b193c7a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -1021,13 +1021,12 @@ static void ath_pci_remove(struct pci_dev *pdev) static int ath_pci_suspend(struct device *device) { - struct pci_dev *pdev = to_pci_dev(device); - struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ieee80211_hw *hw = dev_get_drvdata(device); struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) { - dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n"); + dev_info(device, "WOW is enabled, bypassing PCI suspend\n"); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 18dd8b246022..f1a282364119 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -629,8 +629,7 @@ static int __maybe_unused wil6210_pm_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); wil_dbg_pm(wil, "Runtime idle\n"); @@ -644,8 +643,7 @@ static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev) static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev) { - struct pci_dev *pdev = to_pci_dev(dev); - struct wil6210_priv *wil = pci_get_drvdata(pdev); + struct wil6210_priv *wil = dev_get_drvdata(dev); if (test_bit(wil_status_suspended, wil->status)) { wil_dbg_pm(wil, "trying to suspend while suspended\n"); -- cgit v1.2.3-59-g8ed1b From 35cc054d944e8c9a7e9a31f32bbf360feb01a301 Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Fri, 6 Sep 2019 18:55:01 +0800 Subject: ath10k: remove the warning of sdio not full support Recently, it has the basic feature of sdio tested success, so remove it. Tested with QCA6174 SDIO with firmware WLAN.RMH.4.4.1-00017-QCARMSWP-1. Signed-off-by: Wen Gong Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/sdio.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 9870d2d095c8..120200a93bcc 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2086,9 +2086,6 @@ static int ath10k_sdio_probe(struct sdio_func *func, goto err_free_wq; } - /* TODO: remove this once SDIO support is fully implemented */ - ath10k_warn(ar, "WARNING: ath10k SDIO support is work-in-progress, problems may arise!\n"); - return 0; err_free_wq: -- cgit v1.2.3-59-g8ed1b From b8d17e7d93d2beb89e4f34c59996376b8b544792 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Thu, 19 Sep 2019 20:36:26 -0500 Subject: ath10k: fix memory leak In ath10k_usb_hif_tx_sg the allocated urb should be released if usb_submit_urb fails. Signed-off-by: Navid Emamdoost Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index e1420f67f776..730ed22e08a0 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -435,6 +435,7 @@ static int ath10k_usb_hif_tx_sg(struct ath10k *ar, u8 pipe_id, ath10k_dbg(ar, ATH10K_DBG_USB_BULK, "usb bulk transmit failed: %d\n", ret); usb_unanchor_urb(urb); + usb_free_urb(urb); ret = -EINVAL; goto err_free_urb_to_pipe; } -- cgit v1.2.3-59-g8ed1b From be898fed355e70b9115b439b4b9587b5fea2aca1 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Thu, 9 May 2019 09:48:26 +0000 Subject: brcmfmac: send port authorized event for FT-802.1X With FT-802.1X, driver should send a port authorized event right after sending a roamed event. It is used to indicate that a new AP is already authorized so 802.1X is not required. Acked-by: Arend van Spriel Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 8 ++++++++ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index e3ebb7abbdae..0cf4c795e62e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1647,6 +1647,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) u16 count; profile->use_fwsup = BRCMF_PROFILE_FWSUP_NONE; + profile->is_ft = false; if (!sme->crypto.n_akm_suites) return 0; @@ -1691,11 +1692,13 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) break; case WLAN_AKM_SUITE_FT_8021X: val = WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_FT; + profile->is_ft = true; if (sme->want_1x) profile->use_fwsup = BRCMF_PROFILE_FWSUP_1X; break; case WLAN_AKM_SUITE_FT_PSK: val = WPA2_AUTH_PSK | WPA2_AUTH_FT; + profile->is_ft = true; break; default: bphy_err(drvr, "invalid cipher group (%d)\n", @@ -5554,6 +5557,11 @@ done: cfg80211_roamed(ndev, &roam_info, GFP_KERNEL); brcmf_dbg(CONN, "Report roaming result\n"); + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X && profile->is_ft) { + cfg80211_port_authorized(ndev, profile->bssid, GFP_KERNEL); + brcmf_dbg(CONN, "Report port authorized\n"); + } + set_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); brcmf_dbg(TRACE, "Exit\n"); return err; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 14d5bbad1db1..e29846b1954b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -122,6 +122,7 @@ struct brcmf_cfg80211_profile { struct brcmf_cfg80211_security sec; struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS]; enum brcmf_profile_fwsup use_fwsup; + bool is_ft; }; /** -- cgit v1.2.3-59-g8ed1b From 3f1b32bdbb0a0b4a20e56b220adee76ff29172e3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 15 Sep 2019 21:32:10 +0200 Subject: brcmsmac: remove a useless test 'pih' is known to be non-NULL at this point, so the test can be removed. Signed-off-by: Christophe JAILLET Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 080e829da9b3..6bb34a12a94b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -1816,8 +1816,7 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) udelay(2); brcms_b_core_phy_clk(wlc_hw, ON); - if (pih) - wlc_phy_anacore(pih, ON); + wlc_phy_anacore(pih, ON); } /* switch to and initialize new band */ -- cgit v1.2.3-59-g8ed1b From 1524cbf3621576c639405e7aabeac415f9617c8d Mon Sep 17 00:00:00 2001 From: Adrian Ratiu Date: Wed, 25 Sep 2019 16:44:57 +0300 Subject: brcmfmac: don't WARN when there are no requests When n_reqs == 0 there is nothing to do so it doesn't make sense to search for requests and issue a warning because none is found. Signed-off-by: Martyn Welch Signed-off-by: Adrian Ratiu Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index 14e530601ef3..fabfbb0b40b0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -57,6 +57,10 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) mutex_lock(&pi->req_lock); + /* Nothing to do if we have no requests */ + if (pi->n_reqs == 0) + goto done; + /* find request */ for (i = 0; i < pi->n_reqs; i++) { if (pi->reqs[i]->reqid == reqid) -- cgit v1.2.3-59-g8ed1b From e0ae4bac22effbd644add326f658a3aeeb8d45ee Mon Sep 17 00:00:00 2001 From: Adrian Ratiu Date: Wed, 25 Sep 2019 16:44:58 +0300 Subject: brcmfmac: fix suspend/resume when power is cut off brcmfmac assumed the wifi device always remains powered on and thus hardcoded the MMC_PM_KEEP_POWER flag expecting the wifi device to remain on even during suspend/resume cycles. This is not always the case, some appliances cut power to everything connected via SDIO for efficiency reasons and this leads to wifi not being usable after coming out of suspend because the device was not correctly reinitialized. So we check for the keep_power capability and if it's not present then we remove the device and probe it again during resume to mirror what's happening in hardware and ensure correct reinitialization in the case when MMC_PM_KEEP_POWER is not supported. Suggested-by: Gustavo Padovan Signed-off-by: Adrian Ratiu Signed-off-by: Kalle Valo --- .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 53 ++++++++++++++++------ 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index fc12598b2dd3..96fd8e2bf773 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1108,7 +1108,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev) struct sdio_func *func; struct brcmf_bus *bus_if; struct brcmf_sdio_dev *sdiodev; - mmc_pm_flag_t sdio_flags; + mmc_pm_flag_t pm_caps, sdio_flags; + int ret = 0; func = container_of(dev, struct sdio_func, dev); brcmf_dbg(SDIO, "Enter: F%d\n", func->num); @@ -1119,19 +1120,33 @@ static int brcmf_ops_sdio_suspend(struct device *dev) bus_if = dev_get_drvdata(dev); sdiodev = bus_if->bus_priv.sdio; - brcmf_sdiod_freezer_on(sdiodev); - brcmf_sdio_wd_timer(sdiodev->bus, 0); + pm_caps = sdio_get_host_pm_caps(func); + + if (pm_caps & MMC_PM_KEEP_POWER) { + /* preserve card power during suspend */ + brcmf_sdiod_freezer_on(sdiodev); + brcmf_sdio_wd_timer(sdiodev->bus, 0); + + sdio_flags = MMC_PM_KEEP_POWER; + if (sdiodev->wowl_enabled) { + if (sdiodev->settings->bus.sdio.oob_irq_supported) + enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); + else + sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } + + if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) + brcmf_err("Failed to set pm_flags %x\n", sdio_flags); - sdio_flags = MMC_PM_KEEP_POWER; - if (sdiodev->wowl_enabled) { - if (sdiodev->settings->bus.sdio.oob_irq_supported) - enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); - else - sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; + } else { + /* power will be cut so remove device, probe again in resume */ + brcmf_sdiod_intr_unregister(sdiodev); + ret = brcmf_sdiod_remove(sdiodev); + if (ret) + brcmf_err("Failed to remove device on suspend\n"); } - if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) - brcmf_err("Failed to set pm_flags %x\n", sdio_flags); - return 0; + + return ret; } static int brcmf_ops_sdio_resume(struct device *dev) @@ -1139,13 +1154,23 @@ static int brcmf_ops_sdio_resume(struct device *dev) struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct sdio_func *func = container_of(dev, struct sdio_func, dev); + mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func); + int ret = 0; brcmf_dbg(SDIO, "Enter: F%d\n", func->num); if (func->num != 2) return 0; - brcmf_sdiod_freezer_off(sdiodev); - return 0; + if (!(pm_caps & MMC_PM_KEEP_POWER)) { + /* bus was powered off and device removed, probe again */ + ret = brcmf_sdiod_probe(sdiodev); + if (ret) + brcmf_err("Failed to probe device on resume\n"); + } else { + brcmf_sdiod_freezer_off(sdiodev); + } + + return ret; } static const struct dev_pm_ops brcmf_sdio_pm_ops = { -- cgit v1.2.3-59-g8ed1b From fa38b4fddc7c2ffbaff885eb92f4b20c25b0a81f Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Wed, 25 Sep 2019 23:31:52 +0300 Subject: brcmsmac: remove duplicated if condition The nested 'li_mimo == &locale_bn' check is excessive and always true. Thus it can be safely removed. Signed-off-by: Denis Efremov Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c index db783e94f929..5a6d9c86552a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -496,13 +496,11 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, * table and override CDD later */ if (li_mimo == &locale_bn) { - if (li_mimo == &locale_bn) { - maxpwr20 = QDB(16); - maxpwr40 = 0; + maxpwr20 = QDB(16); + maxpwr40 = 0; - if (chan >= 3 && chan <= 11) - maxpwr40 = QDB(16); - } + if (chan >= 3 && chan <= 11) + maxpwr40 = QDB(16); for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { txpwr->mcs_20_siso[i] = (u8) maxpwr20; -- cgit v1.2.3-59-g8ed1b From 0d32f5d93bbaeb57b607cb5cb1c67626d5754905 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 16 Sep 2019 10:41:40 +0800 Subject: rtw88: 8822c: fix boolreturn.cocci warnings drivers/net/wireless/realtek/rtw88/rtw8822c.c:2606:9-10: WARNING: return of 0/1 in function 'rtw8822c_dpk_coef_iq_check' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci Fixes: 5227c2ee453d ("rtw88: 8822c: add SW DPK support") Reported-by: kbuild test robot Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index c2f6cd76a658..084c18d115d5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2603,9 +2603,9 @@ static bool rtw8822c_dpk_coef_iq_check(struct rtw_dev *rtwdev, { if (coef_i == 0x1000 || coef_i == 0x0fff || coef_q == 0x1000 || coef_q == 0x0fff) - return 1; - else - return 0; + return true; + + return false; } static u32 rtw8822c_dpk_coef_transfer(struct rtw_dev *rtwdev) -- cgit v1.2.3-59-g8ed1b From d563131ef23cbc756026f839a82598c8445bc45f Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 13 Sep 2019 19:08:11 -0500 Subject: rsi: release skb if rsi_prepare_beacon fails In rsi_send_beacon, if rsi_prepare_beacon fails the allocated skb should be released. Signed-off-by: Navid Emamdoost Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 6c7f26ef6476..9cc8a335d519 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -1756,6 +1756,7 @@ static int rsi_send_beacon(struct rsi_common *common) skb_pull(skb, (64 - dword_align_bytes)); if (rsi_prepare_beacon(common, skb)) { rsi_dbg(ERR_ZONE, "Failed to prepare beacon\n"); + dev_kfree_skb(skb); return -EINVAL; } skb_queue_tail(&common->tx_queue[MGMT_BEACON_Q], skb); -- cgit v1.2.3-59-g8ed1b From 15e14f76f85f4f0eab3b8146e1cd3c58ce272823 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 21 Sep 2019 10:44:01 +0200 Subject: mt7601u: fix bbp version check in mt7601u_wait_bbp_ready Fix bbp ready check in mt7601u_wait_bbp_ready. The issue is reported by coverity with the following error: Logical vs. bitwise operator The expression's value does not depend on the operands; inadvertent use of the wrong operator is a likely logic error. Addresses-Coverity-ID: 1309441 ("Logical vs. bitwise operator") Fixes: c869f77d6abb ("add mt7601u driver") Acked-by: Jakub Kicinski Signed-off-by: Lorenzo Bianconi Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 06f5702ab4bd..d863ab4a66c9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -213,7 +213,7 @@ int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) do { val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); - if (val && ~val) + if (val && val != 0xff) break; } while (--i); -- cgit v1.2.3-59-g8ed1b From 6e7d59776311e181160d44ed3c73cc7e65def7f2 Mon Sep 17 00:00:00 2001 From: Austin Kim Date: Tue, 17 Sep 2019 15:50:44 +0900 Subject: rtlwifi: rtl8723ae: Remove unused 'rtstatus' variable 'rtstatus' local variable is not used, so remove it for clean-up. Signed-off-by: Austin Kim Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c index 54a3aec1dfa7..22441dd5fdac 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c @@ -485,15 +485,12 @@ bool rtl8723e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { int i; - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; radioa_arraylen = RTL8723ERADIOA_1TARRAYLENGTH; radioa_array_table = RTL8723E_RADIOA_1TARRAY; - rtstatus = true; - switch (rfpath) { case RF90_PATH_A: for (i = 0; i < radioa_arraylen; i = i + 2) { -- cgit v1.2.3-59-g8ed1b From 3f93616951138a598d930dcaec40f2bfd9ce43bb Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Tue, 24 Sep 2019 20:20:21 -0500 Subject: rtlwifi: prevent memory leak in rtl_usb_probe In rtl_usb_probe if allocation for usb_data fails the allocated hw should be released. In addition the allocated rtlpriv->usb_data should be released on error handling path. Signed-off-by: Navid Emamdoost Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/usb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 4b59f3b46b28..348b0072cdd6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1021,8 +1021,10 @@ int rtl_usb_probe(struct usb_interface *intf, rtlpriv->hw = hw; rtlpriv->usb_data = kcalloc(RTL_USB_MAX_RX_COUNT, sizeof(u32), GFP_KERNEL); - if (!rtlpriv->usb_data) + if (!rtlpriv->usb_data) { + ieee80211_free_hw(hw); return -ENOMEM; + } /* this spin lock must be initialized early */ spin_lock_init(&rtlpriv->locks.usb_lock); @@ -1083,6 +1085,7 @@ error_out2: _rtl_usb_io_handler_release(hw); usb_put_dev(udev); complete(&rtlpriv->firmware_loading_complete); + kfree(rtlpriv->usb_data); return -ENODEV; } EXPORT_SYMBOL(rtl_usb_probe); -- cgit v1.2.3-59-g8ed1b From a0d46f7a0fa5e2a447a25c87612040babf7a3e18 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Wed, 25 Sep 2019 23:58:58 +0300 Subject: rtlwifi: Remove excessive check in _rtl_ps_inactive_ps() There is no need to check "rtlhal->interface == INTF_PCI" twice in _rtl_ps_inactive_ps(). The nested check is always true. Thus, the expression can be simplified. Signed-off-by: Denis Efremov Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/ps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 70f04c2f5b17..6a8127539ea7 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -161,8 +161,7 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && - rtlhal->interface == INTF_PCI) { + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { rtlpriv->intf_ops->disable_aspm(hw); RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } -- cgit v1.2.3-59-g8ed1b From 7da413a18583baaf35dd4a8eb414fa410367d7f2 Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Wed, 18 Sep 2019 22:05:00 +0530 Subject: libertas: fix a potential NULL pointer dereference alloc_workqueue is not checked for errors and as a result, a potential NULL dereference could occur. Signed-off-by: Allen Pais Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/if_sdio.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/libertas/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 242d8845da3f..30f1025ecb9b 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1179,6 +1179,10 @@ static int if_sdio_probe(struct sdio_func *func, spin_lock_init(&card->lock); card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0); + if (unlikely(!card->workqueue)) { + ret = -ENOMEM; + goto err_queue; + } INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); init_waitqueue_head(&card->pwron_waitq); @@ -1230,6 +1234,7 @@ err_activate_card: lbs_remove_card(priv); free: destroy_workqueue(card->workqueue); +err_queue: while (card->packets) { packet = card->packets; card->packets = card->packets->next; -- cgit v1.2.3-59-g8ed1b From 0a3ce169476feca7869255c681884ed227a319c8 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Jun 2019 17:13:21 -0700 Subject: mwifiex: use 'total_ie_len' in mwifiex_update_bss_desc_with_ie() This is clearer than copy/pasting the magic number '+ 2' around, and it even saves the need for one existing comment. Cc: Takashi Iwai Signed-off-by: Brian Norris Reviewed-by: Takashi Iwai Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/scan.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 593c594982cb..98f942b797f7 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1270,7 +1270,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_FH_PARAMS: - if (element_len + 2 < sizeof(*fh_param_set)) + if (total_ie_len < sizeof(*fh_param_set)) return -EINVAL; fh_param_set = (struct ieee_types_fh_param_set *) current_ptr; @@ -1280,7 +1280,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_DS_PARAMS: - if (element_len + 2 < sizeof(*ds_param_set)) + if (total_ie_len < sizeof(*ds_param_set)) return -EINVAL; ds_param_set = (struct ieee_types_ds_param_set *) current_ptr; @@ -1293,7 +1293,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_CF_PARAMS: - if (element_len + 2 < sizeof(*cf_param_set)) + if (total_ie_len < sizeof(*cf_param_set)) return -EINVAL; cf_param_set = (struct ieee_types_cf_param_set *) current_ptr; @@ -1303,7 +1303,7 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; case WLAN_EID_IBSS_PARAMS: - if (element_len + 2 < sizeof(*ibss_param_set)) + if (total_ie_len < sizeof(*ibss_param_set)) return -EINVAL; ibss_param_set = (struct ieee_types_ibss_param_set *) @@ -1460,10 +1460,8 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, break; } - current_ptr += element_len + 2; - - /* Need to account for IE ID and IE Len */ - bytes_left -= (element_len + 2); + current_ptr += total_ie_len; + bytes_left -= total_ie_len; } /* while (bytes_left > 2) */ return ret; -- cgit v1.2.3-59-g8ed1b From 6aff90c5bab77886f99a1b6b1b1933f9b1e9b855 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 23 Sep 2019 13:56:32 +0000 Subject: ath9k: remove unused including Remove including that don't need it. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c index 159490f5a111..956fa7828d0c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c @@ -12,7 +12,6 @@ * initialize the chip when the user-space is ready to extract the init code. */ #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From fa879490e41283c8d59e7a0c751c375875390cf2 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Mon, 23 Sep 2019 21:49:21 +0200 Subject: ath10k: add 2ghz channel arguments to service ready structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add lowest/highest 2ghz channel arguments for use within WMI service ready structure. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 2 ++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.h | 2 ++ 4 files changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c96d1a17fd00..2a0a0086e0ad 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -967,6 +967,8 @@ struct ath10k { u32 num_rf_chains; u32 max_spatial_stream; /* protected by conf_mutex */ + u32 low_2ghz_chan; + u32 high_2ghz_chan; u32 low_5ghz_chan; u32 high_5ghz_chan; bool ani_enabled; diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 363fd0bd1e2d..bda52ca75c7e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1207,6 +1207,8 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = reg->eeprom_rd; + arg->low_2ghz_chan = reg->low_2ghz_chan; + arg->high_2ghz_chan = reg->high_2ghz_chan; arg->low_5ghz_chan = reg->low_5ghz_chan; arg->high_5ghz_chan = reg->high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1ec609d359dd..3ef6ee30ffd1 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5362,6 +5362,8 @@ ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->low_2ghz_chan = ev->hal_reg_capabilities.low_2ghz_chan; + arg->high_2ghz_chan = ev->hal_reg_capabilities.high_2ghz_chan; arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan; arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; @@ -5400,6 +5402,8 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->low_2ghz_chan = ev->hal_reg_capabilities.low_2ghz_chan; + arg->high_2ghz_chan = ev->hal_reg_capabilities.high_2ghz_chan; arg->low_5ghz_chan = ev->hal_reg_capabilities.low_5ghz_chan; arg->high_5ghz_chan = ev->hal_reg_capabilities.high_5ghz_chan; arg->num_mem_reqs = ev->num_mem_reqs; @@ -5454,6 +5458,8 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ar->phy_capability = __le32_to_cpu(arg.phy_capab); ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); ar->hw_eeprom_rd = __le32_to_cpu(arg.eeprom_rd); + ar->low_2ghz_chan = __le32_to_cpu(arg.low_2ghz_chan); + ar->high_2ghz_chan = __le32_to_cpu(arg.high_2ghz_chan); ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan); ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan); diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index bdeebc5b84b4..9ccaeb7ed052 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6870,6 +6870,8 @@ struct wmi_svc_rdy_ev_arg { __le32 num_rf_chains; __le32 eeprom_rd; __le32 num_mem_reqs; + __le32 low_2ghz_chan; + __le32 high_2ghz_chan; __le32 low_5ghz_chan; __le32 high_5ghz_chan; const __le32 *service_map; -- cgit v1.2.3-59-g8ed1b From 275ea1b26f386b5575c83399bb94ff5269ad2d57 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Mon, 23 Sep 2019 21:49:22 +0200 Subject: ath10k: print service ready returned channel range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Displays lowest/highest supported channels for both 2ghz and 5ghz bands as they're fetched within WMI service ready event. These are shown in a frequency format. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3ef6ee30ffd1..b7b80728d53d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5563,7 +5563,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) skip_mem_alloc: ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x low_2ghz_chan %d high_2ghz_chan %d low_5ghz_chan %d high_5ghz_chan %d num_mem_reqs 0x%08x\n", __le32_to_cpu(arg.min_tx_power), __le32_to_cpu(arg.max_tx_power), __le32_to_cpu(arg.ht_cap), @@ -5574,6 +5574,10 @@ skip_mem_alloc: __le32_to_cpu(arg.phy_capab), __le32_to_cpu(arg.num_rf_chains), __le32_to_cpu(arg.eeprom_rd), + __le32_to_cpu(arg.low_2ghz_chan), + __le32_to_cpu(arg.high_2ghz_chan), + __le32_to_cpu(arg.low_5ghz_chan), + __le32_to_cpu(arg.high_5ghz_chan), __le32_to_cpu(arg.num_mem_reqs)); dev_kfree_skb(skb); -- cgit v1.2.3-59-g8ed1b From 73690c4843fb501b675d06b46d75a8e78ea482a2 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Mon, 23 Sep 2019 21:49:23 +0200 Subject: ath10k: print supported MCS rates within service ready event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add vht_supp_mcs argument to service ready structure and print supported MCS rates in WMI service ready debug message. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 6 +++++- drivers/net/wireless/ath/ath10k/wmi.h | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2a0a0086e0ad..153c4a27d78e 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -964,6 +964,7 @@ struct ath10k { u32 hw_eeprom_rd; u32 ht_cap_info; u32 vht_cap_info; + u32 vht_supp_mcs; u32 num_rf_chains; u32 max_spatial_stream; /* protected by conf_mutex */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index bda52ca75c7e..2432a7434289 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1201,6 +1201,7 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->abi.abi_ver0; arg->sw_ver1 = ev->abi.abi_ver1; arg->fw_build = ev->fw_build_vers; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b7b80728d53d..2d43adf4eb56 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5357,6 +5357,7 @@ ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->sw_version; arg->sw_ver1 = ev->sw_version_1; arg->phy_capab = ev->phy_capability; @@ -5398,6 +5399,7 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->max_tx_power = ev->hw_max_tx_power; arg->ht_cap = ev->ht_cap_info; arg->vht_cap = ev->vht_cap_info; + arg->vht_supp_mcs = ev->vht_supp_mcs; arg->sw_ver0 = ev->sw_version; arg->phy_capab = ev->phy_capability; arg->num_rf_chains = ev->num_rf_chains; @@ -5449,6 +5451,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); ar->vht_cap_info = __le32_to_cpu(arg.vht_cap); + ar->vht_supp_mcs = __le32_to_cpu(arg.vht_supp_mcs); ar->fw_version_major = (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24; ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff); @@ -5563,11 +5566,12 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) skip_mem_alloc: ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x low_2ghz_chan %d high_2ghz_chan %d low_5ghz_chan %d high_5ghz_chan %d num_mem_reqs 0x%08x\n", + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_mcs 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x low_2ghz_chan %d high_2ghz_chan %d low_5ghz_chan %d high_5ghz_chan %d num_mem_reqs 0x%08x\n", __le32_to_cpu(arg.min_tx_power), __le32_to_cpu(arg.max_tx_power), __le32_to_cpu(arg.ht_cap), __le32_to_cpu(arg.vht_cap), + __le32_to_cpu(arg.vht_supp_mcs), __le32_to_cpu(arg.sw_ver0), __le32_to_cpu(arg.sw_ver1), __le32_to_cpu(arg.fw_build), diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 9ccaeb7ed052..d9d53e503c54 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -6863,6 +6863,7 @@ struct wmi_svc_rdy_ev_arg { __le32 max_tx_power; __le32 ht_cap; __le32 vht_cap; + __le32 vht_supp_mcs; __le32 sw_ver0; __le32 sw_ver1; __le32 fw_build; -- cgit v1.2.3-59-g8ed1b From 7b3087323faad85ee16f8f852810bb6500fefcb4 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Mon, 23 Sep 2019 21:49:24 +0200 Subject: ath10k: change sw version print format to hex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Software version within WMI event ready message was displayed in a not very useful decimal format. Change this info to be shown in a hexadecimal format instead. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2d43adf4eb56..59d2d2a975df 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5650,7 +5650,7 @@ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) } ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n", + "wmi event ready sw_version 0x%08x abi_version %u mac_addr %pM status %d\n", __le32_to_cpu(arg.sw_version), __le32_to_cpu(arg.abi_version), arg.mac_addr, -- cgit v1.2.3-59-g8ed1b From 306547608c84378084d718be4cc1be03200aabfd Mon Sep 17 00:00:00 2001 From: Erik Stromdahl Date: Mon, 17 Jun 2019 22:01:40 +0200 Subject: ath10k: switch to ieee80211_tx_dequeue_ni Since ath10k_mac_tx_push_txq() can be called from process context, we must explicitly disable softirqs before the call into mac80211. By calling ieee80211_tx_dequeue_ni() instead of ieee80211_tx_dequeue() we make sure softirqs are always disabled even in the case when ath10k_mac_tx_push_txq() is called from process context. Calling ieee80211_tx_dequeue_ni() with softirq's already disabled (e.g., from softirq context) should be safe as the local_bh_disable() and local_bh_enable() functions (called from ieee80211_tx_dequeue_ni) are fully reentrant. Signed-off-by: Erik Stromdahl Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 02ca34b6f1aa..08876f042022 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4065,7 +4065,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, if (ret) return ret; - skb = ieee80211_tx_dequeue(hw, txq); + skb = ieee80211_tx_dequeue_ni(hw, txq); if (!skb) { spin_lock_bh(&ar->htt.tx_lock); ath10k_htt_tx_dec_pending(htt); -- cgit v1.2.3-59-g8ed1b From 93f9fefcf52835a2d886773bd6d06698279e114d Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Thu, 26 Sep 2019 19:07:00 +0530 Subject: ath10k: coredump: fix IRAM addr for QCA9984, QCA4019, QCA9888 and QCA99x0 The IRAM start address in coredump was wrong for QCA9984, QCA4019, QCA9888 and QCA99x0. Tested on: QCA9984, QCA4019 FW version: 10.4-3.9.0.2-00044 Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/coredump.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index de0926c61ee7..839d941b7ab7 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -703,7 +703,7 @@ static const struct ath10k_mem_region qca99x0_hw20_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { @@ -786,7 +786,7 @@ static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { @@ -891,7 +891,7 @@ static const struct ath10k_mem_region qca4019_hw10_mem_regions[] = { }, { .type = ATH10K_MEM_REGION_TYPE_REG, - .start = 0x98000, + .start = 0x980000, .len = 0x50000, .name = "IRAM", .section_table = { -- cgit v1.2.3-59-g8ed1b From d98ddae85a4a57124f87960047b1b6419312147f Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Thu, 26 Sep 2019 19:07:01 +0530 Subject: ath10k: fix backtrace on coredump In a multiradio board with one QCA9984 and one AR9987 after enabling the crashdump with module parameter coredump_mask=7, below backtrace is seen. vmalloc: allocation failure: 0 bytes kworker/u4:0: page allocation failure: order:0, mode:0x80d2 CPU: 0 PID: 6 Comm: kworker/u4:0 Not tainted 3.14.77 #130 Workqueue: ath10k_wq ath10k_core_register_work [ath10k_core] (unwind_backtrace) from [] (show_stack+0x10/0x14) (dump_stack+0x80/0xa0) (warn_alloc_failed+0xd0/0xfc) (__vmalloc_node_range+0x1b4/0x1d8) (__vmalloc_node+0x34/0x40) (vzalloc+0x24/0x30) (ath10k_coredump_register+0x6c/0x88 [ath10k_core]) (ath10k_core_register_work+0x350/0xb34 [ath10k_core]) (process_one_work+0x20c/0x32c) (worker_thread+0x228/0x360) This is due to ath10k_hw_mem_layout is not defined for AR9987. For coredump undefined hw ramdump_size is 0. Check for the ramdump_size before allocation memory. Tested on: AR9987, QCA9984 FW version: 10.4-3.9.0.2-00044 Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/coredump.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 839d941b7ab7..2a4498067024 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -1229,9 +1229,11 @@ static struct ath10k_dump_file_data *ath10k_coredump_build(struct ath10k *ar) dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar); dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_DATA); dump_tlv->tlv_len = cpu_to_le32(crash_data->ramdump_buf_len); - memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf, - crash_data->ramdump_buf_len); - sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + if (crash_data->ramdump_buf_len) { + memcpy(dump_tlv->tlv_data, crash_data->ramdump_buf, + crash_data->ramdump_buf_len); + sofar += sizeof(*dump_tlv) + crash_data->ramdump_buf_len; + } } mutex_unlock(&ar->dump_mutex); @@ -1278,6 +1280,9 @@ int ath10k_coredump_register(struct ath10k *ar) if (test_bit(ATH10K_FW_CRASH_DUMP_RAM_DATA, &ath10k_coredump_mask)) { crash_data->ramdump_buf_len = ath10k_coredump_get_ramdump_size(ar); + if (!crash_data->ramdump_buf_len) + return 0; + crash_data->ramdump_buf = vzalloc(crash_data->ramdump_buf_len); if (!crash_data->ramdump_buf) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 80e84f36412e0c5172447b6947068dca0d04ee82 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Fri, 27 Sep 2019 01:56:04 +0300 Subject: ath9k_hw: fix uninitialized variable data Currently, data variable in ar9003_hw_thermo_cal_apply() could be uninitialized if ar9300_otp_read_word() will fail to read the value. Initialize data variable with 0 to prevent an undefined behavior. This will be enough to handle error case when ar9300_otp_read_word() fails. Fixes: 80fe43f2bbd5 ("ath9k_hw: Read and configure thermocal for AR9462") Cc: Rajkumar Manoharan Cc: John W. Linville Cc: Kalle Valo Cc: "David S. Miller" Cc: stable@vger.kernel.org Signed-off-by: Denis Efremov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2b29bf4730f6..b4885a700296 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4183,7 +4183,7 @@ static void ar9003_hw_thermometer_apply(struct ath_hw *ah) static void ar9003_hw_thermo_cal_apply(struct ath_hw *ah) { - u32 data, ko, kg; + u32 data = 0, ko, kg; if (!AR_SREV_9462_20_OR_LATER(ah)) return; -- cgit v1.2.3-59-g8ed1b From e01fddc19d215f6ad397894ec2a851d99bf154e2 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Fri, 27 Sep 2019 11:51:45 +0900 Subject: ath9k_htc: Modify byte order for an error message rs_datalen is be16 so we need to convert it before printing. Signed-off-by: Masashi Honma Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 4e8e80ac8341..aba0d454c381 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -986,7 +986,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { ath_err(common, "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", - rxstatus->rs_datalen, skb->len); + be16_to_cpu(rxstatus->rs_datalen), skb->len); goto rx_next; } -- cgit v1.2.3-59-g8ed1b From cd486e627e67ee9ab66914d36d3127ef057cc010 Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Fri, 27 Sep 2019 11:51:46 +0900 Subject: ath9k_htc: Discard undersized packets Sometimes the hardware will push small packets that trigger a WARN_ON in mac80211. Discard them early to avoid this issue. This patch ports 2 patches from ath9k to ath9k_htc. commit 3c0efb745a172bfe96459e20cbd37b0c945d5f8d "ath9k: discard undersized packets". commit df5c4150501ee7e86383be88f6490d970adcf157 "ath9k: correctly handle short radar pulses". [ 112.835889] ------------[ cut here ]------------ [ 112.835971] WARNING: CPU: 5 PID: 0 at net/mac80211/rx.c:804 ieee80211_rx_napi+0xaac/0xb40 [mac80211] [ 112.835973] Modules linked in: ath9k_htc ath9k_common ath9k_hw ath mac80211 cfg80211 libarc4 nouveau snd_hda_codec_hdmi intel_rapl_msr intel_rapl_common x86_pkg_temp_thermal intel_powerclamp coretemp snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio snd_hda_intel snd_hda_codec video snd_hda_core ttm snd_hwdep drm_kms_helper snd_pcm crct10dif_pclmul snd_seq_midi drm snd_seq_midi_event crc32_pclmul snd_rawmidi ghash_clmulni_intel snd_seq aesni_intel aes_x86_64 crypto_simd cryptd snd_seq_device glue_helper snd_timer sch_fq_codel i2c_algo_bit fb_sys_fops snd input_leds syscopyarea sysfillrect sysimgblt intel_cstate mei_me intel_rapl_perf soundcore mxm_wmi lpc_ich mei kvm_intel kvm mac_hid irqbypass parport_pc ppdev lp parport ip_tables x_tables autofs4 hid_generic usbhid hid raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear e1000e ahci libahci wmi [ 112.836022] CPU: 5 PID: 0 Comm: swapper/5 Not tainted 5.3.0-wt #1 [ 112.836023] Hardware name: MouseComputer Co.,Ltd. X99-S01/X99-S01, BIOS 1.0C-W7 04/01/2015 [ 112.836056] RIP: 0010:ieee80211_rx_napi+0xaac/0xb40 [mac80211] [ 112.836059] Code: 00 00 66 41 89 86 b0 00 00 00 e9 c8 fa ff ff 4c 89 b5 40 ff ff ff 49 89 c6 e9 c9 fa ff ff 48 c7 c7 e0 a2 a5 c0 e8 47 41 b0 e9 <0f> 0b 48 89 df e8 5a 94 2d ea e9 02 f9 ff ff 41 39 c1 44 89 85 60 [ 112.836060] RSP: 0018:ffffaa6180220da8 EFLAGS: 00010286 [ 112.836062] RAX: 0000000000000024 RBX: ffff909a20eeda00 RCX: 0000000000000000 [ 112.836064] RDX: 0000000000000000 RSI: ffff909a2f957448 RDI: ffff909a2f957448 [ 112.836065] RBP: ffffaa6180220e78 R08: 00000000000006e9 R09: 0000000000000004 [ 112.836066] R10: 000000000000000a R11: 0000000000000001 R12: 0000000000000000 [ 112.836068] R13: ffff909a261a47a0 R14: 0000000000000000 R15: 0000000000000004 [ 112.836070] FS: 0000000000000000(0000) GS:ffff909a2f940000(0000) knlGS:0000000000000000 [ 112.836071] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 112.836073] CR2: 00007f4e3ffffa08 CR3: 00000001afc0a006 CR4: 00000000001606e0 [ 112.836074] Call Trace: [ 112.836076] [ 112.836083] ? finish_td+0xb3/0xf0 [ 112.836092] ? ath9k_rx_prepare.isra.11+0x22f/0x2a0 [ath9k_htc] [ 112.836099] ath9k_rx_tasklet+0x10b/0x1d0 [ath9k_htc] [ 112.836105] tasklet_action_common.isra.22+0x63/0x110 [ 112.836108] tasklet_action+0x22/0x30 [ 112.836115] __do_softirq+0xe4/0x2da [ 112.836118] irq_exit+0xae/0xb0 [ 112.836121] do_IRQ+0x86/0xe0 [ 112.836125] common_interrupt+0xf/0xf [ 112.836126] [ 112.836130] RIP: 0010:cpuidle_enter_state+0xa9/0x440 [ 112.836133] Code: 3d bc 20 38 55 e8 f7 1d 84 ff 49 89 c7 0f 1f 44 00 00 31 ff e8 28 29 84 ff 80 7d d3 00 0f 85 e6 01 00 00 fb 66 0f 1f 44 00 00 <45> 85 ed 0f 89 ff 01 00 00 41 c7 44 24 10 00 00 00 00 48 83 c4 18 [ 112.836134] RSP: 0018:ffffaa61800e3e48 EFLAGS: 00000246 ORIG_RAX: ffffffffffffffde [ 112.836136] RAX: ffff909a2f96b340 RBX: ffffffffabb58200 RCX: 000000000000001f [ 112.836137] RDX: 0000001a458adc5d RSI: 0000000026c9b581 RDI: 0000000000000000 [ 112.836139] RBP: ffffaa61800e3e88 R08: 0000000000000002 R09: 000000000002abc0 [ 112.836140] R10: ffffaa61800e3e18 R11: 000000000000002d R12: ffffca617fb40b00 [ 112.836141] R13: 0000000000000002 R14: ffffffffabb582d8 R15: 0000001a458adc5d [ 112.836145] ? cpuidle_enter_state+0x98/0x440 [ 112.836149] ? menu_select+0x370/0x600 [ 112.836151] cpuidle_enter+0x2e/0x40 [ 112.836154] call_cpuidle+0x23/0x40 [ 112.836156] do_idle+0x204/0x280 [ 112.836159] cpu_startup_entry+0x1d/0x20 [ 112.836164] start_secondary+0x167/0x1c0 [ 112.836169] secondary_startup_64+0xa4/0xb0 [ 112.836173] ---[ end trace 9f4cd18479cc5ae5 ]--- Signed-off-by: Masashi Honma Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index aba0d454c381..9cec5c216e1f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -973,6 +973,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, struct ath_htc_rx_status *rxstatus; struct ath_rx_status rx_stats; bool decrypt_error = false; + __be16 rs_datalen; + bool is_phyerr; if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", @@ -982,11 +984,24 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, rxstatus = (struct ath_htc_rx_status *)skb->data; - if (be16_to_cpu(rxstatus->rs_datalen) - - (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { + rs_datalen = be16_to_cpu(rxstatus->rs_datalen); + if (unlikely(rs_datalen - + (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0)) { ath_err(common, "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", - be16_to_cpu(rxstatus->rs_datalen), skb->len); + rs_datalen, skb->len); + goto rx_next; + } + + is_phyerr = rxstatus->rs_status & ATH9K_RXERR_PHY; + /* + * Discard zero-length packets and packets smaller than an ACK + * which are not PHY_ERROR (short radar pulses have a length of 3) + */ + if (unlikely(!rs_datalen || (rs_datalen < 10 && !is_phyerr))) { + ath_warn(common, + "Short RX data len, dropping (dlen: %d)\n", + rs_datalen); goto rx_next; } @@ -1011,7 +1026,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, * Process PHY errors and return so that the packet * can be dropped. */ - if (rx_stats.rs_status & ATH9K_RXERR_PHY) { + if (unlikely(is_phyerr)) { /* TODO: Not using DFS processing now. */ if (ath_cmn_process_fft(&priv->spec_priv, hdr, &rx_stats, rx_status->mactime)) { -- cgit v1.2.3-59-g8ed1b From 5f71c84038d39def573744a145c573758f52a949 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 1 Oct 2019 01:35:57 -0700 Subject: r8152: Factor out OOB link list waits The same for-loop check for the LINK_LIST_READY bit of an OOB_CTRL register is used in several places. Factor these out into a single function to reduce the lines of code. Change-Id: I20e8f327045a72acc0a83e2d145ae2993ab62915 Signed-off-by: Prashant Malani Reviewed-by: Grant Grundler Acked-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 73 ++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 08726090570e..30a6df73a955 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3377,11 +3377,23 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp) set_bit(PHY_RESET, &tp->flags); } -static void r8152b_exit_oob(struct r8152 *tp) +static void wait_oob_link_list_ready(struct r8152 *tp) { u32 ocp_data; int i; + for (i = 0; i < 1000; i++) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + if (ocp_data & LINK_LIST_READY) + break; + usleep_range(1000, 2000); + } +} + +static void r8152b_exit_oob(struct r8152 *tp) +{ + u32 ocp_data; + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data &= ~RCR_ACPT_ALL; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); @@ -3399,23 +3411,13 @@ static void r8152b_exit_oob(struct r8152 *tp) ocp_data &= ~MCU_BORW_EN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); ocp_data |= RE_INIT_LL; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); rtl8152_nic_reset(tp); @@ -3457,7 +3459,6 @@ static void r8152b_exit_oob(struct r8152 *tp) static void r8152b_enter_oob(struct r8152 *tp) { u32 ocp_data; - int i; ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data &= ~NOW_IS_OOB; @@ -3469,23 +3470,13 @@ static void r8152b_enter_oob(struct r8152 *tp) rtl_disable(tp); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); ocp_data |= RE_INIT_LL; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); @@ -3711,7 +3702,6 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) static void r8153_first_init(struct r8152 *tp) { u32 ocp_data; - int i; r8153_mac_clk_spd(tp, false); rxdy_gated_en(tp, true); @@ -3732,23 +3722,13 @@ static void r8153_first_init(struct r8152 *tp) ocp_data &= ~MCU_BORW_EN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); ocp_data |= RE_INIT_LL; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); rtl_rx_vlan_en(tp, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX); @@ -3773,7 +3753,6 @@ static void r8153_first_init(struct r8152 *tp) static void r8153_enter_oob(struct r8152 *tp) { u32 ocp_data; - int i; r8153_mac_clk_spd(tp, true); @@ -3784,23 +3763,13 @@ static void r8153_enter_oob(struct r8152 *tp) rtl_disable(tp); rtl_reset_bmu(tp); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); ocp_data |= RE_INIT_LL; ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); - for (i = 0; i < 1000; i++) { - ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); - if (ocp_data & LINK_LIST_READY) - break; - usleep_range(1000, 2000); - } + wait_oob_link_list_ready(tp); ocp_data = tp->netdev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, ocp_data); -- cgit v1.2.3-59-g8ed1b From 9fb137aef34e4eedaa23307d309b0ebe8358fea1 Mon Sep 17 00:00:00 2001 From: Peter Fink Date: Mon, 30 Sep 2019 14:04:03 +0200 Subject: net: usb: ax88179_178a: allow optionally getting mac address from device tree Adopt and integrate the feature to pass the MAC address via device tree from asix_device.c (03fc5d4) also to other ax88179 based asix chips. E.g. the bootloader fills in local-mac-address and the driver will then pick up and use this MAC address. Signed-off-by: Peter Fink Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/usb/ax88179_178a.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index daa54486ab09..5a587663e7dc 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1214,6 +1214,29 @@ static int ax88179_led_setting(struct usbnet *dev) return 0; } +static void ax88179_get_mac_addr(struct usbnet *dev) +{ + u8 mac[ETH_ALEN]; + + /* Maybe the boot loader passed the MAC address via device tree */ + if (!eth_platform_get_mac_address(&dev->udev->dev, mac)) { + netif_dbg(dev, ifup, dev->net, + "MAC address read from device tree"); + } else { + ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, + ETH_ALEN, mac); + netif_dbg(dev, ifup, dev->net, + "MAC address read from ASIX chip"); + } + + if (is_valid_ether_addr(mac)) { + memcpy(dev->net->dev_addr, mac, ETH_ALEN); + } else { + netdev_info(dev->net, "invalid MAC address, using random\n"); + eth_hw_addr_random(dev->net); + } +} + static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) { u8 buf[5]; @@ -1240,8 +1263,8 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp); msleep(100); - ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, - ETH_ALEN, dev->net->dev_addr); + /* Read MAC address from DTB or asix chip */ + ax88179_get_mac_addr(dev); memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); /* RX bulk configuration */ @@ -1541,8 +1564,8 @@ static int ax88179_reset(struct usbnet *dev) /* Ethernet PHY Auto Detach*/ ax88179_auto_detach(dev, 0); - ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, - dev->net->dev_addr); + /* Read MAC address from DTB or asix chip */ + ax88179_get_mac_addr(dev); /* RX bulk configuration */ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5); -- cgit v1.2.3-59-g8ed1b From 678799194a5311765263b6aa940910ab232767eb Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 30 Sep 2019 17:12:41 +0200 Subject: hso: fix NULL-deref on tty open Fix NULL-pointer dereference on tty open due to a failure to handle a missing interrupt-in endpoint when probing modem ports: BUG: kernel NULL pointer dereference, address: 0000000000000006 ... RIP: 0010:tiocmget_submit_urb+0x1c/0xe0 [hso] ... Call Trace: hso_start_serial_device+0xdc/0x140 [hso] hso_serial_open+0x118/0x1b0 [hso] tty_open+0xf1/0x490 Fixes: 542f54823614 ("tty: Modem functions for the HSO driver") Signed-off-by: Johan Hovold Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index ce78714f536f..a505b2ab88b8 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2620,14 +2620,18 @@ static struct hso_device *hso_create_bulk_serial_device( */ if (serial->tiocmget) { tiocmget = serial->tiocmget; + tiocmget->endp = hso_get_ep(interface, + USB_ENDPOINT_XFER_INT, + USB_DIR_IN); + if (!tiocmget->endp) { + dev_err(&interface->dev, "Failed to find INT IN ep\n"); + goto exit; + } + tiocmget->urb = usb_alloc_urb(0, GFP_KERNEL); if (tiocmget->urb) { mutex_init(&tiocmget->mutex); init_waitqueue_head(&tiocmget->waitq); - tiocmget->endp = hso_get_ep( - interface, - USB_ENDPOINT_XFER_INT, - USB_DIR_IN); } else hso_free_tiomget(serial); } -- cgit v1.2.3-59-g8ed1b From c01ebd6c46980654220f6d2b660308a074ee29df Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 30 Sep 2019 12:38:18 -0700 Subject: r8152: Use guard clause and fix comment typos Use a guard clause in tx_bottom() to reduce the indentation of the do-while loop. Also, fix a couple of spelling and grammatical mistakes in the r8152_csum_workaround() function comment. Change-Id: I460befde150ad92248fd85b0f189ec2df2ab8431 Signed-off-by: Prashant Malani Reviewed-by: Grant Grundler Acked-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 30a6df73a955..601259238fd7 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1688,7 +1688,7 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) } /* r8152_csum_workaround() - * The hw limites the value the transport offset. When the offset is out of the + * The hw limits the value of the transport offset. When the offset is out of * range, calculate the checksum by sw. */ static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, @@ -2178,6 +2178,7 @@ static void tx_bottom(struct r8152 *tp) int res; do { + struct net_device *netdev = tp->netdev; struct tx_agg *agg; if (skb_queue_empty(&tp->tx_queue)) @@ -2188,24 +2189,23 @@ static void tx_bottom(struct r8152 *tp) break; res = r8152_tx_agg_fill(tp, agg); - if (res) { - struct net_device *netdev = tp->netdev; + if (!res) + continue; - if (res == -ENODEV) { - rtl_set_unplug(tp); - netif_device_detach(netdev); - } else { - struct net_device_stats *stats = &netdev->stats; - unsigned long flags; + if (res == -ENODEV) { + rtl_set_unplug(tp); + netif_device_detach(netdev); + } else { + struct net_device_stats *stats = &netdev->stats; + unsigned long flags; - netif_warn(tp, tx_err, netdev, - "failed tx_urb %d\n", res); - stats->tx_dropped += agg->skb_num; + netif_warn(tp, tx_err, netdev, + "failed tx_urb %d\n", res); + stats->tx_dropped += agg->skb_num; - spin_lock_irqsave(&tp->tx_lock, flags); - list_add_tail(&agg->list, &tp->tx_free); - spin_unlock_irqrestore(&tp->tx_lock, flags); - } + spin_lock_irqsave(&tp->tx_lock, flags); + list_add_tail(&agg->list, &tp->tx_free); + spin_unlock_irqrestore(&tp->tx_lock, flags); } } while (res == 0); } -- cgit v1.2.3-59-g8ed1b From ab8c31dd8c8accea11bd59075bca711579512adc Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Thu, 4 Jul 2019 00:29:34 +0800 Subject: net/wireless: Use kmemdup rather than duplicating its implementation kmemdup is introduced to duplicate a region of memory in a neat way. Rather than kmalloc/kzalloc + memcpy, which the programmer needs to write the size twice (sometimes lead to mistakes), kmemdup improves readability, leads to smaller code and also reduce the chances of mistakes. Suggestion to use kmemdup rather than using kmalloc/kzalloc + memcpy. Signed-off-by: Fuqian Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath6kl/wmi.c | 6 ++---- drivers/net/wireless/st/cw1200/queue.c | 3 +-- drivers/net/wireless/ti/wlcore/main.c | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 2382c6c46851..6885d2ded53a 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3650,7 +3650,7 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, if (wait) return -EINVAL; /* Offload for wait not supported */ - buf = kmalloc(data_len, GFP_KERNEL); + buf = kmemdup(data, data_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -3661,7 +3661,6 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, } kfree(wmi->last_mgmt_tx_frame); - memcpy(buf, data, data_len); wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; @@ -3689,7 +3688,7 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, if (wait) return -EINVAL; /* Offload for wait not supported */ - buf = kmalloc(data_len, GFP_KERNEL); + buf = kmemdup(data, data_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -3700,7 +3699,6 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, } kfree(wmi->last_mgmt_tx_frame); - memcpy(buf, data, data_len); wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; diff --git a/drivers/net/wireless/st/cw1200/queue.c b/drivers/net/wireless/st/cw1200/queue.c index 14133eedb3b6..12952b1c29df 100644 --- a/drivers/net/wireless/st/cw1200/queue.c +++ b/drivers/net/wireless/st/cw1200/queue.c @@ -79,10 +79,9 @@ static void cw1200_queue_register_post_gc(struct list_head *gc_list, struct cw1200_queue_item *item) { struct cw1200_queue_item *gc_item; - gc_item = kmalloc(sizeof(struct cw1200_queue_item), + gc_item = kmemdup(item, sizeof(struct cw1200_queue_item), GFP_ATOMIC); BUG_ON(!gc_item); - memcpy(gc_item, item, sizeof(struct cw1200_queue_item)); list_add_tail(&gc_item->head, gc_list); } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 547ad538d8b6..123afbe10f44 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1434,7 +1434,7 @@ int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, field = &filter->fields[filter->num_fields]; - field->pattern = kzalloc(len, GFP_KERNEL); + field->pattern = kmemdup(pattern, len, GFP_KERNEL); if (!field->pattern) { wl1271_warning("Failed to allocate RX filter pattern"); return -ENOMEM; @@ -1445,7 +1445,6 @@ int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, field->offset = cpu_to_le16(offset); field->flags = flags; field->len = len; - memcpy(field->pattern, pattern, len); return 0; } -- cgit v1.2.3-59-g8ed1b From a2cdd07488e666aa93a49a3fc9c9b1299e27ef3c Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Thu, 19 Sep 2019 22:00:41 -0500 Subject: rtl8xxxu: prevent leaking urb In rtl8xxxu_submit_int_urb if usb_submit_urb fails the allocated urb should be released. Signed-off-by: Navid Emamdoost Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index c6c41fb962ff..776bbae14a8d 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5444,6 +5444,7 @@ static int rtl8xxxu_submit_int_urb(struct ieee80211_hw *hw) ret = usb_submit_urb(urb, GFP_KERNEL); if (ret) { usb_unanchor_urb(urb); + usb_free_urb(urb); goto error; } -- cgit v1.2.3-59-g8ed1b From 4010758eb082467509c4e95e3c0bec57b1dec3d9 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Mon, 30 Sep 2019 16:54:47 +0800 Subject: rtlwifi: Remove set but not used variable 'rtstate' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/ps.c: In function rtl_ps_set_rf_state: drivers/net/wireless/realtek/rtlwifi/ps.c:71:19: warning: variable rtstate set but not used [-Wunused-but-set-variable] It is not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/ps.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 6a8127539ea7..cbf5f186f48b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -68,7 +68,6 @@ static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - enum rf_pwrstate rtstate; bool actionallowed = false; u16 rfwait_cnt = 0; @@ -102,8 +101,6 @@ static bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, } } - rtstate = ppsc->rfpwr_state; - switch (state_toset) { case ERFON: ppsc->rfoff_reason &= (~changesource); -- cgit v1.2.3-59-g8ed1b From 70906d941ccd54c6bf419ea20b240c06753e0956 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Mon, 30 Sep 2019 16:54:48 +0800 Subject: rtlwifi: Remove set but not used variables 'dataempty','hoffset' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/efuse.c: In function efuse_pg_packet_write: drivers/net/wireless/realtek/rtlwifi/efuse.c:937:24: warning: variable dataempty set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/efuse.c: In function efuse_get_current_size: drivers/net/wireless/realtek/rtlwifi/efuse.c:1202:5: warning: variable hoffset set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/efuse.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 264667203f6f..cef9f2a9303b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -915,7 +915,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct pgpkt_struct target_pkt; u8 write_state = PG_STATE_HEADER; - int continual = true, dataempty = true, result = true; + int continual = true, result = true; u16 efuse_addr = 0; u8 efuse_data; u8 target_word_cnts = 0; @@ -942,7 +942,6 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, while (continual && (efuse_addr < (EFUSE_MAX_SIZE - rtlpriv->cfg->maps[EFUSE_OOB_PROTECT_BYTES_LEN]))) { if (write_state == PG_STATE_HEADER) { - dataempty = true; badworden = 0x0F; RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, "efuse PG_STATE_HEADER\n"); @@ -1179,13 +1178,12 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw) { int continual = true; u16 efuse_addr = 0; - u8 hoffset, hworden; + u8 hworden; u8 efuse_data, word_cnts; while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data) && (efuse_addr < EFUSE_MAX_SIZE)) { if (efuse_data != 0xFF) { - hoffset = (efuse_data >> 4) & 0x0F; hworden = efuse_data & 0x0F; word_cnts = efuse_calculate_word_cnts(hworden); efuse_addr = efuse_addr + (word_cnts * 2) + 1; -- cgit v1.2.3-59-g8ed1b From 4a26e11500b85198d54147a82fb44dd9b647bd93 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Mon, 30 Sep 2019 16:54:50 +0800 Subject: rtlwifi: rtl8192ee: Remove set but not used variables 'short_gi','buf_len' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c: In function rtl92ee_tx_fill_desc: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c:656:5: warning: variable short_gi set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c: In function rtl92ee_tx_fill_desc: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c:648:15: warning: variable buf_len set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 27f1a631b569..36a8a51e6096 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -651,7 +651,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, struct rtlwifi_tx_info *tx_info = rtl_tx_skb_cb_info(skb); u16 seq_number; __le16 fc = hdr->frame_control; - unsigned int buf_len; u8 fw_qsel = _rtl92ee_map_hwqueue_to_fwqueue(skb, hw_queue); bool firstseg = ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); @@ -659,7 +658,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0); dma_addr_t mapping; u8 bw_40 = 0; - u8 short_gi; __le32 *pdesc = (__le32 *)pdesc8; if (mac->opmode == NL80211_IFTYPE_STATION) { @@ -677,7 +675,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, skb_push(skb, EM_HDR_LEN); memset(skb->data, 0, EM_HDR_LEN); } - buf_len = skb->len; mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(rtlpci->pdev, mapping)) { @@ -724,11 +721,6 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw, } } - if (ptcb_desc->hw_rate > DESC_RATEMCS0) - short_gi = (ptcb_desc->use_shortgi) ? 1 : 0; - else - short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0; - if (info->flags & IEEE80211_TX_CTL_AMPDU) { set_tx_desc_agg_enable(pdesc, 1); set_tx_desc_max_agg_num(pdesc, 0x14); -- cgit v1.2.3-59-g8ed1b From 533e3de4120566bb90b6193aae7a6c15e26cc4fd Mon Sep 17 00:00:00 2001 From: zhengbin Date: Mon, 30 Sep 2019 16:54:51 +0800 Subject: rtlwifi: rtl8192ee: Remove set but not used variables 'reg_ecc','reg_eac' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c: In function rtl92ee_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c:2805:34: warning: variable reg_ecc set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c: In function rtl92ee_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c:2804:34: warning: variable reg_eac set but not used [-Wunused-but-set-variable] They are not used since commit b1a3bfc97cd9 ("rtlwifi: rtl8192ee: Move driver from staging to the regular tree") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index 222abc41669c..f03de8bdd2d1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -2801,8 +2801,8 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac; - long reg_eb4, reg_ebc, reg_ec4, reg_ecc; + long reg_e94, reg_e9c, reg_ea4; + long reg_eb4, reg_ebc, reg_ec4; bool is12simular, is13simular, is23simular; u8 idx; u32 iqk_bb_reg[IQK_BB_REG_NUM] = { @@ -2873,11 +2873,9 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { @@ -2886,13 +2884,11 @@ void rtl92ee_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e9c = result[final_candidate][1]; rtlphy->reg_e9c = reg_e9c; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; rtlphy->reg_eb4 = reg_eb4; reg_ebc = result[final_candidate][5]; rtlphy->reg_ebc = reg_ebc; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { -- cgit v1.2.3-59-g8ed1b From 66070e86878cc62d8b7e80c1729c4de6bd1b222c Mon Sep 17 00:00:00 2001 From: zhengbin Date: Mon, 30 Sep 2019 16:54:52 +0800 Subject: rtlwifi: rtl8723be: Remove set but not used variables 'reg_ecc','reg_eac' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c: In function rtl8723be_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c:2255:7: warning: variable reg_ecc set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c: In function rtl8723be_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c:2254:34: warning: variable reg_eac set but not used [-Wunused-but-set-variable] They are not used since commit a619d1abe20c ("rtlwifi: rtl8723be: Add new driver") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index aa8a0950fcea..d48364460922 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -2251,8 +2251,8 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate, idx; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4; - long reg_ecc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4; + long reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[9] = { ROFDM0_XARXIQIMBALANCE, @@ -2334,11 +2334,9 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { reg_e94 = result[final_candidate][0]; @@ -2346,13 +2344,11 @@ void rtl8723be_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e9c = result[final_candidate][1]; rtlphy->reg_e9c = reg_e9c; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; rtlphy->reg_eb4 = reg_eb4; reg_ebc = result[final_candidate][5]; rtlphy->reg_ebc = reg_ebc; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { -- cgit v1.2.3-59-g8ed1b From 3c519605850890160848a89690056afa204d0ef6 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:17 +0800 Subject: rtw88: remove redundant flag check helper function These helper functions seems useless. And in some cases we want to use test_and_[set/clear]_bit, these helpers will make the code more complicated. So remove them. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/coex.c | 4 ++-- drivers/net/wireless/realtek/rtw88/mac.c | 2 +- drivers/net/wireless/realtek/rtw88/mac80211.c | 10 +++++----- drivers/net/wireless/realtek/rtw88/main.c | 20 ++++++++++---------- drivers/net/wireless/realtek/rtw88/main.h | 15 --------------- drivers/net/wireless/realtek/rtw88/phy.c | 2 +- drivers/net/wireless/realtek/rtw88/ps.c | 10 +++++----- 7 files changed, 24 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 793b40bdbf7c..4a0b569a6c6b 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -383,9 +383,9 @@ static void rtw_coex_update_wl_link_info(struct rtw_dev *rtwdev, u8 reason) u8 rssi_step; u8 rssi; - scan = rtw_flag_check(rtwdev, RTW_FLAG_SCANNING); + scan = test_bit(RTW_FLAG_SCANNING, rtwdev->flags); coex_stat->wl_connected = !!rtwdev->sta_cnt; - coex_stat->wl_gl_busy = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + coex_stat->wl_gl_busy = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); if (stats->tx_throughput > stats->rx_throughput) coex_stat->wl_tput_dir = COEX_WL_TPUT_TX; diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index b61b073031e5..d8c5da342b11 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -707,7 +707,7 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) rtwdev->h2c.last_box_num = 0; rtwdev->h2c.seq = 0; - rtw_flag_set(rtwdev, RTW_FLAG_FW_RUNNING); + set_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); return 0; diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index e5e3605bb693..6d5cce09eb14 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -19,7 +19,7 @@ static void rtw_ops_tx(struct ieee80211_hw *hw, struct rtw_dev *rtwdev = hw->priv; struct rtw_tx_pkt_info pkt_info = {0}; - if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING)) + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) goto out; rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb); @@ -474,8 +474,8 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, rtw_coex_scan_notify(rtwdev, COEX_SCAN_START); - rtw_flag_set(rtwdev, RTW_FLAG_DIG_DISABLE); - rtw_flag_set(rtwdev, RTW_FLAG_SCANNING); + set_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); + set_bit(RTW_FLAG_SCANNING, rtwdev->flags); mutex_unlock(&rtwdev->mutex); } @@ -489,8 +489,8 @@ static void rtw_ops_sw_scan_complete(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); - rtw_flag_clear(rtwdev, RTW_FLAG_SCANNING); - rtw_flag_clear(rtwdev, RTW_FLAG_DIG_DISABLE); + clear_bit(RTW_FLAG_SCANNING, rtwdev->flags); + clear_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags); ether_addr_copy(rtwvif->mac_addr, vif->addr); config |= PORT_SET_MAC_ADDR; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 6dd457741b15..36ba2211faaf 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -150,20 +150,20 @@ static void rtw_watch_dog_work(struct work_struct *work) struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, watch_dog_work.work); struct rtw_watch_dog_iter_data data = {}; - bool busy_traffic = rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); - if (!rtw_flag_check(rtwdev, RTW_FLAG_RUNNING)) + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) return; ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); if (rtwdev->stats.tx_cnt > 100 || rtwdev->stats.rx_cnt > 100) - rtw_flag_set(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + set_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); else - rtw_flag_clear(rtwdev, RTW_FLAG_BUSY_TRAFFIC); + clear_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); - if (busy_traffic != rtw_flag_check(rtwdev, RTW_FLAG_BUSY_TRAFFIC)) + if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) rtw_coex_wl_status_change_notify(rtwdev); /* reset tx/rx statictics */ @@ -183,7 +183,7 @@ static void rtw_watch_dog_work(struct work_struct *work) data.rtwvif && !data.active && data.assoc_cnt == 1) rtw_enter_lps(rtwdev, data.rtwvif); - if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING)) + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) return; rtw_phy_dynamic_mechanism(rtwdev); @@ -311,7 +311,7 @@ void rtw_set_channel(struct rtw_dev *rtwdev) if (hal->current_band_type == RTW_BAND_5G) { rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_5G); } else { - if (rtw_flag_check(rtwdev, RTW_FLAG_SCANNING)) + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G); else rtw_coex_switchband_notify(rtwdev, COEX_SWITCH_TO_24G_NOFORSCAN); @@ -737,7 +737,7 @@ int rtw_core_start(struct rtw_dev *rtwdev) ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); - rtw_flag_set(rtwdev, RTW_FLAG_RUNNING); + set_bit(RTW_FLAG_RUNNING, rtwdev->flags); return 0; } @@ -752,8 +752,8 @@ void rtw_core_stop(struct rtw_dev *rtwdev) { struct rtw_coex *coex = &rtwdev->coex; - rtw_flag_clear(rtwdev, RTW_FLAG_RUNNING); - rtw_flag_clear(rtwdev, RTW_FLAG_FW_RUNNING); + clear_bit(RTW_FLAG_RUNNING, rtwdev->flags); + clear_bit(RTW_FLAG_FW_RUNNING, rtwdev->flags); cancel_delayed_work_sync(&rtwdev->watch_dog_work); cancel_delayed_work_sync(&coex->bt_relink_work); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index bede3f38516e..11ab9967617b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1378,21 +1378,6 @@ struct rtw_dev { #include "hci.h" -static inline bool rtw_flag_check(struct rtw_dev *rtwdev, enum rtw_flags flag) -{ - return test_bit(flag, rtwdev->flags); -} - -static inline void rtw_flag_clear(struct rtw_dev *rtwdev, enum rtw_flags flag) -{ - clear_bit(flag, rtwdev->flags); -} - -static inline void rtw_flag_set(struct rtw_dev *rtwdev, enum rtw_flags flag) -{ - set_bit(flag, rtwdev->flags); -} - static inline bool rtw_is_assoc(struct rtw_dev *rtwdev) { return !!rtwdev->sta_cnt; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index d3d3f40de75e..8ebe1f4b76ad 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -394,7 +394,7 @@ static void rtw_phy_dig(struct rtw_dev *rtwdev) u8 step[3]; bool linked; - if (rtw_flag_check(rtwdev, RTW_FLAG_DIG_DISABLE)) + if (test_bit(RTW_FLAG_DIG_DISABLE, rtwdev->flags)) return; if (rtw_phy_dig_check_damping(dm_info)) diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 9ecd14feb76b..4896953ec4b9 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -18,14 +18,14 @@ static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) rtw_err(rtwdev, "leave idle state failed\n"); rtw_set_channel(rtwdev); - rtw_flag_clear(rtwdev, RTW_FLAG_INACTIVE_PS); + clear_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); return ret; } int rtw_enter_ips(struct rtw_dev *rtwdev) { - rtw_flag_set(rtwdev, RTW_FLAG_INACTIVE_PS); + set_bit(RTW_FLAG_INACTIVE_PS, rtwdev->flags); rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); @@ -71,7 +71,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) conf->smart_ps = 0; rtw_fw_set_pwr_mode(rtwdev); - rtw_flag_clear(rtwdev, RTW_FLAG_LEISURE_PS); + clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); } @@ -88,7 +88,7 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE); rtw_fw_set_pwr_mode(rtwdev); - rtw_flag_set(rtwdev, RTW_FLAG_LEISURE_PS); + set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } void rtw_lps_work(struct work_struct *work) @@ -137,7 +137,7 @@ void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) bool rtw_in_lps(struct rtw_dev *rtwdev) { - return rtw_flag_check(rtwdev, RTW_FLAG_LEISURE_PS); + return test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) -- cgit v1.2.3-59-g8ed1b From 6f0b0d28fde849a404f4b307887405e326866e11 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:18 +0800 Subject: rtw88: pci: reset H2C queue indexes in a single write If the driver doesn't reset the host's and device's indexes in a single write, the indexes will become different in a short period. And it will confuse the DMA engine, make it start to process non-existed entries. Better to Write-1-to-reset the indexes, for the DMA engine to know that this is a reset of the H2C queue, not a kick off. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/pci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index d90928be663b..509743cfd70a 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -457,9 +457,9 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) /* reset read/write point */ rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff); - /* rest H2C Queue index */ - rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HOST_IDX); - rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HW_IDX); + /* reset H2C Queue index in a single write */ + rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, + BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX); } static void rtw_pci_reset_trx_ring(struct rtw_dev *rtwdev) -- cgit v1.2.3-59-g8ed1b From 61d7309562b51e9600f69ca70f9edf71f841fee7 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:19 +0800 Subject: rtw88: not to enter or leave PS under IRQ Remove PS related *_irqsafe functions to avoid entering/leaving PS under interrupt context. Instead, make PS decision in watch_dog. This could simplify the logic and make the code look clean. But it could have a little side-effect that if the driver is having heavy traffic before the every-2-second watch_dog detect the traffic and decide to leave PS, the thoughput will be lower. Once traffic is detected by watch_dog and left PS state, the throughput will resume to the peak the hardware ought to have again. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 3 ++- drivers/net/wireless/realtek/rtw88/main.h | 1 - drivers/net/wireless/realtek/rtw88/ps.c | 44 ------------------------------- drivers/net/wireless/realtek/rtw88/ps.h | 3 --- drivers/net/wireless/realtek/rtw88/rx.c | 2 -- drivers/net/wireless/realtek/rtw88/tx.c | 2 -- 6 files changed, 2 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 36ba2211faaf..22fc5d6f6b62 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -182,6 +182,8 @@ static void rtw_watch_dog_work(struct work_struct *work) if (rtw_fw_support_lps && data.rtwvif && !data.active && data.assoc_cnt == 1) rtw_enter_lps(rtwdev, data.rtwvif); + else + rtw_leave_lps(rtwdev, rtwdev->lps_conf.rtwvif); if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) return; @@ -1152,7 +1154,6 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtw_tx_report_purge_timer, 0); INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); - INIT_DELAYED_WORK(&rtwdev->lps_work, rtw_lps_work); INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 11ab9967617b..0955970d6f4d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1361,7 +1361,6 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; - struct delayed_work lps_work; struct dentry *debugfs; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 4896953ec4b9..ffba3bd7bb31 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -91,50 +91,6 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -void rtw_lps_work(struct work_struct *work) -{ - struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, - lps_work.work); - struct rtw_lps_conf *conf = &rtwdev->lps_conf; - struct rtw_vif *rtwvif = conf->rtwvif; - - if (WARN_ON(!rtwvif)) - return; - - if (conf->mode == RTW_MODE_LPS) - rtw_enter_lps_core(rtwdev); - else - rtw_leave_lps_core(rtwdev); -} - -void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) -{ - struct rtw_lps_conf *conf = &rtwdev->lps_conf; - - if (rtwvif->in_lps) - return; - - conf->mode = RTW_MODE_LPS; - conf->rtwvif = rtwvif; - rtwvif->in_lps = true; - - ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); -} - -void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) -{ - struct rtw_lps_conf *conf = &rtwdev->lps_conf; - - if (!rtwvif->in_lps) - return; - - conf->mode = RTW_MODE_ACTIVE; - conf->rtwvif = rtwvif; - rtwvif->in_lps = false; - - ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->lps_work, 0); -} - bool rtw_in_lps(struct rtw_dev *rtwdev) { return test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 09e57405dc1b..0ac6c2983a06 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -10,9 +10,6 @@ int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); -void rtw_lps_work(struct work_struct *work); -void rtw_enter_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -void rtw_leave_lps_irqsafe(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); bool rtw_in_lps(struct rtw_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 48b9ed49b79a..16b22eb57171 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -25,8 +25,6 @@ void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtwvif = (struct rtw_vif *)vif->drv_priv; rtwvif->stats.rx_unicast += skb->len; rtwvif->stats.rx_cnt++; - if (rtwvif->stats.rx_cnt > RTW_LPS_THRESHOLD) - rtw_leave_lps_irqsafe(rtwdev, rtwvif); } } } diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 8eaa9809ca44..91bfd8c28ff7 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -27,8 +27,6 @@ void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, rtwvif = (struct rtw_vif *)vif->drv_priv; rtwvif->stats.tx_unicast += skb->len; rtwvif->stats.tx_cnt++; - if (rtwvif->stats.tx_cnt > RTW_LPS_THRESHOLD) - rtw_leave_lps_irqsafe(rtwdev, rtwvif); } } } -- cgit v1.2.3-59-g8ed1b From 3d391c06d917a18f846aa2a0ab155cb6c92ca6ea Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:20 +0800 Subject: rtw88: not to control LPS by each vif The original design of LPS enter/leave routines allows to control the LPS state by each interface. But the hardware cannot actually handle it that way. This means the hardware can only enter LPS once with an associated port, so there is no need to keep tracking the state of each vif. Hence the logic of enter/leave LPS state can be simple, just to check the state of the device's flag. And for leaving LPS state, it will get the same port id to send to inform the hardware. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/coex.c | 10 ++-------- drivers/net/wireless/realtek/rtw88/mac80211.c | 2 +- drivers/net/wireless/realtek/rtw88/main.c | 4 ++-- drivers/net/wireless/realtek/rtw88/main.h | 2 -- drivers/net/wireless/realtek/rtw88/ps.c | 19 +++++-------------- drivers/net/wireless/realtek/rtw88/ps.h | 4 ++-- 6 files changed, 12 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 4a0b569a6c6b..9d8cbd91e5ff 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -810,8 +810,6 @@ static void rtw_coex_ignore_wlan_act(struct rtw_dev *rtwdev, bool enable) static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, u8 lps_val, u8 rpwm_val) { - struct rtw_lps_conf *lps_conf = &rtwdev->lps_conf; - struct rtw_vif *rtwvif; struct rtw_coex *coex = &rtwdev->coex; struct rtw_coex_stat *coex_stat = &coex->stat; u8 lps_mode = 0x0; @@ -823,18 +821,14 @@ static void rtw_coex_power_save_state(struct rtw_dev *rtwdev, u8 ps_type, /* recover to original 32k low power setting */ coex_stat->wl_force_lps_ctrl = false; - rtwvif = lps_conf->rtwvif; - if (rtwvif && rtw_in_lps(rtwdev)) - rtw_leave_lps(rtwdev, rtwvif); + rtw_leave_lps(rtwdev); break; case COEX_PS_LPS_OFF: coex_stat->wl_force_lps_ctrl = true; if (lps_mode) rtw_fw_coex_tdma_type(rtwdev, 0x8, 0, 0, 0, 0); - rtwvif = lps_conf->rtwvif; - if (rtwvif && rtw_in_lps(rtwdev)) - rtw_leave_lps(rtwdev, rtwvif); + rtw_leave_lps(rtwdev); break; default: break; diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 6d5cce09eb14..66c05c492587 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -464,7 +464,7 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; u32 config = 0; - rtw_leave_lps(rtwdev, rtwvif); + rtw_leave_lps(rtwdev); mutex_lock(&rtwdev->mutex); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 22fc5d6f6b62..85d83f154f71 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -181,9 +181,9 @@ static void rtw_watch_dog_work(struct work_struct *work) */ if (rtw_fw_support_lps && data.rtwvif && !data.active && data.assoc_cnt == 1) - rtw_enter_lps(rtwdev, data.rtwvif); + rtw_enter_lps(rtwdev, data.rtwvif->port); else - rtw_leave_lps(rtwdev, rtwdev->lps_conf.rtwvif); + rtw_leave_lps(rtwdev); if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) return; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 0955970d6f4d..8472134c65b7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -533,8 +533,6 @@ enum rtw_pwr_state { }; struct rtw_lps_conf { - /* the interface to enter lps */ - struct rtw_vif *rtwvif; enum rtw_lps_mode mode; enum rtw_pwr_state state; u8 awake_interval; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index ffba3bd7bb31..a1541774cf0d 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -96,36 +96,27 @@ bool rtw_in_lps(struct rtw_dev *rtwdev) return test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; - if (WARN_ON(!rtwvif)) - return; - - if (rtwvif->in_lps) + if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; conf->mode = RTW_MODE_LPS; - conf->rtwvif = rtwvif; - rtwvif->in_lps = true; + conf->port_id = port_id; rtw_enter_lps_core(rtwdev); } -void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +void rtw_leave_lps(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; - if (WARN_ON(!rtwvif)) - return; - - if (!rtwvif->in_lps) + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; conf->mode = RTW_MODE_ACTIVE; - conf->rtwvif = rtwvif; - rtwvif->in_lps = false; rtw_leave_lps_core(rtwdev); } diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 0ac6c2983a06..d2aae613bca4 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -10,8 +10,8 @@ int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); -void rtw_enter_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); -void rtw_leave_lps(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif); +void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id); +void rtw_leave_lps(struct rtw_dev *rtwdev); bool rtw_in_lps(struct rtw_dev *rtwdev); #endif -- cgit v1.2.3-59-g8ed1b From 5235d63640c60ad5384310bd88ce0a6d8f87179e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:21 +0800 Subject: rtw88: remove unused lps state check helper This is no more used, remove it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 5 ----- drivers/net/wireless/realtek/rtw88/ps.h | 1 - 2 files changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index a1541774cf0d..d57996e446fb 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -91,11 +91,6 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -bool rtw_in_lps(struct rtw_dev *rtwdev) -{ - return test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); -} - void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index d2aae613bca4..5aed11b5c182 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -12,6 +12,5 @@ int rtw_leave_ips(struct rtw_dev *rtwdev); void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id); void rtw_leave_lps(struct rtw_dev *rtwdev); -bool rtw_in_lps(struct rtw_dev *rtwdev); #endif -- cgit v1.2.3-59-g8ed1b From d3e20fd17d0b6891a3b6f598abad38da2ab6a70f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:22 +0800 Subject: rtw88: LPS enter/leave should be protected by lock Protect LPS enter/leave routine with rtwdev->mutex. This helps to synchronize with driver's states correctly. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 4 ++-- drivers/net/wireless/realtek/rtw88/main.c | 9 +++++++-- drivers/net/wireless/realtek/rtw88/ps.c | 4 ++++ 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 66c05c492587..984644f64610 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -464,10 +464,10 @@ static void rtw_ops_sw_scan_start(struct ieee80211_hw *hw, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; u32 config = 0; - rtw_leave_lps(rtwdev); - mutex_lock(&rtwdev->mutex); + rtw_leave_lps(rtwdev); + ether_addr_copy(rtwvif->mac_addr, mac_addr); config |= PORT_SET_MAC_ADDR; rtw_vif_port_config(rtwdev, rtwvif, config); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 85d83f154f71..f55eda9da827 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -152,8 +152,10 @@ static void rtw_watch_dog_work(struct work_struct *work) struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + mutex_lock(&rtwdev->mutex); + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) - return; + goto unlock; ieee80211_queue_delayed_work(rtwdev->hw, &rtwdev->watch_dog_work, RTW_WATCH_DOG_DELAY_TIME); @@ -186,11 +188,14 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_leave_lps(rtwdev); if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) - return; + goto unlock; rtw_phy_dynamic_mechanism(rtwdev); rtwdev->watch_dog_cnt++; + +unlock: + mutex_unlock(&rtwdev->mutex); } static void rtw_c2h_work(struct work_struct *work) diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index d57996e446fb..af5c7be2ef0f 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -95,6 +95,8 @@ void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; + lockdep_assert_held(&rtwdev->mutex); + if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; @@ -108,6 +110,8 @@ void rtw_leave_lps(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; + lockdep_assert_held(&rtwdev->mutex); + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; -- cgit v1.2.3-59-g8ed1b From 37ba5de2e731afbfe606d7192a8aeba625abdaba Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:23 +0800 Subject: rtw88: leave PS state for dynamic mechanism Dynamic mechanism requires BB/RF working to adjust hardware settings. But PS state periodically turns off BB/RF, could lead to wrong setting. So leave PS state before DM to make sure it works. And then check if we can enter PS state again. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f55eda9da827..00ebf8cc81b1 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -174,6 +174,14 @@ static void rtw_watch_dog_work(struct work_struct *work) rtwdev->stats.tx_cnt = 0; rtwdev->stats.rx_cnt = 0; + if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) + goto unlock; + + /* make sure BB/RF is working for dynamic mech */ + rtw_leave_lps(rtwdev); + + rtw_phy_dynamic_mechanism(rtwdev); + /* use atomic version to avoid taking local->iflist_mtx mutex */ rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); @@ -184,13 +192,6 @@ static void rtw_watch_dog_work(struct work_struct *work) if (rtw_fw_support_lps && data.rtwvif && !data.active && data.assoc_cnt == 1) rtw_enter_lps(rtwdev, data.rtwvif->port); - else - rtw_leave_lps(rtwdev); - - if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) - goto unlock; - - rtw_phy_dynamic_mechanism(rtwdev); rtwdev->watch_dog_cnt++; -- cgit v1.2.3-59-g8ed1b From 27e117e4b01b5e699a40a3891b4f6924f99011d7 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:24 +0800 Subject: rtw88: add deep power save support Deep power save allows firmware/hardware to operate in a lower power state. And the deep power save mode depends on LPS mode. So, before entering deep PS, driver must first enter LPS mode. Under Deep PS, most of hardware functions are shutdown, driver will not be able to read/write registers and transfer data to the device. Hence TX path must be protected by each interface. Take PCI for example, DMA engine should be idle, and no nore activities on the PCI bus. If driver wants to operate on the device, such as register read/write, it must first acquire the mutex lock and wake up from Deep PS, otherwise the behavior is undefined. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/debug.h | 1 + drivers/net/wireless/realtek/rtw88/hci.h | 6 ++ drivers/net/wireless/realtek/rtw88/mac80211.c | 14 ++++ drivers/net/wireless/realtek/rtw88/main.c | 1 + drivers/net/wireless/realtek/rtw88/main.h | 2 + drivers/net/wireless/realtek/rtw88/pci.c | 71 ++++++++++++++++++ drivers/net/wireless/realtek/rtw88/ps.c | 100 ++++++++++++++++++++++++-- drivers/net/wireless/realtek/rtw88/ps.h | 5 ++ 8 files changed, 195 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index 45851cbbd2ab..9449105f4259 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -16,6 +16,7 @@ enum rtw_debug_mask { RTW_DBG_RFK = 0x00000080, RTW_DBG_REGD = 0x00000100, RTW_DBG_DEBUGFS = 0x00000200, + RTW_DBG_PS = 0x00000400, RTW_DBG_ALL = 0xffffffff }; diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h index aba329c9d0cf..4afbf0d163d1 100644 --- a/drivers/net/wireless/realtek/rtw88/hci.h +++ b/drivers/net/wireless/realtek/rtw88/hci.h @@ -13,6 +13,7 @@ struct rtw_hci_ops { int (*setup)(struct rtw_dev *rtwdev); int (*start)(struct rtw_dev *rtwdev); void (*stop)(struct rtw_dev *rtwdev); + void (*deep_ps)(struct rtw_dev *rtwdev, bool enter); int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size); int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size); @@ -47,6 +48,11 @@ static inline void rtw_hci_stop(struct rtw_dev *rtwdev) rtwdev->hci.ops->stop(rtwdev); } +static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter) +{ + rtwdev->hci.ops->deep_ps(rtwdev, enter); +} + static inline int rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) { diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 984644f64610..e241d054bf0f 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -60,6 +60,8 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed & IEEE80211_CONF_CHANGE_IDLE) { if (hw->conf.flags & IEEE80211_CONF_IDLE) { rtw_enter_ips(rtwdev); @@ -139,6 +141,8 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: @@ -181,6 +185,8 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + eth_zero_addr(rtwvif->mac_addr); config |= PORT_SET_MAC_ADDR; rtwvif->net_type = RTW_NET_NO_LINK; @@ -204,6 +210,8 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed_flags & FIF_ALLMULTI) { if (*new_flags & FIF_ALLMULTI) rtwdev->hal.rcr |= BIT_AM | BIT_AB; @@ -249,6 +257,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (changed & BSS_CHANGED_ASSOC) { struct rtw_chip_info *chip = rtwdev->chip; enum rtw_net_type net_type; @@ -266,6 +276,7 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_send_rsvd_page_h2c(rtwdev); rtw_coex_media_status_notify(rtwdev, conf->assoc); } else { + rtw_leave_lps(rtwdev); net_type = RTW_NET_NO_LINK; rtwvif->aid = 0; rtw_reset_rsvd_page(rtwdev); @@ -397,6 +408,8 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) { hw_key_idx = rtw_sec_get_free_cam(sec); } else { @@ -508,6 +521,7 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, struct rtw_dev *rtwdev = hw->priv; mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); rtw_coex_connect_notify(rtwdev, COEX_ASSOCIATE_START); mutex_unlock(&rtwdev->mutex); } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 00ebf8cc81b1..0d7ad1756bd6 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -922,6 +922,7 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) switch (rtw_hci_type(rtwdev)) { case RTW_HCI_TYPE_PCIE: rtwdev->hci.rpwm_addr = 0x03d9; + rtwdev->hci.cpwm_addr = 0x03da; break; default: rtw_err(rtwdev, "unsupported hci type\n"); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 8472134c65b7..6e6b04759ace 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -50,6 +50,7 @@ struct rtw_hci { enum rtw_hci_type type; u32 rpwm_addr; + u32 cpwm_addr; u8 bulkout_num; }; @@ -309,6 +310,7 @@ enum rtw_flags { RTW_FLAG_SCANNING, RTW_FLAG_INACTIVE_PS, RTW_FLAG_LEISURE_PS, + RTW_FLAG_LEISURE_PS_DEEP, RTW_FLAG_DIG_DISABLE, RTW_FLAG_BUSY_TRAFFIC, diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 509743cfd70a..772a14d851fc 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -9,6 +9,7 @@ #include "tx.h" #include "rx.h" #include "fw.h" +#include "ps.h" #include "debug.h" static bool rtw_disable_msi; @@ -536,6 +537,69 @@ static void rtw_pci_stop(struct rtw_dev *rtwdev) spin_unlock_irqrestore(&rtwpci->irq_lock, flags); } +static void rtw_pci_deep_ps_enter(struct rtw_dev *rtwdev) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + struct rtw_pci_tx_ring *tx_ring; + bool tx_empty = true; + u8 queue; + + lockdep_assert_held(&rtwpci->irq_lock); + + /* Deep PS state is not allowed to TX-DMA */ + for (queue = 0; queue < RTK_MAX_TX_QUEUE_NUM; queue++) { + /* BCN queue is rsvd page, does not have DMA interrupt + * H2C queue is managed by firmware + */ + if (queue == RTW_TX_QUEUE_BCN || + queue == RTW_TX_QUEUE_H2C) + continue; + + tx_ring = &rtwpci->tx_rings[queue]; + + /* check if there is any skb DMAing */ + if (skb_queue_len(&tx_ring->queue)) { + tx_empty = false; + break; + } + } + + if (!tx_empty) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "TX path not empty, cannot enter deep power save state\n"); + return; + } + + set_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags); + rtw_power_mode_change(rtwdev, true); +} + +static void rtw_pci_deep_ps_leave(struct rtw_dev *rtwdev) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + + lockdep_assert_held(&rtwpci->irq_lock); + + if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_power_mode_change(rtwdev, false); +} + +static void rtw_pci_deep_ps(struct rtw_dev *rtwdev, bool enter) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + unsigned long flags; + + spin_lock_irqsave(&rtwpci->irq_lock, flags); + + if (enter && !test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_pci_deep_ps_enter(rtwdev); + + if (!enter && test_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) + rtw_pci_deep_ps_leave(rtwdev); + + spin_unlock_irqrestore(&rtwpci->irq_lock, flags); +} + static u8 ac_to_hwq[] = { [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, @@ -616,6 +680,7 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, u8 *pkt_desc; struct rtw_pci_tx_buffer_desc *buf_desc; u32 bd_idx; + unsigned long flags; ring = &rtwpci->tx_rings[queue]; @@ -651,6 +716,10 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, tx_data = rtw_pci_get_tx_data(skb); tx_data->dma = dma; tx_data->sn = pkt_info->sn; + + spin_lock_irqsave(&rtwpci->irq_lock, flags); + + rtw_pci_deep_ps_leave(rtwdev); skb_queue_tail(&ring->queue, skb); /* kick off tx queue */ @@ -666,6 +735,7 @@ static int rtw_pci_xmit(struct rtw_dev *rtwdev, reg_bcn_work |= BIT_PCI_BCNQ_FLAG; rtw_write8(rtwdev, RTK_PCI_TXBD_BCN_WORK, reg_bcn_work); } + spin_unlock_irqrestore(&rtwpci->irq_lock, flags); return 0; } @@ -1142,6 +1212,7 @@ static struct rtw_hci_ops rtw_pci_ops = { .setup = rtw_pci_setup, .start = rtw_pci_start, .stop = rtw_pci_stop, + .deep_ps = rtw_pci_deep_ps, .read8 = rtw_pci_read8, .read16 = rtw_pci_read16, diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index af5c7be2ef0f..4b5774687d21 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -3,6 +3,7 @@ */ #include "main.h" +#include "reg.h" #include "fw.h" #include "ps.h" #include "mac.h" @@ -61,6 +62,59 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) return 0; } +void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) +{ + u8 request, confirm, polling; + u8 polling_cnt; + u8 retry_cnt = 0; + +retry: + request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); + confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + + /* toggle to request power mode, others remain 0 */ + request ^= request | BIT_RPWM_TOGGLE; + if (!enter) + request |= POWER_MODE_ACK; + else + request |= POWER_MODE_LCLK; + + rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); + + /* check confirm power mode has left power save state */ + if (!enter) { + for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) { + polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + if ((polling ^ confirm) & BIT_RPWM_TOGGLE) + return; + mdelay(20); + } + + /* in case of fw/hw missed the request, retry 3 times */ + if (retry_cnt < 3) { + rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", + retry_cnt); + retry_cnt++; + goto retry; + } + + /* Hit here means that driver failed to change hardware + * power mode to active state after retry 3 times. + * If the power state is locked at Deep sleep, most of + * the hardware circuits is not working, even register + * read/write. It should be treated as fatal error and + * requires an entire analysis about the firmware/hardware + */ + WARN_ON("Hardware power state locked\n"); + } +} +EXPORT_SYMBOL(rtw_power_mode_change); + +static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev) +{ + rtw_hci_deep_ps(rtwdev, false); +} + static void rtw_leave_lps_core(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -76,6 +130,17 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); } +static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) +{ + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "Should enter LPS before entering deep PS\n"); + return; + } + + rtw_hci_deep_ps(rtwdev, true); +} + static void rtw_enter_lps_core(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -91,12 +156,10 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) +static void __rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; - lockdep_assert_held(&rtwdev->mutex); - if (test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; @@ -106,11 +169,15 @@ void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) rtw_enter_lps_core(rtwdev); } -void rtw_leave_lps(struct rtw_dev *rtwdev) +static void __rtw_leave_lps(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; - lockdep_assert_held(&rtwdev->mutex); + if (test_and_clear_bit(RTW_FLAG_LEISURE_PS_DEEP, rtwdev->flags)) { + rtw_dbg(rtwdev, RTW_DBG_PS, + "Should leave deep PS before leaving LPS\n"); + __rtw_leave_lps_deep(rtwdev); + } if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) return; @@ -119,3 +186,26 @@ void rtw_leave_lps(struct rtw_dev *rtwdev) rtw_leave_lps_core(rtwdev); } + +void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) +{ + lockdep_assert_held(&rtwdev->mutex); + + __rtw_enter_lps(rtwdev, port_id); + __rtw_enter_lps_deep(rtwdev); +} + +void rtw_leave_lps(struct rtw_dev *rtwdev) +{ + lockdep_assert_held(&rtwdev->mutex); + + __rtw_leave_lps_deep(rtwdev); + __rtw_leave_lps(rtwdev); +} + +void rtw_leave_lps_deep(struct rtw_dev *rtwdev) +{ + lockdep_assert_held(&rtwdev->mutex); + + __rtw_leave_lps_deep(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 5aed11b5c182..03b08bd98dc4 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -7,10 +7,15 @@ #define RTW_LPS_THRESHOLD 2 +#define POWER_MODE_ACK BIT(6) +#define POWER_MODE_LCLK BIT(0) + int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); +void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter); void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id); void rtw_leave_lps(struct rtw_dev *rtwdev); +void rtw_leave_lps_deep(struct rtw_dev *rtwdev); #endif -- cgit v1.2.3-59-g8ed1b From 3a068a2a65859764198fa606aa9b287fc4fe1f03 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:25 +0800 Subject: rtw88: not to enter LPS by coex strategy Sometimes LPS is not compatible with COEX's strategy, and COEX will not allow driver to enter it. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 4b5774687d21..1661cc2e5fe3 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -191,6 +191,9 @@ void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id) { lockdep_assert_held(&rtwdev->mutex); + if (rtwdev->coex.stat.wl_force_lps_ctrl) + return; + __rtw_enter_lps(rtwdev, port_id); __rtw_enter_lps_deep(rtwdev); } -- cgit v1.2.3-59-g8ed1b From d3be4d115be05b1b4323286bc69de9e577fc9a0f Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:26 +0800 Subject: rtw88: select deep PS mode when module is inserted Add a module parameter to select deep PS mode. And the mode cannot be changed after the module has been inserted and probed. If anyone wants to change the deep mode, should change the mode and probe the device again to setup the changed deep mode. When the device is probed, driver will check the deep PS mode with different IC's PS mode suppotability. If none of the PS mode is matched, the deep PS mode is changed to NONE, means deep PS is disabled. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 9 +++++++++ drivers/net/wireless/realtek/rtw88/main.h | 8 ++++++++ drivers/net/wireless/realtek/rtw88/ps.c | 3 +++ drivers/net/wireless/realtek/rtw88/rtw8822b.c | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 1 + 5 files changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 0d7ad1756bd6..3c366a3314cb 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -14,13 +14,17 @@ #include "efuse.h" #include "debug.h" +unsigned int rtw_fw_lps_deep_mode; +EXPORT_SYMBOL(rtw_fw_lps_deep_mode); static bool rtw_fw_support_lps; unsigned int rtw_debug_mask; EXPORT_SYMBOL(rtw_debug_mask); +module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); module_param_named(support_lps, rtw_fw_support_lps, bool, 0644); module_param_named(debug_mask, rtw_debug_mask, uint, 0644); +MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); MODULE_PARM_DESC(support_lps, "Set Y to enable Leisure Power Save support, to turn radio off between beacons"); MODULE_PARM_DESC(debug_mask, "Debugging mask"); @@ -1152,6 +1156,7 @@ EXPORT_SYMBOL(rtw_chip_info_setup); int rtw_core_init(struct rtw_dev *rtwdev) { + struct rtw_chip_info *chip = rtwdev->chip; struct rtw_coex *coex = &rtwdev->coex; int ret; @@ -1183,6 +1188,10 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtwdev->sec.total_cam_num = 32; rtwdev->hal.current_channel = 1; set_bit(RTW_BC_MC_MACID, rtwdev->mac_id_map); + if (!(BIT(rtw_fw_lps_deep_mode) & chip->lps_deep_mode_supported)) + rtwdev->lps_conf.deep_mode = LPS_DEEP_MODE_NONE; + else + rtwdev->lps_conf.deep_mode = rtw_fw_lps_deep_mode; mutex_lock(&rtwdev->mutex); rtw_add_rsvd_page(rtwdev, RSVD_BEACON, false); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 6e6b04759ace..a59cbaefde4e 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -27,6 +27,7 @@ #define RTW_RF_PATH_MAX 4 #define HW_FEATURE_LEN 13 +extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; extern struct rtw_chip_info rtw8822b_hw_spec; @@ -528,6 +529,11 @@ enum rtw_lps_mode { RTW_MODE_WMM_PS = 2, }; +enum rtw_lps_deep_mode { + LPS_DEEP_MODE_NONE = 0, + LPS_DEEP_MODE_LCLK = 1, +}; + enum rtw_pwr_state { RTW_RF_OFF = 0x0, RTW_RF_ON = 0x4, @@ -536,6 +542,7 @@ enum rtw_pwr_state { struct rtw_lps_conf { enum rtw_lps_mode mode; + enum rtw_lps_deep_mode deep_mode; enum rtw_pwr_state state; u8 awake_interval; u8 rlbm; @@ -844,6 +851,7 @@ struct rtw_chip_info { bool ht_supported; bool vht_supported; + u8 lps_deep_mode_supported; /* init values */ u8 sys_func_en; diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 1661cc2e5fe3..02e104ac7b9e 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -132,6 +132,9 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) { + if (rtwdev->lps_conf.deep_mode == LPS_DEEP_MODE_NONE) + return; + if (!test_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags)) { rtw_dbg(rtwdev, RTW_DBG_PS, "Should enter LPS before entering deep PS\n"); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 63abda3b0ebf..2b6cd7cf763b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -1977,6 +1977,7 @@ struct rtw_chip_info rtw8822b_hw_spec = { .dig_min = 0x1c, .ht_supported = true, .vht_supported = true, + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), .sys_func_en = 0xDC, .pwr_on_seq = card_enable_flow_8822b, .pwr_off_seq = card_disable_flow_8822b, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 084c18d115d5..b92940e501eb 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3747,6 +3747,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .dig_min = 0x20, .ht_supported = true, .vht_supported = true, + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), .sys_func_en = 0xD8, .pwr_on_seq = card_enable_flow_8822c, .pwr_off_seq = card_disable_flow_8822c, -- cgit v1.2.3-59-g8ed1b From 04b786e00987c5495dd9a374deb9c9d7f650a9da Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:27 +0800 Subject: rtw88: add deep PS PG mode for 8822c Compare with LCLK mode, PG mode saves more power, by turning off more circuits. Therefore, to recover from PG mode, driver needs to backup some information into rsvd page. Such as CAM entries, DPK results. As CAM entries can change, it is required to re-download CAM entries after set_key. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 77 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 29 ++++++++++ drivers/net/wireless/realtek/rtw88/mac80211.c | 6 +++ drivers/net/wireless/realtek/rtw88/main.h | 3 ++ drivers/net/wireless/realtek/rtw88/ps.c | 10 +++- drivers/net/wireless/realtek/rtw88/ps.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 2 +- drivers/net/wireless/realtek/rtw88/sec.c | 21 ++++++++ drivers/net/wireless/realtek/rtw88/sec.h | 1 + 9 files changed, 147 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index b082e2cc95f5..430d73cff32e 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -7,6 +7,7 @@ #include "fw.h" #include "tx.h" #include "reg.h" +#include "sec.h" #include "debug.h" static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, @@ -397,6 +398,24 @@ static u8 rtw_get_rsvd_page_location(struct rtw_dev *rtwdev, return location; } +void rtw_fw_set_pg_info(struct rtw_dev *rtwdev) +{ + struct rtw_lps_conf *conf = &rtwdev->lps_conf; + u8 h2c_pkt[H2C_PKT_SIZE] = {0}; + u8 loc_pg, loc_dpk; + + loc_pg = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_INFO); + loc_dpk = rtw_get_rsvd_page_location(rtwdev, RSVD_LPS_PG_DPK); + + SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_LPS_PG_INFO); + + LPS_PG_INFO_LOC(h2c_pkt, loc_pg); + LPS_PG_DPK_LOC(h2c_pkt, loc_dpk); + LPS_PG_SEC_CAM_EN(h2c_pkt, conf->sec_cam_backup); + + rtw_fw_send_h2c_command(rtwdev, h2c_pkt); +} + void rtw_send_rsvd_page_h2c(struct rtw_dev *rtwdev) { u8 h2c_pkt[H2C_PKT_SIZE] = {0}; @@ -442,6 +461,58 @@ rtw_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif) return skb_new; } +static struct sk_buff *rtw_lps_pg_dpk_get(struct ieee80211_hw *hw) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; + struct rtw_lps_pg_dpk_hdr *dpk_hdr; + struct sk_buff *skb; + u32 size; + + size = chip->tx_pkt_desc_sz + sizeof(*dpk_hdr); + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, chip->tx_pkt_desc_sz); + dpk_hdr = skb_put_zero(skb, sizeof(*dpk_hdr)); + dpk_hdr->dpk_ch = dpk_info->dpk_ch; + dpk_hdr->dpk_path_ok = dpk_info->dpk_path_ok[0]; + memcpy(dpk_hdr->dpk_txagc, dpk_info->dpk_txagc, 2); + memcpy(dpk_hdr->dpk_gs, dpk_info->dpk_gs, 4); + memcpy(dpk_hdr->coef, dpk_info->coef, 160); + + return skb; +} + +static struct sk_buff *rtw_lps_pg_info_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_lps_conf *conf = &rtwdev->lps_conf; + struct rtw_lps_pg_info_hdr *pg_info_hdr; + struct sk_buff *skb; + u32 size; + + size = chip->tx_pkt_desc_sz + sizeof(*pg_info_hdr); + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) + return NULL; + + skb_reserve(skb, chip->tx_pkt_desc_sz); + pg_info_hdr = skb_put_zero(skb, sizeof(*pg_info_hdr)); + pg_info_hdr->tx_bu_page_count = rtwdev->fifo.rsvd_drv_pg_num; + pg_info_hdr->macid = find_first_bit(rtwdev->mac_id_map, RTW_MAX_MAC_ID_NUM); + pg_info_hdr->sec_cam_count = + rtw_sec_cam_pg_backup(rtwdev, pg_info_hdr->sec_cam); + + conf->sec_cam_backup = pg_info_hdr->sec_cam_count != 0; + + return skb; +} + static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum rtw_rsvd_packet_type type) @@ -464,6 +535,12 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, case RSVD_QOS_NULL: skb_new = ieee80211_nullfunc_get(hw, vif, true); break; + case RSVD_LPS_PG_DPK: + skb_new = rtw_lps_pg_dpk_get(hw); + break; + case RSVD_LPS_PG_INFO: + skb_new = rtw_lps_pg_info_get(hw, vif); + break; default: return NULL; } diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index e95d85bd097f..f4028ef63ee8 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -58,6 +58,8 @@ enum rtw_rsvd_packet_type { RSVD_PROBE_RESP, RSVD_NULL, RSVD_QOS_NULL, + RSVD_LPS_PG_DPK, + RSVD_LPS_PG_INFO, }; enum rtw_fw_rf_type { @@ -86,6 +88,25 @@ struct rtw_iqk_para { u8 segment_iqk; }; +struct rtw_lps_pg_dpk_hdr { + u16 dpk_path_ok; + u8 dpk_txagc[2]; + u16 dpk_gs[2]; + u32 coef[2][20]; + u8 dpk_ch; +} __packed; + +struct rtw_lps_pg_info_hdr { + u8 macid; + u8 mbssid; + u8 pattern_count; + u8 mu_tab_group_id; + u8 sec_cam_count; + u8 tx_bu_page_count; + u16 rsvd; + u8 sec_cam[MAX_PG_CAM_BACKUP_NUM]; +} __packed; + struct rtw_rsvd_page { struct list_head list; struct sk_buff *skb; @@ -146,6 +167,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) #define H2C_CMD_RSVD_PAGE 0x0 #define H2C_CMD_MEDIA_STATUS_RPT 0x01 #define H2C_CMD_SET_PWR_MODE 0x20 +#define H2C_CMD_LPS_PG_INFO 0x2b #define H2C_CMD_RA_INFO 0x40 #define H2C_CMD_RSSI_MONITOR 0x42 @@ -177,6 +199,12 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id) le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(7, 5)) #define SET_PWR_MODE_SET_PWR_STATE(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x01, value, GENMASK(15, 8)) +#define LPS_PG_INFO_LOC(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(23, 16)) +#define LPS_PG_DPK_LOC(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(31, 24)) +#define LPS_PG_SEC_CAM_EN(h2c_pkt, value) \ + le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8)) #define SET_RSSI_INFO_MACID(h2c_pkt, value) \ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, GENMASK(15, 8)) #define SET_RSSI_INFO_RSSI(h2c_pkt, value) \ @@ -270,6 +298,7 @@ void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev); void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para); void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev); +void rtw_fw_set_pg_info(struct rtw_dev *rtwdev); void rtw_fw_query_bt_info(struct rtw_dev *rtwdev); void rtw_fw_wl_ch_info(struct rtw_dev *rtwdev, u8 link, u8 ch, u8 bw); void rtw_fw_query_bt_mp_info(struct rtw_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index e241d054bf0f..22b13e45fcee 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -272,6 +272,8 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_add_rsvd_page(rtwdev, RSVD_PS_POLL, true); rtw_add_rsvd_page(rtwdev, RSVD_QOS_NULL, true); rtw_add_rsvd_page(rtwdev, RSVD_NULL, true); + rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_DPK, true); + rtw_add_rsvd_page(rtwdev, RSVD_LPS_PG_INFO, true); rtw_fw_download_rsvd_page(rtwdev, vif); rtw_send_rsvd_page_h2c(rtwdev); rtw_coex_media_status_notify(rtwdev, conf->assoc); @@ -435,6 +437,10 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; } + /* download new cam settings for PG to backup */ + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + rtw_fw_download_rsvd_page(rtwdev, vif); + out: mutex_unlock(&rtwdev->mutex); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index a59cbaefde4e..6221dc45fc2a 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -16,6 +16,7 @@ #define RTW_MAX_MAC_ID_NUM 32 #define RTW_MAX_SEC_CAM_NUM 32 +#define MAX_PG_CAM_BACKUP_NUM 8 #define RTW_WATCH_DOG_DELAY_TIME round_jiffies_relative(HZ * 2) @@ -532,6 +533,7 @@ enum rtw_lps_mode { enum rtw_lps_deep_mode { LPS_DEEP_MODE_NONE = 0, LPS_DEEP_MODE_LCLK = 1, + LPS_DEEP_MODE_PG = 2, }; enum rtw_pwr_state { @@ -548,6 +550,7 @@ struct rtw_lps_conf { u8 rlbm; u8 smart_ps; u8 port_id; + bool sec_cam_backup; }; enum rtw_hw_key_type { diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 02e104ac7b9e..83db6cf6a219 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -74,10 +74,13 @@ retry: /* toggle to request power mode, others remain 0 */ request ^= request | BIT_RPWM_TOGGLE; - if (!enter) + if (!enter) { request |= POWER_MODE_ACK; - else + } else { request |= POWER_MODE_LCLK; + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + request |= POWER_MODE_PG; + } rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); @@ -141,6 +144,9 @@ static void __rtw_enter_lps_deep(struct rtw_dev *rtwdev) return; } + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + rtw_fw_set_pg_info(rtwdev); + rtw_hci_deep_ps(rtwdev, true); } diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 03b08bd98dc4..18f687cfe211 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -8,6 +8,7 @@ #define RTW_LPS_THRESHOLD 2 #define POWER_MODE_ACK BIT(6) +#define POWER_MODE_PG BIT(4) #define POWER_MODE_LCLK BIT(0) int rtw_enter_ips(struct rtw_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index b92940e501eb..a300efdf264e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3747,7 +3747,7 @@ struct rtw_chip_info rtw8822c_hw_spec = { .dig_min = 0x20, .ht_supported = true, .vht_supported = true, - .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK), + .lps_deep_mode_supported = BIT(LPS_DEEP_MODE_LCLK) | BIT(LPS_DEEP_MODE_PG), .sys_func_en = 0xD8, .pwr_on_seq = card_enable_flow_8822c, .pwr_off_seq = card_disable_flow_8822c, diff --git a/drivers/net/wireless/realtek/rtw88/sec.c b/drivers/net/wireless/realtek/rtw88/sec.c index c594fc02804d..d0d7fbb10d58 100644 --- a/drivers/net/wireless/realtek/rtw88/sec.c +++ b/drivers/net/wireless/realtek/rtw88/sec.c @@ -96,6 +96,27 @@ void rtw_sec_clear_cam(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTW_SEC_CMD_REG, command); } +u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam) +{ + struct rtw_sec_desc *sec = &rtwdev->sec; + u8 offset = 0; + u8 count, n; + + if (!used_cam) + return 0; + + for (count = 0; count < MAX_PG_CAM_BACKUP_NUM; count++) { + n = find_next_bit(sec->cam_map, RTW_MAX_SEC_CAM_NUM, offset); + if (n == RTW_MAX_SEC_CAM_NUM) + break; + + used_cam[count] = n; + offset = n + 1; + } + + return count; +} + void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev) { struct rtw_sec_desc *sec = &rtwdev->sec; diff --git a/drivers/net/wireless/realtek/rtw88/sec.h b/drivers/net/wireless/realtek/rtw88/sec.h index 8c50a895c797..efcf45433999 100644 --- a/drivers/net/wireless/realtek/rtw88/sec.h +++ b/drivers/net/wireless/realtek/rtw88/sec.h @@ -34,6 +34,7 @@ void rtw_sec_write_cam(struct rtw_dev *rtwdev, void rtw_sec_clear_cam(struct rtw_dev *rtwdev, struct rtw_sec_desc *sec, u8 hw_key_idx); +u8 rtw_sec_cam_pg_backup(struct rtw_dev *rtwdev, u8 *used_cam); void rtw_sec_enable_sec_engine(struct rtw_dev *rtwdev); #endif -- cgit v1.2.3-59-g8ed1b From bcde60e599fb044744b4e379ab74ea323a75ce5e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 10:31:28 +0800 Subject: rtw88: remove misleading module parameter rtw_fw_support_lps The module parameter rtw_fw_support_lps is misleading. It is not used to represent the firmware's property, but to determine if driver wants to ask firmware to enter LPS. However, driver should better enable/disable PS through cfg80211_ops::set_power_mgmt instead. For example, one could use iw command to set PS state. $ sudo iw wlanX set power_save [on/off] So rtw_fw_support_lps should be removed because it is misleading and useless. Instead of checking the parameter, set PS mode according to IEEE80211_CONF_PS. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 9 ++++++++ drivers/net/wireless/realtek/rtw88/main.c | 33 ++++++++++++--------------- drivers/net/wireless/realtek/rtw88/main.h | 1 + 3 files changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 22b13e45fcee..97777c7fdce8 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -74,6 +74,15 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) } } + if (changed & IEEE80211_CONF_CHANGE_PS) { + if (hw->conf.flags & IEEE80211_CONF_PS) { + rtwdev->ps_enabled = true; + } else { + rtwdev->ps_enabled = false; + rtw_leave_lps(rtwdev); + } + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) rtw_set_channel(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 3c366a3314cb..a3e9f917adef 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -16,16 +16,13 @@ unsigned int rtw_fw_lps_deep_mode; EXPORT_SYMBOL(rtw_fw_lps_deep_mode); -static bool rtw_fw_support_lps; unsigned int rtw_debug_mask; EXPORT_SYMBOL(rtw_debug_mask); module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); -module_param_named(support_lps, rtw_fw_support_lps, bool, 0644); module_param_named(debug_mask, rtw_debug_mask, uint, 0644); MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); -MODULE_PARM_DESC(support_lps, "Set Y to enable Leisure Power Save support, to turn radio off between beacons"); MODULE_PARM_DESC(debug_mask, "Debugging mask"); static struct ieee80211_channel rtw_channeltable_2g[] = { @@ -117,8 +114,6 @@ static struct ieee80211_supported_band rtw_band_5ghz = { struct rtw_watch_dog_iter_data { struct rtw_vif *rtwvif; - bool active; - u8 assoc_cnt; }; static void rtw_vif_watch_dog_iter(void *data, u8 *mac, @@ -127,18 +122,9 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, struct rtw_watch_dog_iter_data *iter_data = data; struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; - if (vif->type == NL80211_IFTYPE_STATION) { - if (vif->bss_conf.assoc) { - iter_data->assoc_cnt++; + if (vif->type == NL80211_IFTYPE_STATION) + if (vif->bss_conf.assoc) iter_data->rtwvif = rtwvif; - } - if (rtwvif->stats.tx_cnt > RTW_LPS_THRESHOLD || - rtwvif->stats.rx_cnt > RTW_LPS_THRESHOLD) - iter_data->active = true; - } else { - /* only STATION mode can enter lps */ - iter_data->active = true; - } rtwvif->stats.tx_unicast = 0; rtwvif->stats.rx_unicast = 0; @@ -155,6 +141,7 @@ static void rtw_watch_dog_work(struct work_struct *work) watch_dog_work.work); struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); + bool ps_active; mutex_lock(&rtwdev->mutex); @@ -172,6 +159,12 @@ static void rtw_watch_dog_work(struct work_struct *work) if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) rtw_coex_wl_status_change_notify(rtwdev); + if (rtwdev->stats.tx_cnt > RTW_LPS_THRESHOLD || + rtwdev->stats.rx_cnt > RTW_LPS_THRESHOLD) + ps_active = true; + else + ps_active = false; + /* reset tx/rx statictics */ rtwdev->stats.tx_unicast = 0; rtwdev->stats.rx_unicast = 0; @@ -192,9 +185,13 @@ static void rtw_watch_dog_work(struct work_struct *work) /* fw supports only one station associated to enter lps, if there are * more than two stations associated to the AP, then we can not enter * lps, because fw does not handle the overlapped beacon interval + * + * mac80211 should iterate vifs and determine if driver can enter + * ps by passing IEEE80211_CONF_PS to us, all we need to do is to + * get that vif and check if device is having traffic more than the + * threshold. */ - if (rtw_fw_support_lps && - data.rtwvif && !data.active && data.assoc_cnt == 1) + if (rtwdev->ps_enabled && data.rtwvif && !ps_active) rtw_enter_lps(rtwdev, data.rtwvif->port); rtwdev->watch_dog_cnt++; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 6221dc45fc2a..161297ad7d99 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -1372,6 +1372,7 @@ struct rtw_dev { /* lps power state & handler work */ struct rtw_lps_conf lps_conf; + bool ps_enabled; struct dentry *debugfs; -- cgit v1.2.3-59-g8ed1b From 4a50d454502f1401171ff061a5424583f91266db Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Oct 2019 14:45:01 +0300 Subject: cw1200: Fix a signedness bug in cw1200_load_firmware() The "priv->hw_type" is an enum and in this context GCC will treat it as an unsigned int so the error handling will never trigger. Fixes: a910e4a94f69 ("cw1200: add driver for the ST-E CW1100 & CW1200 WLAN chipsets") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/st/cw1200/fwio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/st/cw1200/fwio.c b/drivers/net/wireless/st/cw1200/fwio.c index 6574e78e05ea..2a03dc533b6a 100644 --- a/drivers/net/wireless/st/cw1200/fwio.c +++ b/drivers/net/wireless/st/cw1200/fwio.c @@ -320,12 +320,12 @@ int cw1200_load_firmware(struct cw1200_common *priv) goto out; } - priv->hw_type = cw1200_get_hw_type(val32, &major_revision); - if (priv->hw_type < 0) { + ret = cw1200_get_hw_type(val32, &major_revision); + if (ret < 0) { pr_err("Can't deduce hardware type.\n"); - ret = -ENOTSUPP; goto out; } + priv->hw_type = ret; /* Set DPLL Reg value, and read back to confirm writes work */ ret = cw1200_reg_write_32(priv, ST90TDS_TSET_GEN_R_W_REG_ID, -- cgit v1.2.3-59-g8ed1b From f1cdaa077ccacb0d78a2da5c9df9b4aa7b7a0927 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 30 Sep 2019 10:15:11 +0200 Subject: mlxsw: spectrum: Use per-netns netdevice notifier registration The mlxsw_sp instance is not interested in events happening in other network namespaces. So use "_net" variants for netdevice notifier registration/unregistration and get only events which are happening in the net the instance is in. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index dcf9562bce8a..a54a0dc82ff2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4864,7 +4864,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, * respin. */ mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; - err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb); + err = register_netdevice_notifier_net(&init_net, + &mlxsw_sp->netdevice_nb); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n"); goto err_netdev_notifier; @@ -4887,7 +4888,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, err_ports_create: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: - unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); + unregister_netdevice_notifier_net(&init_net, + &mlxsw_sp->netdevice_nb); err_netdev_notifier: if (mlxsw_sp->clock) mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); @@ -4973,7 +4975,8 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_ports_remove(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); - unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); + unregister_netdevice_notifier_net(&init_net, + &mlxsw_sp->netdevice_nb); if (mlxsw_sp->clock) { mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); mlxsw_sp->ptp_ops->clock_fini(mlxsw_sp->clock); -- cgit v1.2.3-59-g8ed1b From da0729e8d2ae3f2e725b4fa8c3bf99eeb12debec Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 30 Sep 2019 20:03:22 -0700 Subject: ionic: simplify returns in devlink info There is no need for a goto in this bit of code. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_devlink.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c index af1647afa4e8..6fb27dcc5787 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c @@ -19,31 +19,30 @@ static int ionic_dl_info_get(struct devlink *dl, struct devlink_info_req *req, err = devlink_info_driver_name_put(req, IONIC_DRV_NAME); if (err) - goto info_out; + return err; err = devlink_info_version_running_put(req, DEVLINK_INFO_VERSION_GENERIC_FW, idev->dev_info.fw_version); if (err) - goto info_out; + return err; snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_type); err = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf); if (err) - goto info_out; + return err; snprintf(buf, sizeof(buf), "0x%x", idev->dev_info.asic_rev); err = devlink_info_version_fixed_put(req, DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf); if (err) - goto info_out; + return err; err = devlink_info_serial_number_put(req, idev->dev_info.serial_num); -info_out: return err; } -- cgit v1.2.3-59-g8ed1b From d229be4b27a8b76d897f73dede9c25e6a6d3a6ad Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 30 Sep 2019 20:03:23 -0700 Subject: ionic: use wait_on_bit_lock() rather than open code Replace the open-coded ionic_wait_for_bit() with the kernel's wait_on_bit_lock(). Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 12 ++++++++---- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 5 +++-- drivers/net/ethernet/pensando/ionic/ionic_lif.h | 9 ++------- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index 7d10265f782a..7760fcd709b4 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -453,6 +453,7 @@ static int ionic_set_ringparam(struct net_device *netdev, { struct ionic_lif *lif = netdev_priv(netdev); bool running; + int err; if (ring->rx_mini_pending || ring->rx_jumbo_pending) { netdev_info(netdev, "Changing jumbo or mini descriptors not supported\n"); @@ -470,8 +471,9 @@ static int ionic_set_ringparam(struct net_device *netdev, ring->rx_pending == lif->nrxq_descs) return 0; - if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) - return -EBUSY; + err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + if (err) + return err; running = test_bit(IONIC_LIF_UP, lif->state); if (running) @@ -504,6 +506,7 @@ static int ionic_set_channels(struct net_device *netdev, { struct ionic_lif *lif = netdev_priv(netdev); bool running; + int err; if (!ch->combined_count || ch->other_count || ch->rx_count || ch->tx_count) @@ -512,8 +515,9 @@ static int ionic_set_channels(struct net_device *netdev, if (ch->combined_count == lif->nxqs) return 0; - if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) - return -EBUSY; + err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + if (err) + return err; running = test_bit(IONIC_LIF_UP, lif->state); if (running) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 72107a0627a9..4d5883a7e586 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1619,8 +1619,9 @@ int ionic_reset_queues(struct ionic_lif *lif) /* Put off the next watchdog timeout */ netif_trans_update(lif->netdev); - if (!ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET)) - return -EBUSY; + err = ionic_wait_for_bit(lif, IONIC_LIF_QUEUE_RESET); + if (err) + return err; running = netif_running(lif->netdev); if (running) diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index 812190e729c2..b74f7e9ee82d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -185,15 +185,10 @@ struct ionic_lif { #define lif_to_txq(lif, i) (&lif_to_txqcq((lif), i)->q) #define lif_to_rxq(lif, i) (&lif_to_txqcq((lif), i)->q) +/* return 0 if successfully set the bit, else non-zero */ static inline int ionic_wait_for_bit(struct ionic_lif *lif, int bitname) { - unsigned long tlimit = jiffies + HZ; - - while (test_and_set_bit(bitname, lif->state) && - time_before(jiffies, tlimit)) - usleep_range(100, 200); - - return test_bit(bitname, lif->state); + return wait_on_bit_lock(lif->state, bitname, TASK_INTERRUPTIBLE); } static inline u32 ionic_coal_usec_to_hw(struct ionic *ionic, u32 usecs) -- cgit v1.2.3-59-g8ed1b From 780eded34cccca642c241dad54d54de70f6c43ac Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 30 Sep 2019 20:03:24 -0700 Subject: ionic: report users coalesce request The user's request for an interrupt coalescing value gets translated into a hardware value to be used with the NIC, and was getting reported back based on the hw value, which, due to hw tic resolution, could be reported as a different number than what the user originally asked for. This code now tracks both the user request and what was put into the hardware so we can report back to the user what they requested. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_ethtool.c | 22 +++++++++++----------- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 11 +++++------ drivers/net/ethernet/pensando/ionic/ionic_lif.h | 4 +++- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index 7760fcd709b4..63cc14c060d6 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -372,7 +372,6 @@ static int ionic_set_coalesce(struct net_device *netdev, struct ionic_identity *ident; struct ionic_qcq *qcq; unsigned int i; - u32 usecs; u32 coal; if (coalesce->rx_max_coalesced_frames || @@ -410,26 +409,27 @@ static int ionic_set_coalesce(struct net_device *netdev, return -EINVAL; } + /* Convert the usec request to a HW useable value. If they asked + * for non-zero and it resolved to zero, bump it up + */ coal = ionic_coal_usec_to_hw(lif->ionic, coalesce->rx_coalesce_usecs); - - if (coal > IONIC_INTR_CTRL_COAL_MAX) - return -ERANGE; - - /* If they asked for non-zero and it resolved to zero, bump it up */ if (!coal && coalesce->rx_coalesce_usecs) coal = 1; - /* Convert it back to get device resolution */ - usecs = ionic_coal_hw_to_usec(lif->ionic, coal); + if (coal > IONIC_INTR_CTRL_COAL_MAX) + return -ERANGE; - if (usecs != lif->rx_coalesce_usecs) { - lif->rx_coalesce_usecs = usecs; + /* Save the new value */ + lif->rx_coalesce_usecs = coalesce->rx_coalesce_usecs; + if (coal != lif->rx_coalesce_hw) { + lif->rx_coalesce_hw = coal; if (test_bit(IONIC_LIF_UP, lif->state)) { for (i = 0; i < lif->nxqs; i++) { qcq = lif->rxqcqs[i].qcq; ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, - qcq->intr.index, coal); + qcq->intr.index, + lif->rx_coalesce_hw); } } } diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 4d5883a7e586..372329389c84 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1430,7 +1430,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) unsigned int flags; unsigned int i; int err = 0; - u32 coal; flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG; for (i = 0; i < lif->nxqs; i++) { @@ -1447,7 +1446,6 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) } flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_INTR; - coal = ionic_coal_usec_to_hw(lif->ionic, lif->rx_coalesce_usecs); for (i = 0; i < lif->nxqs; i++) { err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags, lif->nrxq_descs, @@ -1460,7 +1458,8 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) lif->rxqcqs[i].qcq->stats = lif->rxqcqs[i].stats; ionic_intr_coal_init(lif->ionic->idev.intr_ctrl, - lif->rxqcqs[i].qcq->intr.index, coal); + lif->rxqcqs[i].qcq->intr.index, + lif->rx_coalesce_hw); ionic_link_qcq_interrupts(lif->rxqcqs[i].qcq, lif->txqcqs[i].qcq); } @@ -1640,7 +1639,6 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index struct net_device *netdev; struct ionic_lif *lif; int tbl_sz; - u32 coal; int err; netdev = alloc_etherdev_mqs(sizeof(*lif), @@ -1671,8 +1669,9 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index lif->nrxq_descs = IONIC_DEF_TXRX_DESC; /* Convert the default coalesce value to actual hw resolution */ - coal = ionic_coal_usec_to_hw(lif->ionic, IONIC_ITR_COAL_USEC_DEFAULT); - lif->rx_coalesce_usecs = ionic_coal_hw_to_usec(lif->ionic, coal); + lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT; + lif->rx_coalesce_hw = ionic_coal_hw_to_usec(lif->ionic, + lif->rx_coalesce_usecs); snprintf(lif->name, sizeof(lif->name), "lif%u", index); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h index b74f7e9ee82d..cf243a9d0168 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h @@ -175,7 +175,9 @@ struct ionic_lif { unsigned long *dbid_inuse; unsigned int dbid_count; struct dentry *dentry; - u32 rx_coalesce_usecs; + u32 rx_coalesce_usecs; /* what the user asked for */ + u32 rx_coalesce_hw; /* what the hw is using */ + u32 flags; struct work_struct tx_timeout_work; }; -- cgit v1.2.3-59-g8ed1b From e95f922f4c2f27bd7b7479a8fd6bdc689e2062be Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 30 Sep 2019 20:03:25 -0700 Subject: ionic: implement ethtool set-fec Wire up the --set-fec and --show-fec features in the ethtool callbacks and pull the related code out of set_link_ksettings. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- .../net/ethernet/pensando/ionic/ionic_ethtool.c | 94 +++++++++++++++------- 1 file changed, 67 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c index 63cc14c060d6..f778fff034f5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -254,12 +254,9 @@ static int ionic_set_link_ksettings(struct net_device *netdev, struct ionic_lif *lif = netdev_priv(netdev); struct ionic *ionic = lif->ionic; struct ionic_dev *idev; - u32 req_rs, req_fc; - u8 fec_type; int err = 0; idev = &lif->ionic->idev; - fec_type = IONIC_PORT_FEC_TYPE_NONE; /* set autoneg */ if (ks->base.autoneg != idev->port_info->config.an_enable) { @@ -281,29 +278,6 @@ static int ionic_set_link_ksettings(struct net_device *netdev, return err; } - /* set FEC */ - req_rs = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_RS); - req_fc = ethtool_link_ksettings_test_link_mode(ks, advertising, FEC_BASER); - if (req_rs && req_fc) { - netdev_info(netdev, "Only select one FEC mode at a time\n"); - return -EINVAL; - } else if (req_fc) { - fec_type = IONIC_PORT_FEC_TYPE_FC; - } else if (req_rs) { - fec_type = IONIC_PORT_FEC_TYPE_RS; - } else if (!(req_rs | req_fc)) { - fec_type = IONIC_PORT_FEC_TYPE_NONE; - } - - if (fec_type != idev->port_info->config.fec_type) { - mutex_lock(&ionic->dev_cmd_lock); - ionic_dev_cmd_port_fec(idev, fec_type); - err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); - mutex_unlock(&ionic->dev_cmd_lock); - if (err) - return err; - } - return 0; } @@ -353,6 +327,70 @@ static int ionic_set_pauseparam(struct net_device *netdev, return 0; } +static int ionic_get_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fec) +{ + struct ionic_lif *lif = netdev_priv(netdev); + + switch (lif->ionic->idev.port_info->config.fec_type) { + case IONIC_PORT_FEC_TYPE_NONE: + fec->active_fec = ETHTOOL_FEC_OFF; + break; + case IONIC_PORT_FEC_TYPE_RS: + fec->active_fec = ETHTOOL_FEC_RS; + break; + case IONIC_PORT_FEC_TYPE_FC: + fec->active_fec = ETHTOOL_FEC_BASER; + break; + } + + fec->fec = ETHTOOL_FEC_OFF | ETHTOOL_FEC_RS | ETHTOOL_FEC_BASER; + + return 0; +} + +static int ionic_set_fecparam(struct net_device *netdev, + struct ethtool_fecparam *fec) +{ + struct ionic_lif *lif = netdev_priv(netdev); + u8 fec_type; + int ret = 0; + + if (lif->ionic->idev.port_info->config.an_enable) { + netdev_err(netdev, "FEC request not allowed while autoneg is enabled\n"); + return -EINVAL; + } + + switch (fec->fec) { + case ETHTOOL_FEC_NONE: + fec_type = IONIC_PORT_FEC_TYPE_NONE; + break; + case ETHTOOL_FEC_OFF: + fec_type = IONIC_PORT_FEC_TYPE_NONE; + break; + case ETHTOOL_FEC_RS: + fec_type = IONIC_PORT_FEC_TYPE_RS; + break; + case ETHTOOL_FEC_BASER: + fec_type = IONIC_PORT_FEC_TYPE_FC; + break; + case ETHTOOL_FEC_AUTO: + default: + netdev_err(netdev, "FEC request 0x%04x not supported\n", + fec->fec); + return -EINVAL; + } + + if (fec_type != lif->ionic->idev.port_info->config.fec_type) { + mutex_lock(&lif->ionic->dev_cmd_lock); + ionic_dev_cmd_port_fec(&lif->ionic->idev, fec_type); + ret = ionic_dev_cmd_wait(lif->ionic, DEVCMD_TIMEOUT); + mutex_unlock(&lif->ionic->dev_cmd_lock); + } + + return ret; +} + static int ionic_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) { @@ -751,6 +789,7 @@ static const struct ethtool_ops ionic_ethtool_ops = { .get_regs = ionic_get_regs, .get_link = ethtool_op_get_link, .get_link_ksettings = ionic_get_link_ksettings, + .set_link_ksettings = ionic_set_link_ksettings, .get_coalesce = ionic_get_coalesce, .set_coalesce = ionic_set_coalesce, .get_ringparam = ionic_get_ringparam, @@ -773,7 +812,8 @@ static const struct ethtool_ops ionic_ethtool_ops = { .get_module_eeprom = ionic_get_module_eeprom, .get_pauseparam = ionic_get_pauseparam, .set_pauseparam = ionic_set_pauseparam, - .set_link_ksettings = ionic_set_link_ksettings, + .get_fecparam = ionic_get_fecparam, + .set_fecparam = ionic_set_fecparam, .nway_reset = ionic_nway_reset, }; -- cgit v1.2.3-59-g8ed1b From e982ae6aa4e1505d7567a54ef3f259a9647dfd35 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 30 Sep 2019 20:03:26 -0700 Subject: ionic: add lif_quiesce to wait for queue activity to stop Even though we've already turned off the queue activity with the ionic_qcq_disable(), we need to wait for any device queues that are processing packets to drain down before we try to flush our packets and tear down the queues. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 372329389c84..559b96ae48f5 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -242,6 +242,21 @@ static int ionic_qcq_disable(struct ionic_qcq *qcq) return ionic_adminq_post_wait(lif, &ctx); } +static void ionic_lif_quiesce(struct ionic_lif *lif) +{ + struct ionic_admin_ctx ctx = { + .work = COMPLETION_INITIALIZER_ONSTACK(ctx.work), + .cmd.lif_setattr = { + .opcode = IONIC_CMD_LIF_SETATTR, + .attr = IONIC_LIF_ATTR_STATE, + .index = lif->index, + .state = IONIC_LIF_DISABLE + }, + }; + + ionic_adminq_post_wait(lif, &ctx); +} + static void ionic_lif_qcq_deinit(struct ionic_lif *lif, struct ionic_qcq *qcq) { struct ionic_dev *idev = &lif->ionic->idev; @@ -1589,6 +1604,7 @@ int ionic_stop(struct net_device *netdev) netif_tx_disable(netdev); ionic_txrx_disable(lif); + ionic_lif_quiesce(lif); ionic_txrx_deinit(lif); ionic_txrx_free(lif); -- cgit v1.2.3-59-g8ed1b From 09c1b412558b8adf01f733dfe665b5f75dfdf347 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 1 Oct 2019 22:17:59 +0300 Subject: net: dsa: sja1105: Don't use "inline" function declarations in C files Let the compiler decide. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_clocking.c | 2 +- drivers/net/dsa/sja1105/sja1105_main.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c index 608126a15d72..2903f5dbd182 100644 --- a/drivers/net/dsa/sja1105/sja1105_clocking.c +++ b/drivers/net/dsa/sja1105/sja1105_clocking.c @@ -405,7 +405,7 @@ sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd, } /* Valid range in degrees is an integer between 73.8 and 101.7 */ -static inline u64 sja1105_rgmii_delay(u64 phase) +static u64 sja1105_rgmii_delay(u64 phase) { /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9. * To avoid floating point operations we'll multiply by 10 diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index b9def744bcb3..c418fe34d139 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -458,9 +458,8 @@ static int sja1105_init_general_params(struct sja1105_private *priv) #define SJA1105_RATE_MBPS(speed) (((speed) * 64000) / 1000) -static inline void -sja1105_setup_policer(struct sja1105_l2_policing_entry *policing, - int index) +static void sja1105_setup_policer(struct sja1105_l2_policing_entry *policing, + int index) { policing[index].sharindx = index; policing[index].smax = 65535; /* Burst size in bytes */ @@ -951,7 +950,7 @@ sja1105_static_fdb_change(struct sja1105_private *priv, int port, * For the placement of a newly learnt FDB entry, the switch selects the bin * based on a hash function, and the way within that bin incrementally. */ -static inline int sja1105et_fdb_index(int bin, int way) +static int sja1105et_fdb_index(int bin, int way) { return bin * SJA1105ET_FDB_BIN_SIZE + way; } -- cgit v1.2.3-59-g8ed1b From dff79620c3e8c3a1793e0e4751b8cd7bd15f1565 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 1 Oct 2019 22:18:00 +0300 Subject: net: dsa: sja1105: Replace sja1105_spi_send_int with sja1105_xfer_{u32, u64} Having a function that takes a variable number of unpacked bytes which it generically calls an "int" is confusing and makes auditing patches next to impossible. We only use spi_send_int with the int sizes of 32 and 64 bits. So just make the spi_send_int function less generic and replace it with the appropriate two explicit functions, which can now type-check the int pointer type. Note that there is still a small weirdness in the u32 function, which has to convert it to a u64 temporary. This is because of how the packing API works at the moment, but the weirdness is at least hidden from callers of sja1105_xfer_u32 now. Suggested-by: David S. Miller Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 7 ++-- drivers/net/dsa/sja1105/sja1105_main.c | 7 ++-- drivers/net/dsa/sja1105/sja1105_ptp.c | 3 +- drivers/net/dsa/sja1105/sja1105_spi.c | 62 +++++++++++++++++++++------------- 4 files changed, 47 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index e53e494c22e0..cba0beb87d9c 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -130,9 +130,10 @@ int sja1105_static_config_reload(struct sja1105_private *priv); int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, void *packed_buf, size_t size_bytes); -int sja1105_spi_send_int(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - u64 *value, u64 size_bytes); +int sja1105_xfer_u32(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value); +int sja1105_xfer_u64(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value); int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 base_addr, void *packed_buf, u64 buf_len); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index c418fe34d139..fd567ee6a23f 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2109,17 +2109,16 @@ static int sja1105_check_device_id(struct sja1105_private *priv) const struct sja1105_regs *regs = priv->info->regs; u8 prod_id[SJA1105_SIZE_DEVICE_ID] = {0}; struct device *dev = &priv->spidev->dev; - u64 device_id; + u32 device_id; u64 part_no; int rc; - rc = sja1105_spi_send_int(priv, SPI_READ, regs->device_id, - &device_id, SJA1105_SIZE_DEVICE_ID); + rc = sja1105_xfer_u32(priv, SPI_READ, regs->device_id, &device_id); if (rc < 0) return rc; if (device_id != priv->info->device_id) { - dev_err(dev, "Expected device ID 0x%llx but read 0x%llx\n", + dev_err(dev, "Expected device ID 0x%llx but read 0x%x\n", priv->info->device_id, device_id); return -ENODEV; } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index d8e8dd59f3d1..42cc698fcc90 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -327,8 +327,7 @@ static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) u64 ptptsclk = 0; int rc; - rc = sja1105_spi_send_int(priv, SPI_READ, regs->ptptsclk, - &ptptsclk, 8); + rc = sja1105_xfer_u64(priv, SPI_READ, regs->ptptsclk, &ptptsclk); if (rc < 0) dev_err_ratelimited(priv->ds->dev, "failed to read ptp cycle counter: %d\n", diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 84dc603138cf..77a8c0fbc0eb 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -7,7 +7,6 @@ #include #include "sja1105.h" -#define SJA1105_SIZE_PORT_CTRL 4 #define SJA1105_SIZE_RESET_CMD 4 #define SJA1105_SIZE_SPI_MSG_HEADER 4 #define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) @@ -103,35 +102,52 @@ int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, /* If @rw is: * - SPI_WRITE: creates and sends an SPI write message at absolute - * address reg_addr, taking size_bytes from *packed_buf + * address reg_addr * - SPI_READ: creates and sends an SPI read message from absolute - * address reg_addr, writing size_bytes into *packed_buf + * address reg_addr * * The u64 *value is unpacked, meaning that it's stored in the native * CPU endianness and directly usable by software running on the core. - * - * This is a wrapper around sja1105_spi_send_packed_buf(). */ -int sja1105_spi_send_int(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - u64 *value, u64 size_bytes) +int sja1105_xfer_u64(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value) { - u8 packed_buf[SJA1105_SIZE_SPI_MSG_MAXLEN]; + u8 packed_buf[8]; int rc; - if (size_bytes > SJA1105_SIZE_SPI_MSG_MAXLEN) - return -ERANGE; - if (rw == SPI_WRITE) - sja1105_pack(packed_buf, value, 8 * size_bytes - 1, 0, - size_bytes); + sja1105_pack(packed_buf, value, 63, 0, 8); - rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, - size_bytes); + rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, 8); if (rw == SPI_READ) - sja1105_unpack(packed_buf, value, 8 * size_bytes - 1, 0, - size_bytes); + sja1105_unpack(packed_buf, value, 63, 0, 8); + + return rc; +} + +/* Same as above, but transfers only a 4 byte word */ +int sja1105_xfer_u32(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value) +{ + u8 packed_buf[4]; + u64 tmp; + int rc; + + if (rw == SPI_WRITE) { + /* The packing API only supports u64 as CPU word size, + * so we need to convert. + */ + tmp = *value; + sja1105_pack(packed_buf, &tmp, 31, 0, 4); + } + + rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, 4); + + if (rw == SPI_READ) { + sja1105_unpack(packed_buf, &tmp, 31, 0, 4); + *value = tmp; + } return rc; } @@ -287,11 +303,11 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, unsigned long port_bitmap, bool tx_inhibited) { const struct sja1105_regs *regs = priv->info->regs; - u64 inhibit_cmd; + u32 inhibit_cmd; int rc; - rc = sja1105_spi_send_int(priv, SPI_READ, regs->port_control, - &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); + rc = sja1105_xfer_u32(priv, SPI_READ, regs->port_control, + &inhibit_cmd); if (rc < 0) return rc; @@ -300,8 +316,8 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, else inhibit_cmd &= ~port_bitmap; - return sja1105_spi_send_int(priv, SPI_WRITE, regs->port_control, - &inhibit_cmd, SJA1105_SIZE_PORT_CTRL); + return sja1105_xfer_u32(priv, SPI_WRITE, regs->port_control, + &inhibit_cmd); } struct sja1105_status { -- cgit v1.2.3-59-g8ed1b From 1bd448703895473e500c0ce4c6258aeac1f67c20 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 1 Oct 2019 22:18:01 +0300 Subject: net: dsa: sja1105: Rename sja1105_spi_send_packed_buf to sja1105_xfer_buf The most commonly called function in the driver is long due for a rename. The "packed" word is redundant (it doesn't make sense to transfer an unpacked structure, since that is in CPU endianness yadda yadda), and the "spi" word is also redundant since argument 2 of the function is SPI_READ or SPI_WRITE. As for the sja1105_spi_send_long_packed_buf function, it is only being used from sja1105_spi.c, so remove its global prototype. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 9 ++-- drivers/net/dsa/sja1105/sja1105_clocking.c | 63 ++++++++++-------------- drivers/net/dsa/sja1105/sja1105_dynamic_config.c | 12 ++--- drivers/net/dsa/sja1105/sja1105_ethtool.c | 16 +++--- drivers/net/dsa/sja1105/sja1105_main.c | 4 +- drivers/net/dsa/sja1105/sja1105_ptp.c | 14 +++--- drivers/net/dsa/sja1105/sja1105_spi.c | 39 +++++++-------- 7 files changed, 69 insertions(+), 88 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index cba0beb87d9c..8681ff9d1a76 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -127,16 +127,13 @@ typedef enum { int sja1105_static_config_reload(struct sja1105_private *priv); /* From sja1105_spi.c */ -int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - void *packed_buf, size_t size_bytes); +int sja1105_xfer_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + void *packed_buf, size_t size_bytes); int sja1105_xfer_u32(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value); int sja1105_xfer_u64(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value); -int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 base_addr, - void *packed_buf, u64 buf_len); int sja1105_static_config_upload(struct sja1105_private *priv); int sja1105_inhibit_tx(const struct sja1105_private *priv, unsigned long port_bitmap, bool tx_inhibited); diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c index 2903f5dbd182..9082e52b55e9 100644 --- a/drivers/net/dsa/sja1105/sja1105_clocking.c +++ b/drivers/net/dsa/sja1105/sja1105_clocking.c @@ -118,9 +118,8 @@ static int sja1105_cgu_idiv_config(struct sja1105_private *priv, int port, idiv.pd = enabled ? 0 : 1; /* Power down? */ sja1105_cgu_idiv_packing(packed_buf, &idiv, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->cgu_idiv[port], packed_buf, - SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->cgu_idiv[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static void @@ -167,9 +166,8 @@ static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv, mii_tx_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &mii_tx_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->mii_tx_clk[port], packed_buf, - SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_tx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int @@ -192,9 +190,8 @@ sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port) mii_rx_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &mii_rx_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->mii_rx_clk[port], packed_buf, - SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_rx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int @@ -217,9 +214,8 @@ sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port) mii_ext_tx_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_tx_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->mii_ext_tx_clk[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_tx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int @@ -242,9 +238,8 @@ sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port) mii_ext_rx_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &mii_ext_rx_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->mii_ext_rx_clk[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->mii_ext_rx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int sja1105_mii_clocking_setup(struct sja1105_private *priv, int port, @@ -337,9 +332,8 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv, txc.pd = 0; sja1105_cgu_mii_control_packing(packed_buf, &txc, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->rgmii_tx_clk[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgmii_tx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } /* AGU */ @@ -383,9 +377,8 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv, pad_mii_tx.clk_ipud = 2; /* TX_CLK input stage (default) */ sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->pad_mii_tx[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static void @@ -442,9 +435,8 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port) pad_mii_id.txc_pd = 1; sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK); - rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->pad_mii_id[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port], + packed_buf, SJA1105_SIZE_CGU_CMD); if (rc < 0) return rc; @@ -459,9 +451,8 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port) } sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->pad_mii_id[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_id[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port, @@ -547,9 +538,8 @@ static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv, ref_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &ref_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->rmii_ref_clk[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ref_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int @@ -565,9 +555,8 @@ sja1105_cgu_rmii_ext_tx_clk_config(struct sja1105_private *priv, int port) ext_tx_clk.pd = 0; /* Power Down off => enabled */ sja1105_cgu_mii_control_packing(packed_buf, &ext_tx_clk, PACK); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, - regs->rmii_ext_tx_clk[port], - packed_buf, SJA1105_SIZE_CGU_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_ext_tx_clk[port], + packed_buf, SJA1105_SIZE_CGU_CMD); } static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv) @@ -595,8 +584,8 @@ static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv) pll.pd = 0x1; sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK); - rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rmii_pll1, - packed_buf, SJA1105_SIZE_CGU_CMD); + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf, + SJA1105_SIZE_CGU_CMD); if (rc < 0) { dev_err(dev, "failed to configure PLL1 for 50MHz\n"); return rc; @@ -606,8 +595,8 @@ static int sja1105_cgu_rmii_pll_config(struct sja1105_private *priv) pll.pd = 0x0; sja1105_cgu_pll_control_packing(packed_buf, &pll, PACK); - rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rmii_pll1, - packed_buf, SJA1105_SIZE_CGU_CMD); + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->rmii_pll1, packed_buf, + SJA1105_SIZE_CGU_CMD); if (rc < 0) { dev_err(dev, "failed to enable PLL1\n"); return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c index 91da430045ff..25381bd65ed7 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c @@ -686,8 +686,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv, ops->entry_packing(packed_buf, entry, PACK); /* Send SPI write operation: read config table entry */ - rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr, - packed_buf, ops->packed_size); + rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, + ops->packed_size); if (rc < 0) return rc; @@ -698,8 +698,8 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv, memset(packed_buf, 0, ops->packed_size); /* Retrieve the read operation's result */ - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, ops->addr, - packed_buf, ops->packed_size); + rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf, + ops->packed_size); if (rc < 0) return rc; @@ -771,8 +771,8 @@ int sja1105_dynamic_config_write(struct sja1105_private *priv, ops->entry_packing(packed_buf, entry, PACK); /* Send SPI write operation: read config table entry */ - rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE, ops->addr, - packed_buf, ops->packed_size); + rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, + ops->packed_size); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c index ab581a28cd41..064301cc7d5b 100644 --- a/drivers/net/dsa/sja1105/sja1105_ethtool.c +++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c @@ -167,8 +167,8 @@ static int sja1105_port_status_get_mac(struct sja1105_private *priv, int rc; /* MAC area */ - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac[port], - packed_buf, SJA1105_SIZE_MAC_AREA); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac[port], packed_buf, + SJA1105_SIZE_MAC_AREA); if (rc < 0) return rc; @@ -185,8 +185,8 @@ static int sja1105_port_status_get_hl1(struct sja1105_private *priv, u8 packed_buf[SJA1105_SIZE_HL1_AREA] = {0}; int rc; - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl1[port], - packed_buf, SJA1105_SIZE_HL1_AREA); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl1[port], packed_buf, + SJA1105_SIZE_HL1_AREA); if (rc < 0) return rc; @@ -203,8 +203,8 @@ static int sja1105_port_status_get_hl2(struct sja1105_private *priv, u8 packed_buf[SJA1105_SIZE_QLEVEL_AREA] = {0}; int rc; - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->mac_hl2[port], - packed_buf, SJA1105_SIZE_HL2_AREA); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->mac_hl2[port], packed_buf, + SJA1105_SIZE_HL2_AREA); if (rc < 0) return rc; @@ -215,8 +215,8 @@ static int sja1105_port_status_get_hl2(struct sja1105_private *priv, priv->info->device_id == SJA1105T_DEVICE_ID) return 0; - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->qlevel[port], - packed_buf, SJA1105_SIZE_QLEVEL_AREA); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->qlevel[port], packed_buf, + SJA1105_SIZE_QLEVEL_AREA); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index fd567ee6a23f..e95039727c1c 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2123,8 +2123,8 @@ static int sja1105_check_device_id(struct sja1105_private *priv) return -ENODEV; } - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, regs->prod_id, - prod_id, SJA1105_SIZE_DEVICE_ID); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->prod_id, prod_id, + SJA1105_SIZE_DEVICE_ID); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 42cc698fcc90..0df1bbec475a 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -91,8 +91,8 @@ int sja1105et_ptp_cmd(const void *ctx, const void *data) sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 2, 2, size); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, - buf, SJA1105_SIZE_PTP_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, + SJA1105_SIZE_PTP_CMD); } int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) @@ -108,8 +108,8 @@ int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 3, 3, size); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->ptp_control, - buf, SJA1105_SIZE_PTP_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, + SJA1105_SIZE_PTP_CMD); } /* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap @@ -180,10 +180,8 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) int rc; do { - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, - regs->ptpegr_ts[port], - packed_buf, - priv->info->ptpegr_ts_bytes); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->ptpegr_ts[port], + packed_buf, priv->info->ptpegr_ts_bytes); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 77a8c0fbc0eb..6dda2e328fe2 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -63,11 +63,11 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) * * This function should only be called if it is priorly known that * @size_bytes is smaller than SIZE_SPI_MSG_MAXLEN. Larger packed buffers - * are chunked in smaller pieces by sja1105_spi_send_long_packed_buf below. + * are chunked in smaller pieces by sja1105_xfer_long_buf below. */ -int sja1105_spi_send_packed_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - void *packed_buf, size_t size_bytes) +int sja1105_xfer_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + void *packed_buf, size_t size_bytes) { u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; @@ -118,7 +118,7 @@ int sja1105_xfer_u64(const struct sja1105_private *priv, if (rw == SPI_WRITE) sja1105_pack(packed_buf, value, 63, 0, 8); - rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, 8); + rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 8); if (rw == SPI_READ) sja1105_unpack(packed_buf, value, 63, 0, 8); @@ -142,7 +142,7 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, sja1105_pack(packed_buf, &tmp, 31, 0, 4); } - rc = sja1105_spi_send_packed_buf(priv, rw, reg_addr, packed_buf, 4); + rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 4); if (rw == SPI_READ) { sja1105_unpack(packed_buf, &tmp, 31, 0, 4); @@ -156,9 +156,9 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, * must be sent/received. Splitting the buffer into chunks and assembling * those into SPI messages is done automatically by this function. */ -int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 base_addr, - void *packed_buf, u64 buf_len) +int sja1105_xfer_long_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 base_addr, + void *packed_buf, u64 buf_len) { struct chunk { void *buf_ptr; @@ -174,8 +174,8 @@ int sja1105_spi_send_long_packed_buf(const struct sja1105_private *priv, chunk.len = min_t(int, buf_len, SJA1105_SIZE_SPI_MSG_MAXLEN); while (chunk.len) { - rc = sja1105_spi_send_packed_buf(priv, rw, chunk.spi_address, - chunk.buf_ptr, chunk.len); + rc = sja1105_xfer_buf(priv, rw, chunk.spi_address, + chunk.buf_ptr, chunk.len); if (rc < 0) return rc; @@ -257,8 +257,8 @@ static int sja1105et_reset_cmd(const void *ctx, const void *data) sja1105et_reset_cmd_pack(packed_buf, reset); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rgu, - packed_buf, SJA1105_SIZE_RESET_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, + SJA1105_SIZE_RESET_CMD); } static int sja1105pqrs_reset_cmd(const void *ctx, const void *data) @@ -287,8 +287,8 @@ static int sja1105pqrs_reset_cmd(const void *ctx, const void *data) sja1105pqrs_reset_cmd_pack(packed_buf, reset); - return sja1105_spi_send_packed_buf(priv, SPI_WRITE, regs->rgu, - packed_buf, SJA1105_SIZE_RESET_CMD); + return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, + SJA1105_SIZE_RESET_CMD); } static int sja1105_cold_reset(const struct sja1105_private *priv) @@ -355,9 +355,7 @@ static int sja1105_status_get(struct sja1105_private *priv, u8 packed_buf[4]; int rc; - rc = sja1105_spi_send_packed_buf(priv, SPI_READ, - regs->status, - packed_buf, 4); + rc = sja1105_xfer_buf(priv, SPI_READ, regs->status, packed_buf, 4); if (rc < 0) return rc; @@ -451,9 +449,8 @@ int sja1105_static_config_upload(struct sja1105_private *priv) /* Wait for the switch to come out of reset */ usleep_range(1000, 5000); /* Upload the static config to the device */ - rc = sja1105_spi_send_long_packed_buf(priv, SPI_WRITE, - regs->config, - config_buf, buf_len); + rc = sja1105_xfer_long_buf(priv, SPI_WRITE, regs->config, + config_buf, buf_len); if (rc < 0) { dev_err(dev, "Failed to upload config, retrying...\n"); continue; -- cgit v1.2.3-59-g8ed1b From cc6df017e55764ffef9819dd9554053182535ffd Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 17 Oct 2017 17:03:12 -0700 Subject: ath10k: fix offchannel tx failure when no ath10k_mac_tx_frm_has_freq Offchannel management frames were failing: [18099.253732] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780 [18102.293686] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780 [18105.333653] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780 [18108.373712] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3780 [18111.413687] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e36c0 [18114.453726] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3f00 [18117.493773] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e36c0 [18120.533631] ath10k_pci 0000:01:00.0: timed out waiting for offchannel skb cf0e3f00 This bug appears to have been added between 4.0 (which works for us), and 4.4, which does not work. I think this is because the tx-offchannel logic gets in a loop when ath10k_mac_tx_frm_has_freq(ar) is false, so pkt is never actually sent to the firmware for transmit. This patch fixes the problem on 4.9 for me, and now HS20 clients can work again with my firmware. Antonio: tested with 10.4-3.5.3-00057 on QCA4019 and QCA9888 Signed-off-by: Ben Greear Tested-by: Antonio Quartulli [kvalo@codeaurora.org: improve commit log, remove unneeded parenthesis] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 08876f042022..caea4c37c073 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3708,7 +3708,7 @@ static int ath10k_mac_tx(struct ath10k *ar, struct ieee80211_vif *vif, enum ath10k_hw_txrx_mode txmode, enum ath10k_mac_tx_path txpath, - struct sk_buff *skb) + struct sk_buff *skb, bool noque_offchan) { struct ieee80211_hw *hw = ar->hw; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -3738,10 +3738,10 @@ static int ath10k_mac_tx(struct ath10k *ar, } } - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { + if (!noque_offchan && info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { if (!ath10k_mac_tx_frm_has_freq(ar)) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "queued offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac queued offchannel skb %pK len %d\n", + skb, skb->len); skb_queue_tail(&ar->offchan_tx_queue, skb); ieee80211_queue_work(hw, &ar->offchan_tx_work); @@ -3803,8 +3803,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) mutex_lock(&ar->conf_mutex); - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK\n", - skb); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac offchannel skb %pK len %d\n", + skb, skb->len); hdr = (struct ieee80211_hdr *)skb->data; peer_addr = ieee80211_get_DA(hdr); @@ -3850,7 +3850,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode); - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, true); if (ret) { ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", ret); @@ -3860,8 +3860,8 @@ void ath10k_offchan_tx_work(struct work_struct *work) time_left = wait_for_completion_timeout(&ar->offchan_tx_completed, 3 * HZ); if (time_left == 0) - ath10k_warn(ar, "timed out waiting for offchannel skb %pK\n", - skb); + ath10k_warn(ar, "timed out waiting for offchannel skb %pK, len: %d\n", + skb, skb->len); if (!peer && tmp_peer_created) { ret = ath10k_peer_delete(ar, vdev_id, peer_addr); @@ -4097,7 +4097,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (unlikely(ret)) { ath10k_warn(ar, "failed to push frame: %d\n", ret); @@ -4378,7 +4378,7 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, spin_unlock_bh(&ar->htt.tx_lock); } - ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb); + ret = ath10k_mac_tx(ar, vif, txmode, txpath, skb, false); if (ret) { ath10k_warn(ar, "failed to transmit frame: %d\n", ret); if (is_htt) { -- cgit v1.2.3-59-g8ed1b From f8914a14623a79b73f72b2b1ee4cd9b2cb91b735 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 6 Sep 2019 23:54:23 +0200 Subject: ath10k: restore QCA9880-AR1A (v1) detection This patch restores the old behavior that read the chip_id on the QCA988x before resetting the chip. This needs to be done in this order since the unsupported QCA988x AR1A chips fall off the bus when resetted. Otherwise the next MMIO Op after the reset causes a BUS ERROR and panic. Cc: stable@vger.kernel.org Fixes: 1a7fecb766c8 ("ath10k: reset chip before reading chip_id in probe") Signed-off-by: Christian Lamparter Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 36 ++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index bc3dc79de01a..bb44f5a0941b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3486,7 +3486,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, struct ath10k_pci *ar_pci; enum ath10k_hw_rev hw_rev; struct ath10k_bus_params bus_params = {}; - bool pci_ps; + bool pci_ps, is_qca988x = false; int (*pci_soft_reset)(struct ath10k *ar); int (*pci_hard_reset)(struct ath10k *ar); u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr); @@ -3496,6 +3496,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; pci_ps = false; + is_qca988x = true; pci_soft_reset = ath10k_pci_warm_reset; pci_hard_reset = ath10k_pci_qca988x_chip_reset; targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; @@ -3615,25 +3616,34 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_deinit_irq; } + bus_params.dev_type = ATH10K_DEV_TYPE_LL; + bus_params.link_can_suspend = true; + /* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that + * fall off the bus during chip_reset. These chips have the same pci + * device id as the QCA9880 BR4A or 2R4E. So that's why the check. + */ + if (is_qca988x) { + bus_params.chip_id = + ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); + if (bus_params.chip_id != 0xffffffff) { + if (!ath10k_pci_chip_is_supported(pdev->device, + bus_params.chip_id)) + goto err_unsupported; + } + } + ret = ath10k_pci_chip_reset(ar); if (ret) { ath10k_err(ar, "failed to reset chip: %d\n", ret); goto err_free_irq; } - bus_params.dev_type = ATH10K_DEV_TYPE_LL; - bus_params.link_can_suspend = true; bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); - if (bus_params.chip_id == 0xffffffff) { - ath10k_err(ar, "failed to get chip id\n"); - goto err_free_irq; - } + if (bus_params.chip_id == 0xffffffff) + goto err_unsupported; - if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { - ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", - pdev->device, bus_params.chip_id); + if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) goto err_free_irq; - } ret = ath10k_core_register(ar, &bus_params); if (ret) { @@ -3643,6 +3653,10 @@ static int ath10k_pci_probe(struct pci_dev *pdev, return 0; +err_unsupported: + ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", + pdev->device, bus_params.chip_id); + err_free_irq: ath10k_pci_free_irq(ar); ath10k_pci_rx_retry_sync(ar); -- cgit v1.2.3-59-g8ed1b From 1382993f882b6b96c99837fd8b705300a208de3a Mon Sep 17 00:00:00 2001 From: Wen Gong Date: Tue, 1 Oct 2019 15:04:56 +0300 Subject: ath10k: add support for hardware rfkill When hardware rfkill is enabled in the firmware it will report the capability via using WMI_TLV_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY event to the host. ath10k will check the capability, and if it is enabled then ath10k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM. When the firmware detects hardware rfkill is enabled by the user, it will report it via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath10k receives the event it will send wmi command WMI_PDEV_SET_PARAM to the firmware to enable/disable the radio and also notifies cfg80211. We can't power off the device when rfkill is enabled, as otherwise the firmware would not be able to detect GPIO changes and report them to the host. So when rfkill is enabled, we need to keep the firmware running. Tested with QCA6174 PCI with firmware WLAN.RM.4.4.1-00109-QCARMSWPZ-1. Signed-off-by: Alan Liu Signed-off-by: Wen Gong Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 5 ++ drivers/net/wireless/ath/ath10k/hw.c | 3 ++ drivers/net/wireless/ath/ath10k/hw.h | 3 ++ drivers/net/wireless/ath/ath10k/mac.c | 79 ++++++++++++++++++++++++++++++- drivers/net/wireless/ath/ath10k/mac.h | 1 + drivers/net/wireless/ath/ath10k/wmi-tlv.c | 49 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.h | 27 +++++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 9 ++++ drivers/net/wireless/ath/ath10k/wmi.h | 3 ++ 9 files changed, 178 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 153c4a27d78e..af68eb5d0776 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -973,6 +973,11 @@ struct ath10k { u32 low_5ghz_chan; u32 high_5ghz_chan; bool ani_enabled; + u32 sys_cap_info; + + /* protected by data_lock */ + bool hw_rfkill_on; + /* protected by conf_mutex */ u8 ps_state_enable; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index c415e971735b..55849173e55d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -155,6 +155,9 @@ const struct ath10k_hw_values qca6174_values = { .num_target_ce_config_wlan = 7, .ce_desc_meta_data_mask = 0xFFFC, .ce_desc_meta_data_lsb = 2, + .rfkill_pin = 16, + .rfkill_cfg = 0, + .rfkill_on_level = 1, }; const struct ath10k_hw_values qca99x0_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 2ae57c1de7b5..35a362329a4f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -379,6 +379,9 @@ struct ath10k_hw_values { u8 num_target_ce_config_wlan; u16 ce_desc_meta_data_mask; u8 ce_desc_meta_data_lsb; + u32 rfkill_pin; + u32 rfkill_cfg; + bool rfkill_on_level; }; extern const struct ath10k_hw_values qca988x_values; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index caea4c37c073..3d2c8fcba952 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "hif.h" #include "core.h" @@ -4754,6 +4755,63 @@ static int __ath10k_fetch_bb_timing_dt(struct ath10k *ar, return 0; } +static int ath10k_mac_rfkill_config(struct ath10k *ar) +{ + u32 param; + int ret; + + if (ar->hw_values->rfkill_pin == 0) { + ath10k_warn(ar, "ath10k does not support hardware rfkill with this device\n"); + return -EOPNOTSUPP; + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d", + ar->hw_values->rfkill_pin, ar->hw_values->rfkill_cfg, + ar->hw_values->rfkill_on_level); + + param = FIELD_PREP(WMI_TLV_RFKILL_CFG_RADIO_LEVEL, + ar->hw_values->rfkill_on_level) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM, + ar->hw_values->rfkill_pin) | + FIELD_PREP(WMI_TLV_RFKILL_CFG_PIN_AS_GPIO, + ar->hw_values->rfkill_cfg); + + ret = ath10k_wmi_pdev_set_param(ar, + ar->wmi.pdev_param->rfkill_config, + param); + if (ret) { + ath10k_warn(ar, + "failed to set rfkill config 0x%x: %d\n", + param, ret); + return ret; + } + return 0; +} + +int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable) +{ + enum wmi_tlv_rfkill_enable_radio param; + int ret; + + if (enable) + param = WMI_TLV_RFKILL_ENABLE_RADIO_ON; + else + param = WMI_TLV_RFKILL_ENABLE_RADIO_OFF; + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac rfkill enable %d", param); + + ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->rfkill_enable, + param); + if (ret) { + ath10k_warn(ar, "failed to set rfkill enable param %d: %d\n", + param, ret); + return ret; + } + + return 0; +} + static int ath10k_start(struct ieee80211_hw *hw) { struct ath10k *ar = hw->priv; @@ -4788,6 +4846,16 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err; } + spin_lock_bh(&ar->data_lock); + + if (ar->hw_rfkill_on) { + ar->hw_rfkill_on = false; + spin_unlock_bh(&ar->data_lock); + goto err; + } + + spin_unlock_bh(&ar->data_lock); + ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "Could not init hif: %d\n", ret); @@ -4801,6 +4869,14 @@ static int ath10k_start(struct ieee80211_hw *hw) goto err_power_down; } + if (ar->sys_cap_info & WMI_TLV_SYS_CAP_INFO_RFKILL) { + ret = ath10k_mac_rfkill_config(ar); + if (ret && ret != -EOPNOTSUPP) { + ath10k_warn(ar, "failed to configure rfkill: %d", ret); + goto err_core_stop; + } + } + param = ar->wmi.pdev_param->pmf_qos; ret = ath10k_wmi_pdev_set_param(ar, param, 1); if (ret) { @@ -4960,7 +5036,8 @@ static void ath10k_stop(struct ieee80211_hw *hw) mutex_lock(&ar->conf_mutex); if (ar->state != ATH10K_STATE_OFF) { - ath10k_halt(ar); + if (!ar->hw_rfkill_on) + ath10k_halt(ar); ar->state = ATH10K_STATE_OFF; } mutex_unlock(&ar->conf_mutex); diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 1fe84948b868..98d83a26ea60 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -72,6 +72,7 @@ struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar, u8 tid); int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val); void ath10k_mac_wait_tx_complete(struct ath10k *ar); +int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable); static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 2432a7434289..69a1ec53df29 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -409,6 +409,49 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static void ath10k_wmi_tlv_event_rfkill_state_change(struct ath10k *ar, + struct sk_buff *skb) +{ + const struct wmi_tlv_rfkill_state_change_ev *ev; + const void **tb; + bool radio; + int ret; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath10k_warn(ar, + "failed to parse rfkill state change event: %d\n", + ret); + return; + } + + ev = tb[WMI_TLV_TAG_STRUCT_RFKILL_EVENT]; + if (!ev) { + kfree(tb); + return; + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, + "wmi tlv rfkill state change gpio %d type %d radio_state %d\n", + __le32_to_cpu(ev->gpio_pin_num), + __le32_to_cpu(ev->int_type), + __le32_to_cpu(ev->radio_state)); + + radio = (__le32_to_cpu(ev->radio_state) == WMI_TLV_RFKILL_RADIO_STATE_ON); + + spin_lock_bh(&ar->data_lock); + + if (!radio) + ar->hw_rfkill_on = true; + + spin_unlock_bh(&ar->data_lock); + + /* notify cfg80211 radio state change */ + ath10k_mac_rfkill_enable_radio(ar, radio); + wiphy_rfkill_set_hw_state(ar->hw->wiphy, !radio); +} + static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar, struct sk_buff *skb) { @@ -629,6 +672,9 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_TX_PAUSE_EVENTID: ath10k_wmi_tlv_event_tx_pause(ar, skb); break; + case WMI_TLV_RFKILL_STATE_CHANGE_EVENTID: + ath10k_wmi_tlv_event_rfkill_state_change(ar, skb); + break; case WMI_TLV_PDEV_TEMPERATURE_EVENTID: ath10k_wmi_tlv_event_temperature(ar, skb); break; @@ -1215,6 +1261,7 @@ static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar, arg->num_mem_reqs = ev->num_mem_reqs; arg->service_map = svc_bmap; arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap); + arg->sys_cap_info = ev->sys_cap_info; ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs), ath10k_wmi_tlv_parse_mem_reqs, arg); @@ -4214,6 +4261,8 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .rfkill_config = WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG, + .rfkill_enable = WMI_TLV_PDEV_PARAM_RFKILL_ENABLE, }; static struct wmi_peer_param_map wmi_tlv_peer_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index 5a85f2eedfe0..4972dc12991c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -7,6 +7,8 @@ #ifndef _WMI_TLV_H #define _WMI_TLV_H +#include + #define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1) #define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1) #define WMI_TLV_CMD_UNSUPPORTED 0 @@ -2276,6 +2278,31 @@ struct wmi_tlv_tdls_peer_event { __le32 vdev_id; } __packed; +enum wmi_tlv_sys_cap_info_flags { + WMI_TLV_SYS_CAP_INFO_RXTX_LED = BIT(0), + WMI_TLV_SYS_CAP_INFO_RFKILL = BIT(1), +}; + +#define WMI_TLV_RFKILL_CFG_GPIO_PIN_NUM GENMASK(5, 0) +#define WMI_TLV_RFKILL_CFG_RADIO_LEVEL BIT(6) +#define WMI_TLV_RFKILL_CFG_PIN_AS_GPIO GENMASK(10, 7) + +enum wmi_tlv_rfkill_enable_radio { + WMI_TLV_RFKILL_ENABLE_RADIO_ON = 0, + WMI_TLV_RFKILL_ENABLE_RADIO_OFF = 1, +}; + +enum wmi_tlv_rfkill_radio_state { + WMI_TLV_RFKILL_RADIO_STATE_OFF = 1, + WMI_TLV_RFKILL_RADIO_STATE_ON = 2, +}; + +struct wmi_tlv_rfkill_state_change_ev { + __le32 gpio_pin_num; + __le32 int_type; + __le32 radio_state; +}; + void ath10k_wmi_tlv_attach(struct ath10k *ar); enum wmi_nlo_auth_algorithm { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 59d2d2a975df..f0ab11556dc2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5412,6 +5412,12 @@ ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb, arg->service_map = ev->wmi_service_bitmap; arg->service_map_len = sizeof(ev->wmi_service_bitmap); + /* Deliberately skipping ev->sys_cap_info as WMI and WMI-TLV have + * different values. We would need a translation to handle that, + * but as we don't currently need anything from sys_cap_info from + * WMI interface (only from WMI-TLV) safest it to skip it. + */ + n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), ARRAY_SIZE(arg->mem_reqs)); for (i = 0; i < n; i++) @@ -5465,9 +5471,12 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work) ar->high_2ghz_chan = __le32_to_cpu(arg.high_2ghz_chan); ar->low_5ghz_chan = __le32_to_cpu(arg.low_5ghz_chan); ar->high_5ghz_chan = __le32_to_cpu(arg.high_5ghz_chan); + ar->sys_cap_info = __le32_to_cpu(arg.sys_cap_info); ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", arg.service_map, arg.service_map_len); + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sys_cap_info 0x%x\n", + ar->sys_cap_info); if (ar->num_rf_chains > ar->max_spatial_stream) { ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index d9d53e503c54..74adce1dd3a9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3788,6 +3788,8 @@ struct wmi_pdev_param_map { u32 arp_srcaddr; u32 arp_dstaddr; u32 enable_btcoex; + u32 rfkill_config; + u32 rfkill_enable; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -6875,6 +6877,7 @@ struct wmi_svc_rdy_ev_arg { __le32 high_2ghz_chan; __le32 low_5ghz_chan; __le32 high_5ghz_chan; + __le32 sys_cap_info; const __le32 *service_map; size_t service_map_len; const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; -- cgit v1.2.3-59-g8ed1b From 315cee426f87658a6799815845788fde965ddaad Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Mon, 30 Sep 2019 23:31:47 +0300 Subject: ar5523: check NULL before memcpy() in ar5523_cmd() memcpy() call with "idata == NULL && ilen == 0" results in undefined behavior in ar5523_cmd(). For example, NULL is passed in callchain "ar5523_stat_work() -> ar5523_cmd_write() -> ar5523_cmd()". This patch adds ilen check before memcpy() call in ar5523_cmd() to prevent an undefined behavior. Cc: Pontus Fuchs Cc: Kalle Valo Cc: "David S. Miller" Cc: David Laight Cc: stable@vger.kernel.org Signed-off-by: Denis Efremov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ar5523/ar5523.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index b94759daeacc..da2d179430ca 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -255,7 +255,8 @@ static int ar5523_cmd(struct ar5523 *ar, u32 code, const void *idata, if (flags & AR5523_CMD_FLAG_MAGIC) hdr->magic = cpu_to_be32(1 << 24); - memcpy(hdr + 1, idata, ilen); + if (ilen) + memcpy(hdr + 1, idata, ilen); cmd->odata = odata; cmd->olen = olen; -- cgit v1.2.3-59-g8ed1b From 2c840676be8ffc624bf9bb4490d944fd13c02d71 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Tue, 1 Oct 2019 15:08:23 +0300 Subject: wil6210: check len before memcpy() calls memcpy() in wmi_set_ie() and wmi_update_ft_ies() is called with src == NULL and len == 0. This is an undefined behavior. Fix it by checking "ie_len > 0" before the memcpy() calls. As suggested by GCC documentation: "The pointers passed to memmove (and similar functions in ) must be non-null even when nbytes==0, so GCC can use that information to remove the check after the memmove call." [1] [1] https://gcc.gnu.org/gcc-4.9/porting_to.html Cc: Maya Erez Cc: Kalle Valo Cc: "David S. Miller" Cc: stable@vger.kernel.org Signed-off-by: Denis Efremov Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/wmi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index daf16bc01bb3..f9a006d58a95 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -2505,7 +2505,8 @@ int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie) cmd->mgmt_frm_type = type; /* BUG: FW API define ieLen as u8. Will fix FW */ cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len); kfree(cmd); out: @@ -2541,7 +2542,8 @@ int wmi_update_ft_ies(struct wil6210_vif *vif, u16 ie_len, const void *ie) } cmd->ie_len = cpu_to_le16(ie_len); - memcpy(cmd->ie_info, ie, ie_len); + if (ie_len) + memcpy(cmd->ie_info, ie, ie_len); rc = wmi_send(wil, WMI_UPDATE_FT_IES_CMDID, vif->mid, cmd, len); kfree(cmd); -- cgit v1.2.3-59-g8ed1b From 21d549769e793607c081328c9811e03ad851f9dc Mon Sep 17 00:00:00 2001 From: "rd.dunlab@gmail.com" Date: Tue, 1 Oct 2019 16:04:00 -0700 Subject: Isolate CAIF transport drivers into their own menu Isolate CAIF transport drivers into their own menu. This cleans up the main Network device support menu, makes it easier to find the CAIF drivers, and makes it easier to enable/disable them as a group. Signed-off-by: Randy Dunlap Cc: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/caif/Kconfig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index 2b9a2f117113..ab071565a943 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -3,7 +3,13 @@ # CAIF physical drivers # -comment "CAIF transport drivers" +menuconfig CAIF_DRIVERS + bool "CAIF transport drivers" + depends on CAIF + help + Enable this to see CAIF physical drivers. + +if CAIF_DRIVERS config CAIF_TTY tristate "CAIF TTY transport driver" @@ -55,3 +61,5 @@ config CAIF_VIRTIO if CAIF_VIRTIO source "drivers/vhost/Kconfig.vringh" endif + +endif # CAIF_DRIVERS -- cgit v1.2.3-59-g8ed1b From 0f04f8ea62ce79f5a8bb1a7c2d92513799532239 Mon Sep 17 00:00:00 2001 From: "rd.dunlab@gmail.com" Date: Tue, 1 Oct 2019 16:04:01 -0700 Subject: Minor fixes to the CAIF Transport drivers Kconfig file Minor fixes to the CAIF Transport drivers Kconfig file: - end sentence with period - capitalize CAIF acronym Signed-off-by: Randy Dunlap Cc: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/caif/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index ab071565a943..96d7cef3289f 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -28,7 +28,7 @@ config CAIF_SPI_SLAVE The CAIF Link layer SPI Protocol driver for Slave SPI interface. This driver implements a platform driver to accommodate for a platform specific SPI device. A sample CAIF SPI Platform device is - provided in Documentation/networking/caif/spi_porting.txt + provided in . config CAIF_SPI_SYNC bool "Next command and length in start of frame" @@ -44,7 +44,7 @@ config CAIF_HSI depends on CAIF default n ---help--- - The caif low level driver for CAIF over HSI. + The CAIF low level driver for CAIF over HSI. Be aware that if you enable this then you also need to enable a low-level HSI driver. @@ -56,7 +56,7 @@ config CAIF_VIRTIO select GENERIC_ALLOCATOR default n ---help--- - The caif driver for CAIF over Virtio. + The CAIF driver for CAIF over Virtio. if CAIF_VIRTIO source "drivers/vhost/Kconfig.vringh" -- cgit v1.2.3-59-g8ed1b From 80f60a911e5ea4de9e25b539bec4f597af7b2ff4 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Wed, 2 Oct 2019 23:49:04 +0200 Subject: mvpp2: remove misleading comment Recycling in mvpp2 has gone long time ago, but two comment still refers to it. Remove those two misleading comments as they generate confusion. Fixes: 7ef7e1d949cd ("net: mvpp2: drop useless fields in mvpp2_bm_pool and related code") Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 111b3b8239e1..5fea65256b9d 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2863,7 +2863,7 @@ static void mvpp2_rx_csum(struct mvpp2_port *port, u32 status, skb->ip_summed = CHECKSUM_NONE; } -/* Reuse skb if possible, or allocate a new skb and add it to BM pool */ +/* Allocate a new skb and add it to BM pool */ static int mvpp2_rx_refill(struct mvpp2_port *port, struct mvpp2_bm_pool *bm_pool, int pool) { @@ -2871,7 +2871,6 @@ static int mvpp2_rx_refill(struct mvpp2_port *port, phys_addr_t phys_addr; void *buf; - /* No recycle or too many buffers are in use, so allocate a new skb */ buf = mvpp2_buf_alloc(port, bm_pool, &dma_addr, &phys_addr, GFP_ATOMIC); if (!buf) -- cgit v1.2.3-59-g8ed1b From 151ea094378d057dfca76c0110da76dd29cf1de3 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 2 Oct 2019 14:09:33 -0700 Subject: r8152: Add identifier names for function pointers Checkpatch throws warnings for function pointer declarations which lack identifier names. An example of such a warning is: WARNING: function definition argument 'struct r8152 *' should also have an identifier name 739: FILE: drivers/net/usb/r8152.c:739: + void (*init)(struct r8152 *); So, fix those warnings by adding the identifier names. While we are at it, also fix a character limit violation which was causing another checkpatch warning. Change-Id: Idec857ce2dc9592caf3173188be1660052c052ce Signed-off-by: Prashant Malani Reviewed-by: Grant Grundler Acked-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 601259238fd7..8ba478c1ffeb 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -736,16 +736,16 @@ struct r8152 { struct tasklet_struct tx_tl; struct rtl_ops { - void (*init)(struct r8152 *); - int (*enable)(struct r8152 *); - void (*disable)(struct r8152 *); - void (*up)(struct r8152 *); - void (*down)(struct r8152 *); - void (*unload)(struct r8152 *); - int (*eee_get)(struct r8152 *, struct ethtool_eee *); - int (*eee_set)(struct r8152 *, struct ethtool_eee *); - bool (*in_nway)(struct r8152 *); - void (*hw_phy_cfg)(struct r8152 *); + void (*init)(struct r8152 *tp); + int (*enable)(struct r8152 *tp); + void (*disable)(struct r8152 *tp); + void (*up)(struct r8152 *tp); + void (*down)(struct r8152 *tp); + void (*unload)(struct r8152 *tp); + int (*eee_get)(struct r8152 *tp, struct ethtool_eee *eee); + int (*eee_set)(struct r8152 *tp, struct ethtool_eee *eee); + bool (*in_nway)(struct r8152 *tp); + void (*hw_phy_cfg)(struct r8152 *tp); void (*autosuspend_en)(struct r8152 *tp, bool enable); } rtl_ops; @@ -5603,7 +5603,8 @@ static int rtl8152_probe(struct usb_interface *intf, } if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial && - (!strcmp(udev->serial, "000001000000") || !strcmp(udev->serial, "000002000000"))) { + (!strcmp(udev->serial, "000001000000") || + !strcmp(udev->serial, "000002000000"))) { dev_info(&udev->dev, "Dell TB16 Dock, disable RX aggregation"); set_bit(DELL_TB_RX_AGG_BUG, &tp->flags); } -- cgit v1.2.3-59-g8ed1b From 968a2978cb39a754750d35a47049781660682a31 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 2 Oct 2019 16:52:57 +0200 Subject: net: stmmac: Only enable enhanced addressing mode when needed Enhanced addressing mode is only required when more than 32 bits need to be addressed. Add a DMA configuration parameter to enable this mode only when needed. Signed-off-by: Thierry Reding Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 5 ++++- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 7 +++++++ include/linux/stmmac.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 53c4a40d8386..19ef037393dd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -27,7 +27,10 @@ static void dwxgmac2_dma_init(void __iomem *ioaddr, if (dma_cfg->aal) value |= XGMAC_AAL; - writel(value | XGMAC_EAME, ioaddr + XGMAC_DMA_SYSBUS_MODE); + if (dma_cfg->eame) + value |= XGMAC_EAME; + + writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE); } static void dwxgmac2_dma_init_chan(void __iomem *ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index d3232738fb25..2da1f77bb604 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4514,6 +4514,13 @@ int stmmac_dvr_probe(struct device *device, if (!ret) { dev_info(priv->device, "Using %d bits DMA width\n", priv->dma_cap.addr64); + + /* + * If more than 32 bits can be addressed, make sure to + * enable enhanced addressing mode. + */ + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT)) + priv->plat->dma_cfg->eame = true; } else { ret = dma_set_mask_and_coherent(device, DMA_BIT_MASK(32)); if (ret) { diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index dc60d03c4b60..86f9464c3f5d 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -92,6 +92,7 @@ struct stmmac_dma_cfg { int fixed_burst; int mixed_burst; bool aal; + bool eame; }; #define AXI_BLEN 7 -- cgit v1.2.3-59-g8ed1b From 560c07cba1319cf6765884ea9feedecf3020997d Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 2 Oct 2019 16:52:58 +0200 Subject: net: stmmac: Support enhanced addressing mode for DWMAC 4.10 The address width of the controller can be read from hardware feature registers much like on XGMAC. Add support for parsing the ADDR64 field so that the DMA mask can be set accordingly. This avoids getting swiotlb involved for DMA on Tegra186 and later. Also make sure that the upper 32 bits of the DMA address are written to the DMA descriptors when enhanced addressing mode is used. Similarily, for each channel, the upper 32 bits of the DMA descriptor ring's base address also need to be programmed to make sure the correct memory can be fetched when the DMA descriptor ring is located beyond the 32-bit boundary. Signed-off-by: Thierry Reding Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 4 ++-- drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 28 ++++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h | 3 +++ 4 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 89a3420eba42..2fe45fa3c482 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -205,6 +205,7 @@ enum power_event { #define GMAC_HW_HASH_TB_SZ GENMASK(25, 24) #define GMAC_HW_FEAT_AVSEL BIT(20) #define GMAC_HW_TSOEN BIT(18) +#define GMAC_HW_ADDR64 GENMASK(15, 14) #define GMAC_HW_TXFIFOSIZE GENMASK(10, 6) #define GMAC_HW_RXFIFOSIZE GENMASK(4, 0) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index 15eb1abba91d..707ab5eba8da 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -431,8 +431,8 @@ static void dwmac4_get_addr(struct dma_desc *p, unsigned int *addr) static void dwmac4_set_addr(struct dma_desc *p, dma_addr_t addr) { - p->des0 = cpu_to_le32(addr); - p->des1 = 0; + p->des0 = cpu_to_le32(lower_32_bits(addr)); + p->des1 = cpu_to_le32(upper_32_bits(addr)); } static void dwmac4_clear(struct dma_desc *p) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 68c157979b94..229059cef949 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -79,6 +79,10 @@ static void dwmac4_dma_init_rx_chan(void __iomem *ioaddr, value = value | (rxpbl << DMA_BUS_MODE_RPBL_SHIFT); writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan)); + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame)) + writel(upper_32_bits(dma_rx_phy), + ioaddr + DMA_CHAN_RX_BASE_ADDR_HI(chan)); + writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_CHAN_RX_BASE_ADDR(chan)); } @@ -97,6 +101,10 @@ static void dwmac4_dma_init_tx_chan(void __iomem *ioaddr, writel(value, ioaddr + DMA_CHAN_TX_CONTROL(chan)); + if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && likely(dma_cfg->eame)) + writel(upper_32_bits(dma_tx_phy), + ioaddr + DMA_CHAN_TX_BASE_ADDR_HI(chan)); + writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_CHAN_TX_BASE_ADDR(chan)); } @@ -132,6 +140,9 @@ static void dwmac4_dma_init(void __iomem *ioaddr, if (dma_cfg->aal) value |= DMA_SYS_BUS_AAL; + if (dma_cfg->eame) + value |= DMA_SYS_BUS_EAME; + writel(value, ioaddr + DMA_SYS_BUS_MODE); } @@ -356,6 +367,23 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr, dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24; dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20; dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18; + + dma_cap->addr64 = (hw_cap & GMAC_HW_ADDR64) >> 14; + switch (dma_cap->addr64) { + case 0: + dma_cap->addr64 = 32; + break; + case 1: + dma_cap->addr64 = 40; + break; + case 2: + dma_cap->addr64 = 48; + break; + default: + dma_cap->addr64 = 32; + break; + } + /* RX and TX FIFO sizes are encoded as log2(n / 128). Undo that by * shifting and store the sizes in bytes. */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index b66da0237d2a..5299fa1001a3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -65,6 +65,7 @@ #define DMA_SYS_BUS_MB BIT(14) #define DMA_AXI_1KBBE BIT(13) #define DMA_SYS_BUS_AAL BIT(12) +#define DMA_SYS_BUS_EAME BIT(11) #define DMA_AXI_BLEN256 BIT(7) #define DMA_AXI_BLEN128 BIT(6) #define DMA_AXI_BLEN64 BIT(5) @@ -91,7 +92,9 @@ #define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x) #define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4) #define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8) +#define DMA_CHAN_TX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x10) #define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14) +#define DMA_CHAN_RX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x18) #define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c) #define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20) #define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28) -- cgit v1.2.3-59-g8ed1b From 6aaee55cc8c6c305bb758545e7ceadc1bfcf7684 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Thu, 3 Oct 2019 08:44:49 +0300 Subject: mlxsw: PCI: Send EMAD traffic on a separate queue Currently mlxsw distributes sent traffic among all the available send queues. That includes control traffic as well as EMADs, which are used for configuration of the device. However because all the queues have the same traffic class of 3, they all end up being directed to the same traffic class buffer. If the control traffic in the buffer cannot be serviced quickly enough, the EMAD traffic might be shut out, which causes transient failures, typically in FDB maintenance, counter upkeep and other periodic work. To address this issue, dedicate SDQ 0 to EMAD traffic, with TC 0. Distribute the control traffic among the remaining queues, which are left with their current TC 3. Suggested-by: Ido Schimmel Signed-off-by: Petr Machata Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 16 ++++++++++++++-- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 615455a21567..f1294b00efdf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -284,15 +284,18 @@ static dma_addr_t __mlxsw_pci_queue_page_get(struct mlxsw_pci_queue *q, static int mlxsw_pci_sdq_init(struct mlxsw_pci *mlxsw_pci, char *mbox, struct mlxsw_pci_queue *q) { + int tclass; int i; int err; q->producer_counter = 0; q->consumer_counter = 0; + tclass = q->num == MLXSW_PCI_SDQ_EMAD_INDEX ? MLXSW_PCI_SDQ_EMAD_TC : + MLXSW_PCI_SDQ_CTL_TC; /* Set CQ of same number of this SDQ. */ mlxsw_cmd_mbox_sw2hw_dq_cq_set(mbox, q->num); - mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, 3); + mlxsw_cmd_mbox_sw2hw_dq_sdq_tclass_set(mbox, tclass); mlxsw_cmd_mbox_sw2hw_dq_log2_dq_sz_set(mbox, 3); /* 8 pages */ for (i = 0; i < MLXSW_PCI_AQ_PAGES; i++) { dma_addr_t mapaddr = __mlxsw_pci_queue_page_get(q, i); @@ -963,6 +966,7 @@ static int mlxsw_pci_aqs_init(struct mlxsw_pci *mlxsw_pci, char *mbox) eq_log2sz = mlxsw_cmd_mbox_query_aq_cap_log_max_eq_sz_get(mbox); if (num_sdqs + num_rdqs > num_cqs || + num_sdqs < MLXSW_PCI_SDQS_MIN || num_cqs > MLXSW_PCI_CQS_MAX || num_eqs != MLXSW_PCI_EQS_COUNT) { dev_err(&pdev->dev, "Unsupported number of queues\n"); return -EINVAL; @@ -1520,7 +1524,15 @@ static struct mlxsw_pci_queue * mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, const struct mlxsw_tx_info *tx_info) { - u8 sdqn = tx_info->local_port % mlxsw_pci_sdq_count(mlxsw_pci); + u8 ctl_sdq_count = mlxsw_pci_sdq_count(mlxsw_pci) - 1; + u8 sdqn; + + if (tx_info->is_emad) { + sdqn = MLXSW_PCI_SDQ_EMAD_INDEX; + } else { + BUILD_BUG_ON(MLXSW_PCI_SDQ_EMAD_INDEX != 0); + sdqn = 1 + (tx_info->local_port % ctl_sdq_count); + } return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index e57e42e2d2b2..2b3aec482742 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -51,6 +51,11 @@ #define MLXSW_PCI_EQ_ASYNC_NUM 0 #define MLXSW_PCI_EQ_COMP_NUM 1 +#define MLXSW_PCI_SDQS_MIN 2 /* EMAD and control traffic */ +#define MLXSW_PCI_SDQ_EMAD_INDEX 0 +#define MLXSW_PCI_SDQ_EMAD_TC 0 +#define MLXSW_PCI_SDQ_CTL_TC 3 + #define MLXSW_PCI_AQ_PAGES 8 #define MLXSW_PCI_AQ_SIZE (MLXSW_PCI_PAGE_SIZE * MLXSW_PCI_AQ_PAGES) #define MLXSW_PCI_WQE_SIZE 32 /* 32 bytes per element */ -- cgit v1.2.3-59-g8ed1b From 7908d2ce63ea16bacfc50a4c7737470fef041feb Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 3 Oct 2019 10:21:12 +0200 Subject: net: phy: at803x: add ar9331 support Mostly this hardware can work with generic PHY driver, but this change is needed to provided interrupt handling support. Tested with dsa ar9331-switch driver. Signed-off-by: Oleksij Rempel Reviewed-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 2aa7b2e60046..7d778b8deb94 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -53,6 +53,7 @@ #define AT803X_DEBUG_REG_5 0x05 #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) +#define ATH9331_PHY_ID 0x004dd041 #define ATH8030_PHY_ID 0x004dd076 #define ATH8031_PHY_ID 0x004dd074 #define ATH8035_PHY_ID 0x004dd072 @@ -402,6 +403,16 @@ static struct phy_driver at803x_driver[] = { .aneg_done = at803x_aneg_done, .ack_interrupt = &at803x_ack_interrupt, .config_intr = &at803x_config_intr, +}, { + /* ATHEROS AR9331 */ + PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), + .name = "Atheros AR9331 built-in PHY", + .config_init = at803x_config_init, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_BASIC_FEATURES */ + .ack_interrupt = &at803x_ack_interrupt, + .config_intr = &at803x_config_intr, } }; module_phy_driver(at803x_driver); @@ -410,6 +421,7 @@ static struct mdio_device_id __maybe_unused atheros_tbl[] = { { ATH8030_PHY_ID, AT803X_PHY_ID_MASK }, { ATH8031_PHY_ID, AT803X_PHY_ID_MASK }, { ATH8035_PHY_ID, AT803X_PHY_ID_MASK }, + { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, { } }; -- cgit v1.2.3-59-g8ed1b From 7271df0bf03f2c0abc817d6cbd2849372f3c5cbc Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Thu, 3 Oct 2019 10:21:13 +0200 Subject: net: phy: at803x: remove probe and struct at803x_priv struct at803x_priv is never used in this driver. So remove it and the probe function allocating it. Suggested-by: Heiner Kallweit Signed-off-by: Oleksij Rempel Reviewed-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 7d778b8deb94..ac29279d7bfb 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -63,10 +63,6 @@ MODULE_DESCRIPTION("Atheros 803x PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); -struct at803x_priv { - bool phy_reset:1; -}; - struct at803x_context { u16 bmcr; u16 advertise; @@ -232,20 +228,6 @@ static int at803x_resume(struct phy_device *phydev) return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); } -static int at803x_probe(struct phy_device *phydev) -{ - struct device *dev = &phydev->mdio.dev; - struct at803x_priv *priv; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - phydev->priv = priv; - - return 0; -} - static int at803x_config_init(struct phy_device *phydev) { int ret; @@ -364,7 +346,6 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8035_PHY_ID, .name = "Atheros 8035 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, - .probe = at803x_probe, .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, @@ -378,7 +359,6 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8030_PHY_ID, .name = "Atheros 8030 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, - .probe = at803x_probe, .config_init = at803x_config_init, .link_change_notify = at803x_link_change_notify, .set_wol = at803x_set_wol, @@ -393,7 +373,6 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8031_PHY_ID, .name = "Atheros 8031 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, - .probe = at803x_probe, .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, -- cgit v1.2.3-59-g8ed1b From 2ce113de31320756b25179f3f4512a522bc45263 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 2 Oct 2019 11:12:25 +0200 Subject: mac80211: simplify TX aggregation start There really is no need to make drivers call the ieee80211_start_tx_ba_cb_irqsafe() function and then schedule the worker if all we want is to set a bit. Add a new return value (that was previously considered invalid) to indicate that the driver is immediately ready for the session, and make drivers use it. The only drivers that remain different are the Intel ones as they need to negotiate more with the firmware. Link: https://lore.kernel.org/r/1570007543-I152912660131cbab2e5d80b4218238c20f8a06e5@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- drivers/net/wireless/ath/carl9170/main.c | 3 +-- drivers/net/wireless/ath/wcn36xx/main.c | 5 +++-- .../net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c | 3 +-- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/tx.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 5 ++--- drivers/net/wireless/mac80211_hwsim.c | 3 +-- drivers/net/wireless/marvell/mwl8k.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 +-- drivers/net/wireless/mediatek/mt7601u/main.c | 3 +-- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/base.c | 3 +-- drivers/net/wireless/realtek/rtw88/mac80211.c | 3 +-- drivers/net/wireless/rsi/rsi_91x_mac80211.c | 3 +-- include/net/mac80211.h | 11 +++++++++-- net/mac80211/agg-tx.c | 9 ++++++++- 20 files changed, 39 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index a82ad739ab80..791f6633667c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1674,7 +1674,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: ret = ath9k_htc_tx_aggr_oper(priv, vif, sta, action, tid); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 34121fbf32e3..0548aa3702e3 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1921,7 +1921,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 40a8054f8aa6..5914926a5c5b 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1449,8 +1449,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, rcu_assign_pointer(sta_info->agg[tid], tid_info); spin_unlock_bh(&ar->tx_ampdu_list_lock); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 79998a3ddb7a..a276dae30887 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1084,6 +1084,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action = params->action; u16 tid = params->tid; u16 *ssn = ¶ms->ssn; + int ret = 0; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", action, tid); @@ -1106,7 +1107,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; spin_unlock_bh(&sta_priv->ampdu_lock); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_OPERATIONAL: spin_lock_bh(&sta_priv->ampdu_lock); @@ -1131,7 +1132,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw, mutex_unlock(&wcn->conf_mutex); - return 0; + return ret; } static const struct ieee80211_ops wcn36xx_ops = { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 6188275b17e5..8e8b685cfe09 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -850,8 +850,7 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw, "START: tid %d is not agg\'able\n", tid); return -EINVAL; } - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index ffb705b18fb1..51fdd7ce30af 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -2265,7 +2265,7 @@ il4965_tx_agg_start(struct il_priv *il, struct ieee80211_vif *vif, if (tid_data->tfds_in_queue == 0) { D_HT("HW queue is empty\n"); tid_data->agg.state = IL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; } else { D_HT("HW queue is NOT empty: %d packets in HW queue\n", tid_data->tfds_in_queue); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 3029e3f6de63..cd73fc5cfcbb 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -621,7 +621,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); tid_data->agg.state = IWL_AGG_STARTING; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; } else { IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " "next_reclaimed = %d\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 0bedba4c61f2..1d6bc62b104c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2818,13 +2818,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (normalized_ssn == tid_data->next_reclaimed) { tid_data->state = IWL_AGG_STARTING; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; } else { tid_data->state = IWL_EMPTYING_HW_QUEUE_ADDBA; + ret = 0; } - ret = 0; - out: spin_unlock_bh(&mvmsta->lock); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 635956024e88..1aeb38296ec3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1979,8 +1979,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_TX_START: - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index c4db6417748f..d55f229abeea 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5520,7 +5520,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rc = -EBUSY; break; } - ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); + rc = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 25d5b1608bc9..4b3217b43a04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -582,8 +582,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 87c748715b5d..b6d78212306a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -477,8 +477,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; mt7615_mcu_set_tx_ba(dev, params, 0); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index aec73a0295e8..414b22399d93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -393,8 +393,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 72e608cc53af..671d8897ae76 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -372,8 +372,7 @@ mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: msta->agg_ssn[tid] = ssn << 4; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index f1cdcd61c54a..25466454b73e 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -10476,7 +10476,7 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * when the hw reorders frames due to aggregation. */ if (sta_priv->wcid > WCID_END) - return 1; + return -ENOSPC; switch (action) { case IEEE80211_AMPDU_RX_START: @@ -10489,7 +10489,7 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ break; case IEEE80211_AMPDU_TX_START: - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index ac746c322554..c75192c4447f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1776,8 +1776,7 @@ int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, tid_data->agg.agg_state = RTL_AGG_START; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - return 0; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; } int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index e5e3605bb693..a203b4705b94 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -437,8 +437,7 @@ static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, switch (params->action) { case IEEE80211_AMPDU_TX_START: - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index ce5e92d82efc..440088293aff 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -1140,8 +1140,7 @@ static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw, else if ((vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_P2P_GO)) rsta->seq_start[tid] = seq_no; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - status = 0; + status = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 523c6a09e1c8..d69081c38788 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3095,7 +3095,9 @@ enum ieee80211_filter_flags { * * @IEEE80211_AMPDU_RX_START: start RX aggregation * @IEEE80211_AMPDU_RX_STOP: stop RX aggregation - * @IEEE80211_AMPDU_TX_START: start TX aggregation + * @IEEE80211_AMPDU_TX_START: start TX aggregation, the driver must either + * call ieee80211_start_tx_ba_cb_irqsafe() or return the special + * status %IEEE80211_AMPDU_TX_START_IMMEDIATE. * @IEEE80211_AMPDU_TX_OPERATIONAL: TX aggregation has become operational * @IEEE80211_AMPDU_TX_STOP_CONT: stop TX aggregation but continue transmitting * queued packets, now unaggregated. After all packets are transmitted the @@ -3119,6 +3121,8 @@ enum ieee80211_ampdu_mlme_action { IEEE80211_AMPDU_TX_OPERATIONAL, }; +#define IEEE80211_AMPDU_TX_START_IMMEDIATE 1 + /** * struct ieee80211_ampdu_params - AMPDU action parameters * @@ -3896,7 +3900,10 @@ struct ieee80211_ops { * * Even ``189`` would be wrong since 1 could be lost again. * - * Returns a negative error code on failure. + * Returns a negative error code on failure. The driver may return + * %IEEE80211_AMPDU_TX_START_IMMEDIATE for %IEEE80211_AMPDU_TX_START + * if the session can start immediately. + * * The callback can sleep. */ int (*ampdu_action)(struct ieee80211_hw *hw, diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b11883d26875..33da6f738c99 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -485,7 +485,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) params.ssn = sta->tid_seq[tid] >> 4; ret = drv_ampdu_action(local, sdata, ¶ms); - if (ret) { + if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) { + /* + * We didn't send the request yet, so don't need to check + * here if we already got a response, just mark as driver + * ready immediately. + */ + set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state); + } else if (ret) { ht_dbg(sdata, "BA request denied - HW unavailable for %pM tid %d\n", sta->sta.addr, tid); -- cgit v1.2.3-59-g8ed1b From 3a2dd6b7cadfc627378d2c3af065f82ebb1d4cbf Mon Sep 17 00:00:00 2001 From: Chin-Yen Lee Date: Wed, 2 Oct 2019 14:35:18 +0800 Subject: rtw88: check firmware leave lps successfully Driver needs to wait for firmware to restore hardware setting to active mode after leaving lps. After getting H2C from driver for leaving lps, firmware will issue null packet without PS bit to inform AP driver is active, and then restore REG_TCR Register if AP has receiced null packet. But the transmission of null packet may cost much more time in noisy environment. If driver does not wait for firmware, null packet with PS bit could be sent due to incorrect REG_TCR setting. And AP will be confused. In our test, 100ms is enough for firmware to send null packet to AP. If REG_TCR Register is still wrong after 100ms, we will modify it directly, force the PS bit to be cleared Signed-off-by: Chin-Yen Lee Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 29 +++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/ps.h | 2 ++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + 3 files changed, 32 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 83db6cf6a219..bf149956b04e 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -9,6 +9,7 @@ #include "mac.h" #include "coex.h" #include "debug.h" +#include "reg.h" static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) { @@ -118,6 +119,32 @@ static void __rtw_leave_lps_deep(struct rtw_dev *rtwdev) rtw_hci_deep_ps(rtwdev, false); } +static void rtw_fw_leave_lps_state_check(struct rtw_dev *rtwdev) +{ + int i; + + /* Driver needs to wait for firmware to leave LPS state + * successfully. Firmware will send null packet to inform AP, + * and see if AP sends an ACK back, then firmware will restore + * the REG_TCR register. + * + * If driver does not wait for firmware, null packet with + * PS bit could be sent due to incorrect REG_TCR setting. + * + * In our test, 100ms should be enough for firmware to finish + * the flow. If REG_TCR Register is still incorrect after 100ms, + * just modify it directly, and throw a warn message. + */ + for (i = 0 ; i < LEAVE_LPS_TRY_CNT; i++) { + if (rtw_read32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN) == 0) + return; + msleep(20); + } + + rtw_write32_mask(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN, 0); + rtw_warn(rtwdev, "firmware failed to restore hardware setting\n"); +} + static void rtw_leave_lps_core(struct rtw_dev *rtwdev) { struct rtw_lps_conf *conf = &rtwdev->lps_conf; @@ -128,6 +155,8 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) conf->smart_ps = 0; rtw_fw_set_pwr_mode(rtwdev); + rtw_fw_leave_lps_state_check(rtwdev); + clear_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); rtw_coex_lps_notify(rtwdev, COEX_LPS_DISABLE); diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 18f687cfe211..25925eedbad4 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -11,6 +11,8 @@ #define POWER_MODE_PG BIT(4) #define POWER_MODE_LCLK BIT(0) +#define LEAVE_LPS_TRY_CNT 5 + int rtw_enter_ips(struct rtw_dev *rtwdev); int rtw_leave_ips(struct rtw_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index fe793e270d22..60014077de77 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -271,6 +271,7 @@ #define BIT_TSFT_SEL_TIMER0 (BIT(4) | BIT(5) | BIT(6)) #define REG_TCR 0x0604 +#define BIT_PWRMGT_HWDATA_EN BIT(7) #define REG_RCR 0x0608 #define BIT_APP_FCS BIT(31) #define BIT_APP_MIC BIT(30) -- cgit v1.2.3-59-g8ed1b From 942e2a5d39a9706aa0115078a67659b4d071aece Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:19 +0800 Subject: rtw88: allows to set RTS in TX descriptor Allows driver to send RTS by filling tx descriptor. The user may want to set the rts threshold. But since we have not been taking over rate control from mac80211 to driver by setting flag IEEE80211_HW_HAS_RATE_CONTROL, there is nothing we can do about it. So here just store the value, and mac80211 will tell us to use rts protection by ieee80211_tx_info::control::use_rts. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 12 ++++++++++++ drivers/net/wireless/realtek/rtw88/main.h | 2 ++ drivers/net/wireless/realtek/rtw88/tx.c | 4 ++++ drivers/net/wireless/realtek/rtw88/tx.h | 2 ++ 4 files changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 97777c7fdce8..1646f38fd940 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -541,6 +541,17 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct rtw_dev *rtwdev = hw->priv; + + mutex_lock(&rtwdev->mutex); + rtwdev->rts_threshold = value; + mutex_unlock(&rtwdev->mutex); + + return 0; +} + const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, .start = rtw_ops_start, @@ -557,5 +568,6 @@ const struct ieee80211_ops rtw_ops = { .sw_scan_start = rtw_ops_sw_scan_start, .sw_scan_complete = rtw_ops_sw_scan_complete, .mgd_prepare_tx = rtw_ops_mgd_prepare_tx, + .set_rts_threshold = rtw_ops_set_rts_threshold, }; EXPORT_SYMBOL(rtw_ops); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 161297ad7d99..810bf151ad36 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -484,6 +484,7 @@ struct rtw_tx_pkt_info { bool fs; bool short_gi; bool report; + bool rts; }; struct rtw_rx_pkt_stat { @@ -1377,6 +1378,7 @@ struct rtw_dev { struct dentry *debugfs; u8 sta_cnt; + u32 rts_threshold; DECLARE_BITMAP(mac_id_map, RTW_MAX_MAC_ID_NUM); DECLARE_BITMAP(flags, NUM_OF_RTW_FLAGS); diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 91bfd8c28ff7..25fa932d0208 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -56,6 +56,7 @@ void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) 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); } EXPORT_SYMBOL(rtw_tx_fill_tx_desc); @@ -258,6 +259,9 @@ static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, ampdu_density = get_tx_ampdu_density(sta); } + if (info->control.use_rts) + pkt_info->rts = true; + if (sta->vht_cap.vht_supported) rate = get_highest_vht_tx_rate(rtwdev, sta); else if (sta->ht_cap.ht_supported) diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index 8338dbf55576..ab5b71f8ac22 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -35,6 +35,8 @@ le32p_replace_bits((__le32 *)(txdesc) + 0x09, value, GENMASK(23, 12)) #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_AMPDU_DENSITY(txdesc, value) \ le32p_replace_bits((__le32 *)(txdesc) + 0x02, value, GENMASK(22, 20)) #define SET_TX_DESC_DATA_STBC(txdesc, value) \ -- cgit v1.2.3-59-g8ed1b From 3745d3e550d1e6c4301596ac05a5fe82c11301ce Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:20 +0800 Subject: rtw88: add driver TX queue support The mac80211 provides software TX queue for driver, as long as driver has hooked ieee80211_ops::wake_tx_queue. Each time a packet is queued onto the TX queue, that queue will be woken up the inform driver to serve the queue. Now driver only supports PCI interface ICs, there's no specific traffic control for each queue, just schedule a tasklet, and dump all of the packets at once to the DMA ring. Instead of TX the packets whenever TX queue is woke, tasklet handler can have more packets dumped to the device, takes advantage of burst write with DMA engine. And if the driver is going to support USB/SDIO ICs, the tasklet can be more flexible for aggregating the packets, enhance the efficiency of bandwidth usage. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 40 ++++++++--- drivers/net/wireless/realtek/rtw88/main.c | 7 ++ drivers/net/wireless/realtek/rtw88/main.h | 17 +++++ drivers/net/wireless/realtek/rtw88/tx.c | 95 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/tx.h | 6 ++ 5 files changed, 156 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 1646f38fd940..47ea69434b96 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -17,19 +17,30 @@ static void rtw_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct rtw_dev *rtwdev = hw->priv; - struct rtw_tx_pkt_info pkt_info = {0}; - if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) - goto out; + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) { + ieee80211_free_txskb(hw, skb); + return; + } - rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb); - if (rtw_hci_tx(rtwdev, &pkt_info, skb)) - goto out; + rtw_tx(rtwdev, control, skb); +} - return; +static void rtw_ops_wake_tx_queue(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; -out: - ieee80211_free_txskb(hw, skb); + if (!test_bit(RTW_FLAG_RUNNING, rtwdev->flags)) + return; + + spin_lock_bh(&rtwdev->txq_lock); + if (list_empty(&rtwtxq->list)) + list_add_tail(&rtwtxq->list, &rtwdev->txqs); + spin_unlock_bh(&rtwdev->txq_lock); + + tasklet_schedule(&rtwdev->tx_tasklet); } static int rtw_ops_start(struct ieee80211_hw *hw) @@ -147,6 +158,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, rtwvif->stats.rx_cnt = 0; rtwvif->in_lps = false; rtwvif->conf = &rtw_vif_port[port]; + rtw_txq_init(rtwdev, vif->txq); mutex_lock(&rtwdev->mutex); @@ -196,6 +208,8 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw, rtw_leave_lps_deep(rtwdev); + rtw_txq_cleanup(rtwdev, vif->txq); + eth_zero_addr(rtwvif->mac_addr); config |= PORT_SET_MAC_ADDR; rtwvif->net_type = RTW_NET_NO_LINK; @@ -333,6 +347,7 @@ static int rtw_ops_sta_add(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int i; int ret = 0; mutex_lock(&rtwdev->mutex); @@ -347,6 +362,8 @@ static int rtw_ops_sta_add(struct ieee80211_hw *hw, si->vif = vif; si->init_ra_lv = 1; ewma_rssi_init(&si->avg_rssi); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw_txq_init(rtwdev, sta->txq[i]); rtw_update_sta_info(rtwdev, si); rtw_fw_media_status_report(rtwdev, si->mac_id, true); @@ -367,12 +384,16 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw, { struct rtw_dev *rtwdev = hw->priv; struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int i; mutex_lock(&rtwdev->mutex); rtw_release_macid(rtwdev, si->mac_id); rtw_fw_media_status_report(rtwdev, si->mac_id, false); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + rtw_txq_cleanup(rtwdev, sta->txq[i]); + rtwdev->sta_cnt--; rtw_info(rtwdev, "sta %pM with macid %d left\n", @@ -554,6 +575,7 @@ static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, + .wake_tx_queue = rtw_ops_wake_tx_queue, .start = rtw_ops_start, .stop = rtw_ops_stop, .config = rtw_ops_config, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a3e9f917adef..3a09a5b123a7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -12,6 +12,7 @@ #include "phy.h" #include "reg.h" #include "efuse.h" +#include "tx.h" #include "debug.h" unsigned int rtw_fw_lps_deep_mode; @@ -1158,9 +1159,12 @@ int rtw_core_init(struct rtw_dev *rtwdev) int ret; INIT_LIST_HEAD(&rtwdev->rsvd_page_list); + INIT_LIST_HEAD(&rtwdev->txqs); timer_setup(&rtwdev->tx_report.purge_timer, rtw_tx_report_purge_timer, 0); + tasklet_init(&rtwdev->tx_tasklet, rtw_tx_tasklet, + (unsigned long)rtwdev); INIT_DELAYED_WORK(&rtwdev->watch_dog_work, rtw_watch_dog_work); INIT_DELAYED_WORK(&coex->bt_relink_work, rtw_coex_bt_relink_work); @@ -1174,6 +1178,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) spin_lock_init(&rtwdev->dm_lock); spin_lock_init(&rtwdev->rf_lock); spin_lock_init(&rtwdev->h2c.lock); + spin_lock_init(&rtwdev->txq_lock); spin_lock_init(&rtwdev->tx_report.q_lock); mutex_init(&rtwdev->mutex); @@ -1218,6 +1223,7 @@ void rtw_core_deinit(struct rtw_dev *rtwdev) if (fw->firmware) release_firmware(fw->firmware); + tasklet_kill(&rtwdev->tx_tasklet); spin_lock_irqsave(&rtwdev->tx_report.q_lock, flags); skb_queue_purge(&rtwdev->tx_report.queue); spin_unlock_irqrestore(&rtwdev->tx_report.q_lock, flags); @@ -1243,6 +1249,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->extra_tx_headroom = max_tx_headroom; hw->queues = IEEE80211_NUM_ACS; + hw->txq_data_size = sizeof(struct rtw_txq); hw->sta_data_size = sizeof(struct rtw_sta_info); hw->vif_data_size = sizeof(struct rtw_vif); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 810bf151ad36..cfe94a685dde 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -587,6 +587,11 @@ struct rtw_tx_report { struct timer_list purge_timer; }; +struct rtw_txq { + struct list_head list; + unsigned long last_push; +}; + #define RTW_BC_MC_MACID 1 DECLARE_EWMA(rssi, 10, 16); @@ -1361,6 +1366,11 @@ struct rtw_dev { struct sk_buff_head c2h_queue; struct work_struct c2h_work; + /* used to protect txqs list */ + spinlock_t txq_lock; + struct list_head txqs; + struct tasklet_struct tx_tasklet; + struct rtw_tx_report tx_report; struct { @@ -1396,6 +1406,13 @@ static inline bool rtw_is_assoc(struct rtw_dev *rtwdev) return !!rtwdev->sta_cnt; } +static inline struct ieee80211_txq *rtwtxq_to_txq(struct rtw_txq *rtwtxq) +{ + void *p = rtwtxq; + + return container_of(p, struct ieee80211_txq, drv_priv); +} + void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *ch_param); bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target); diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 25fa932d0208..1e19bdac1d45 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -367,3 +367,98 @@ void rtw_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, pkt_info->qsel = TX_DESC_QSEL_MGMT; pkt_info->ls = true; } + +void rtw_tx(struct rtw_dev *rtwdev, + struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct rtw_tx_pkt_info pkt_info = {0}; + + rtw_tx_pkt_info_update(rtwdev, &pkt_info, control, skb); + if (rtw_hci_tx(rtwdev, &pkt_info, skb)) + goto out; + + return; + +out: + ieee80211_free_txskb(rtwdev->hw, skb); +} + +static bool rtw_txq_dequeue(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq) +{ + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + struct ieee80211_tx_control control; + struct sk_buff *skb; + + skb = ieee80211_tx_dequeue(rtwdev->hw, txq); + if (!skb) + return false; + + control.sta = txq->sta; + rtw_tx(rtwdev, &control, skb); + rtwtxq->last_push = jiffies; + + return true; +} + +static void rtw_txq_push(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq, + unsigned long frames) +{ + int i; + + rcu_read_lock(); + + for (i = 0; i < frames; i++) + if (!rtw_txq_dequeue(rtwdev, rtwtxq)) + break; + + rcu_read_unlock(); +} + +void rtw_tx_tasklet(unsigned long data) +{ + struct rtw_dev *rtwdev = (void *)data; + struct rtw_txq *rtwtxq, *tmp; + + spin_lock_bh(&rtwdev->txq_lock); + + list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + unsigned long frame_cnt; + unsigned long byte_cnt; + + ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); + rtw_txq_push(rtwdev, rtwtxq, frame_cnt); + + list_del_init(&rtwtxq->list); + } + + spin_unlock_bh(&rtwdev->txq_lock); +} + +void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) +{ + struct rtw_txq *rtwtxq; + + if (!txq) + return; + + rtwtxq = (struct rtw_txq *)txq->drv_priv; + INIT_LIST_HEAD(&rtwtxq->list); +} + +void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) +{ + struct rtw_txq *rtwtxq; + + if (!txq) + return; + + rtwtxq = (struct rtw_txq *)txq->drv_priv; + spin_lock_bh(&rtwdev->txq_lock); + if (!list_empty(&rtwtxq->list)) + list_del_init(&rtwtxq->list); + spin_unlock_bh(&rtwdev->txq_lock); +} diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h index ab5b71f8ac22..9ca4f74a501b 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.h +++ b/drivers/net/wireless/realtek/rtw88/tx.h @@ -77,6 +77,12 @@ enum rtw_tx_desc_queue_select { TX_DESC_QSEL_H2C = 19, }; +void rtw_tx(struct rtw_dev *rtwdev, + struct ieee80211_tx_control *control, + struct sk_buff *skb); +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_tasklet(unsigned long data); void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, struct rtw_tx_pkt_info *pkt_info, struct ieee80211_tx_control *control, -- cgit v1.2.3-59-g8ed1b From 46ebb1743f339eae14daaa3afe094957f6b67d1d Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:21 +0800 Subject: rtw88: take over rate control from mac80211 We can indicate IEEE80211_HW_HAS_RATE_CONTROL to mac80211 because the hardware has its own rate control algorithm. And what driver needs to do is to choose an RA mask according the peer's capabilities. But the hardware is not able to setup BA session by itself. So driver requires to initiate tx BA session for hardware, and tells it if it is possible to transmit AMPDU. The hardware can then aggregate MPDUs. And the size of AMPDU is controlled by the TX descriptor and the register value. Since the TX descriptor will reference the max AMPDU size from ieee80211_sta::ht_cap::ampdu_factor, just set the register value to 0x3f, and let it be controlled by TX descriptor. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 5 ++++ drivers/net/wireless/realtek/rtw88/main.c | 36 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.h | 10 ++++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 4 +-- drivers/net/wireless/realtek/rtw88/tx.c | 34 +++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 47ea69434b96..fe58a99ca48e 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -483,6 +483,8 @@ static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, { struct ieee80211_sta *sta = params->sta; u16 tid = params->tid; + struct ieee80211_txq *txq = sta->txq[tid]; + struct rtw_txq *rtwtxq = (struct rtw_txq *)txq->drv_priv; switch (params->action) { case IEEE80211_AMPDU_TX_START: @@ -491,9 +493,12 @@ static int rtw_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_CONT: case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + clear_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: + set_bit(RTW_TXQ_AMPDU, &rtwtxq->flags); + break; case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: break; diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 3a09a5b123a7..0cee91869daa 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -213,6 +213,40 @@ static void rtw_c2h_work(struct work_struct *work) } } +struct rtw_txq_ba_iter_data { +}; + +static void rtw_txq_ba_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + int ret; + u8 tid; + + tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); + while (tid != IEEE80211_NUM_TIDS) { + clear_bit(tid, si->tid_ba); + ret = ieee80211_start_tx_ba_session(sta, tid, 0); + if (ret == -EINVAL) { + struct ieee80211_txq *txq; + struct rtw_txq *rtwtxq; + + txq = sta->txq[tid]; + rtwtxq = (struct rtw_txq *)txq->drv_priv; + set_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags); + } + + tid = find_first_bit(si->tid_ba, IEEE80211_NUM_TIDS); + } +} + +static void rtw_txq_ba_work(struct work_struct *work) +{ + struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, ba_work); + struct rtw_txq_ba_iter_data data; + + rtw_iterate_stas_atomic(rtwdev, rtw_txq_ba_iter, &data); +} + void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *chan_params) { @@ -1171,6 +1205,7 @@ int rtw_core_init(struct rtw_dev *rtwdev) INIT_DELAYED_WORK(&coex->bt_reenable_work, rtw_coex_bt_reenable_work); INIT_DELAYED_WORK(&coex->defreeze_work, rtw_coex_defreeze_work); INIT_WORK(&rtwdev->c2h_work, rtw_c2h_work); + INIT_WORK(&rtwdev->ba_work, rtw_txq_ba_work); skb_queue_head_init(&rtwdev->c2h_queue); skb_queue_head_init(&rtwdev->coex.queue); skb_queue_head_init(&rtwdev->tx_report.queue); @@ -1262,6 +1297,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); + ieee80211_hw_set(hw, HAS_RATE_CONTROL); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index cfe94a685dde..dcf806ac8155 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -306,6 +306,11 @@ enum rtw_regulatory_domains { RTW_REGD_MAX }; +enum rtw_txq_flags { + RTW_TXQ_AMPDU, + RTW_TXQ_BLOCK_BA, +}; + enum rtw_flags { RTW_FLAG_RUNNING, RTW_FLAG_FW_RUNNING, @@ -589,6 +594,8 @@ struct rtw_tx_report { struct rtw_txq { struct list_head list; + + unsigned long flags; unsigned long last_push; }; @@ -614,6 +621,8 @@ struct rtw_sta_info { bool updated; u8 init_ra_lv; u64 ra_mask; + + DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS); }; struct rtw_vif { @@ -1370,6 +1379,7 @@ struct rtw_dev { spinlock_t txq_lock; struct list_head txqs; struct tasklet_struct tx_tasklet; + struct work_struct ba_work; struct rtw_tx_report tx_report; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index a300efdf264e..3b3bc39cf740 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1088,8 +1088,8 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) #define WLAN_AMPDU_MAX_TIME 0x70 #define WLAN_RTS_LEN_TH 0xFF #define WLAN_RTS_TX_TIME_TH 0x08 -#define WLAN_MAX_AGG_PKT_LIMIT 0x20 -#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x20 +#define WLAN_MAX_AGG_PKT_LIMIT 0x3f +#define WLAN_RTS_MAX_AGG_PKT_LIMIT 0x3f #define WLAN_PRE_TXCNT_TIME_TH 0x1E0 #define FAST_EDCA_VO_TH 0x06 #define FAST_EDCA_VI_TH 0x06 diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 1e19bdac1d45..24c39c60c99a 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -384,6 +384,38 @@ out: ieee80211_free_txskb(rtwdev->hw, skb); } +static void rtw_txq_check_agg(struct rtw_dev *rtwdev, + struct rtw_txq *rtwtxq, + struct sk_buff *skb) +{ + struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); + struct ieee80211_tx_info *info; + struct rtw_sta_info *si; + + if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) { + info = IEEE80211_SKB_CB(skb); + info->flags |= IEEE80211_TX_CTL_AMPDU; + return; + } + + if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) + return; + + if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags)) + return; + + if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) + return; + + if (!txq->sta) + return; + + si = (struct rtw_sta_info *)txq->sta->drv_priv; + set_bit(txq->tid, si->tid_ba); + + ieee80211_queue_work(rtwdev->hw, &rtwdev->ba_work); +} + static bool rtw_txq_dequeue(struct rtw_dev *rtwdev, struct rtw_txq *rtwtxq) { @@ -395,6 +427,8 @@ static bool rtw_txq_dequeue(struct rtw_dev *rtwdev, if (!skb) return false; + rtw_txq_check_agg(rtwdev, rtwtxq, skb); + control.sta = txq->sta; rtw_tx(rtwdev, &control, skb); rtwtxq->last_push = jiffies; -- cgit v1.2.3-59-g8ed1b From 699c7730cf2303728673351ff8dd0100552cde8e Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Wed, 2 Oct 2019 14:35:22 +0800 Subject: rtw88: report tx rate to mac80211 stack Whenever the firmware increases/decreases the bit rate used to transmit to a peer, it sends an RA report through C2H to driver. Driver can then record the bit rate in the peer's struct rtw_sta_info, and report to mac80211 when it asks us for the statistics of the sta by ieee80211_ops::sta_statistics Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 73 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/fw.h | 6 +++ drivers/net/wireless/realtek/rtw88/mac80211.c | 12 +++++ drivers/net/wireless/realtek/rtw88/main.c | 12 +++++ drivers/net/wireless/realtek/rtw88/main.h | 10 ++++ drivers/net/wireless/realtek/rtw88/rx.c | 22 ++------ drivers/net/wireless/realtek/rtw88/util.c | 27 ++++++++++ 7 files changed, 143 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 430d73cff32e..4b41bf531998 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -9,6 +9,7 @@ #include "reg.h" #include "sec.h" #include "debug.h" +#include "util.h" static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, struct sk_buff *skb) @@ -28,6 +29,75 @@ static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, } } +struct rtw_fw_iter_ra_data { + struct rtw_dev *rtwdev; + u8 *payload; +}; + +static void rtw_fw_ra_report_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_fw_iter_ra_data *ra_data = data; + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + u8 mac_id, rate, sgi, bw; + u8 mcs, nss; + u32 bit_rate; + + mac_id = GET_RA_REPORT_MACID(ra_data->payload); + if (si->mac_id != mac_id) + return; + + si->ra_report.txrate.flags = 0; + + rate = GET_RA_REPORT_RATE(ra_data->payload); + sgi = GET_RA_REPORT_SGI(ra_data->payload); + bw = GET_RA_REPORT_BW(ra_data->payload); + + if (rate < DESC_RATEMCS0) { + si->ra_report.txrate.legacy = rtw_desc_to_bitrate(rate); + goto legacy; + } + + rtw_desc_to_mcsrate(rate, &mcs, &nss); + if (rate >= DESC_RATEVHT1SS_MCS0) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + else if (rate >= DESC_RATEMCS0) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_MCS; + + if (rate >= DESC_RATEMCS0) { + si->ra_report.txrate.mcs = mcs; + si->ra_report.txrate.nss = nss; + } + + if (sgi) + si->ra_report.txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + + if (bw == RTW_CHANNEL_WIDTH_80) + si->ra_report.txrate.bw = RATE_INFO_BW_80; + else if (bw == RTW_CHANNEL_WIDTH_40) + si->ra_report.txrate.bw = RATE_INFO_BW_40; + else + si->ra_report.txrate.bw = RATE_INFO_BW_20; + +legacy: + bit_rate = cfg80211_calculate_bitrate(&si->ra_report.txrate); + + si->ra_report.desc_rate = rate; + si->ra_report.bit_rate = bit_rate; +} + +static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, + u8 length) +{ + struct rtw_fw_iter_ra_data ra_data; + + if (WARN(length < 7, "invalid ra report c2h length\n")) + return; + + ra_data.rtwdev = rtwdev; + ra_data.payload = payload; + rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); +} + void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) { struct rtw_c2h_cmd *c2h; @@ -50,6 +120,9 @@ void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb) case C2H_HALMAC: rtw_fw_c2h_cmd_handle_ext(rtwdev, skb); break; + case C2H_RA_RPT: + rtw_fw_ra_report_handle(rtwdev, c2h->payload, len); + break; default: break; } diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index f4028ef63ee8..fd34986a13d2 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -36,6 +36,7 @@ enum rtw_c2h_cmd_id { C2H_BT_INFO = 0x09, C2H_BT_MP_INFO = 0x0b, + C2H_RA_RPT = 0x0c, C2H_HW_FEATURE_REPORT = 0x19, C2H_WLAN_INFO = 0x27, C2H_HW_FEATURE_DUMP = 0xfd, @@ -119,6 +120,11 @@ struct rtw_rsvd_page { #define GET_CCX_REPORT_SEQNUM(c2h_payload) (c2h_payload[8] & 0xfc) #define GET_CCX_REPORT_STATUS(c2h_payload) (c2h_payload[9] & 0xc0) +#define GET_RA_REPORT_RATE(c2h_payload) (c2h_payload[0] & 0x7f) +#define GET_RA_REPORT_SGI(c2h_payload) ((c2h_payload[0] & 0x80) >> 7) +#define GET_RA_REPORT_BW(c2h_payload) (c2h_payload[6]) +#define GET_RA_REPORT_MACID(c2h_payload) (c2h_payload[1]) + /* PKT H2C */ #define H2C_PKT_CMD_ID 0xFF #define H2C_PKT_CATEGORY 0x01 diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index fe58a99ca48e..9c77c86d3021 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -578,6 +578,17 @@ static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return 0; } +static void rtw_ops_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct station_info *sinfo) +{ + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + + sinfo->txrate = si->ra_report.txrate; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); +} + const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, .wake_tx_queue = rtw_ops_wake_tx_queue, @@ -596,5 +607,6 @@ const struct ieee80211_ops rtw_ops = { .sw_scan_complete = rtw_ops_sw_scan_complete, .mgd_prepare_tx = rtw_ops_mgd_prepare_tx, .set_rts_threshold = rtw_ops_set_rts_threshold, + .sta_statistics = rtw_ops_sta_statistics, }; EXPORT_SYMBOL(rtw_ops); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 0cee91869daa..690a5c4d64e7 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -86,6 +86,18 @@ static struct ieee80211_rate rtw_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +u16 rtw_desc_to_bitrate(u8 desc_rate) +{ + struct ieee80211_rate rate; + + if (WARN(desc_rate >= ARRAY_SIZE(rtw_ratetable), "invalid desc rate\n")) + return 0; + + rate = rtw_ratetable[desc_rate]; + + return rate.bitrate; +} + static struct ieee80211_supported_band rtw_band_2ghz = { .band = NL80211_BAND_2GHZ, diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index dcf806ac8155..cd34d4d77b52 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -592,6 +592,12 @@ struct rtw_tx_report { struct timer_list purge_timer; }; +struct rtw_ra_report { + struct rate_info txrate; + u32 bit_rate; + u8 desc_rate; +}; + struct rtw_txq { struct list_head list; @@ -623,6 +629,8 @@ struct rtw_sta_info { u64 ra_mask; DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS); + + struct rtw_ra_report ra_report; }; struct rtw_vif { @@ -1430,6 +1438,7 @@ bool ltecoex_read_reg(struct rtw_dev *rtwdev, u16 offset, u32 *val); bool ltecoex_reg_write(struct rtw_dev *rtwdev, u16 offset, u32 value); void rtw_restore_reg(struct rtw_dev *rtwdev, struct rtw_backup_info *bckp, u32 num); +void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss); void rtw_set_channel(struct rtw_dev *rtwdev); void rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif, u32 config); @@ -1442,5 +1451,6 @@ int rtw_core_init(struct rtw_dev *rtwdev); void rtw_core_deinit(struct rtw_dev *rtwdev); int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw); void rtw_unregister_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw); +u16 rtw_desc_to_bitrate(u8 desc_rate); #endif diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 16b22eb57171..d97d2c2c57c2 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -103,25 +103,9 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, else if (pkt_stat->rate >= DESC_RATEMCS0) rx_status->encoding = RX_ENC_HT; - if (pkt_stat->rate >= DESC_RATEVHT1SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT1SS_MCS9) { - rx_status->nss = 1; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT1SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT2SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT2SS_MCS9) { - rx_status->nss = 2; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT2SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT3SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT3SS_MCS9) { - rx_status->nss = 3; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT3SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEVHT4SS_MCS0 && - pkt_stat->rate <= DESC_RATEVHT4SS_MCS9) { - rx_status->nss = 4; - rx_status->rate_idx = pkt_stat->rate - DESC_RATEVHT4SS_MCS0; - } else if (pkt_stat->rate >= DESC_RATEMCS0 && - pkt_stat->rate <= DESC_RATEMCS15) { - rx_status->rate_idx = pkt_stat->rate - DESC_RATEMCS0; + if (pkt_stat->rate >= DESC_RATEMCS0) { + rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx, + &rx_status->nss); } else if (rx_status->band == NL80211_BAND_5GHZ && pkt_stat->rate >= DESC_RATE6M && pkt_stat->rate <= DESC_RATE54M) { diff --git a/drivers/net/wireless/realtek/rtw88/util.c b/drivers/net/wireless/realtek/rtw88/util.c index 212070c2baa8..10f1117c0cfb 100644 --- a/drivers/net/wireless/realtek/rtw88/util.c +++ b/drivers/net/wireless/realtek/rtw88/util.c @@ -70,3 +70,30 @@ void rtw_restore_reg(struct rtw_dev *rtwdev, } } } + +void rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss) +{ + if (rate <= DESC_RATE54M) + return; + + if (rate >= DESC_RATEVHT1SS_MCS0 && + rate <= DESC_RATEVHT1SS_MCS9) { + *nss = 1; + *mcs = rate - DESC_RATEVHT1SS_MCS0; + } else if (rate >= DESC_RATEVHT2SS_MCS0 && + rate <= DESC_RATEVHT2SS_MCS9) { + *nss = 2; + *mcs = rate - DESC_RATEVHT2SS_MCS0; + } else if (rate >= DESC_RATEVHT3SS_MCS0 && + rate <= DESC_RATEVHT3SS_MCS9) { + *nss = 3; + *mcs = rate - DESC_RATEVHT3SS_MCS0; + } else if (rate >= DESC_RATEVHT4SS_MCS0 && + rate <= DESC_RATEVHT4SS_MCS9) { + *nss = 4; + *mcs = rate - DESC_RATEVHT4SS_MCS0; + } else if (rate >= DESC_RATEMCS0 && + rate <= DESC_RATEMCS15) { + *mcs = rate - DESC_RATEMCS0; + } +} -- cgit v1.2.3-59-g8ed1b From 127eef1d46f80056fe9f18406c6eab38778d8a06 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:23 +0800 Subject: rtw88: add TX-AMSDU support Based on the mac80211's TXQ implementation, TX-AMSDU can be used to get higher MAC efficiency. To make mac80211 aggregate MSDUs, low level driver just need to leave skbs in the TXQ, and mac80211 will try to aggregate them if possible. As driver will schedule a tasklet when the TX queue is woke, until the tasklet being served, there will have some skbs in the queue if traffic is heavy. Driver can control the max AMSDU size depending on the current bit rate used by hardware/firmware. The higher rates are used, the larger AMSDU size can be. It is tested that can achieve higher T-Put at higher rates. If the environment is relatively clean, and the bit_rate is high enough, we can get about 80Mbps improvement. For lower bit rates, not much gain can we get, so leave the max_amsdu length low to prevent aggregation. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 24 ++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.c | 1 + 2 files changed, 25 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 4b41bf531998..51649df7cc98 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -29,6 +29,28 @@ static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev, } } +static u16 get_max_amsdu_len(u32 bit_rate) +{ + /* lower than ofdm, do not aggregate */ + if (bit_rate < 550) + return 1; + + /* lower than 20M 2ss mcs8, make it small */ + if (bit_rate < 1800) + return 1200; + + /* lower than 40M 2ss mcs9, make it medium */ + if (bit_rate < 4000) + return 2600; + + /* not yet 80M 2ss mcs8/9, make it twice regular packet size */ + if (bit_rate < 7000) + return 3500; + + /* unlimited */ + return 0; +} + struct rtw_fw_iter_ra_data { struct rtw_dev *rtwdev; u8 *payload; @@ -83,6 +105,8 @@ legacy: si->ra_report.desc_rate = rate; si->ra_report.bit_rate = bit_rate; + + sta->max_rc_amsdu_len = get_max_amsdu_len(bit_rate); } static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 690a5c4d64e7..f7044e8bcb5b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1310,6 +1310,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, HAS_RATE_CONTROL); + ieee80211_hw_set(hw, TX_AMSDU); hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | -- cgit v1.2.3-59-g8ed1b From 1131ad7fe57541b78db92d1332c69158e13762dc Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:24 +0800 Subject: rtw88: flush hardware tx queues Sometimes mac80211 will ask us to flush the hardware queues. To flush them, first we need to get the corresponding priority queues from the RQPN mapping table. Then we can check the available pages are equal to the originally reserved pages, which means the hardware has returned all of the pages it used to transmit. Note that now we only check for 100 ms for the priority queue, but sometimes if we have a lot of traffic (ex. 100Mbps up), some of the packets could be dropped. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.c | 88 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/mac.h | 1 + drivers/net/wireless/realtek/rtw88/mac80211.c | 14 +++++ drivers/net/wireless/realtek/rtw88/main.h | 3 +- 4 files changed, 105 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index d8c5da342b11..f40877bc9c9a 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -719,6 +719,93 @@ dlfw_fail: return ret; } +static u32 get_priority_queues(struct rtw_dev *rtwdev, u32 queues) +{ + struct rtw_rqpn *rqpn = rtwdev->fifo.rqpn; + u32 prio_queues = 0; + + if (queues & BIT(IEEE80211_AC_VO)) + prio_queues |= BIT(rqpn->dma_map_vo); + if (queues & BIT(IEEE80211_AC_VI)) + prio_queues |= BIT(rqpn->dma_map_vi); + if (queues & BIT(IEEE80211_AC_BE)) + prio_queues |= BIT(rqpn->dma_map_be); + if (queues & BIT(IEEE80211_AC_BK)) + prio_queues |= BIT(rqpn->dma_map_bk); + + return prio_queues; +} + +static void __rtw_mac_flush_prio_queue(struct rtw_dev *rtwdev, + u32 prio_queue, bool drop) +{ + u32 addr; + u16 avail_page, rsvd_page; + int i; + + switch (prio_queue) { + case RTW_DMA_MAPPING_EXTRA: + addr = REG_FIFOPAGE_INFO_4; + break; + case RTW_DMA_MAPPING_LOW: + addr = REG_FIFOPAGE_INFO_2; + break; + case RTW_DMA_MAPPING_NORMAL: + addr = REG_FIFOPAGE_INFO_3; + break; + case RTW_DMA_MAPPING_HIGH: + addr = REG_FIFOPAGE_INFO_1; + break; + default: + return; + } + + /* check if all of the reserved pages are available for 100 msecs */ + for (i = 0; i < 5; i++) { + rsvd_page = rtw_read16(rtwdev, addr); + avail_page = rtw_read16(rtwdev, addr + 2); + if (rsvd_page == avail_page) + return; + + msleep(20); + } + + /* priority queue is still not empty, throw a warning, + * + * Note that if we want to flush the tx queue when having a lot of + * traffic (ex, 100Mbps up), some of the packets could be dropped. + * And it requires like ~2secs to flush the full priority queue. + */ + if (!drop) + rtw_warn(rtwdev, "timed out to flush queue %d\n", prio_queue); +} + +static void rtw_mac_flush_prio_queues(struct rtw_dev *rtwdev, + u32 prio_queues, bool drop) +{ + u32 q; + + for (q = 0; q < RTW_DMA_MAPPING_MAX; q++) + if (prio_queues & BIT(q)) + __rtw_mac_flush_prio_queue(rtwdev, q, drop); +} + +void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop) +{ + u32 prio_queues = 0; + + /* If all of the hardware queues are requested to flush, + * or the priority queues are not mapped yet, + * flush all of the priority queues + */ + if (queues == BIT(rtwdev->hw->queues) - 1 || !rtwdev->fifo.rqpn) + prio_queues = BIT(RTW_DMA_MAPPING_MAX) - 1; + else + prio_queues = get_priority_queues(rtwdev, queues); + + rtw_mac_flush_prio_queues(rtwdev, prio_queues, drop); +} + static int txdma_queue_mapping(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -743,6 +830,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) return -EINVAL; } + rtwdev->fifo.rqpn = rqpn; txdma_pq_map |= BIT_TXDMA_HIQ_MAP(rqpn->dma_map_hi); txdma_pq_map |= BIT_TXDMA_MGQ_MAP(rqpn->dma_map_mg); txdma_pq_map |= BIT_TXDMA_BKQ_MAP(rqpn->dma_map_bk); diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index efe6f731f240..a67fa82973e4 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -31,5 +31,6 @@ int rtw_mac_power_on(struct rtw_dev *rtwdev); void rtw_mac_power_off(struct rtw_dev *rtwdev); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); +void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 9c77c86d3021..cb7436949ff6 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -589,6 +589,19 @@ static void rtw_ops_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } +static void rtw_ops_flush(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct rtw_dev *rtwdev = hw->priv; + + mutex_lock(&rtwdev->mutex); + rtw_leave_lps_deep(rtwdev); + + rtw_mac_flush_queues(rtwdev, queues, drop); + mutex_unlock(&rtwdev->mutex); +} + const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, .wake_tx_queue = rtw_ops_wake_tx_queue, @@ -608,5 +621,6 @@ const struct ieee80211_ops rtw_ops = { .mgd_prepare_tx = rtw_ops_mgd_prepare_tx, .set_rts_threshold = rtw_ops_set_rts_threshold, .sta_statistics = rtw_ops_sta_statistics, + .flush = rtw_ops_flush, }; EXPORT_SYMBOL(rtw_ops); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index cd34d4d77b52..00d2cf07a176 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -780,6 +780,7 @@ enum rtw_dma_mapping { RTW_DMA_MAPPING_NORMAL = 2, RTW_DMA_MAPPING_HIGH = 3, + RTW_DMA_MAPPING_MAX, RTW_DMA_MAPPING_UNDEF, }; @@ -1286,7 +1287,7 @@ struct rtw_fifo_conf { u16 rsvd_cpu_instr_addr; u16 rsvd_fw_txbuf_addr; u16 rsvd_csibuf_addr; - enum rtw_dma_mapping pq_map[RTW_PQ_MAP_NUM]; + struct rtw_rqpn *rqpn; }; struct rtw_fw_state { -- cgit v1.2.3-59-g8ed1b From c3594559f49c601d410dee4b767c3536a5535bfd Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:25 +0800 Subject: rtw88: fix beaconing mode rsvd_page memory violation issue When downloading the reserved page, the first page always contains a beacon for the firmware to reference. For non-beaconing modes such as station mode, also put a blank skb with length=1. And for the beaconing modes, driver will get a real beacon with a length approximate to the page size. But as the beacon is always put at the first page, it does not need a tx_desc, because the TX path will generate one when TXing the reserved page to the hardware. So we could allocate a buffer with a size smaller than the reserved page, when using memcpy() to copy the content of reserved page to the buffer, the over-sized reserved page will violate the kernel memory. To fix it, add the tx_desc before memcpy() the reserved packets to the buffer, then we can get SKBs with correct length when counting the pages in total. And for page 0, count the extra tx_desc_sz that the TX path will generate. This way, the first beacon that allocated without tx_desc can be counted with the extra tx_desc_sz to get actual pages it requires. Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 52 +++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 51649df7cc98..65594393dd1e 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -672,9 +672,6 @@ static void rtw_rsvd_page_list_to_buf(struct rtw_dev *rtwdev, u8 page_size, { struct sk_buff *skb = rsvd_pkt->skb; - if (rsvd_pkt->add_txdesc) - rtw_fill_rsvd_page_desc(rtwdev, skb); - if (page >= 1) memcpy(buf + page_margin + page_size * (page - 1), skb->data, skb->len); @@ -799,16 +796,37 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) { iter = rtw_get_rsvd_page_skb(hw, vif, rsvd_pkt->type); if (!iter) { - rtw_err(rtwdev, "fail to build rsvd packet\n"); + rtw_err(rtwdev, "failed to build rsvd packet\n"); goto release_skb; } + + /* Fill the tx_desc for the rsvd pkt that requires one. + * And iter->len will be added with size of tx_desc_sz. + */ + if (rsvd_pkt->add_txdesc) + rtw_fill_rsvd_page_desc(rtwdev, iter); + rsvd_pkt->skb = iter; rsvd_pkt->page = total_page; - if (rsvd_pkt->add_txdesc) + + /* Reserved page is downloaded via TX path, and TX path will + * generate a tx_desc at the header to describe length of + * the buffer. If we are not counting page numbers with the + * size of tx_desc added at the first rsvd_pkt (usually a + * beacon, firmware default refer to the first page as the + * content of beacon), we could generate a buffer which size + * is smaller than the actual size of the whole rsvd_page + */ + if (total_page == 0) { + if (rsvd_pkt->type != RSVD_BEACON) { + rtw_err(rtwdev, "first page should be a beacon\n"); + goto release_skb; + } total_page += rtw_len_to_page(iter->len + tx_desc_sz, page_size); - else + } else { total_page += rtw_len_to_page(iter->len, page_size); + } } if (total_page > rtwdev->fifo.rsvd_drv_pg_num) { @@ -821,13 +839,24 @@ static u8 *rtw_build_rsvd_page(struct rtw_dev *rtwdev, if (!buf) goto release_skb; + /* Copy the content of each rsvd_pkt to the buf, and they should + * be aligned to the pages. + * + * Note that the first rsvd_pkt is a beacon no matter what vif->type. + * And that rsvd_pkt does not require tx_desc because when it goes + * through TX path, the TX path will generate one for it. + */ list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) { rtw_rsvd_page_list_to_buf(rtwdev, page_size, page_margin, page, buf, rsvd_pkt); - page += rtw_len_to_page(rsvd_pkt->skb->len, page_size); - } - list_for_each_entry(rsvd_pkt, &rtwdev->rsvd_page_list, list) + if (page == 0) + page += rtw_len_to_page(rsvd_pkt->skb->len + + tx_desc_sz, page_size); + else + page += rtw_len_to_page(rsvd_pkt->skb->len, page_size); + kfree_skb(rsvd_pkt->skb); + } return buf; @@ -880,6 +909,11 @@ int rtw_fw_download_rsvd_page(struct rtw_dev *rtwdev, struct ieee80211_vif *vif) goto free; } + /* The last thing is to download the *ONLY* beacon again, because + * the previous tx_desc is to describe the total rsvd page. Download + * the beacon again to replace the TX desc header, and we will get + * a correct tx_desc for the beacon in the rsvd page. + */ ret = rtw_download_beacon(rtwdev, vif); if (ret) { rtw_err(rtwdev, "failed to download beacon\n"); -- cgit v1.2.3-59-g8ed1b From 0649ff58a0f64df51bd24b38420da0875fbc7c00 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 2 Oct 2019 14:35:26 +0800 Subject: rtw88: Don't set RX_FLAG_DECRYPTED if packet has no encryption The value of GET_RX_DESC_SWDEC() indicates that if this RX packet requires software decryption or not. And software decryption is required when the packet was encrypted and the hardware failed to decrypt it. So, GET_RX_DESC_SWDEC() is negative does not mean that this packet is decrypted, it might just have no encryption at all. To actually see if the packet is decrypted, driver needs to further check if the hardware has successfully decrypted it, with a specific type of encryption algorithm. Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 3 ++- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 3 ++- drivers/net/wireless/realtek/rtw88/rx.h | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 2b6cd7cf763b..1e20c4465bc9 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -836,7 +836,8 @@ static void rtw8822b_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc); + pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && + GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 3b3bc39cf740..5075c7045b8f 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1704,7 +1704,8 @@ static void rtw8822c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc, pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc); pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc); pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc); - pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc); + pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) && + GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE; pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc); pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc); pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc); diff --git a/drivers/net/wireless/realtek/rtw88/rx.h b/drivers/net/wireless/realtek/rtw88/rx.h index 383f3b2babc1..3342e3761281 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.h +++ b/drivers/net/wireless/realtek/rtw88/rx.h @@ -5,6 +5,15 @@ #ifndef __RTW_RX_H_ #define __RTW_RX_H_ +enum rtw_rx_desc_enc { + RX_DESC_ENC_NONE = 0, + RX_DESC_ENC_WEP40 = 1, + RX_DESC_ENC_TKIP_WO_MIC = 2, + RX_DESC_ENC_TKIP_MIC = 3, + RX_DESC_ENC_AES = 4, + RX_DESC_ENC_WEP104 = 5, +}; + #define GET_RX_DESC_PHYST(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), BIT(26)) #define GET_RX_DESC_ICV_ERR(rxdesc) \ @@ -21,6 +30,8 @@ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(19, 16)) #define GET_RX_DESC_SHIFT(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(25, 24)) +#define GET_RX_DESC_ENC_TYPE(rxdesc) \ + le32_get_bits(*((__le32 *)(rxdesc) + 0x00), GENMASK(22, 20)) #define GET_RX_DESC_RX_RATE(rxdesc) \ le32_get_bits(*((__le32 *)(rxdesc) + 0x03), GENMASK(6, 0)) #define GET_RX_DESC_MACID(rxdesc) \ -- cgit v1.2.3-59-g8ed1b From bf06c7ec45087066f638bddcccf6f0fd41903535 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:27 +0800 Subject: rtw88: configure TX queue EDCA parameters Set CWmax/CWmin, TXOP and AIFS according to ieee80211_tx_queue_params. Do note that hardware has only one group of EDCA[ac] registers, if more than one vif are added, the EDCA[ac] registers will contain value of params of the most recent set by ieee80211_ops::conf_tx(). And AIFS = AIFSN[ac] * slot_time + SIFS, so if use_short_slot is changed, need to also change AIFS. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 71 +++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.h | 8 +++ drivers/net/wireless/realtek/rtw88/reg.h | 4 ++ 3 files changed, 83 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index cb7436949ff6..d03b0b7a0e70 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -269,6 +269,54 @@ static void rtw_ops_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +/* Only have one group of EDCA parameters now */ +static const u32 ac_to_edca_param[IEEE80211_NUM_ACS] = { + [IEEE80211_AC_VO] = REG_EDCA_VO_PARAM, + [IEEE80211_AC_VI] = REG_EDCA_VI_PARAM, + [IEEE80211_AC_BE] = REG_EDCA_BE_PARAM, + [IEEE80211_AC_BK] = REG_EDCA_BK_PARAM, +}; + +static u8 rtw_aifsn_to_aifs(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, u8 aifsn) +{ + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + u8 slot_time; + u8 sifs; + + slot_time = vif->bss_conf.use_short_slot ? 9 : 20; + sifs = rtwdev->hal.current_band_type == RTW_BAND_5G ? 16 : 10; + + return aifsn * slot_time + sifs; +} + +static void __rtw_conf_tx(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif, u16 ac) +{ + struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; + u32 edca_param = ac_to_edca_param[ac]; + u8 ecw_max, ecw_min; + u8 aifs; + + /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ + ecw_max = ilog2(params->cw_max + 1); + ecw_min = ilog2(params->cw_min + 1); + aifs = rtw_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_TXOP_LMT, params->txop); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMAX, ecw_max); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_CWMIN, ecw_min); + rtw_write32_mask(rtwdev, edca_param, BIT_MASK_AIFS, aifs); +} + +static void rtw_conf_tx(struct rtw_dev *rtwdev, + struct rtw_vif *rtwvif) +{ + u16 ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + __rtw_conf_tx(rtwdev, rtwvif, ac); +} + static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf, @@ -320,11 +368,33 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON) rtw_fw_download_rsvd_page(rtwdev, vif); + if (changed & BSS_CHANGED_ERP_SLOT) + rtw_conf_tx(rtwdev, rtwvif); + rtw_vif_port_config(rtwdev, rtwvif, config); mutex_unlock(&rtwdev->mutex); } +static int rtw_ops_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 ac, + const struct ieee80211_tx_queue_params *params) +{ + struct rtw_dev *rtwdev = hw->priv; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + + mutex_lock(&rtwdev->mutex); + + rtw_leave_lps_deep(rtwdev); + + rtwvif->tx_params[ac] = *params; + __rtw_conf_tx(rtwdev, rtwvif, ac); + + mutex_unlock(&rtwdev->mutex); + + return 0; +} + static u8 rtw_acquire_macid(struct rtw_dev *rtwdev) { unsigned long mac_id; @@ -612,6 +682,7 @@ const struct ieee80211_ops rtw_ops = { .remove_interface = rtw_ops_remove_interface, .configure_filter = rtw_ops_configure_filter, .bss_info_changed = rtw_ops_bss_info_changed, + .conf_tx = rtw_ops_conf_tx, .sta_add = rtw_ops_sta_add, .sta_remove = rtw_ops_sta_remove, .set_key = rtw_ops_set_key, diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 00d2cf07a176..f3eab96dba86 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -641,6 +641,7 @@ struct rtw_vif { u8 bssid[ETH_ALEN]; u8 port; u8 bcn_ctrl; + struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; const struct rtw_vif_port *conf; struct rtw_traffic_stats stats; @@ -1432,6 +1433,13 @@ static inline struct ieee80211_txq *rtwtxq_to_txq(struct rtw_txq *rtwtxq) return container_of(p, struct ieee80211_txq, drv_priv); } +static inline struct ieee80211_vif *rtwvif_to_vif(struct rtw_vif *rtwvif) +{ + void *p = rtwvif; + + return container_of(p, struct ieee80211_vif, drv_priv); +} + void rtw_get_channel_params(struct cfg80211_chan_def *chandef, struct rtw_channel_params *ch_param); bool check_hw_ready(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 target); diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 60014077de77..bd04c3fad1ee 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -239,6 +239,10 @@ #define REG_EDCA_VI_PARAM 0x0504 #define REG_EDCA_BE_PARAM 0x0508 #define REG_EDCA_BK_PARAM 0x050C +#define BIT_MASK_TXOP_LMT GENMASK(26, 16) +#define BIT_MASK_CWMAX GENMASK(15, 12) +#define BIT_MASK_CWMIN GENMASK(11, 8) +#define BIT_MASK_AIFS GENMASK(7, 0) #define REG_PIFS 0x0512 #define REG_SIFS 0x0514 #define BIT_SHIFT_SIFS_OFDM_CTX 8 -- cgit v1.2.3-59-g8ed1b From bc3696e0a436d747b699363293ef76829998ac63 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Wed, 2 Oct 2019 14:35:28 +0800 Subject: rtw88: raise firmware version debug level It's better to print firmware version at load time. But since we need to set debug_mask properly to default print rtw_dbg(), raise the debug level to rtw_info() instead. Also change the multiple line style to one line only, it will be easier for log analyzing. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index f40877bc9c9a..75f35a97dca7 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -578,10 +578,8 @@ static void update_firmware_info(struct rtw_dev *rtwdev, fw->sub_version = *(data + FW_HDR_SUBVERSION); fw->sub_index = *(data + FW_HDR_SUBINDEX); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw h2c version: %x\n", fw->h2c_version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw version: %x\n", fw->version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub version: %x\n", fw->sub_version); - rtw_dbg(rtwdev, RTW_DBG_FW, "fw sub index: %x\n", fw->sub_index); + rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", + fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); } static int -- cgit v1.2.3-59-g8ed1b From cc20a713983684b6760a21591516fb64e29aecfd Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 2 Oct 2019 14:35:29 +0800 Subject: rtw88: use struct rtw_fw_hdr to access firmware header This commit doesn't change logic at all, just use struct rtw_fw_hdr to access fixed part of 64 bytes header. Since remaining part is variable length data of actual firmware, we don't define them within the struct. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.h | 45 ++++++++++++++++++++------------ drivers/net/wireless/realtek/rtw88/mac.c | 37 +++++++++++++------------- 2 files changed, 48 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index fd34986a13d2..4f7999394235 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -11,22 +11,6 @@ /* FW bin information */ #define FW_HDR_SIZE 64 #define FW_HDR_CHKSUM_SIZE 8 -#define FW_HDR_VERSION 4 -#define FW_HDR_SUBVERSION 6 -#define FW_HDR_SUBINDEX 7 -#define FW_HDR_MONTH 16 -#define FW_HDR_DATE 17 -#define FW_HDR_HOUR 18 -#define FW_HDR_MIN 19 -#define FW_HDR_YEAR 20 -#define FW_HDR_MEM_USAGE 24 -#define FW_HDR_H2C_FMT_VER 28 -#define FW_HDR_DMEM_ADDR 32 -#define FW_HDR_DMEM_SIZE 36 -#define FW_HDR_IMEM_SIZE 48 -#define FW_HDR_EMEM_SIZE 52 -#define FW_HDR_EMEM_ADDR 56 -#define FW_HDR_IMEM_ADDR 60 #define FIFO_PAGE_SIZE_SHIFT 12 #define FIFO_PAGE_SIZE 4096 @@ -116,6 +100,35 @@ struct rtw_rsvd_page { bool add_txdesc; }; +struct rtw_fw_hdr { + __le16 signature; + u8 category; + u8 function; + __le16 version; /* 0x04 */ + u8 subversion; + u8 subindex; + __le32 rsvd; /* 0x08 */ + __le32 rsvd2; /* 0x0C */ + u8 month; /* 0x10 */ + u8 day; + u8 hour; + u8 min; + __le16 year; /* 0x14 */ + __le16 rsvd3; + u8 mem_usage; /* 0x18 */ + u8 rsvd4[3]; + __le16 h2c_fmt_ver; /* 0x1C */ + __le16 rsvd5; + __le32 dmem_addr; /* 0x20 */ + __le32 dmem_size; + __le32 rsvd6; + __le32 rsvd7; + __le32 imem_size; /* 0x30 */ + __le32 emem_size; + __le32 emem_addr; + __le32 imem_addr; +}; + /* C2H */ #define GET_CCX_REPORT_SEQNUM(c2h_payload) (c2h_payload[8] & 0xfc) #define GET_CCX_REPORT_STATUS(c2h_payload) (c2h_payload[9] & 0xc0) diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 75f35a97dca7..aa1f15e18c7a 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -312,15 +312,16 @@ void rtw_mac_power_off(struct rtw_dev *rtwdev) static bool check_firmware_size(const u8 *data, u32 size) { + const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; u32 dmem_size; u32 imem_size; u32 emem_size; u32 real_size; - dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); - imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); - emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? - le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; + dmem_size = le32_to_cpu(fw_hdr->dmem_size); + imem_size = le32_to_cpu(fw_hdr->imem_size); + emem_size = (fw_hdr->mem_usage & BIT(4)) ? + le32_to_cpu(fw_hdr->emem_size) : 0; dmem_size += FW_HDR_CHKSUM_SIZE; imem_size += FW_HDR_CHKSUM_SIZE; @@ -569,14 +570,13 @@ download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, static void update_firmware_info(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - const u8 *data = fw->firmware->data; + const struct rtw_fw_hdr *fw_hdr = + (const struct rtw_fw_hdr *)fw->firmware->data; - fw->h2c_version = - le16_to_cpu(*((__le16 *)(data + FW_HDR_H2C_FMT_VER))); - fw->version = - le16_to_cpu(*((__le16 *)(data + FW_HDR_VERSION))); - fw->sub_version = *(data + FW_HDR_SUBVERSION); - fw->sub_index = *(data + FW_HDR_SUBINDEX); + fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); + fw->version = le16_to_cpu(fw_hdr->version); + fw->sub_version = fw_hdr->subversion; + fw->sub_index = fw_hdr->subindex; rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); @@ -585,6 +585,7 @@ static void update_firmware_info(struct rtw_dev *rtwdev, static int start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) { + const struct rtw_fw_hdr *fw_hdr = (const struct rtw_fw_hdr *)data; const u8 *cur_fw; u16 val; u32 imem_size; @@ -593,10 +594,10 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) u32 addr; int ret; - dmem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_SIZE))); - imem_size = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_SIZE))); - emem_size = ((*(data + FW_HDR_MEM_USAGE)) & BIT(4)) ? - le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_SIZE))) : 0; + dmem_size = le32_to_cpu(fw_hdr->dmem_size); + imem_size = le32_to_cpu(fw_hdr->imem_size); + emem_size = (fw_hdr->mem_usage & BIT(4)) ? + le32_to_cpu(fw_hdr->emem_size) : 0; dmem_size += FW_HDR_CHKSUM_SIZE; imem_size += FW_HDR_CHKSUM_SIZE; emem_size += emem_size ? FW_HDR_CHKSUM_SIZE : 0; @@ -606,14 +607,14 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) rtw_write16(rtwdev, REG_MCUFW_CTRL, val); cur_fw = data + FW_HDR_SIZE; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_DMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->dmem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, dmem_size); if (ret) return ret; cur_fw = data + FW_HDR_SIZE + dmem_size; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_IMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->imem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, imem_size); if (ret) @@ -621,7 +622,7 @@ start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) if (emem_size) { cur_fw = data + FW_HDR_SIZE + dmem_size + imem_size; - addr = le32_to_cpu(*((__le32 *)(data + FW_HDR_EMEM_ADDR))); + addr = le32_to_cpu(fw_hdr->emem_addr); addr &= ~BIT(31); ret = download_firmware_to_mem(rtwdev, cur_fw, 0, addr, emem_size); -- cgit v1.2.3-59-g8ed1b From 4f5bb7ff8b8d4bafd91243fc969ed240e67aa1ca Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 2 Oct 2019 14:35:30 +0800 Subject: rtw88: fix NSS of hw_cap 8822C is a 2x2 11ac chip, and then NSS must be less or equal to 2. However, current nss of hw cap is 3, likes hw cap: hci=0x0f, bw=0x07, ptcl=0x03, ant_num=7, nss=3 This commit adds constraint to make sure NSS <= rf_path_num, and result looks like hw cap: hci=0x0f, bw=0x07, ptcl=0x03, ant_num=7, nss=2 Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index f7044e8bcb5b..bd2d3f9bc049 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1077,7 +1077,8 @@ static int rtw_dump_hw_feature(struct rtw_dev *rtwdev) rtw_hw_config_rf_ant_num(rtwdev, efuse->hw_cap.ant_num); - if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE) + if (efuse->hw_cap.nss == EFUSE_HW_CAP_IGNORE || + efuse->hw_cap.nss > rtwdev->hal.rf_path_num) efuse->hw_cap.nss = rtwdev->hal.rf_path_num; rtw_dbg(rtwdev, RTW_DBG_EFUSE, -- cgit v1.2.3-59-g8ed1b From f4268729eb1eefe23f6746849c1b5626d9030532 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Wed, 2 Oct 2019 14:35:31 +0800 Subject: rtw88: fix error handling when setup efuse info Disable efuse if the efuse is enabled when we failed to setup the efuse information, otherwise the hardware will not turn off. Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver") Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index bd2d3f9bc049..e0cc4c11e513 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1105,19 +1105,19 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) /* power on mac to read efuse */ ret = rtw_chip_efuse_enable(rtwdev); if (ret) - goto out; + goto out_unlock; ret = rtw_parse_efuse_map(rtwdev); if (ret) - goto out; + goto out_disable; ret = rtw_dump_hw_feature(rtwdev); if (ret) - goto out; + goto out_disable; ret = rtw_check_supported_rfe(rtwdev); if (ret) - goto out; + goto out_disable; if (efuse->crystal_cap == 0xff) efuse->crystal_cap = 0; @@ -1144,9 +1144,10 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) efuse->ext_pa_5g = efuse->pa_type_5g & BIT(0) ? 1 : 0; efuse->ext_lna_2g = efuse->lna_type_5g & BIT(3) ? 1 : 0; +out_disable: rtw_chip_efuse_disable(rtwdev); -out: +out_unlock: mutex_unlock(&rtwdev->mutex); return ret; } -- cgit v1.2.3-59-g8ed1b From 3b1e0a7bdfeedbde49b8d424aeb88ac3c0cf8182 Mon Sep 17 00:00:00 2001 From: Chung-Hsien Hsu Date: Wed, 2 Oct 2019 09:31:12 +0000 Subject: brcmfmac: add support for SAE authentication offload The firmware may have SAE authentication code built-in. This is detected by the driver and indicated in the wiphy features flags. User-space can use this flag to determine whether or not to provide the password material for SAE authentication in the nl80211 CONNECT command. Signed-off-by: Chung-Hsien Hsu Signed-off-by: Chi-Hsien Lin Signed-off-by: Kalle Valo --- .../broadcom/brcm80211/brcmfmac/cfg80211.c | 73 ++++++++++++++++++++-- .../broadcom/brcm80211/brcmfmac/cfg80211.h | 3 +- .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 3 +- .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 4 +- .../broadcom/brcm80211/brcmfmac/fwil_types.h | 13 ++++ .../broadcom/brcm80211/include/brcmu_wifi.h | 2 + 6 files changed, 90 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 0cf4c795e62e..5598bbd09b62 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1282,6 +1282,31 @@ static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) return err; } +static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, + u16 pwd_len) +{ + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, pwd_data, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; +} + static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); @@ -1505,6 +1530,8 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_3) + val = WPA3_AUTH_SAE_PSK; else val = WPA_AUTH_DISABLED; brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); @@ -1537,6 +1564,10 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, val = 1; brcmf_dbg(CONN, "shared key\n"); break; + case NL80211_AUTHTYPE_SAE: + val = 3; + brcmf_dbg(CONN, "SAE authentication\n"); + break; default: val = 2; brcmf_dbg(CONN, "automatic, auth type (%d)\n", sme->auth_type); @@ -1705,6 +1736,16 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) sme->crypto.cipher_group); return -EINVAL; } + } else if (val & WPA3_AUTH_SAE_PSK) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_SAE: + val = WPA3_AUTH_SAE_PSK; + break; + default: + bphy_err(drvr, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } } if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_1X) @@ -1776,7 +1817,8 @@ brcmf_set_sharedkey(struct net_device *ndev, brcmf_dbg(CONN, "wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise); - if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) + if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2 | + NL80211_WPA_VERSION_3)) return 0; if (!(sec->cipher_pairwise & @@ -1983,7 +2025,13 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } - if (sme->crypto.psk) { + if (sme->crypto.sae_pwd) { + brcmf_dbg(INFO, "using SAE offload\n"); + profile->use_fwsup = BRCMF_PROFILE_FWSUP_SAE; + } + + if (sme->crypto.psk && + profile->use_fwsup != BRCMF_PROFILE_FWSUP_SAE) { if (WARN_ON(profile->use_fwsup != BRCMF_PROFILE_FWSUP_NONE)) { err = -EINVAL; goto done; @@ -2001,12 +2049,23 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, } } - if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) { + if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_PSK) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); - if (err) + else if (profile->use_fwsup == BRCMF_PROFILE_FWSUP_SAE) { + /* clean up user-space RSNE */ + if (brcmf_fil_iovar_data_set(ifp, "wpaie", NULL, 0)) { + bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; + } + err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, + sme->crypto.sae_pwd_len); + if (!err && sme->crypto.psk) + err = brcmf_set_pmk(ifp, sme->crypto.psk, + BRCMF_WSEC_MAX_PSK_LEN); } + if (err) + goto done; /* Join with specific BSSID and cached SSID * If SSID is zero join based on BSSID only @@ -5362,7 +5421,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif, if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { brcmf_dbg(CONN, "Processing set ssid\n"); memcpy(vif->profile.bssid, e->addr, ETH_ALEN); - if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK) + if (vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_PSK && + vif->profile.use_fwsup != BRCMF_PROFILE_FWSUP_SAE) return true; set_bit(BRCMF_VIF_STATUS_ASSOC_SUCCESS, &vif->sme_state); @@ -6672,6 +6732,9 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X); + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SAE_OFFLOAD); } wiphy->mgmt_stypes = brcmf_txrx_stypes; wiphy->max_remain_on_channel_duration = 5000; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index e29846b1954b..6ce48f6275a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -107,7 +107,8 @@ struct brcmf_cfg80211_security { enum brcmf_profile_fwsup { BRCMF_PROFILE_FWSUP_NONE, BRCMF_PROFILE_FWSUP_PSK, - BRCMF_PROFILE_FWSUP_1X + BRCMF_PROFILE_FWSUP_1X, + BRCMF_PROFILE_FWSUP_SAE }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 2c3526aeca6f..1c9c74cc958e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -39,7 +39,8 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { { BRCMF_FEAT_P2P, "p2p" }, { BRCMF_FEAT_MONITOR, "monitor" }, { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, - { BRCMF_FEAT_DOT11H, "802.11h" } + { BRCMF_FEAT_DOT11H, "802.11h" }, + { BRCMF_FEAT_SAE, "sae" }, }; #ifdef DEBUG diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 736a8179f62f..280a1f6412d4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -26,6 +26,7 @@ * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header * MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header * DOT11H: firmware supports 802.11h + * SAE: simultaneous authentication of equals */ #define BRCMF_FEAT_LIST \ BRCMF_FEAT_DEF(MBSS) \ @@ -45,7 +46,8 @@ BRCMF_FEAT_DEF(MONITOR) \ BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \ BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \ - BRCMF_FEAT_DEF(DOT11H) + BRCMF_FEAT_DEF(DOT11H) \ + BRCMF_FEAT_DEF(SAE) /* * Quirks: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 37c512036e0e..de0ef1b545c4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -61,6 +61,8 @@ #define BRCMF_WSEC_MAX_PSK_LEN 32 #define BRCMF_WSEC_PASSPHRASE BIT(0) +#define BRCMF_WSEC_MAX_SAE_PASSWORD_LEN 128 + /* primary (ie tx) key */ #define BRCMF_PRIMARY_KEY (1 << 1) #define DOT11_BSSTYPE_ANY 2 @@ -518,6 +520,17 @@ struct brcmf_wsec_pmk_le { u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; }; +/** + * struct brcmf_wsec_sae_pwd_le - firmware SAE password material. + * + * @key_len: number of octets in key materials. + * @key: SAE password material. + */ +struct brcmf_wsec_sae_pwd_le { + __le16 key_len; + u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; +}; + /* Used to get specific STA parameters */ struct brcmf_scb_val_le { __le32 val; diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h index 7b31c212694d..7552bdb91991 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcmu_wifi.h @@ -231,6 +231,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec) #define WPA2_AUTH_FT 0x4000 /* Fast BSS Transition */ #define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */ +#define WPA3_AUTH_SAE_PSK 0x40000 /* SAE with 4-way handshake */ + #define DOT11_DEFAULT_RTS_LEN 2347 #define DOT11_DEFAULT_FRAG_LEN 2346 -- cgit v1.2.3-59-g8ed1b From 60b5b49f6a6ed3a5dd5e1b4b72b8c792387a0f8c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 2 Oct 2019 11:15:17 +0100 Subject: libertas: remove redundant assignment to variable ret The variable ret is being assigned a value that is never read and is being re-assigned a little later on. The assignment is redundant and hence can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Reviewed-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/libertas/mesh.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/libertas/mesh.c b/drivers/net/wireless/marvell/libertas/mesh.c index 2747c957d18c..44c8a550da4c 100644 --- a/drivers/net/wireless/marvell/libertas/mesh.c +++ b/drivers/net/wireless/marvell/libertas/mesh.c @@ -1003,7 +1003,6 @@ static int lbs_add_mesh(struct lbs_private *priv) if (priv->mesh_tlv) { sprintf(mesh_wdev->ssid, "mesh"); mesh_wdev->mesh_id_up_len = 4; - ret = 1; } mesh_wdev->netdev = mesh_dev; -- cgit v1.2.3-59-g8ed1b From f170d44bc4ec2feae5f6206980e7ae7fbf0432a0 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Wed, 2 Oct 2019 20:18:11 +0300 Subject: rsi: fix potential null dereference in rsi_probe() The id pointer can be NULL in rsi_probe(). It is checked everywhere except for the else branch in the idProduct condition. The patch adds NULL check before the id dereference in the rsi_dbg() call. Fixes: 54fdb318c111 ("rsi: add new device model for 9116") Cc: Amitkumar Karwar Cc: Siva Rebbagondla Cc: Kalle Valo Signed-off-by: Denis Efremov Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 760eaffeebd6..23a1d00b5f38 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -793,7 +793,7 @@ static int rsi_probe(struct usb_interface *pfunction, adapter->device_model = RSI_DEV_9116; } else { rsi_dbg(ERR_ZONE, "%s: Unsupported RSI device id 0x%x\n", - __func__, id->idProduct); + __func__, id ? id->idProduct : 0x0); goto err1; } -- cgit v1.2.3-59-g8ed1b From a5facc4cac4dc504397428c936ef1492ce4edd19 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:26 +0200 Subject: netdevsim: change fib accounting and limitations to be per-device Currently, the accounting is done per-namespace. However, devlink instance is always in init_net namespace for now, so only the accounting related to init_net is used. Limitations set using devlink resources are only considered for init_net. nsim_devlink_net() always returns init_net always. Make the accounting per-device. This brings no functional change. Per-device accounting has the same values as per-net. For a single netdevsim instance, the behaviour is exactly the same as before. When multiple netdevsim instances are created, each can have different limits. This is in prepare to implement proper devlink netns support. After that, the devlink instance which would exist in particular netns would account and limit that netns. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 79 +++++---------------- drivers/net/netdevsim/fib.c | 144 ++++++++++++++++++++++++-------------- drivers/net/netdevsim/netdev.c | 9 +-- drivers/net/netdevsim/netdevsim.h | 10 +-- 4 files changed, 114 insertions(+), 128 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 56576d4f34a5..6087f5b99e47 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -123,39 +123,6 @@ static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port) debugfs_remove_recursive(nsim_dev_port->ddir); } -static struct net *nsim_devlink_net(struct devlink *devlink) -{ - return &init_net; -} - -static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv) -{ - struct net *net = priv; - - return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false); -} - -static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv) -{ - struct net *net = priv; - - return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false); -} - -static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv) -{ - struct net *net = priv; - - return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false); -} - -static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv) -{ - struct net *net = priv; - - return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false); -} - static int nsim_dev_resources_register(struct devlink *devlink) { struct devlink_resource_size_params params = { @@ -163,9 +130,7 @@ static int nsim_dev_resources_register(struct devlink *devlink) .size_granularity = 1, .unit = DEVLINK_RESOURCE_UNIT_ENTRY }; - struct net *net = nsim_devlink_net(devlink); int err; - u64 n; /* Resources for IPv4 */ err = devlink_resource_register(devlink, "IPv4", (u64)-1, @@ -177,8 +142,7 @@ static int nsim_dev_resources_register(struct devlink *devlink) goto out; } - n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true); - err = devlink_resource_register(devlink, "fib", n, + err = devlink_resource_register(devlink, "fib", (u64)-1, NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4, ¶ms); if (err) { @@ -186,8 +150,7 @@ static int nsim_dev_resources_register(struct devlink *devlink) return err; } - n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true); - err = devlink_resource_register(devlink, "fib-rules", n, + err = devlink_resource_register(devlink, "fib-rules", (u64)-1, NSIM_RESOURCE_IPV4_FIB_RULES, NSIM_RESOURCE_IPV4, ¶ms); if (err) { @@ -205,8 +168,7 @@ static int nsim_dev_resources_register(struct devlink *devlink) goto out; } - n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true); - err = devlink_resource_register(devlink, "fib", n, + err = devlink_resource_register(devlink, "fib", (u64)-1, NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6, ¶ms); if (err) { @@ -214,8 +176,7 @@ static int nsim_dev_resources_register(struct devlink *devlink) return err; } - n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true); - err = devlink_resource_register(devlink, "fib-rules", n, + err = devlink_resource_register(devlink, "fib-rules", (u64)-1, NSIM_RESOURCE_IPV6_FIB_RULES, NSIM_RESOURCE_IPV6, ¶ms); if (err) { @@ -223,22 +184,6 @@ static int nsim_dev_resources_register(struct devlink *devlink) return err; } - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV4_FIB, - nsim_dev_ipv4_fib_resource_occ_get, - net); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV4_FIB_RULES, - nsim_dev_ipv4_fib_rules_res_occ_get, - net); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV6_FIB, - nsim_dev_ipv6_fib_resource_occ_get, - net); - devlink_resource_occ_get_register(devlink, - NSIM_RESOURCE_IPV6_FIB_RULES, - nsim_dev_ipv6_fib_rules_res_occ_get, - net); out: return err; } @@ -533,11 +478,11 @@ static int nsim_dev_reload_down(struct devlink *devlink, static int nsim_dev_reload_up(struct devlink *devlink, struct netlink_ext_ack *extack) { + struct nsim_dev *nsim_dev = devlink_priv(devlink); enum nsim_resource_id res_ids[] = { NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES }; - struct net *net = nsim_devlink_net(devlink); int i; for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { @@ -546,7 +491,8 @@ static int nsim_dev_reload_up(struct devlink *devlink, err = devlink_resource_size_get(devlink, res_ids[i], &val); if (!err) { - err = nsim_fib_set_max(net, res_ids[i], val, extack); + err = nsim_fib_set_max(nsim_dev->fib_data, + res_ids[i], val, extack); if (err) return err; } @@ -681,9 +627,15 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) if (err) goto err_devlink_free; + nsim_dev->fib_data = nsim_fib_create(devlink); + if (IS_ERR(nsim_dev->fib_data)) { + err = PTR_ERR(nsim_dev->fib_data); + goto err_resources_unregister; + } + err = devlink_register(devlink, &nsim_bus_dev->dev); if (err) - goto err_resources_unregister; + goto err_fib_destroy; err = devlink_params_register(devlink, nsim_devlink_params, ARRAY_SIZE(nsim_devlink_params)); @@ -721,6 +673,8 @@ err_params_unregister: ARRAY_SIZE(nsim_devlink_params)); err_dl_unregister: devlink_unregister(devlink); +err_fib_destroy: + nsim_fib_destroy(devlink, nsim_dev->fib_data); err_resources_unregister: devlink_resources_unregister(devlink, NULL); err_devlink_free: @@ -739,6 +693,7 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev) devlink_params_unregister(devlink, nsim_devlink_params, ARRAY_SIZE(nsim_devlink_params)); devlink_unregister(devlink); + nsim_fib_destroy(devlink, nsim_dev->fib_data); devlink_resources_unregister(devlink, NULL); mutex_destroy(&nsim_dev->port_list_lock); devlink_free(devlink); diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index f61d094746c0..7de17e42d77a 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "netdevsim.h" @@ -33,15 +33,14 @@ struct nsim_per_fib_data { }; struct nsim_fib_data { + struct notifier_block fib_nb; struct nsim_per_fib_data ipv4; struct nsim_per_fib_data ipv6; }; -static unsigned int nsim_fib_net_id; - -u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max) +u64 nsim_fib_get_val(struct nsim_fib_data *fib_data, + enum nsim_resource_id res_id, bool max) { - struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id); struct nsim_fib_entry *entry; switch (res_id) { @@ -64,10 +63,10 @@ u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max) return max ? entry->max : entry->num; } -int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val, +int nsim_fib_set_max(struct nsim_fib_data *fib_data, + enum nsim_resource_id res_id, u64 val, struct netlink_ext_ack *extack) { - struct nsim_fib_data *fib_data = net_generic(net, nsim_fib_net_id); struct nsim_fib_entry *entry; int err = 0; @@ -120,9 +119,9 @@ static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add, return err; } -static int nsim_fib_rule_event(struct fib_notifier_info *info, bool add) +static int nsim_fib_rule_event(struct nsim_fib_data *data, + struct fib_notifier_info *info, bool add) { - struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id); struct netlink_ext_ack *extack = info->extack; int err = 0; @@ -157,9 +156,9 @@ static int nsim_fib_account(struct nsim_fib_entry *entry, bool add, return err; } -static int nsim_fib_event(struct fib_notifier_info *info, bool add) +static int nsim_fib_event(struct nsim_fib_data *data, + struct fib_notifier_info *info, bool add) { - struct nsim_fib_data *data = net_generic(info->net, nsim_fib_net_id); struct netlink_ext_ack *extack = info->extack; int err = 0; @@ -178,18 +177,25 @@ static int nsim_fib_event(struct fib_notifier_info *info, bool add) static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event, void *ptr) { + struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data, + fib_nb); struct fib_notifier_info *info = ptr; int err = 0; + if (!net_eq(info->net, &init_net)) + return NOTIFY_DONE; + switch (event) { case FIB_EVENT_RULE_ADD: /* fall through */ case FIB_EVENT_RULE_DEL: - err = nsim_fib_rule_event(info, event == FIB_EVENT_RULE_ADD); + err = nsim_fib_rule_event(data, info, + event == FIB_EVENT_RULE_ADD); break; case FIB_EVENT_ENTRY_ADD: /* fall through */ case FIB_EVENT_ENTRY_DEL: - err = nsim_fib_event(info, event == FIB_EVENT_ENTRY_ADD); + err = nsim_fib_event(data, info, + event == FIB_EVENT_ENTRY_ADD); break; } @@ -199,68 +205,98 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event, /* inconsistent dump, trying again */ static void nsim_fib_dump_inconsistent(struct notifier_block *nb) { - struct nsim_fib_data *data; - struct net *net; + struct nsim_fib_data *data = container_of(nb, struct nsim_fib_data, + fib_nb); - rcu_read_lock(); - for_each_net_rcu(net) { - data = net_generic(net, nsim_fib_net_id); + data->ipv4.fib.num = 0ULL; + data->ipv4.rules.num = 0ULL; + data->ipv6.fib.num = 0ULL; + data->ipv6.rules.num = 0ULL; +} - data->ipv4.fib.num = 0ULL; - data->ipv4.rules.num = 0ULL; +static u64 nsim_fib_ipv4_resource_occ_get(void *priv) +{ + struct nsim_fib_data *data = priv; - data->ipv6.fib.num = 0ULL; - data->ipv6.rules.num = 0ULL; - } - rcu_read_unlock(); + return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB, false); } -static struct notifier_block nsim_fib_nb = { - .notifier_call = nsim_fib_event_nb, -}; - -/* Initialize per network namespace state */ -static int __net_init nsim_fib_netns_init(struct net *net) +static u64 nsim_fib_ipv4_rules_res_occ_get(void *priv) { - struct nsim_fib_data *data = net_generic(net, nsim_fib_net_id); + struct nsim_fib_data *data = priv; - data->ipv4.fib.max = (u64)-1; - data->ipv4.rules.max = (u64)-1; + return nsim_fib_get_val(data, NSIM_RESOURCE_IPV4_FIB_RULES, false); +} - data->ipv6.fib.max = (u64)-1; - data->ipv6.rules.max = (u64)-1; +static u64 nsim_fib_ipv6_resource_occ_get(void *priv) +{ + struct nsim_fib_data *data = priv; - return 0; + return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB, false); } -static struct pernet_operations nsim_fib_net_ops = { - .init = nsim_fib_netns_init, - .id = &nsim_fib_net_id, - .size = sizeof(struct nsim_fib_data), -}; - -void nsim_fib_exit(void) +static u64 nsim_fib_ipv6_rules_res_occ_get(void *priv) { - unregister_pernet_subsys(&nsim_fib_net_ops); - unregister_fib_notifier(&nsim_fib_nb); + struct nsim_fib_data *data = priv; + + return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB_RULES, false); } -int nsim_fib_init(void) +struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) { + struct nsim_fib_data *data; int err; - err = register_pernet_subsys(&nsim_fib_net_ops); - if (err < 0) { - pr_err("Failed to register pernet subsystem\n"); - goto err_out; - } + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); - err = register_fib_notifier(&nsim_fib_nb, nsim_fib_dump_inconsistent); - if (err < 0) { + data->ipv4.fib.max = (u64)-1; + data->ipv4.rules.max = (u64)-1; + + data->ipv6.fib.max = (u64)-1; + data->ipv6.rules.max = (u64)-1; + + data->fib_nb.notifier_call = nsim_fib_event_nb; + err = register_fib_notifier(&data->fib_nb, nsim_fib_dump_inconsistent); + if (err) { pr_err("Failed to register fib notifier\n"); goto err_out; } + devlink_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV4_FIB, + nsim_fib_ipv4_resource_occ_get, + data); + devlink_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV4_FIB_RULES, + nsim_fib_ipv4_rules_res_occ_get, + data); + devlink_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV6_FIB, + nsim_fib_ipv6_resource_occ_get, + data); + devlink_resource_occ_get_register(devlink, + NSIM_RESOURCE_IPV6_FIB_RULES, + nsim_fib_ipv6_rules_res_occ_get, + data); + return data; + err_out: - return err; + kfree(data); + return ERR_PTR(err); +} + +void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) +{ + devlink_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV6_FIB_RULES); + devlink_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV6_FIB); + devlink_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV4_FIB_RULES); + devlink_resource_occ_get_unregister(devlink, + NSIM_RESOURCE_IPV4_FIB); + unregister_fib_notifier(&data->fib_nb); + kfree(data); } diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 55f57f76d01b..0740940f41b1 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -357,18 +357,12 @@ static int __init nsim_module_init(void) if (err) goto err_dev_exit; - err = nsim_fib_init(); - if (err) - goto err_bus_exit; - err = rtnl_link_register(&nsim_link_ops); if (err) - goto err_fib_exit; + goto err_bus_exit; return 0; -err_fib_exit: - nsim_fib_exit(); err_bus_exit: nsim_bus_exit(); err_dev_exit: @@ -379,7 +373,6 @@ err_dev_exit: static void __exit nsim_module_exit(void) { rtnl_link_unregister(&nsim_link_ops); - nsim_fib_exit(); nsim_bus_exit(); nsim_dev_exit(); } diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 66bf13765ad0..ac506cf253b6 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -173,10 +173,12 @@ int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_index); -int nsim_fib_init(void); -void nsim_fib_exit(void); -u64 nsim_fib_get_val(struct net *net, enum nsim_resource_id res_id, bool max); -int nsim_fib_set_max(struct net *net, enum nsim_resource_id res_id, u64 val, +struct nsim_fib_data *nsim_fib_create(struct devlink *devlink); +void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data); +u64 nsim_fib_get_val(struct nsim_fib_data *fib_data, + enum nsim_resource_id res_id, bool max); +int nsim_fib_set_max(struct nsim_fib_data *fib_data, + enum nsim_resource_id res_id, u64 val, struct netlink_ext_ack *extack); #if IS_ENABLED(CONFIG_XFRM_OFFLOAD) -- cgit v1.2.3-59-g8ed1b From 7c550daffe22a97282effa75fe7c1f6b83563ecb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:27 +0200 Subject: net: fib_notifier: make FIB notifier per-netns Currently all users of FIB notifier only cares about events in init_net. Later in this patchset, users get interested in other namespaces too. However, for every registered block user is interested only about one namespace. Make the FIB notifier registration per-netns and avoid unnecessary calls of notifier block for other namespaces. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c | 7 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 9 +-- drivers/net/ethernet/rocker/rocker_main.c | 9 +-- drivers/net/netdevsim/fib.c | 8 +- include/linux/mroute_base.h | 10 +-- include/net/fib_notifier.h | 7 +- include/net/ip6_fib.h | 2 +- include/net/ip_fib.h | 2 +- net/core/fib_notifier.c | 87 ++++++++++------------ net/core/fib_rules.c | 7 +- net/ipv4/fib_notifier.c | 4 +- net/ipv4/fib_trie.c | 17 ++--- net/ipv4/ipmr_base.c | 4 +- net/ipv6/fib6_notifier.c | 4 +- net/ipv6/ip6_fib.c | 6 +- 15 files changed, 78 insertions(+), 105 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c index 5d20d615663e..fe0cc969cf94 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c @@ -248,9 +248,6 @@ static int mlx5_lag_fib_event(struct notifier_block *nb, struct net_device *fib_dev; struct fib_info *fi; - if (!net_eq(info->net, &init_net)) - return NOTIFY_DONE; - if (info->family != AF_INET) return NOTIFY_DONE; @@ -311,7 +308,7 @@ int mlx5_lag_mp_init(struct mlx5_lag *ldev) return 0; mp->fib_nb.notifier_call = mlx5_lag_fib_event; - err = register_fib_notifier(&mp->fib_nb, + err = register_fib_notifier(&init_net, &mp->fib_nb, mlx5_lag_fib_event_flush); if (err) mp->fib_nb.notifier_call = NULL; @@ -326,6 +323,6 @@ void mlx5_lag_mp_cleanup(struct mlx5_lag *ldev) if (!mp->fib_nb.notifier_call) return; - unregister_fib_notifier(&mp->fib_nb); + unregister_fib_notifier(&init_net, &mp->fib_nb); mp->fib_nb.notifier_call = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a330b369e899..d0db9ea71323 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -6213,7 +6213,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event, rule = fr_info->rule; /* Rule only affects locally generated traffic */ - if (rule->iifindex == info->net->loopback_dev->ifindex) + if (rule->iifindex == init_net.loopback_dev->ifindex) return 0; switch (info->family) { @@ -6250,8 +6250,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, struct mlxsw_sp_router *router; int err; - if (!net_eq(info->net, &init_net) || - (info->family != AF_INET && info->family != AF_INET6 && + if ((info->family != AF_INET && info->family != AF_INET6 && info->family != RTNL_FAMILY_IPMR && info->family != RTNL_FAMILY_IP6MR)) return NOTIFY_DONE; @@ -8155,7 +8154,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) goto err_dscp_init; mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; - err = register_fib_notifier(&mlxsw_sp->router->fib_nb, + err = register_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb, mlxsw_sp_router_fib_dump_flush); if (err) goto err_register_fib_notifier; @@ -8195,7 +8194,7 @@ err_register_inetaddr_notifier: void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { - unregister_fib_notifier(&mlxsw_sp->router->fib_nb); + unregister_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb); unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 786b158bd305..e54f6341a785 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2189,9 +2189,6 @@ static int rocker_router_fib_event(struct notifier_block *nb, struct rocker_fib_event_work *fib_work; struct fib_notifier_info *info = ptr; - if (!net_eq(info->net, &init_net)) - return NOTIFY_DONE; - if (info->family != AF_INET) return NOTIFY_DONE; @@ -2994,7 +2991,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) * the device, so no need to pass a callback. */ rocker->fib_nb.notifier_call = rocker_router_fib_event; - err = register_fib_notifier(&rocker->fib_nb, NULL); + err = register_fib_notifier(&init_net, &rocker->fib_nb, NULL); if (err) goto err_register_fib_notifier; @@ -3021,7 +3018,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_register_switchdev_blocking_notifier: unregister_switchdev_notifier(&rocker_switchdev_notifier); err_register_switchdev_notifier: - unregister_fib_notifier(&rocker->fib_nb); + unregister_fib_notifier(&init_net, &rocker->fib_nb); err_register_fib_notifier: rocker_remove_ports(rocker); err_probe_ports: @@ -3057,7 +3054,7 @@ static void rocker_remove(struct pci_dev *pdev) unregister_switchdev_blocking_notifier(nb); unregister_switchdev_notifier(&rocker_switchdev_notifier); - unregister_fib_notifier(&rocker->fib_nb); + unregister_fib_notifier(&init_net, &rocker->fib_nb); rocker_remove_ports(rocker); rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); destroy_workqueue(rocker->rocker_owq); diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index 7de17e42d77a..01ee9cc54605 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -182,9 +182,6 @@ static int nsim_fib_event_nb(struct notifier_block *nb, unsigned long event, struct fib_notifier_info *info = ptr; int err = 0; - if (!net_eq(info->net, &init_net)) - return NOTIFY_DONE; - switch (event) { case FIB_EVENT_RULE_ADD: /* fall through */ case FIB_EVENT_RULE_DEL: @@ -258,7 +255,8 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) data->ipv6.rules.max = (u64)-1; data->fib_nb.notifier_call = nsim_fib_event_nb; - err = register_fib_notifier(&data->fib_nb, nsim_fib_dump_inconsistent); + err = register_fib_notifier(&init_net, &data->fib_nb, + nsim_fib_dump_inconsistent); if (err) { pr_err("Failed to register fib notifier\n"); goto err_out; @@ -297,6 +295,6 @@ void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) NSIM_RESOURCE_IPV4_FIB_RULES); devlink_resource_occ_get_unregister(devlink, NSIM_RESOURCE_IPV4_FIB); - unregister_fib_notifier(&data->fib_nb); + unregister_fib_notifier(&init_net, &data->fib_nb); kfree(data); } diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h index 34de06b426ef..0931631bbc13 100644 --- a/include/linux/mroute_base.h +++ b/include/linux/mroute_base.h @@ -47,7 +47,6 @@ struct vif_entry_notifier_info { }; static inline int mr_call_vif_notifier(struct notifier_block *nb, - struct net *net, unsigned short family, enum fib_event_type event_type, struct vif_device *vif, @@ -56,7 +55,6 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb, struct vif_entry_notifier_info info = { .info = { .family = family, - .net = net, }, .dev = vif->dev, .vif_index = vif_index, @@ -64,7 +62,7 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb, .tb_id = tb_id, }; - return call_fib_notifier(nb, net, event_type, &info.info); + return call_fib_notifier(nb, event_type, &info.info); } static inline int mr_call_vif_notifiers(struct net *net, @@ -77,7 +75,6 @@ static inline int mr_call_vif_notifiers(struct net *net, struct vif_entry_notifier_info info = { .info = { .family = family, - .net = net, }, .dev = vif->dev, .vif_index = vif_index, @@ -173,7 +170,6 @@ struct mfc_entry_notifier_info { }; static inline int mr_call_mfc_notifier(struct notifier_block *nb, - struct net *net, unsigned short family, enum fib_event_type event_type, struct mr_mfc *mfc, u32 tb_id) @@ -181,13 +177,12 @@ static inline int mr_call_mfc_notifier(struct notifier_block *nb, struct mfc_entry_notifier_info info = { .info = { .family = family, - .net = net, }, .mfc = mfc, .tb_id = tb_id }; - return call_fib_notifier(nb, net, event_type, &info.info); + return call_fib_notifier(nb, event_type, &info.info); } static inline int mr_call_mfc_notifiers(struct net *net, @@ -199,7 +194,6 @@ static inline int mr_call_mfc_notifiers(struct net *net, struct mfc_entry_notifier_info info = { .info = { .family = family, - .net = net, }, .mfc = mfc, .tb_id = tb_id diff --git a/include/net/fib_notifier.h b/include/net/fib_notifier.h index c49d7bfb5c30..23353f67b2b0 100644 --- a/include/net/fib_notifier.h +++ b/include/net/fib_notifier.h @@ -8,7 +8,6 @@ struct module; struct fib_notifier_info { - struct net *net; int family; struct netlink_ext_ack *extack; }; @@ -35,14 +34,14 @@ struct fib_notifier_ops { struct rcu_head rcu; }; -int call_fib_notifier(struct notifier_block *nb, struct net *net, +int call_fib_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info); int call_fib_notifiers(struct net *net, enum fib_event_type event_type, struct fib_notifier_info *info); -int register_fib_notifier(struct notifier_block *nb, +int register_fib_notifier(struct net *net, struct notifier_block *nb, void (*cb)(struct notifier_block *nb)); -int unregister_fib_notifier(struct notifier_block *nb); +int unregister_fib_notifier(struct net *net, struct notifier_block *nb); struct fib_notifier_ops * fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net); void fib_notifier_ops_unregister(struct fib_notifier_ops *ops); diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 4b5656c71abc..14e9fca0e326 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -478,7 +478,7 @@ struct ipv6_route_iter { extern const struct seq_operations ipv6_route_seq_ops; -int call_fib6_notifier(struct notifier_block *nb, struct net *net, +int call_fib6_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info); int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index ab1ca9e238d2..a9df85304f40 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -219,7 +219,7 @@ struct fib_nh_notifier_info { struct fib_nh *fib_nh; }; -int call_fib4_notifier(struct notifier_block *nb, struct net *net, +int call_fib4_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info); int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c index 470a606d5e8d..fbd029425638 100644 --- a/net/core/fib_notifier.c +++ b/net/core/fib_notifier.c @@ -12,17 +12,15 @@ static unsigned int fib_notifier_net_id; struct fib_notifier_net { struct list_head fib_notifier_ops; + struct atomic_notifier_head fib_chain; }; -static ATOMIC_NOTIFIER_HEAD(fib_chain); - -int call_fib_notifier(struct notifier_block *nb, struct net *net, +int call_fib_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info) { int err; - info->net = net; err = nb->notifier_call(nb, event_type, info); return notifier_to_errno(err); } @@ -31,35 +29,29 @@ EXPORT_SYMBOL(call_fib_notifier); int call_fib_notifiers(struct net *net, enum fib_event_type event_type, struct fib_notifier_info *info) { + struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); int err; - info->net = net; - err = atomic_notifier_call_chain(&fib_chain, event_type, info); + err = atomic_notifier_call_chain(&fn_net->fib_chain, event_type, info); return notifier_to_errno(err); } EXPORT_SYMBOL(call_fib_notifiers); -static unsigned int fib_seq_sum(void) +static unsigned int fib_seq_sum(struct net *net) { - struct fib_notifier_net *fn_net; + struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); struct fib_notifier_ops *ops; unsigned int fib_seq = 0; - struct net *net; rtnl_lock(); - down_read(&net_rwsem); - for_each_net(net) { - fn_net = net_generic(net, fib_notifier_net_id); - rcu_read_lock(); - list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { - if (!try_module_get(ops->owner)) - continue; - fib_seq += ops->fib_seq_read(net); - module_put(ops->owner); - } - rcu_read_unlock(); + rcu_read_lock(); + list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { + if (!try_module_get(ops->owner)) + continue; + fib_seq += ops->fib_seq_read(net); + module_put(ops->owner); } - up_read(&net_rwsem); + rcu_read_unlock(); rtnl_unlock(); return fib_seq; @@ -69,68 +61,66 @@ static int fib_net_dump(struct net *net, struct notifier_block *nb) { struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); struct fib_notifier_ops *ops; + int err = 0; + rcu_read_lock(); list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { - int err; - if (!try_module_get(ops->owner)) continue; err = ops->fib_dump(net, nb); module_put(ops->owner); if (err) - return err; + goto unlock; } - return 0; +unlock: + rcu_read_unlock(); + + return err; } -static bool fib_dump_is_consistent(struct notifier_block *nb, +static bool fib_dump_is_consistent(struct net *net, struct notifier_block *nb, void (*cb)(struct notifier_block *nb), unsigned int fib_seq) { - atomic_notifier_chain_register(&fib_chain, nb); - if (fib_seq == fib_seq_sum()) + struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); + + atomic_notifier_chain_register(&fn_net->fib_chain, nb); + if (fib_seq == fib_seq_sum(net)) return true; - atomic_notifier_chain_unregister(&fib_chain, nb); + atomic_notifier_chain_unregister(&fn_net->fib_chain, nb); if (cb) cb(nb); return false; } #define FIB_DUMP_MAX_RETRIES 5 -int register_fib_notifier(struct notifier_block *nb, +int register_fib_notifier(struct net *net, struct notifier_block *nb, void (*cb)(struct notifier_block *nb)) { int retries = 0; int err; do { - unsigned int fib_seq = fib_seq_sum(); - struct net *net; - - rcu_read_lock(); - for_each_net_rcu(net) { - err = fib_net_dump(net, nb); - if (err) - goto err_fib_net_dump; - } - rcu_read_unlock(); - - if (fib_dump_is_consistent(nb, cb, fib_seq)) + unsigned int fib_seq = fib_seq_sum(net); + + err = fib_net_dump(net, nb); + if (err) + return err; + + if (fib_dump_is_consistent(net, nb, cb, fib_seq)) return 0; } while (++retries < FIB_DUMP_MAX_RETRIES); return -EBUSY; - -err_fib_net_dump: - rcu_read_unlock(); - return err; } EXPORT_SYMBOL(register_fib_notifier); -int unregister_fib_notifier(struct notifier_block *nb) +int unregister_fib_notifier(struct net *net, struct notifier_block *nb) { - return atomic_notifier_chain_unregister(&fib_chain, nb); + struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); + + return atomic_notifier_chain_unregister(&fn_net->fib_chain, nb); } EXPORT_SYMBOL(unregister_fib_notifier); @@ -181,6 +171,7 @@ static int __net_init fib_notifier_net_init(struct net *net) struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); INIT_LIST_HEAD(&fn_net->fib_notifier_ops); + ATOMIC_INIT_NOTIFIER_HEAD(&fn_net->fib_chain); return 0; } diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index dd220ce7ca7a..28cbf07102bc 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -321,7 +321,7 @@ out: } EXPORT_SYMBOL_GPL(fib_rules_lookup); -static int call_fib_rule_notifier(struct notifier_block *nb, struct net *net, +static int call_fib_rule_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_rule *rule, int family) { @@ -330,7 +330,7 @@ static int call_fib_rule_notifier(struct notifier_block *nb, struct net *net, .rule = rule, }; - return call_fib_notifier(nb, net, event_type, &info.info); + return call_fib_notifier(nb, event_type, &info.info); } static int call_fib_rule_notifiers(struct net *net, @@ -359,8 +359,7 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family) if (!ops) return -EAFNOSUPPORT; list_for_each_entry_rcu(rule, &ops->rules_list, list) - call_fib_rule_notifier(nb, net, FIB_EVENT_RULE_ADD, rule, - family); + call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD, rule, family); rules_ops_put(ops); return 0; diff --git a/net/ipv4/fib_notifier.c b/net/ipv4/fib_notifier.c index b804ccbdb241..1a128c1346fb 100644 --- a/net/ipv4/fib_notifier.c +++ b/net/ipv4/fib_notifier.c @@ -9,12 +9,12 @@ #include #include -int call_fib4_notifier(struct notifier_block *nb, struct net *net, +int call_fib4_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info) { info->family = AF_INET; - return call_fib_notifier(nb, net, event_type, info); + return call_fib_notifier(nb, event_type, info); } int call_fib4_notifiers(struct net *net, enum fib_event_type event_type, diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1ab2fb6bb37d..5b600b2a2aa3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -74,7 +74,7 @@ #include #include "fib_lookup.h" -static int call_fib_entry_notifier(struct notifier_block *nb, struct net *net, +static int call_fib_entry_notifier(struct notifier_block *nb, enum fib_event_type event_type, u32 dst, int dst_len, struct fib_alias *fa) { @@ -86,7 +86,7 @@ static int call_fib_entry_notifier(struct notifier_block *nb, struct net *net, .type = fa->fa_type, .tb_id = fa->tb_id, }; - return call_fib4_notifier(nb, net, event_type, &info.info); + return call_fib4_notifier(nb, event_type, &info.info); } static int call_fib_entry_notifiers(struct net *net, @@ -2015,8 +2015,8 @@ void fib_info_notify_update(struct net *net, struct nl_info *info) } } -static void fib_leaf_notify(struct net *net, struct key_vector *l, - struct fib_table *tb, struct notifier_block *nb) +static void fib_leaf_notify(struct key_vector *l, struct fib_table *tb, + struct notifier_block *nb) { struct fib_alias *fa; @@ -2032,20 +2032,19 @@ static void fib_leaf_notify(struct net *net, struct key_vector *l, if (tb->tb_id != fa->tb_id) continue; - call_fib_entry_notifier(nb, net, FIB_EVENT_ENTRY_ADD, l->key, + call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_ADD, l->key, KEYLENGTH - fa->fa_slen, fa); } } -static void fib_table_notify(struct net *net, struct fib_table *tb, - struct notifier_block *nb) +static void fib_table_notify(struct fib_table *tb, struct notifier_block *nb) { struct trie *t = (struct trie *)tb->tb_data; struct key_vector *l, *tp = t->kv; t_key key = 0; while ((l = leaf_walk_rcu(&tp, key)) != NULL) { - fib_leaf_notify(net, l, tb, nb); + fib_leaf_notify(l, tb, nb); key = l->key + 1; /* stop in case of wrap around */ @@ -2063,7 +2062,7 @@ void fib_notify(struct net *net, struct notifier_block *nb) struct fib_table *tb; hlist_for_each_entry_rcu(tb, head, tb_hlist) - fib_table_notify(net, tb, nb); + fib_table_notify(tb, nb); } } diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c index ea48bd15a575..4dcc3214e3cc 100644 --- a/net/ipv4/ipmr_base.c +++ b/net/ipv4/ipmr_base.c @@ -409,7 +409,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, if (!v->dev) continue; - mr_call_vif_notifier(nb, net, family, + mr_call_vif_notifier(nb, family, FIB_EVENT_VIF_ADD, v, vifi, mrt->id); } @@ -417,7 +417,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, /* Notify on table MFC entries */ list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) - mr_call_mfc_notifier(nb, net, family, + mr_call_mfc_notifier(nb, family, FIB_EVENT_ENTRY_ADD, mfc, mrt->id); } diff --git a/net/ipv6/fib6_notifier.c b/net/ipv6/fib6_notifier.c index 05f82baaa99e..4fe79296999a 100644 --- a/net/ipv6/fib6_notifier.c +++ b/net/ipv6/fib6_notifier.c @@ -7,12 +7,12 @@ #include #include -int call_fib6_notifier(struct notifier_block *nb, struct net *net, +int call_fib6_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib_notifier_info *info) { info->family = AF_INET6; - return call_fib_notifier(nb, net, event_type, info); + return call_fib_notifier(nb, event_type, info); } int call_fib6_notifiers(struct net *net, enum fib_event_type event_type, diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 6e2af411cd9c..f6fae48b2e18 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -357,7 +357,7 @@ unsigned int fib6_tables_seq_read(struct net *net) return fib_seq; } -static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net, +static int call_fib6_entry_notifier(struct notifier_block *nb, enum fib_event_type event_type, struct fib6_info *rt) { @@ -365,7 +365,7 @@ static int call_fib6_entry_notifier(struct notifier_block *nb, struct net *net, .rt = rt, }; - return call_fib6_notifier(nb, net, event_type, &info.info); + return call_fib6_notifier(nb, event_type, &info.info); } int call_fib6_entry_notifiers(struct net *net, @@ -407,7 +407,7 @@ static void fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg) { if (rt == arg->net->ipv6.fib6_null_entry) return; - call_fib6_entry_notifier(arg->nb, arg->net, FIB_EVENT_ENTRY_ADD, rt); + call_fib6_entry_notifier(arg->nb, FIB_EVENT_ENTRY_ADD, rt); } static int fib6_node_dump(struct fib6_walker *w) -- cgit v1.2.3-59-g8ed1b From 3f9e5c119a47d0fce01f8524ff0aba3acca71bb9 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:29 +0200 Subject: mlxsw: spectrum_router: Don't rely on missing extack to symbolize dump Currently if info->extack is NULL, mlxsw assumes that the event came down from dump. Originally, the dump did not propagate the return value back to the original caller (fib_notifier_register()). However, that is now happening. So benefit from this and push the error up if it happened. Remove rule cases in work handlers that are now dead code. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index d0db9ea71323..1eeff1d23b13 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -6019,12 +6019,6 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work) mlxsw_sp_router_fib4_del(mlxsw_sp, &fib_work->fen_info); fib_info_put(fib_work->fen_info.fi); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; case FIB_EVENT_NH_ADD: /* fall through */ case FIB_EVENT_NH_DEL: mlxsw_sp_nexthop4_event(mlxsw_sp, fib_work->event, @@ -6065,12 +6059,6 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work) fib_work->fib6_work.nrt6); mlxsw_sp_router_fib6_work_fini(&fib_work->fib6_work); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; } rtnl_unlock(); kfree(fib_work); @@ -6112,12 +6100,6 @@ static void mlxsw_sp_router_fibmr_event_work(struct work_struct *work) &fib_work->ven_info); dev_put(fib_work->ven_info.dev); break; - case FIB_EVENT_RULE_ADD: - /* if we get here, a rule was added that we do not support. - * just do the fib_abort - */ - mlxsw_sp_router_fib_abort(mlxsw_sp); - break; } rtnl_unlock(); kfree(fib_work); @@ -6262,9 +6244,7 @@ static int mlxsw_sp_router_fib_event(struct notifier_block *nb, case FIB_EVENT_RULE_DEL: err = mlxsw_sp_router_fib_rule_event(event, info, router->mlxsw_sp); - if (!err || info->extack) - return notifier_from_errno(err); - break; + return notifier_from_errno(err); case FIB_EVENT_ENTRY_ADD: case FIB_EVENT_ENTRY_REPLACE: /* fall through */ case FIB_EVENT_ENTRY_APPEND: /* fall through */ -- cgit v1.2.3-59-g8ed1b From b7a595577ef3dc9add2b3e6d00869d017306bfbe Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:30 +0200 Subject: net: fib_notifier: propagate extack down to the notifier block callback Since errors are propagated all the way up to the caller, propagate possible extack of the caller all the way down to the notifier block callback. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c | 2 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 2 +- drivers/net/ethernet/rocker/rocker_main.c | 2 +- drivers/net/netdevsim/fib.c | 2 +- include/linux/mroute_base.h | 18 ++++++++++++------ include/net/fib_notifier.h | 6 ++++-- include/net/fib_rules.h | 3 ++- include/net/ip6_fib.h | 9 ++++++--- include/net/ip_fib.h | 9 ++++++--- net/core/fib_notifier.c | 10 ++++++---- net/core/fib_rules.c | 9 ++++++--- net/ipv4/fib_notifier.c | 7 ++++--- net/ipv4/fib_rules.c | 5 +++-- net/ipv4/fib_trie.c | 20 +++++++++++++------- net/ipv4/ipmr.c | 13 ++++++++----- net/ipv4/ipmr_base.c | 12 +++++++----- net/ipv6/fib6_notifier.c | 7 ++++--- net/ipv6/fib6_rules.c | 5 +++-- net/ipv6/ip6_fib.c | 12 +++++++++--- net/ipv6/ip6mr.c | 13 ++++++++----- 20 files changed, 105 insertions(+), 61 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c index fe0cc969cf94..13e2944b1274 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c @@ -309,7 +309,7 @@ int mlx5_lag_mp_init(struct mlx5_lag *ldev) mp->fib_nb.notifier_call = mlx5_lag_fib_event; err = register_fib_notifier(&init_net, &mp->fib_nb, - mlx5_lag_fib_event_flush); + mlx5_lag_fib_event_flush, NULL); if (err) mp->fib_nb.notifier_call = NULL; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 1eeff1d23b13..445e2daa54ac 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8135,7 +8135,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; err = register_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb, - mlxsw_sp_router_fib_dump_flush); + mlxsw_sp_router_fib_dump_flush, NULL); if (err) goto err_register_fib_notifier; diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index e54f6341a785..bc4f951315da 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -2991,7 +2991,7 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) * the device, so no need to pass a callback. */ rocker->fib_nb.notifier_call = rocker_router_fib_event; - err = register_fib_notifier(&init_net, &rocker->fib_nb, NULL); + err = register_fib_notifier(&init_net, &rocker->fib_nb, NULL, NULL); if (err) goto err_register_fib_notifier; diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index 01ee9cc54605..d2aeac0f4c2c 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -256,7 +256,7 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) data->fib_nb.notifier_call = nsim_fib_event_nb; err = register_fib_notifier(&init_net, &data->fib_nb, - nsim_fib_dump_inconsistent); + nsim_fib_dump_inconsistent, NULL); if (err) { pr_err("Failed to register fib notifier\n"); goto err_out; diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h index 0931631bbc13..8071148f29a6 100644 --- a/include/linux/mroute_base.h +++ b/include/linux/mroute_base.h @@ -50,11 +50,13 @@ static inline int mr_call_vif_notifier(struct notifier_block *nb, unsigned short family, enum fib_event_type event_type, struct vif_device *vif, - unsigned short vif_index, u32 tb_id) + unsigned short vif_index, u32 tb_id, + struct netlink_ext_ack *extack) { struct vif_entry_notifier_info info = { .info = { .family = family, + .extack = extack, }, .dev = vif->dev, .vif_index = vif_index, @@ -172,11 +174,13 @@ struct mfc_entry_notifier_info { static inline int mr_call_mfc_notifier(struct notifier_block *nb, unsigned short family, enum fib_event_type event_type, - struct mr_mfc *mfc, u32 tb_id) + struct mr_mfc *mfc, u32 tb_id, + struct netlink_ext_ack *extack) { struct mfc_entry_notifier_info info = { .info = { .family = family, + .extack = extack, }, .mfc = mfc, .tb_id = tb_id @@ -295,10 +299,11 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, int (*rules_dump)(struct net *net, - struct notifier_block *nb), + struct notifier_block *nb, + struct netlink_ext_ack *extack), struct mr_table *(*mr_iter)(struct net *net, struct mr_table *mrt), - rwlock_t *mrt_lock); + rwlock_t *mrt_lock, struct netlink_ext_ack *extack); #else static inline void vif_device_init(struct vif_device *v, struct net_device *dev, @@ -349,10 +354,11 @@ mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb, static inline int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, int (*rules_dump)(struct net *net, - struct notifier_block *nb), + struct notifier_block *nb, + struct netlink_ext_ack *extack), struct mr_table *(*mr_iter)(struct net *net, struct mr_table *mrt), - rwlock_t *mrt_lock) + rwlock_t *mrt_lock, struct netlink_ext_ack *extack) { return -EINVAL; } diff --git a/include/net/fib_notifier.h b/include/net/fib_notifier.h index 23353f67b2b0..6d59221ff05a 100644 --- a/include/net/fib_notifier.h +++ b/include/net/fib_notifier.h @@ -29,7 +29,8 @@ struct fib_notifier_ops { int family; struct list_head list; unsigned int (*fib_seq_read)(struct net *net); - int (*fib_dump)(struct net *net, struct notifier_block *nb); + int (*fib_dump)(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack); struct module *owner; struct rcu_head rcu; }; @@ -40,7 +41,8 @@ int call_fib_notifier(struct notifier_block *nb, int call_fib_notifiers(struct net *net, enum fib_event_type event_type, struct fib_notifier_info *info); int register_fib_notifier(struct net *net, struct notifier_block *nb, - void (*cb)(struct notifier_block *nb)); + void (*cb)(struct notifier_block *nb), + struct netlink_ext_ack *extack); int unregister_fib_notifier(struct net *net, struct notifier_block *nb); struct fib_notifier_ops * fib_notifier_ops_register(const struct fib_notifier_ops *tmpl, struct net *net); diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 20dcadd8eed9..54e227e6b06a 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -194,7 +194,8 @@ int fib_rules_lookup(struct fib_rules_ops *, struct flowi *, int flags, int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table, u32 flags); bool fib_rule_matchall(const struct fib_rule *rule); -int fib_rules_dump(struct net *net, struct notifier_block *nb, int family); +int fib_rules_dump(struct net *net, struct notifier_block *nb, int family, + struct netlink_ext_ack *extack); unsigned int fib_rules_seq_read(struct net *net, int family); int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 14e9fca0e326..5d1615463138 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -488,7 +488,8 @@ int __net_init fib6_notifier_init(struct net *net); void __net_exit fib6_notifier_exit(struct net *net); unsigned int fib6_tables_seq_read(struct net *net); -int fib6_tables_dump(struct net *net, struct notifier_block *nb); +int fib6_tables_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack); void fib6_update_sernum(struct net *net, struct fib6_info *rt); void fib6_update_sernum_upto_root(struct net *net, struct fib6_info *rt); @@ -504,7 +505,8 @@ static inline bool fib6_metric_locked(struct fib6_info *f6i, int metric) int fib6_rules_init(void); void fib6_rules_cleanup(void); bool fib6_rule_default(const struct fib_rule *rule); -int fib6_rules_dump(struct net *net, struct notifier_block *nb); +int fib6_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack); unsigned int fib6_rules_seq_read(struct net *net); static inline bool fib6_rules_early_flow_dissect(struct net *net, @@ -537,7 +539,8 @@ static inline bool fib6_rule_default(const struct fib_rule *rule) { return true; } -static inline int fib6_rules_dump(struct net *net, struct notifier_block *nb) +static inline int fib6_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return 0; } diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 05c1fd9c5e23..52b2406a5dfc 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -229,7 +229,8 @@ int __net_init fib4_notifier_init(struct net *net); void __net_exit fib4_notifier_exit(struct net *net); void fib_info_notify_update(struct net *net, struct nl_info *info); -int fib_notify(struct net *net, struct notifier_block *nb); +int fib_notify(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack); struct fib_table { struct hlist_node tb_hlist; @@ -315,7 +316,8 @@ static inline bool fib4_rule_default(const struct fib_rule *rule) return true; } -static inline int fib4_rules_dump(struct net *net, struct notifier_block *nb) +static inline int fib4_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return 0; } @@ -377,7 +379,8 @@ out: } bool fib4_rule_default(const struct fib_rule *rule); -int fib4_rules_dump(struct net *net, struct notifier_block *nb); +int fib4_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack); unsigned int fib4_rules_seq_read(struct net *net); static inline bool fib4_rules_early_flow_dissect(struct net *net, diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c index fbd029425638..fc96259807b6 100644 --- a/net/core/fib_notifier.c +++ b/net/core/fib_notifier.c @@ -57,7 +57,8 @@ static unsigned int fib_seq_sum(struct net *net) return fib_seq; } -static int fib_net_dump(struct net *net, struct notifier_block *nb) +static int fib_net_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct fib_notifier_net *fn_net = net_generic(net, fib_notifier_net_id); struct fib_notifier_ops *ops; @@ -67,7 +68,7 @@ static int fib_net_dump(struct net *net, struct notifier_block *nb) list_for_each_entry_rcu(ops, &fn_net->fib_notifier_ops, list) { if (!try_module_get(ops->owner)) continue; - err = ops->fib_dump(net, nb); + err = ops->fib_dump(net, nb, extack); module_put(ops->owner); if (err) goto unlock; @@ -96,7 +97,8 @@ static bool fib_dump_is_consistent(struct net *net, struct notifier_block *nb, #define FIB_DUMP_MAX_RETRIES 5 int register_fib_notifier(struct net *net, struct notifier_block *nb, - void (*cb)(struct notifier_block *nb)) + void (*cb)(struct notifier_block *nb), + struct netlink_ext_ack *extack) { int retries = 0; int err; @@ -104,7 +106,7 @@ int register_fib_notifier(struct net *net, struct notifier_block *nb, do { unsigned int fib_seq = fib_seq_sum(net); - err = fib_net_dump(net, nb); + err = fib_net_dump(net, nb, extack); if (err) return err; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 592d8aef90e3..3e7e15278c46 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -323,10 +323,12 @@ EXPORT_SYMBOL_GPL(fib_rules_lookup); static int call_fib_rule_notifier(struct notifier_block *nb, enum fib_event_type event_type, - struct fib_rule *rule, int family) + struct fib_rule *rule, int family, + struct netlink_ext_ack *extack) { struct fib_rule_notifier_info info = { .info.family = family, + .info.extack = extack, .rule = rule, }; @@ -350,7 +352,8 @@ static int call_fib_rule_notifiers(struct net *net, } /* Called with rcu_read_lock() */ -int fib_rules_dump(struct net *net, struct notifier_block *nb, int family) +int fib_rules_dump(struct net *net, struct notifier_block *nb, int family, + struct netlink_ext_ack *extack) { struct fib_rules_ops *ops; struct fib_rule *rule; @@ -361,7 +364,7 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family) return -EAFNOSUPPORT; list_for_each_entry_rcu(rule, &ops->rules_list, list) { err = call_fib_rule_notifier(nb, FIB_EVENT_RULE_ADD, - rule, family); + rule, family, extack); if (err) break; } diff --git a/net/ipv4/fib_notifier.c b/net/ipv4/fib_notifier.c index 0c57f68a9340..0c28bd469a68 100644 --- a/net/ipv4/fib_notifier.c +++ b/net/ipv4/fib_notifier.c @@ -34,15 +34,16 @@ static unsigned int fib4_seq_read(struct net *net) return net->ipv4.fib_seq + fib4_rules_seq_read(net); } -static int fib4_dump(struct net *net, struct notifier_block *nb) +static int fib4_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { int err; - err = fib4_rules_dump(net, nb); + err = fib4_rules_dump(net, nb, extack); if (err) return err; - return fib_notify(net, nb); + return fib_notify(net, nb, extack); } static const struct fib_notifier_ops fib4_notifier_ops_template = { diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index b43a7ba5c6a4..f99e3bac5cab 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -65,9 +65,10 @@ bool fib4_rule_default(const struct fib_rule *rule) } EXPORT_SYMBOL_GPL(fib4_rule_default); -int fib4_rules_dump(struct net *net, struct notifier_block *nb) +int fib4_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { - return fib_rules_dump(net, nb, AF_INET); + return fib_rules_dump(net, nb, AF_INET, extack); } unsigned int fib4_rules_seq_read(struct net *net) diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 568e59423773..b9df9c09b84e 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -76,9 +76,11 @@ static int call_fib_entry_notifier(struct notifier_block *nb, enum fib_event_type event_type, u32 dst, - int dst_len, struct fib_alias *fa) + int dst_len, struct fib_alias *fa, + struct netlink_ext_ack *extack) { struct fib_entry_notifier_info info = { + .info.extack = extack, .dst = dst, .dst_len = dst_len, .fi = fa->fa_info, @@ -2016,7 +2018,8 @@ void fib_info_notify_update(struct net *net, struct nl_info *info) } static int fib_leaf_notify(struct key_vector *l, struct fib_table *tb, - struct notifier_block *nb) + struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct fib_alias *fa; int err; @@ -2034,14 +2037,16 @@ static int fib_leaf_notify(struct key_vector *l, struct fib_table *tb, continue; err = call_fib_entry_notifier(nb, FIB_EVENT_ENTRY_ADD, l->key, - KEYLENGTH - fa->fa_slen, fa); + KEYLENGTH - fa->fa_slen, + fa, extack); if (err) return err; } return 0; } -static int fib_table_notify(struct fib_table *tb, struct notifier_block *nb) +static int fib_table_notify(struct fib_table *tb, struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct trie *t = (struct trie *)tb->tb_data; struct key_vector *l, *tp = t->kv; @@ -2049,7 +2054,7 @@ static int fib_table_notify(struct fib_table *tb, struct notifier_block *nb) int err; while ((l = leaf_walk_rcu(&tp, key)) != NULL) { - err = fib_leaf_notify(l, tb, nb); + err = fib_leaf_notify(l, tb, nb, extack); if (err) return err; @@ -2061,7 +2066,8 @@ static int fib_table_notify(struct fib_table *tb, struct notifier_block *nb) return 0; } -int fib_notify(struct net *net, struct notifier_block *nb) +int fib_notify(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { unsigned int h; int err; @@ -2071,7 +2077,7 @@ int fib_notify(struct net *net, struct notifier_block *nb) struct fib_table *tb; hlist_for_each_entry_rcu(tb, head, tb_hlist) { - err = fib_table_notify(tb, nb); + err = fib_table_notify(tb, nb, extack); if (err) return err; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 313470f6bb14..051f365b64d2 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -278,9 +278,10 @@ static void __net_exit ipmr_rules_exit(struct net *net) rtnl_unlock(); } -static int ipmr_rules_dump(struct net *net, struct notifier_block *nb) +static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { - return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR); + return fib_rules_dump(net, nb, RTNL_FAMILY_IPMR, extack); } static unsigned int ipmr_rules_seq_read(struct net *net) @@ -336,7 +337,8 @@ static void __net_exit ipmr_rules_exit(struct net *net) rtnl_unlock(); } -static int ipmr_rules_dump(struct net *net, struct notifier_block *nb) +static int ipmr_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return 0; } @@ -3040,10 +3042,11 @@ static unsigned int ipmr_seq_read(struct net *net) return net->ipv4.ipmr_seq + ipmr_rules_seq_read(net); } -static int ipmr_dump(struct net *net, struct notifier_block *nb) +static int ipmr_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return mr_dump(net, nb, RTNL_FAMILY_IPMR, ipmr_rules_dump, - ipmr_mr_table_iter, &mrt_lock); + ipmr_mr_table_iter, &mrt_lock, extack); } static const struct fib_notifier_ops ipmr_notifier_ops_template = { diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c index c4e23c2a0d5c..aa8738a91210 100644 --- a/net/ipv4/ipmr_base.c +++ b/net/ipv4/ipmr_base.c @@ -386,15 +386,17 @@ EXPORT_SYMBOL(mr_rtm_dumproute); int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, int (*rules_dump)(struct net *net, - struct notifier_block *nb), + struct notifier_block *nb, + struct netlink_ext_ack *extack), struct mr_table *(*mr_iter)(struct net *net, struct mr_table *mrt), - rwlock_t *mrt_lock) + rwlock_t *mrt_lock, + struct netlink_ext_ack *extack) { struct mr_table *mrt; int err; - err = rules_dump(net, nb); + err = rules_dump(net, nb, extack); if (err) return err; @@ -411,7 +413,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, err = mr_call_vif_notifier(nb, family, FIB_EVENT_VIF_ADD, - v, vifi, mrt->id); + v, vifi, mrt->id, extack); if (err) break; } @@ -424,7 +426,7 @@ int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family, list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) { err = mr_call_mfc_notifier(nb, family, FIB_EVENT_ENTRY_ADD, - mfc, mrt->id); + mfc, mrt->id, extack); if (err) return err; } diff --git a/net/ipv6/fib6_notifier.c b/net/ipv6/fib6_notifier.c index 4fe79296999a..f87ae33e1d01 100644 --- a/net/ipv6/fib6_notifier.c +++ b/net/ipv6/fib6_notifier.c @@ -27,15 +27,16 @@ static unsigned int fib6_seq_read(struct net *net) return fib6_tables_seq_read(net) + fib6_rules_seq_read(net); } -static int fib6_dump(struct net *net, struct notifier_block *nb) +static int fib6_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { int err; - err = fib6_rules_dump(net, nb); + err = fib6_rules_dump(net, nb, extack); if (err) return err; - return fib6_tables_dump(net, nb); + return fib6_tables_dump(net, nb, extack); } static const struct fib_notifier_ops fib6_notifier_ops_template = { diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index f9e8fe3ff0c5..fafe556d21e0 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -47,9 +47,10 @@ bool fib6_rule_default(const struct fib_rule *rule) } EXPORT_SYMBOL_GPL(fib6_rule_default); -int fib6_rules_dump(struct net *net, struct notifier_block *nb) +int fib6_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { - return fib_rules_dump(net, nb, AF_INET6); + return fib_rules_dump(net, nb, AF_INET6, extack); } unsigned int fib6_rules_seq_read(struct net *net) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 76124a909395..f66bc2af4e9d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -359,9 +359,11 @@ unsigned int fib6_tables_seq_read(struct net *net) static int call_fib6_entry_notifier(struct notifier_block *nb, enum fib_event_type event_type, - struct fib6_info *rt) + struct fib6_info *rt, + struct netlink_ext_ack *extack) { struct fib6_entry_notifier_info info = { + .info.extack = extack, .rt = rt, }; @@ -401,13 +403,15 @@ int call_fib6_multipath_entry_notifiers(struct net *net, struct fib6_dump_arg { struct net *net; struct notifier_block *nb; + struct netlink_ext_ack *extack; }; static int fib6_rt_dump(struct fib6_info *rt, struct fib6_dump_arg *arg) { if (rt == arg->net->ipv6.fib6_null_entry) return 0; - return call_fib6_entry_notifier(arg->nb, FIB_EVENT_ENTRY_ADD, rt); + return call_fib6_entry_notifier(arg->nb, FIB_EVENT_ENTRY_ADD, + rt, arg->extack); } static int fib6_node_dump(struct fib6_walker *w) @@ -437,7 +441,8 @@ static int fib6_table_dump(struct net *net, struct fib6_table *tb, } /* Called with rcu_read_lock() */ -int fib6_tables_dump(struct net *net, struct notifier_block *nb) +int fib6_tables_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { struct fib6_dump_arg arg; struct fib6_walker *w; @@ -451,6 +456,7 @@ int fib6_tables_dump(struct net *net, struct notifier_block *nb) w->func = fib6_node_dump; arg.net = net; arg.nb = nb; + arg.extack = extack; w->args = &arg; for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 857a89ad4d6c..bfa49ff70531 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -265,9 +265,10 @@ static void __net_exit ip6mr_rules_exit(struct net *net) rtnl_unlock(); } -static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb) +static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { - return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR); + return fib_rules_dump(net, nb, RTNL_FAMILY_IP6MR, extack); } static unsigned int ip6mr_rules_seq_read(struct net *net) @@ -324,7 +325,8 @@ static void __net_exit ip6mr_rules_exit(struct net *net) rtnl_unlock(); } -static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb) +static int ip6mr_rules_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return 0; } @@ -1256,10 +1258,11 @@ static unsigned int ip6mr_seq_read(struct net *net) return net->ipv6.ipmr_seq + ip6mr_rules_seq_read(net); } -static int ip6mr_dump(struct net *net, struct notifier_block *nb) +static int ip6mr_dump(struct net *net, struct notifier_block *nb, + struct netlink_ext_ack *extack) { return mr_dump(net, nb, RTNL_FAMILY_IP6MR, ip6mr_rules_dump, - ip6mr_mr_table_iter, &mrt_lock); + ip6mr_mr_table_iter, &mrt_lock, extack); } static struct notifier_block ip6_mr_notifier = { -- cgit v1.2.3-59-g8ed1b From 053e92aa3c20d37ab40692a851d63b4a40d1ff79 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:32 +0200 Subject: mlxsw: spectrum: Take devlink net instead of init_net Follow-up patch is going to allow to reload devlink instance into different network namespace, so use devlink_net() helper instead of init_net. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.h | 6 +++++ drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 ++--- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 6 +++++ drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c | 2 +- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 29 +++++++++++++--------- .../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 2 +- 6 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 5d7d2ab6d155..e1ef4d255b93 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "trap.h" @@ -350,6 +351,11 @@ u64 mlxsw_core_res_get(struct mlxsw_core *mlxsw_core, #define MLXSW_CORE_RES_GET(mlxsw_core, short_res_id) \ mlxsw_core_res_get(mlxsw_core, MLXSW_RES_ID_##short_res_id) +static inline struct net *mlxsw_core_net(struct mlxsw_core *mlxsw_core) +{ + return devlink_net(priv_to_devlink(mlxsw_core)); +} + #define MLXSW_BUS_F_TXRX BIT(0) #define MLXSW_BUS_F_RESET BIT(1) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index a54a0dc82ff2..250448aecd67 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4864,7 +4864,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, * respin. */ mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; - err = register_netdevice_notifier_net(&init_net, + err = register_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->netdevice_nb); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to register netdev notifier\n"); @@ -4888,7 +4888,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, err_ports_create: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: - unregister_netdevice_notifier_net(&init_net, + unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->netdevice_nb); err_netdev_notifier: if (mlxsw_sp->clock) @@ -4975,7 +4975,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_ports_remove(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); - unregister_netdevice_notifier_net(&init_net, + unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->netdevice_nb); if (mlxsw_sp->clock) { mlxsw_sp->ptp_ops->fini(mlxsw_sp->ptp_state); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index b2a0028b1694..f58d45e770cd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -982,4 +983,9 @@ int mlxsw_sp_trap_action_set(struct mlxsw_core *mlxsw_core, int mlxsw_sp_trap_group_init(struct mlxsw_core *mlxsw_core, const struct devlink_trap_group *group); +static inline struct net *mlxsw_sp_net(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_core_net(mlxsw_sp->core); +} + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c index 17f334b46c40..2153bcc4b585 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve.c @@ -870,7 +870,7 @@ void mlxsw_sp_nve_fid_disable(struct mlxsw_sp *mlxsw_sp, mlxsw_sp_fid_vni(fid, &vni))) goto out; - nve_dev = dev_get_by_index(&init_net, nve_ifindex); + nve_dev = dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex); if (!nve_dev) goto out; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 445e2daa54ac..3479f805b377 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -2551,14 +2552,14 @@ static int mlxsw_sp_router_schedule_work(struct net *net, struct mlxsw_sp_netevent_work *net_work; struct mlxsw_sp_router *router; - if (!net_eq(net, &init_net)) + router = container_of(nb, struct mlxsw_sp_router, netevent_nb); + if (!net_eq(net, mlxsw_sp_net(router->mlxsw_sp))) return NOTIFY_DONE; net_work = kzalloc(sizeof(*net_work), GFP_ATOMIC); if (!net_work) return NOTIFY_BAD; - router = container_of(nb, struct mlxsw_sp_router, netevent_nb); INIT_WORK(&net_work->work, cb); net_work->mlxsw_sp = router->mlxsw_sp; mlxsw_core_schedule_work(&net_work->work); @@ -6195,7 +6196,7 @@ static int mlxsw_sp_router_fib_rule_event(unsigned long event, rule = fr_info->rule; /* Rule only affects locally generated traffic */ - if (rule->iifindex == init_net.loopback_dev->ifindex) + if (rule->iifindex == mlxsw_sp_net(mlxsw_sp)->loopback_dev->ifindex) return 0; switch (info->family) { @@ -7953,9 +7954,10 @@ static void mlxsw_sp_mp_hash_field_set(char *recr2_pl, int field) mlxsw_reg_recr2_outer_header_fields_enable_set(recr2_pl, field, true); } -static void mlxsw_sp_mp4_hash_init(char *recr2_pl) +static void mlxsw_sp_mp4_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) { - bool only_l3 = !init_net.ipv4.sysctl_fib_multipath_hash_policy; + struct net *net = mlxsw_sp_net(mlxsw_sp); + bool only_l3 = !net->ipv4.sysctl_fib_multipath_hash_policy; mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV4_EN_NOT_TCP_NOT_UDP); @@ -7970,9 +7972,9 @@ static void mlxsw_sp_mp4_hash_init(char *recr2_pl) mlxsw_sp_mp_hash_field_set(recr2_pl, MLXSW_REG_RECR2_TCP_UDP_DPORT); } -static void mlxsw_sp_mp6_hash_init(char *recr2_pl) +static void mlxsw_sp_mp6_hash_init(struct mlxsw_sp *mlxsw_sp, char *recr2_pl) { - bool only_l3 = !ip6_multipath_hash_policy(&init_net); + bool only_l3 = !ip6_multipath_hash_policy(mlxsw_sp_net(mlxsw_sp)); mlxsw_sp_mp_hash_header_set(recr2_pl, MLXSW_REG_RECR2_IPV6_EN_NOT_TCP_NOT_UDP); @@ -8000,8 +8002,8 @@ static int mlxsw_sp_mp_hash_init(struct mlxsw_sp *mlxsw_sp) seed = jhash(mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac), 0); mlxsw_reg_recr2_pack(recr2_pl, seed); - mlxsw_sp_mp4_hash_init(recr2_pl); - mlxsw_sp_mp6_hash_init(recr2_pl); + mlxsw_sp_mp4_hash_init(mlxsw_sp, recr2_pl); + mlxsw_sp_mp6_hash_init(mlxsw_sp, recr2_pl); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(recr2), recr2_pl); } @@ -8032,7 +8034,8 @@ static int mlxsw_sp_dscp_init(struct mlxsw_sp *mlxsw_sp) static int __mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) { - bool usp = init_net.ipv4.sysctl_ip_fwd_update_priority; + struct net *net = mlxsw_sp_net(mlxsw_sp); + bool usp = net->ipv4.sysctl_ip_fwd_update_priority; char rgcr_pl[MLXSW_REG_RGCR_LEN]; u64 max_rifs; int err; @@ -8134,7 +8137,8 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) goto err_dscp_init; mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; - err = register_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb, + err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->router->fib_nb, mlxsw_sp_router_fib_dump_flush, NULL); if (err) goto err_register_fib_notifier; @@ -8174,7 +8178,8 @@ err_register_inetaddr_notifier: void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) { - unregister_fib_notifier(&init_net, &mlxsw_sp->router->fib_nb); + unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), + &mlxsw_sp->router->fib_nb); unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 5ecb45118400..a3af171c6358 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -2591,7 +2591,7 @@ __mlxsw_sp_fdb_notify_mac_uc_tunnel_process(struct mlxsw_sp *mlxsw_sp, if (err) return err; - dev = __dev_get_by_index(&init_net, nve_ifindex); + dev = __dev_get_by_index(mlxsw_sp_net(mlxsw_sp), nve_ifindex); if (!dev) return -EINVAL; *nve_dev = dev; -- cgit v1.2.3-59-g8ed1b From 6b2a880f9dd1c8632f1afc5e3f77759ce3ff815f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:33 +0200 Subject: mlxsw: Register port netdevices into net of core When creating netdevices for ports, put them under network namespace that the core/parent devlink belongs to. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/minimal.c | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 + drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 471b0ca6d69a..cee16ad58307 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -172,6 +172,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) } SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); + dev_net_set(dev, mlxsw_core_net(mlxsw_m->core)); mlxsw_m_port = netdev_priv(dev); mlxsw_m_port->dev = dev; mlxsw_m_port->mlxsw_m = mlxsw_m; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 250448aecd67..a9ea9c7b9e59 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3635,6 +3635,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_alloc_etherdev; } SET_NETDEV_DEV(dev, mlxsw_sp->bus_info->dev); + dev_net_set(dev, mlxsw_sp_net(mlxsw_sp)); mlxsw_sp_port = netdev_priv(dev); mlxsw_sp_port->dev = dev; mlxsw_sp_port->mlxsw_sp = mlxsw_sp; diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 1c14c051ee52..a4d09392a8d7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -992,6 +992,7 @@ static int __mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port, if (!dev) return -ENOMEM; SET_NETDEV_DEV(dev, mlxsw_sx->bus_info->dev); + dev_net_set(dev, mlxsw_core_net(mlxsw_sx->core)); mlxsw_sx_port = netdev_priv(dev); mlxsw_sx_port->dev = dev; mlxsw_sx_port->mlxsw_sx = mlxsw_sx; -- cgit v1.2.3-59-g8ed1b From 5bcfb6a45a614253a65ad45904fba4d93bde372d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:34 +0200 Subject: mlxsw: Propagate extack down to register_fib_notifier() During the devlink reaload the extack is present, so propagate it all the way down to register_fib_notifier() call in spectrum_router.c. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 13 ++++++++----- drivers/net/ethernet/mellanox/mlxsw/core.h | 6 ++++-- drivers/net/ethernet/mellanox/mlxsw/i2c.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/minimal.c | 3 ++- drivers/net/ethernet/mellanox/mlxsw/pci.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 15 +++++++++------ drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 ++- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 +++-- drivers/net/ethernet/mellanox/mlxsw/switchib.c | 3 ++- drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 3 ++- 10 files changed, 34 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 14dcc786926d..1e61a012ca43 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1005,7 +1005,7 @@ mlxsw_devlink_core_bus_device_reload_up(struct devlink *devlink, return mlxsw_core_bus_device_register(mlxsw_core->bus_info, mlxsw_core->bus, mlxsw_core->bus_priv, true, - devlink); + devlink, extack); } static int mlxsw_devlink_flash_update(struct devlink *devlink, @@ -1098,7 +1098,8 @@ static int __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink) + struct devlink *devlink, + struct netlink_ext_ack *extack) { const char *device_kind = mlxsw_bus_info->device_kind; struct mlxsw_core *mlxsw_core; @@ -1172,7 +1173,7 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, } if (mlxsw_driver->init) { - err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info); + err = mlxsw_driver->init(mlxsw_core, mlxsw_bus_info, extack); if (err) goto err_driver_init; } @@ -1223,14 +1224,16 @@ err_devlink_alloc: int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink) + struct devlink *devlink, + struct netlink_ext_ack *extack) { bool called_again = false; int err; again: err = __mlxsw_core_bus_device_register(mlxsw_bus_info, mlxsw_bus, - bus_priv, reload, devlink); + bus_priv, reload, + devlink, extack); /* -EAGAIN is returned in case the FW was updated. FW needs * a reset, so lets try to call __mlxsw_core_bus_device_register() * again. diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index e1ef4d255b93..3377a1b39b03 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -37,7 +37,8 @@ void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, const struct mlxsw_bus *mlxsw_bus, void *bus_priv, bool reload, - struct devlink *devlink); + struct devlink *devlink, + struct netlink_ext_ack *extack); void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload); struct mlxsw_tx_info { @@ -253,7 +254,8 @@ struct mlxsw_driver { const char *kind; size_t priv_size; int (*init)(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info); + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack); void (*fini)(struct mlxsw_core *mlxsw_core); int (*basic_trap_groups_set)(struct mlxsw_core *mlxsw_core); int (*port_type_set)(struct mlxsw_core *mlxsw_core, u8 local_port, diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c index 95f408d0e103..34566eb62c47 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c +++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c @@ -640,7 +640,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, &mlxsw_i2c_bus, mlxsw_i2c, false, - NULL); + NULL, NULL); if (err) { dev_err(&client->dev, "Fail to register core bus\n"); return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index cee16ad58307..5edd8de57a24 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -327,7 +327,8 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) } static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index f1294b00efdf..914c33e46fb4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1802,7 +1802,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, &mlxsw_pci_bus, mlxsw_pci, false, - NULL); + NULL, NULL); if (err) { dev_err(&pdev->dev, "cannot register bus device\n"); goto err_bus_device_register; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index a9ea9c7b9e59..c91b8238c8c5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4739,7 +4739,8 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *unused, unsigned long event, void *ptr); static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); int err; @@ -4832,7 +4833,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_acl_init; } - err = mlxsw_sp_router_init(mlxsw_sp); + err = mlxsw_sp_router_init(mlxsw_sp, extack); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); goto err_router_init; @@ -4927,7 +4928,8 @@ err_fids_init: } static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); @@ -4947,11 +4949,12 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->listeners = mlxsw_sp1_listener; mlxsw_sp->listeners_count = ARRAY_SIZE(mlxsw_sp1_listener); - return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); + return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); @@ -4967,7 +4970,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->port_type_speed_ops = &mlxsw_sp2_port_type_speed_ops; mlxsw_sp->ptp_ops = &mlxsw_sp2_ptp_ops; - return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info); + return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info, extack); } static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index f58d45e770cd..8f99d70d6b8b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -525,7 +525,8 @@ union mlxsw_sp_l3addr { struct in6_addr addr6; }; -int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp); +int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, + struct netlink_ext_ack *extack); void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp); int mlxsw_sp_netdevice_router_port_event(struct net_device *dev, unsigned long event, void *ptr); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 3479f805b377..0e99b64450ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -8061,7 +8061,8 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rgcr), rgcr_pl); } -int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) +int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, + struct netlink_ext_ack *extack) { struct mlxsw_sp_router *router; int err; @@ -8139,7 +8140,7 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp->router->fib_nb.notifier_call = mlxsw_sp_router_fib_event; err = register_fib_notifier(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->router->fib_nb, - mlxsw_sp_router_fib_dump_flush, NULL); + mlxsw_sp_router_fib_dump_flush, extack); if (err) goto err_register_fib_notifier; diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c index 0d9356b3f65d..4ff1e623aa76 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchib.c @@ -446,7 +446,8 @@ static int mlxsw_sib_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) } static int mlxsw_sib_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sib *mlxsw_sib = mlxsw_core_driver_priv(mlxsw_core); int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index a4d09392a8d7..de6cb22f68b1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -1564,7 +1564,8 @@ static int mlxsw_sx_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) } static int mlxsw_sx_init(struct mlxsw_core *mlxsw_core, - const struct mlxsw_bus_info *mlxsw_bus_info) + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) { struct mlxsw_sx *mlxsw_sx = mlxsw_core_driver_priv(mlxsw_core); int err; -- cgit v1.2.3-59-g8ed1b From 7f36a77ade6eefc243c64c64b8f8252fa43ea55e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:35 +0200 Subject: netdevsim: add all ports in nsim_dev_create() and del them in destroy() Currently the probe/remove function does this separately. Put the addition an deletion of ports into nsim_dev_create() and nsim_dev_destroy(). Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 175 +++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 82 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 6087f5b99e47..3cc101aee991 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -603,8 +603,92 @@ static const struct devlink_ops nsim_dev_devlink_ops = { #define NSIM_DEV_MAX_MACS_DEFAULT 32 #define NSIM_DEV_TEST1_DEFAULT true +static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, + unsigned int port_index) +{ + struct nsim_dev_port *nsim_dev_port; + struct devlink_port *devlink_port; + int err; + + nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); + if (!nsim_dev_port) + return -ENOMEM; + nsim_dev_port->port_index = port_index; + + devlink_port = &nsim_dev_port->devlink_port; + devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, + port_index + 1, 0, 0, + nsim_dev->switch_id.id, + nsim_dev->switch_id.id_len); + err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port, + port_index); + if (err) + goto err_port_free; + + err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); + if (err) + goto err_dl_port_unregister; + + nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); + if (IS_ERR(nsim_dev_port->ns)) { + err = PTR_ERR(nsim_dev_port->ns); + goto err_port_debugfs_exit; + } + + devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); + list_add(&nsim_dev_port->list, &nsim_dev->port_list); + + return 0; + +err_port_debugfs_exit: + nsim_dev_port_debugfs_exit(nsim_dev_port); +err_dl_port_unregister: + devlink_port_unregister(devlink_port); +err_port_free: + kfree(nsim_dev_port); + return err; +} + +static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) +{ + struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; + + list_del(&nsim_dev_port->list); + devlink_port_type_clear(devlink_port); + nsim_destroy(nsim_dev_port->ns); + nsim_dev_port_debugfs_exit(nsim_dev_port); + devlink_port_unregister(devlink_port); + kfree(nsim_dev_port); +} + +static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) +{ + struct nsim_dev_port *nsim_dev_port, *tmp; + + list_for_each_entry_safe(nsim_dev_port, tmp, + &nsim_dev->port_list, list) + __nsim_dev_port_del(nsim_dev_port); +} + +static int nsim_dev_port_add_all(struct nsim_dev *nsim_dev, + unsigned int port_count) +{ + int i, err; + + for (i = 0; i < port_count; i++) { + err = __nsim_dev_port_add(nsim_dev, i); + if (err) + goto err_port_del_all; + } + return 0; + +err_port_del_all: + nsim_dev_port_del_all(nsim_dev); + return err; +} + static struct nsim_dev * -nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) +nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) { struct nsim_dev *nsim_dev; struct devlink *devlink; @@ -659,9 +743,15 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) if (err) goto err_debugfs_exit; + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + if (err) + goto err_bpf_dev_exit; + devlink_params_publish(devlink); return nsim_dev; +err_bpf_dev_exit: + nsim_bpf_dev_exit(nsim_dev); err_debugfs_exit: nsim_dev_debugfs_exit(nsim_dev); err_traps_exit: @@ -686,6 +776,7 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev) { struct devlink *devlink = priv_to_devlink(nsim_dev); + nsim_dev_port_del_all(nsim_dev); nsim_bpf_dev_exit(nsim_dev); nsim_dev_debugfs_exit(nsim_dev); nsim_dev_traps_exit(devlink); @@ -699,102 +790,22 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev) devlink_free(devlink); } -static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, - unsigned int port_index) -{ - struct nsim_dev_port *nsim_dev_port; - struct devlink_port *devlink_port; - int err; - - nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL); - if (!nsim_dev_port) - return -ENOMEM; - nsim_dev_port->port_index = port_index; - - devlink_port = &nsim_dev_port->devlink_port; - devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL, - port_index + 1, 0, 0, - nsim_dev->switch_id.id, - nsim_dev->switch_id.id_len); - err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port, - port_index); - if (err) - goto err_port_free; - - err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port); - if (err) - goto err_dl_port_unregister; - - nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port); - if (IS_ERR(nsim_dev_port->ns)) { - err = PTR_ERR(nsim_dev_port->ns); - goto err_port_debugfs_exit; - } - - devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev); - list_add(&nsim_dev_port->list, &nsim_dev->port_list); - - return 0; - -err_port_debugfs_exit: - nsim_dev_port_debugfs_exit(nsim_dev_port); -err_dl_port_unregister: - devlink_port_unregister(devlink_port); -err_port_free: - kfree(nsim_dev_port); - return err; -} - -static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) -{ - struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; - - list_del(&nsim_dev_port->list); - devlink_port_type_clear(devlink_port); - nsim_destroy(nsim_dev_port->ns); - nsim_dev_port_debugfs_exit(nsim_dev_port); - devlink_port_unregister(devlink_port); - kfree(nsim_dev_port); -} - -static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) -{ - struct nsim_dev_port *nsim_dev_port, *tmp; - - list_for_each_entry_safe(nsim_dev_port, tmp, - &nsim_dev->port_list, list) - __nsim_dev_port_del(nsim_dev_port); -} - int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) { struct nsim_dev *nsim_dev; - int i; - int err; - nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count); + nsim_dev = nsim_dev_create(nsim_bus_dev); if (IS_ERR(nsim_dev)) return PTR_ERR(nsim_dev); dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); - for (i = 0; i < nsim_bus_dev->port_count; i++) { - err = __nsim_dev_port_add(nsim_dev, i); - if (err) - goto err_port_del_all; - } return 0; - -err_port_del_all: - nsim_dev_port_del_all(nsim_dev); - nsim_dev_destroy(nsim_dev); - return err; } void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) { struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); - nsim_dev_port_del_all(nsim_dev); nsim_dev_destroy(nsim_dev); } -- cgit v1.2.3-59-g8ed1b From 75ba029f3c07f4755b88ee3a9c441e9ffb468e6a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:36 +0200 Subject: netdevsim: implement proper devlink reload During devlink reload, all driver objects should be reinstantiated with the exception of devlink instance and devlink resources and params. Move existing devlink_resource_size_get() calls into fib_create() just before fib notifier is registered. Also, make sure that extack is propagated down to fib_notifier_register() call. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 95 +++++++++++++++++++++++++++------------ drivers/net/netdevsim/fib.c | 53 ++++++++++++---------- drivers/net/netdevsim/netdevsim.h | 8 ++-- 3 files changed, 99 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 3cc101aee991..7de80faab047 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -469,9 +469,16 @@ static void nsim_dev_traps_exit(struct devlink *devlink) kfree(nsim_dev->trap_data); } +static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, + struct netlink_ext_ack *extack); +static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); + static int nsim_dev_reload_down(struct devlink *devlink, struct netlink_ext_ack *extack) { + struct nsim_dev *nsim_dev = devlink_priv(devlink); + + nsim_dev_reload_destroy(nsim_dev); return 0; } @@ -479,27 +486,8 @@ static int nsim_dev_reload_up(struct devlink *devlink, struct netlink_ext_ack *extack) { struct nsim_dev *nsim_dev = devlink_priv(devlink); - enum nsim_resource_id res_ids[] = { - NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, - NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES - }; - int i; - - for (i = 0; i < ARRAY_SIZE(res_ids); ++i) { - int err; - u64 val; - - err = devlink_resource_size_get(devlink, res_ids[i], &val); - if (!err) { - err = nsim_fib_set_max(nsim_dev->fib_data, - res_ids[i], val, extack); - if (err) - return err; - } - } - nsim_devlink_param_load_driverinit_values(devlink); - return 0; + return nsim_dev_reload_create(nsim_dev, extack); } #define NSIM_DEV_FLASH_SIZE 500000 @@ -687,8 +675,49 @@ err_port_del_all: return err; } -static struct nsim_dev * -nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) +static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, + struct netlink_ext_ack *extack) +{ + struct nsim_bus_dev *nsim_bus_dev = nsim_dev->nsim_bus_dev; + struct devlink *devlink; + int err; + + devlink = priv_to_devlink(nsim_dev); + nsim_dev = devlink_priv(devlink); + INIT_LIST_HEAD(&nsim_dev->port_list); + mutex_init(&nsim_dev->port_list_lock); + nsim_dev->fw_update_status = true; + + nsim_dev->fib_data = nsim_fib_create(devlink, extack); + if (IS_ERR(nsim_dev->fib_data)) + return PTR_ERR(nsim_dev->fib_data); + + nsim_devlink_param_load_driverinit_values(devlink); + + err = nsim_dev_dummy_region_init(nsim_dev, devlink); + if (err) + goto err_fib_destroy; + + err = nsim_dev_traps_init(devlink); + if (err) + goto err_dummy_region_exit; + + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + if (err) + goto err_traps_exit; + + return 0; + +err_traps_exit: + nsim_dev_traps_exit(devlink); +err_dummy_region_exit: + nsim_dev_dummy_region_exit(nsim_dev); +err_fib_destroy: + nsim_fib_destroy(devlink, nsim_dev->fib_data); + return err; +} + +static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) { struct nsim_dev *nsim_dev; struct devlink *devlink; @@ -711,7 +740,7 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) if (err) goto err_devlink_free; - nsim_dev->fib_data = nsim_fib_create(devlink); + nsim_dev->fib_data = nsim_fib_create(devlink, NULL); if (IS_ERR(nsim_dev->fib_data)) { err = PTR_ERR(nsim_dev->fib_data); goto err_resources_unregister; @@ -772,21 +801,31 @@ err_devlink_free: return ERR_PTR(err); } -static void nsim_dev_destroy(struct nsim_dev *nsim_dev) +static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) { struct devlink *devlink = priv_to_devlink(nsim_dev); + if (devlink_is_reload_failed(devlink)) + return; nsim_dev_port_del_all(nsim_dev); - nsim_bpf_dev_exit(nsim_dev); - nsim_dev_debugfs_exit(nsim_dev); nsim_dev_traps_exit(devlink); nsim_dev_dummy_region_exit(nsim_dev); + mutex_destroy(&nsim_dev->port_list_lock); + nsim_fib_destroy(devlink, nsim_dev->fib_data); +} + +static void nsim_dev_destroy(struct nsim_dev *nsim_dev) +{ + struct devlink *devlink = priv_to_devlink(nsim_dev); + + nsim_dev_reload_destroy(nsim_dev); + + nsim_bpf_dev_exit(nsim_dev); + nsim_dev_debugfs_exit(nsim_dev); devlink_params_unregister(devlink, nsim_devlink_params, ARRAY_SIZE(nsim_devlink_params)); devlink_unregister(devlink); - nsim_fib_destroy(devlink, nsim_dev->fib_data); devlink_resources_unregister(devlink, NULL); - mutex_destroy(&nsim_dev->port_list_lock); devlink_free(devlink); } diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index d2aeac0f4c2c..fdc682f3a09a 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -63,12 +63,10 @@ u64 nsim_fib_get_val(struct nsim_fib_data *fib_data, return max ? entry->max : entry->num; } -int nsim_fib_set_max(struct nsim_fib_data *fib_data, - enum nsim_resource_id res_id, u64 val, - struct netlink_ext_ack *extack) +static void nsim_fib_set_max(struct nsim_fib_data *fib_data, + enum nsim_resource_id res_id, u64 val) { struct nsim_fib_entry *entry; - int err = 0; switch (res_id) { case NSIM_RESOURCE_IPV4_FIB: @@ -84,20 +82,10 @@ int nsim_fib_set_max(struct nsim_fib_data *fib_data, entry = &fib_data->ipv6.rules; break; default: - return 0; - } - - /* not allowing a new max to be less than curren occupancy - * --> no means of evicting entries - */ - if (val < entry->num) { - NL_SET_ERR_MSG_MOD(extack, "New size is less than current occupancy"); - err = -EINVAL; - } else { - entry->max = val; + WARN_ON(1); + return; } - - return err; + entry->max = val; } static int nsim_fib_rule_account(struct nsim_fib_entry *entry, bool add, @@ -239,7 +227,28 @@ static u64 nsim_fib_ipv6_rules_res_occ_get(void *priv) return nsim_fib_get_val(data, NSIM_RESOURCE_IPV6_FIB_RULES, false); } -struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) +static void nsim_fib_set_max_all(struct nsim_fib_data *data, + struct devlink *devlink) +{ + enum nsim_resource_id res_ids[] = { + NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES, + NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES + }; + int i; + + for (i = 0; i < ARRAY_SIZE(res_ids); i++) { + int err; + u64 val; + + err = devlink_resource_size_get(devlink, res_ids[i], &val); + if (err) + val = (u64) -1; + nsim_fib_set_max(data, res_ids[i], val); + } +} + +struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, + struct netlink_ext_ack *extack) { struct nsim_fib_data *data; int err; @@ -248,15 +257,11 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink) if (!data) return ERR_PTR(-ENOMEM); - data->ipv4.fib.max = (u64)-1; - data->ipv4.rules.max = (u64)-1; - - data->ipv6.fib.max = (u64)-1; - data->ipv6.rules.max = (u64)-1; + nsim_fib_set_max_all(data, devlink); data->fib_nb.notifier_call = nsim_fib_event_nb; err = register_fib_notifier(&init_net, &data->fib_nb, - nsim_fib_dump_inconsistent, NULL); + nsim_fib_dump_inconsistent, extack); if (err) { pr_err("Failed to register fib notifier\n"); goto err_out; diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index ac506cf253b6..702d951fe160 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -173,13 +173,11 @@ int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_index); -struct nsim_fib_data *nsim_fib_create(struct devlink *devlink); -void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data); +struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, + struct netlink_ext_ack *extack); +void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *fib_data); u64 nsim_fib_get_val(struct nsim_fib_data *fib_data, enum nsim_resource_id res_id, bool max); -int nsim_fib_set_max(struct nsim_fib_data *fib_data, - enum nsim_resource_id res_id, u64 val, - struct netlink_ext_ack *extack); #if IS_ENABLED(CONFIG_XFRM_OFFLOAD) void nsim_ipsec_init(struct netdevsim *ns); -- cgit v1.2.3-59-g8ed1b From 90d299138dd42579084715d6d25f9c27b63211af Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:37 +0200 Subject: netdevsim: register port netdevices into net of device Register newly created port netdevice into net namespace that the parent device belongs to. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/netdevsim/netdev.c | 1 + drivers/net/netdevsim/netdevsim.h | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 0740940f41b1..2908e0a0d6e1 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -290,6 +290,7 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port) if (!dev) return ERR_PTR(-ENOMEM); + dev_net_set(dev, nsim_dev_net(nsim_dev)); ns = netdev_priv(dev); ns->netdev = dev; ns->nsim_dev = nsim_dev; diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 702d951fe160..198ca31cec94 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -164,6 +164,11 @@ struct nsim_dev { struct devlink_region *dummy_region; }; +static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev) +{ + return devlink_net(priv_to_devlink(nsim_dev)); +} + int nsim_dev_init(void); void nsim_dev_exit(void); int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev); -- cgit v1.2.3-59-g8ed1b From 4f174bbcc96c80720722e25f198580a184803c3a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:38 +0200 Subject: netdevsim: take devlink net instead of init_net Follow-up patch is going to allow to reload devlink instance into different network namespace, so use devlink_net() helper instead of init_net. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/netdevsim/fib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index fdc682f3a09a..13540dee7364 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -260,7 +260,7 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, nsim_fib_set_max_all(data, devlink); data->fib_nb.notifier_call = nsim_fib_event_nb; - err = register_fib_notifier(&init_net, &data->fib_nb, + err = register_fib_notifier(devlink_net(devlink), &data->fib_nb, nsim_fib_dump_inconsistent, extack); if (err) { pr_err("Failed to register fib notifier\n"); @@ -300,6 +300,6 @@ void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) NSIM_RESOURCE_IPV4_FIB_RULES); devlink_resource_occ_get_unregister(devlink, NSIM_RESOURCE_IPV4_FIB); - unregister_fib_notifier(&init_net, &data->fib_nb); + unregister_fib_notifier(devlink_net(devlink), &data->fib_nb); kfree(data); } -- cgit v1.2.3-59-g8ed1b From 070c63f20f6c739a3c534555f56c7327536bfcc2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Oct 2019 11:49:39 +0200 Subject: net: devlink: allow to change namespaces during reload All devlink instances are created in init_net and stay there for a lifetime. Allow user to be able to move devlink instances into namespaces during devlink reload operation. That ensures proper re-instantiation of driver objects, including netdevices. Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 6 +- drivers/net/ethernet/mellanox/mlxsw/core.c | 1 + drivers/net/netdevsim/dev.c | 2 +- include/net/devlink.h | 2 +- include/uapi/linux/devlink.h | 4 + net/core/devlink.c | 154 +++++++++++++++++++++++++++-- 6 files changed, 158 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index fce9b3a24347..22c72fb7206a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -3935,13 +3935,17 @@ static void mlx4_restart_one_down(struct pci_dev *pdev); static int mlx4_restart_one_up(struct pci_dev *pdev, bool reload, struct devlink *devlink); -static int mlx4_devlink_reload_down(struct devlink *devlink, +static int mlx4_devlink_reload_down(struct devlink *devlink, bool netns_change, struct netlink_ext_ack *extack) { struct mlx4_priv *priv = devlink_priv(devlink); struct mlx4_dev *dev = &priv->dev; struct mlx4_dev_persistent *persist = dev->persist; + if (netns_change) { + NL_SET_ERR_MSG_MOD(extack, "Namespace change is not supported"); + return -EOPNOTSUPP; + } if (persist->num_vfs) mlx4_warn(persist->dev, "Reload performed on PF, will cause reset on operating Virtual Functions\n"); mlx4_restart_one_down(persist->pdev); diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 1e61a012ca43..1c29522a2af3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -985,6 +985,7 @@ mlxsw_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, static int mlxsw_devlink_core_bus_device_reload_down(struct devlink *devlink, + bool netns_change, struct netlink_ext_ack *extack) { struct mlxsw_core *mlxsw_core = devlink_priv(devlink); diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 7de80faab047..3f3c7cc21077 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -473,7 +473,7 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, struct netlink_ext_ack *extack); static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev); -static int nsim_dev_reload_down(struct devlink *devlink, +static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, struct netlink_ext_ack *extack) { struct nsim_dev *nsim_dev = devlink_priv(devlink); diff --git a/include/net/devlink.h b/include/net/devlink.h index 5ac2be0f0857..3c9d4a063c98 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -643,7 +643,7 @@ enum devlink_trap_group_generic_id { } struct devlink_ops { - int (*reload_down)(struct devlink *devlink, + int (*reload_down)(struct devlink *devlink, bool netns_change, struct netlink_ext_ack *extack); int (*reload_up)(struct devlink *devlink, struct netlink_ext_ack *extack); diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 580b7a2e40e1..b558ea88b766 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -421,6 +421,10 @@ enum devlink_attr { DEVLINK_ATTR_RELOAD_FAILED, /* u8 0 or 1 */ + DEVLINK_ATTR_NETNS_FD, /* u32 */ + DEVLINK_ATTR_NETNS_PID, /* u32 */ + DEVLINK_ATTR_NETNS_ID, /* u32 */ + /* add new attributes above here, update the policy in devlink.c */ __DEVLINK_ATTR_MAX, diff --git a/net/core/devlink.c b/net/core/devlink.c index 362cbbcca225..c4d8c4ab0fb5 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -435,8 +435,16 @@ static void devlink_nl_post_doit(const struct genl_ops *ops, { struct devlink *devlink; - devlink = devlink_get_from_info(info); - if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) + /* When devlink changes netns, it would not be found + * by devlink_get_from_info(). So try if it is stored first. + */ + if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) { + devlink = info->user_ptr[0]; + } else { + devlink = devlink_get_from_info(info); + WARN_ON(IS_ERR(devlink)); + } + if (!IS_ERR(devlink) && ~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) mutex_unlock(&devlink->lock); mutex_unlock(&devlink_mutex); } @@ -2675,6 +2683,72 @@ devlink_resources_validate(struct devlink *devlink, return err; } +static struct net *devlink_netns_get(struct sk_buff *skb, + struct genl_info *info) +{ + struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID]; + struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD]; + struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID]; + struct net *net; + + if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) { + NL_SET_ERR_MSG(info->extack, "multiple netns identifying attributes specified"); + return ERR_PTR(-EINVAL); + } + + if (netns_pid_attr) { + net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr)); + } else if (netns_fd_attr) { + net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr)); + } else if (netns_id_attr) { + net = get_net_ns_by_id(sock_net(skb->sk), + nla_get_u32(netns_id_attr)); + if (!net) + net = ERR_PTR(-EINVAL); + } else { + WARN_ON(1); + net = ERR_PTR(-EINVAL); + } + if (IS_ERR(net)) { + NL_SET_ERR_MSG(info->extack, "Unknown network namespace"); + return ERR_PTR(-EINVAL); + } + if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { + put_net(net); + return ERR_PTR(-EPERM); + } + return net; +} + +static void devlink_param_notify(struct devlink *devlink, + unsigned int port_index, + struct devlink_param_item *param_item, + enum devlink_command cmd); + +static void devlink_reload_netns_change(struct devlink *devlink, + struct net *dest_net) +{ + struct devlink_param_item *param_item; + + /* Userspace needs to be notified about devlink objects + * removed from original and entering new network namespace. + * The rest of the devlink objects are re-created during + * reload process so the notifications are generated separatelly. + */ + + list_for_each_entry(param_item, &devlink->param_list, list) + devlink_param_notify(devlink, 0, param_item, + DEVLINK_CMD_PARAM_DEL); + devlink_notify(devlink, DEVLINK_CMD_DEL); + + devlink_net_set(devlink, dest_net); + + devlink_notify(devlink, DEVLINK_CMD_NEW); + list_for_each_entry(param_item, &devlink->param_list, list) + devlink_param_notify(devlink, 0, param_item, + DEVLINK_CMD_PARAM_NEW); +} + static bool devlink_reload_supported(struct devlink *devlink) { return devlink->ops->reload_down && devlink->ops->reload_up; @@ -2695,9 +2769,27 @@ bool devlink_is_reload_failed(const struct devlink *devlink) } EXPORT_SYMBOL_GPL(devlink_is_reload_failed); +static int devlink_reload(struct devlink *devlink, struct net *dest_net, + struct netlink_ext_ack *extack) +{ + int err; + + err = devlink->ops->reload_down(devlink, !!dest_net, extack); + if (err) + return err; + + if (dest_net && !net_eq(dest_net, devlink_net(devlink))) + devlink_reload_netns_change(devlink, dest_net); + + err = devlink->ops->reload_up(devlink, extack); + devlink_reload_failed_set(devlink, !!err); + return err; +} + static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) { struct devlink *devlink = info->user_ptr[0]; + struct net *dest_net = NULL; int err; if (!devlink_reload_supported(devlink)) @@ -2708,11 +2800,20 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info) NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed"); return err; } - err = devlink->ops->reload_down(devlink, info->extack); - if (err) - return err; - err = devlink->ops->reload_up(devlink, info->extack); - devlink_reload_failed_set(devlink, !!err); + + if (info->attrs[DEVLINK_ATTR_NETNS_PID] || + info->attrs[DEVLINK_ATTR_NETNS_FD] || + info->attrs[DEVLINK_ATTR_NETNS_ID]) { + dest_net = devlink_netns_get(skb, info); + if (IS_ERR(dest_net)) + return PTR_ERR(dest_net); + } + + err = devlink_reload(devlink, dest_net, info->extack); + + if (dest_net) + put_net(dest_net); + return err; } @@ -5794,6 +5895,9 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING }, [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 }, [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING }, + [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 }, + [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 }, + [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 }, }; static const struct genl_ops devlink_nl_ops[] = { @@ -8061,9 +8165,43 @@ int devlink_compat_switch_id_get(struct net_device *dev, return 0; } +static void __net_exit devlink_pernet_pre_exit(struct net *net) +{ + struct devlink *devlink; + int err; + + /* In case network namespace is getting destroyed, reload + * all devlink instances from this namespace into init_net. + */ + mutex_lock(&devlink_mutex); + list_for_each_entry(devlink, &devlink_list, list) { + if (net_eq(devlink_net(devlink), net)) { + if (WARN_ON(!devlink_reload_supported(devlink))) + continue; + err = devlink_reload(devlink, &init_net, NULL); + if (err) + pr_warn("Failed to reload devlink instance into init_net\n"); + } + } + mutex_unlock(&devlink_mutex); +} + +static struct pernet_operations devlink_pernet_ops __net_initdata = { + .pre_exit = devlink_pernet_pre_exit, +}; + static int __init devlink_init(void) { - return genl_register_family(&devlink_nl_family); + int err; + + err = genl_register_family(&devlink_nl_family); + if (err) + goto out; + err = register_pernet_subsys(&devlink_pernet_ops); + +out: + WARN_ON(err); + return err; } subsys_initcall(devlink_init); -- cgit v1.2.3-59-g8ed1b From fea7fda7f50a6059220f83251e70709e45cc8040 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 3 Oct 2019 11:43:51 -0700 Subject: net: phy: broadcom: Fix RGMII delays configuration for BCM54210E Commit 0fc9ae107669 ("net: phy: broadcom: add support for BCM54210E") added support for BCM54210E but also unconditionally cleared the RXC to RXD skew and the TXD to TXC skew, thus only making PHY_INTERFACE_MODE_RGMII a possible configuration. Use bcm54xx_config_clock_delay() which correctly sets the registers depending on the 4 possible PHY interface values that exist for RGMII. Fixes: 0fc9ae107669 ("net: phy: broadcom: add support for BCM54210E") Reported-by: Manasa Mudireddy Reported-by: Ray Jui Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 937d0059e8ac..5e956089bf52 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -26,18 +26,13 @@ MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); +static int bcm54xx_config_clock_delay(struct phy_device *phydev); + static int bcm54210e_config_init(struct phy_device *phydev) { int val; - val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); - val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; - val |= MII_BCM54XX_AUXCTL_MISC_WREN; - bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val); - - val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL); - val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN; - bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val); + bcm54xx_config_clock_delay(phydev); if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { val = phy_read(phydev, MII_CTRL1000); -- cgit v1.2.3-59-g8ed1b From bea5d143880128daa4036f7799bae32a70b56b05 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 3 Oct 2019 11:43:52 -0700 Subject: net: phy: broadcom: Use bcm54xx_config_clock_delay() for BCM54612E bcm54612e_config_init() duplicates what bcm54xx_config_clock_delay() does with respect to configuring RGMII TX/RX delays appropriately. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 5e956089bf52..4313c74b4fd8 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -47,26 +47,7 @@ static int bcm54612e_config_init(struct phy_device *phydev) { int reg; - /* Clear TX internal delay unless requested. */ - if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && - (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) { - /* Disable TXD to GTXCLK clock delay (default set) */ - /* Bit 9 is the only field in shadow register 00011 */ - bcm_phy_write_shadow(phydev, 0x03, 0); - } - - /* Clear RX internal delay unless requested. */ - if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) && - (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) { - reg = bcm54xx_auxctl_read(phydev, - MII_BCM54XX_AUXCTL_SHDWSEL_MISC); - /* Disable RXD to RXC delay (default set) */ - reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN; - /* Clear shadow selector field */ - reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK; - bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, - MII_BCM54XX_AUXCTL_MISC_WREN | reg); - } + bcm54xx_config_clock_delay(phydev); /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { -- cgit v1.2.3-59-g8ed1b From 511e6ca047457bcf200d9b6ad75e310b0e77af19 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 4 Oct 2019 03:33:47 +0300 Subject: net: dsa: sja1105: Add support for port mirroring Amazingly, of all features, this does not require a switch reset. Tested with: tc qdisc add dev swp2 clsact tc filter add dev swp2 ingress matchall skip_sw \ action mirred egress mirror dev swp3 tc filter show dev swp2 ingress tc filter del dev swp2 ingress pref 49152 Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 88 ++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index e95039727c1c..06fcd45a6099 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -382,8 +382,8 @@ static int sja1105_init_l2_forwarding_params(struct sja1105_private *priv) static int sja1105_init_general_params(struct sja1105_private *priv) { struct sja1105_general_params_entry default_general_params = { - /* Disallow dynamic changing of the mirror port */ - .mirr_ptacu = 0, + /* Allow dynamic changing of the mirror port */ + .mirr_ptacu = true, .switchid = priv->ds->index, /* Priority queue for link-local management frames * (both ingress to and egress from CPU - PTP, STP etc) @@ -403,8 +403,8 @@ static int sja1105_init_general_params(struct sja1105_private *priv) * by installing a temporary 'management route' */ .host_port = dsa_upstream_port(priv->ds, 0), - /* Same as host port */ - .mirr_port = dsa_upstream_port(priv->ds, 0), + /* Default to an invalid value */ + .mirr_port = SJA1105_NUM_PORTS, /* Link-local traffic received on casc_port will be forwarded * to host_port without embedding the source port and device ID * info in the destination MAC address (presumably because it @@ -2069,6 +2069,84 @@ static int sja1105_port_setup_tc(struct dsa_switch *ds, int port, } } +/* We have a single mirror (@to) port, but can configure ingress and egress + * mirroring on all other (@from) ports. + * We need to allow mirroring rules only as long as the @to port is always the + * same, and we need to unset the @to port from mirr_port only when there is no + * mirroring rule that references it. + */ +static int sja1105_mirror_apply(struct sja1105_private *priv, int from, int to, + bool ingress, bool enabled) +{ + struct sja1105_general_params_entry *general_params; + struct sja1105_mac_config_entry *mac; + struct sja1105_table *table; + bool already_enabled; + u64 new_mirr_port; + int rc; + + table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; + general_params = table->entries; + + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; + + already_enabled = (general_params->mirr_port != SJA1105_NUM_PORTS); + if (already_enabled && enabled && general_params->mirr_port != to) { + dev_err(priv->ds->dev, + "Delete mirroring rules towards port %llu first\n", + general_params->mirr_port); + return -EBUSY; + } + + new_mirr_port = to; + if (!enabled) { + bool keep = false; + int port; + + /* Anybody still referencing mirr_port? */ + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + if (mac[port].ing_mirr || mac[port].egr_mirr) { + keep = true; + break; + } + } + /* Unset already_enabled for next time */ + if (!keep) + new_mirr_port = SJA1105_NUM_PORTS; + } + if (new_mirr_port != general_params->mirr_port) { + general_params->mirr_port = new_mirr_port; + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_GENERAL_PARAMS, + 0, general_params, true); + if (rc < 0) + return rc; + } + + if (ingress) + mac[from].ing_mirr = enabled; + else + mac[from].egr_mirr = enabled; + + return sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, from, + &mac[from], true); +} + +static int sja1105_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + return sja1105_mirror_apply(ds->priv, port, mirror->to_local_port, + ingress, true); +} + +static void sja1105_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + sja1105_mirror_apply(ds->priv, port, mirror->to_local_port, + mirror->ingress, false); +} + static const struct dsa_switch_ops sja1105_switch_ops = { .get_tag_protocol = sja1105_get_tag_protocol, .setup = sja1105_setup, @@ -2102,6 +2180,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_rxtstamp = sja1105_port_rxtstamp, .port_txtstamp = sja1105_port_txtstamp, .port_setup_tc = sja1105_port_setup_tc, + .port_mirror_add = sja1105_mirror_add, + .port_mirror_del = sja1105_mirror_del, }; static int sja1105_check_device_id(struct sja1105_private *priv) -- cgit v1.2.3-59-g8ed1b From 26e0105550862a137eba701e2f4e3eeb343759e9 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 17:57:30 +0800 Subject: net: dsa: sja1105: Make function sja1105_xfer_long_buf static Fix sparse warnings: drivers/net/dsa/sja1105/sja1105_spi.c:159:5: warning: symbol 'sja1105_xfer_long_buf' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 6dda2e328fe2..423ee7eedd8c 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -156,9 +156,9 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, * must be sent/received. Splitting the buffer into chunks and assembling * those into SPI messages is done automatically by this function. */ -int sja1105_xfer_long_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 base_addr, - void *packed_buf, u64 buf_len) +static int sja1105_xfer_long_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 base_addr, + void *packed_buf, u64 buf_len) { struct chunk { void *buf_ptr; -- cgit v1.2.3-59-g8ed1b From 8538d29cea9530f114159e06bfa31b2358161493 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Fri, 4 Oct 2019 16:19:22 -0700 Subject: net/tls: add tracing for device/offload events Add tracing of device-related interaction to aid performance analysis, especially around resync: tls:tls_device_offload_set tls:tls_device_rx_resync_send tls:tls_device_rx_resync_nh_schedule tls:tls_device_rx_resync_nh_delay tls:tls_device_tx_resync_req tls:tls_device_tx_resync_send Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 3 +- include/net/tls.h | 8 +- net/tls/Makefile | 4 +- net/tls/tls_device.c | 30 +++- net/tls/trace.c | 10 ++ net/tls/trace.h | 169 +++++++++++++++++++++ 6 files changed, 213 insertions(+), 11 deletions(-) create mode 100644 net/tls/trace.c create mode 100644 net/tls/trace.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 61aabffc8888..bcdcd6de7dea 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -872,7 +872,8 @@ nfp_net_tls_tx(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec, /* jump forward, a TX may have gotten lost, need to sync TX */ if (!resync_pending && seq - ntls->next_seq < U32_MAX / 4) - tls_offload_tx_resync_request(nskb->sk); + tls_offload_tx_resync_request(nskb->sk, seq, + ntls->next_seq); *nr_frags = 0; return nskb; diff --git a/include/net/tls.h b/include/net/tls.h index 5c48cb9e0c18..38086ade65ce 100644 --- a/include/net/tls.h +++ b/include/net/tls.h @@ -594,13 +594,6 @@ tls_offload_rx_resync_set_type(struct sock *sk, enum tls_offload_sync_type type) tls_offload_ctx_rx(tls_ctx)->resync_type = type; } -static inline void tls_offload_tx_resync_request(struct sock *sk) -{ - struct tls_context *tls_ctx = tls_get_ctx(sk); - - WARN_ON(test_and_set_bit(TLS_TX_SYNC_SCHED, &tls_ctx->flags)); -} - /* Driver's seq tracking has to be disabled until resync succeeded */ static inline bool tls_offload_tx_resync_pending(struct sock *sk) { @@ -634,6 +627,7 @@ void tls_device_free_resources_tx(struct sock *sk); int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx); void tls_device_offload_cleanup_rx(struct sock *sk); void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq); +void tls_offload_tx_resync_request(struct sock *sk, u32 got_seq, u32 exp_seq); int tls_device_decrypted(struct sock *sk, struct sk_buff *skb); #else static inline void tls_device_init(void) {} diff --git a/net/tls/Makefile b/net/tls/Makefile index 95d8c06a14b9..0606d43d7582 100644 --- a/net/tls/Makefile +++ b/net/tls/Makefile @@ -3,9 +3,11 @@ # Makefile for the TLS subsystem. # +CFLAGS_trace.o := -I$(src) + obj-$(CONFIG_TLS) += tls.o -tls-y := tls_main.o tls_sw.o +tls-y := tls_main.o tls_sw.o trace.o tls-$(CONFIG_TLS_TOE) += tls_toe.o tls-$(CONFIG_TLS_DEVICE) += tls_device.o tls_device_fallback.o diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index f959487c5cd1..9f423caf48e3 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -38,6 +38,8 @@ #include #include +#include "trace.h" + /* device_offload_lock is used to synchronize tls_dev_add * against NETDEV_DOWN notifications. */ @@ -202,6 +204,15 @@ void tls_device_free_resources_tx(struct sock *sk) tls_free_partial_record(sk, tls_ctx); } +void tls_offload_tx_resync_request(struct sock *sk, u32 got_seq, u32 exp_seq) +{ + struct tls_context *tls_ctx = tls_get_ctx(sk); + + trace_tls_device_tx_resync_req(sk, got_seq, exp_seq); + WARN_ON(test_and_set_bit(TLS_TX_SYNC_SCHED, &tls_ctx->flags)); +} +EXPORT_SYMBOL_GPL(tls_offload_tx_resync_request); + static void tls_device_resync_tx(struct sock *sk, struct tls_context *tls_ctx, u32 seq) { @@ -216,6 +227,7 @@ static void tls_device_resync_tx(struct sock *sk, struct tls_context *tls_ctx, rcd_sn = tls_ctx->tx.rec_seq; + trace_tls_device_tx_resync_send(sk, seq, rcd_sn); down_read(&device_offload_lock); netdev = tls_ctx->netdev; if (netdev) @@ -637,10 +649,13 @@ void tls_device_write_space(struct sock *sk, struct tls_context *ctx) static void tls_device_resync_rx(struct tls_context *tls_ctx, struct sock *sk, u32 seq, u8 *rcd_sn) { + struct tls_offload_context_rx *rx_ctx = tls_offload_ctx_rx(tls_ctx); struct net_device *netdev; if (WARN_ON(test_and_set_bit(TLS_RX_SYNC_RUNNING, &tls_ctx->flags))) return; + + trace_tls_device_rx_resync_send(sk, seq, rcd_sn, rx_ctx->resync_type); netdev = READ_ONCE(tls_ctx->netdev); if (netdev) netdev->tlsdev_ops->tls_dev_resync(netdev, sk, seq, rcd_sn, @@ -653,8 +668,8 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq) struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_offload_context_rx *rx_ctx; u8 rcd_sn[TLS_MAX_REC_SEQ_SIZE]; + u32 sock_data, is_req_pending; struct tls_prot_info *prot; - u32 is_req_pending; s64 resync_req; u32 req_seq; @@ -683,8 +698,12 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq) /* head of next rec is already in, note that the sock_inq will * include the currently parsed message when called from parser */ - if (tcp_inq(sk) > rcd_len) + sock_data = tcp_inq(sk); + if (sock_data > rcd_len) { + trace_tls_device_rx_resync_nh_delay(sk, sock_data, + rcd_len); return; + } rx_ctx->resync_nh_do_now = 0; seq += rcd_len; @@ -728,6 +747,7 @@ static void tls_device_core_ctrl_rx_resync(struct tls_context *tls_ctx, /* head of next rec is already in, parser will sync for us */ if (tcp_inq(sk) > rxm->full_len) { + trace_tls_device_rx_resync_nh_schedule(sk); ctx->resync_nh_do_now = 1; } else { struct tls_prot_info *prot = &tls_ctx->prot_info; @@ -1013,6 +1033,8 @@ int tls_set_device_offload(struct sock *sk, struct tls_context *ctx) rc = netdev->tlsdev_ops->tls_dev_add(netdev, sk, TLS_OFFLOAD_CTX_DIR_TX, &ctx->crypto_send.info, tcp_sk(sk)->write_seq); + trace_tls_device_offload_set(sk, TLS_OFFLOAD_CTX_DIR_TX, + tcp_sk(sk)->write_seq, rec_seq, rc); if (rc) goto release_lock; @@ -1049,6 +1071,7 @@ free_marker_record: int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) { + struct tls12_crypto_info_aes_gcm_128 *info; struct tls_offload_context_rx *context; struct net_device *netdev; int rc = 0; @@ -1096,6 +1119,9 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) rc = netdev->tlsdev_ops->tls_dev_add(netdev, sk, TLS_OFFLOAD_CTX_DIR_RX, &ctx->crypto_recv.info, tcp_sk(sk)->copied_seq); + info = (void *)&ctx->crypto_recv.info; + trace_tls_device_offload_set(sk, TLS_OFFLOAD_CTX_DIR_RX, + tcp_sk(sk)->copied_seq, info->rec_seq, rc); if (rc) goto free_sw_resources; diff --git a/net/tls/trace.c b/net/tls/trace.c new file mode 100644 index 000000000000..e374913cf9c9 --- /dev/null +++ b/net/tls/trace.c @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (C) 2019 Netronome Systems, Inc. */ + +#include + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/net/tls/trace.h b/net/tls/trace.h new file mode 100644 index 000000000000..95b6ded2f9b2 --- /dev/null +++ b/net/tls/trace.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright (C) 2019 Netronome Systems, Inc. */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tls + +#if !defined(_TLS_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _TLS_TRACE_H_ + +#include +#include + +struct sock; + +TRACE_EVENT(tls_device_offload_set, + + TP_PROTO(struct sock *sk, int dir, u32 tcp_seq, u8 *rec_no, int ret), + + TP_ARGS(sk, dir, tcp_seq, rec_no, ret), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + __field( u64, rec_no ) + __field( int, dir ) + __field( u32, tcp_seq ) + __field( int, ret ) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->rec_no = get_unaligned_be64(rec_no); + __entry->dir = dir; + __entry->tcp_seq = tcp_seq; + __entry->ret = ret; + ), + + TP_printk( + "sk=%p direction=%d tcp_seq=%u rec_no=%llu ret=%d", + __entry->sk, __entry->dir, __entry->tcp_seq, __entry->rec_no, + __entry->ret + ) +); + +TRACE_EVENT(tls_device_rx_resync_send, + + TP_PROTO(struct sock *sk, u32 tcp_seq, u8 *rec_no, int sync_type), + + TP_ARGS(sk, tcp_seq, rec_no, sync_type), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + __field( u64, rec_no ) + __field( u32, tcp_seq ) + __field( int, sync_type ) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->rec_no = get_unaligned_be64(rec_no); + __entry->tcp_seq = tcp_seq; + __entry->sync_type = sync_type; + ), + + TP_printk( + "sk=%p tcp_seq=%u rec_no=%llu sync_type=%d", + __entry->sk, __entry->tcp_seq, __entry->rec_no, + __entry->sync_type + ) +); + +TRACE_EVENT(tls_device_rx_resync_nh_schedule, + + TP_PROTO(struct sock *sk), + + TP_ARGS(sk), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + ), + + TP_fast_assign( + __entry->sk = sk; + ), + + TP_printk( + "sk=%p", __entry->sk + ) +); + +TRACE_EVENT(tls_device_rx_resync_nh_delay, + + TP_PROTO(struct sock *sk, u32 sock_data, u32 rec_len), + + TP_ARGS(sk, sock_data, rec_len), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + __field( u32, sock_data ) + __field( u32, rec_len ) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->sock_data = sock_data; + __entry->rec_len = rec_len; + ), + + TP_printk( + "sk=%p sock_data=%u rec_len=%u", + __entry->sk, __entry->sock_data, __entry->rec_len + ) +); + +TRACE_EVENT(tls_device_tx_resync_req, + + TP_PROTO(struct sock *sk, u32 tcp_seq, u32 exp_tcp_seq), + + TP_ARGS(sk, tcp_seq, exp_tcp_seq), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + __field( u32, tcp_seq ) + __field( u32, exp_tcp_seq ) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->tcp_seq = tcp_seq; + __entry->exp_tcp_seq = exp_tcp_seq; + ), + + TP_printk( + "sk=%p tcp_seq=%u exp_tcp_seq=%u", + __entry->sk, __entry->tcp_seq, __entry->exp_tcp_seq + ) +); + +TRACE_EVENT(tls_device_tx_resync_send, + + TP_PROTO(struct sock *sk, u32 tcp_seq, u8 *rec_no), + + TP_ARGS(sk, tcp_seq, rec_no), + + TP_STRUCT__entry( + __field( struct sock *, sk ) + __field( u64, rec_no ) + __field( u32, tcp_seq ) + ), + + TP_fast_assign( + __entry->sk = sk; + __entry->rec_no = get_unaligned_be64(rec_no); + __entry->tcp_seq = tcp_seq; + ), + + TP_printk( + "sk=%p tcp_seq=%u rec_no=%llu", + __entry->sk, __entry->tcp_seq, __entry->rec_no + ) +); + +#endif /* _TLS_TRACE_H_ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +#include -- cgit v1.2.3-59-g8ed1b From 7b60027bbc6738b067bb9ed732a8c56b0ac430b2 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 5 Oct 2019 08:10:32 +0200 Subject: netdevsim: create devlink and netdev instances in namespace When user does create new netdevsim instance using sysfs bus file, create the devlink instance and related netdev instance in the namespace of the caller. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/bus.c | 1 + drivers/net/netdevsim/dev.c | 1 + drivers/net/netdevsim/netdevsim.h | 3 +++ 3 files changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 1a0ff3d7747b..6aeed0c600f8 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -283,6 +283,7 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count) nsim_bus_dev->dev.bus = &nsim_bus; nsim_bus_dev->dev.type = &nsim_bus_dev_type; nsim_bus_dev->port_count = port_count; + nsim_bus_dev->initial_net = current->nsproxy->net_ns; err = device_register(&nsim_bus_dev->dev); if (err) diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 3f3c7cc21077..fbc4cdcfe551 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -726,6 +726,7 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); if (!devlink) return ERR_PTR(-ENOMEM); + devlink_net_set(devlink, nsim_bus_dev->initial_net); nsim_dev = devlink_priv(devlink); nsim_dev->nsim_bus_dev = nsim_bus_dev; nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 198ca31cec94..8168a5475fe7 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -220,6 +220,9 @@ struct nsim_bus_dev { struct device dev; struct list_head list; unsigned int port_count; + struct net *initial_net; /* Purpose of this is to carry net pointer + * during the probe time only. + */ unsigned int num_vfs; struct nsim_vf_config *vfconfigs; }; -- cgit v1.2.3-59-g8ed1b From 155ddfc5e54a68f0e8d20f31f2b4b6b25e1071b5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 6 Oct 2019 08:30:01 +0200 Subject: netdevsim: add couple of debugfs bools to debug devlink reload Add flag to disallow reload and another one that causes reload to always fail. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 20 ++++++++++++++++++++ drivers/net/netdevsim/netdevsim.h | 2 ++ 2 files changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index fbc4cdcfe551..31d1752c703a 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -90,6 +90,10 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev) &nsim_dev->test1); debugfs_create_file("take_snapshot", 0200, nsim_dev->ddir, nsim_dev, &nsim_dev_take_snapshot_fops); + debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir, + &nsim_dev->dont_allow_reload); + debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir, + &nsim_dev->fail_reload); return 0; } @@ -478,6 +482,14 @@ static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, { struct nsim_dev *nsim_dev = devlink_priv(devlink); + if (nsim_dev->dont_allow_reload) { + /* For testing purposes, user set debugfs dont_allow_reload + * value to true. So forbid it. + */ + NL_SET_ERR_MSG_MOD(extack, "User forbidded reload for testing purposes"); + return -EOPNOTSUPP; + } + nsim_dev_reload_destroy(nsim_dev); return 0; } @@ -487,6 +499,14 @@ static int nsim_dev_reload_up(struct devlink *devlink, { struct nsim_dev *nsim_dev = devlink_priv(devlink); + if (nsim_dev->fail_reload) { + /* For testing purposes, user set debugfs fail_reload + * value to true. Fail right away. + */ + NL_SET_ERR_MSG_MOD(extack, "User setup the reload to fail for testing purposes"); + return -EINVAL; + } + return nsim_dev_reload_create(nsim_dev, extack); } diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 8168a5475fe7..24358385d869 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -161,6 +161,8 @@ struct nsim_dev { bool fw_update_status; u32 max_macs; bool test1; + bool dont_allow_reload; + bool fail_reload; struct devlink_region *dummy_region; }; -- cgit v1.2.3-59-g8ed1b From 5cfa030a1c2cf70e2fb0815a74fab1b459bc2a2b Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 6 Oct 2019 09:34:48 +0300 Subject: mlxsw: reg: Extend MGPIR register with new field exposing the number of QSFP modules Extend MGPIR - Management General Peripheral Information Register with new field "num_of_modules" exposing the number of modules supported by specific system. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 2 +- drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 3 ++- drivers/net/ethernet/mellanox/mlxsw/reg.h | 10 +++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c index 5b00726c4346..69c192839bf9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c @@ -590,7 +590,7 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) if (err) return err; - mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL); + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, NULL, NULL, NULL); if (!gbox_num) return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c index 35a1dc89c28a..b2c76a95f671 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c @@ -913,7 +913,8 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, if (err) return err; - mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL); + mlxsw_reg_mgpir_unpack(mgpir_pl, &thermal->tz_gearbox_num, NULL, NULL, + NULL); if (!thermal->tz_gearbox_num) return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 5494cf93f34c..7b538e698a3d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -9531,6 +9531,12 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); */ MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); +/* num_of_modules + * Number of modules. + * Access: RO + */ +MLXSW_ITEM32(reg, mgpir, num_of_modules, 0x04, 0, 8); + static inline void mlxsw_reg_mgpir_pack(char *payload) { MLXSW_REG_ZERO(mgpir, payload); @@ -9539,7 +9545,7 @@ static inline void mlxsw_reg_mgpir_pack(char *payload) static inline void mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, enum mlxsw_reg_mgpir_device_type *device_type, - u8 *devices_per_flash) + u8 *devices_per_flash, u8 *num_of_modules) { if (num_of_devices) *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); @@ -9548,6 +9554,8 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, if (devices_per_flash) *devices_per_flash = mlxsw_reg_mgpir_devices_per_flash_get(payload); + if (num_of_modules) + *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); } /* TNGCR - Tunneling NVE General Configuration Register -- cgit v1.2.3-59-g8ed1b From ea30a92a4674eab955aee7bb8a017791f0e7d002 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 6 Oct 2019 09:34:49 +0300 Subject: mlxsw: hwmon: Provide optimization for QSFP modules number detection Use new field "num_of_modules" of MGPIR register for "hwmon" interface in order to get the number of modules supported by system directly from the system configuration, instead of getting it from port to module mapping info. Reading this info through MGPIR register is faster and does not depend on possible dynamic re-configuration of ports. In case of port dynamic re-configuration some modules can logically "disappear" as a result of port split and un-spilt operations, which can cause missing of some modules, in case this info is taken from port to module mapping info. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 64 +++++++++++------------- 1 file changed, 29 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c index 69c192839bf9..9bf8da5f6daf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c @@ -41,7 +41,7 @@ struct mlxsw_hwmon { struct mlxsw_hwmon_attr hwmon_attrs[MLXSW_HWMON_ATTR_COUNT]; unsigned int attrs_count; u8 sensor_count; - u8 module_sensor_count; + u8 module_sensor_max; }; static ssize_t mlxsw_hwmon_temp_show(struct device *dev, @@ -56,7 +56,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, int err; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -79,7 +79,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, int err; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -109,7 +109,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, return -EINVAL; index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, - mlxsw_hwmon->module_sensor_count); + mlxsw_hwmon->module_sensor_max); mlxsw_reg_mtmp_pack(mtmp_pl, index, true, true); err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); if (err) { @@ -336,7 +336,7 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, container_of(attr, struct mlxsw_hwmon_attr, dev_attr); struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; int index = mlwsw_hwmon_attr->type_index - - mlxsw_hwmon->module_sensor_count + 1; + mlxsw_hwmon->module_sensor_max + 1; return sprintf(buf, "gearbox %03u\n", index); } @@ -528,51 +528,45 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) { - unsigned int module_count = mlxsw_core_max_ports(mlxsw_hwmon->core); - char pmlp_pl[MLXSW_REG_PMLP_LEN] = {0}; - int i, index; - u8 width; - int err; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 module_sensor_max; + int i, err; if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) return 0; + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, + &module_sensor_max); + /* Add extra attributes for module temperature. Sensor index is * assigned to sensor_count value, while all indexed before * sensor_count are already utilized by the sensors connected through * mtmp register by mlxsw_hwmon_temp_init(). */ - index = mlxsw_hwmon->sensor_count; - for (i = 1; i < module_count; i++) { - mlxsw_reg_pmlp_pack(pmlp_pl, i); - err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(pmlp), - pmlp_pl); - if (err) { - dev_err(mlxsw_hwmon->bus_info->dev, "Failed to read module index %d\n", - i); - return err; - } - width = mlxsw_reg_pmlp_width_get(pmlp_pl); - if (!width) - continue; + mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count + + module_sensor_max; + for (i = mlxsw_hwmon->sensor_count; + i < mlxsw_hwmon->module_sensor_max; i++) { mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, index, - index); + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, - index, index); + i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, - MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, - index, index); + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, + i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, - index, index); + i, i); mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, - index, index); - index++; + i, i); } - mlxsw_hwmon->module_sensor_count = index; return 0; } @@ -594,10 +588,10 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) if (!gbox_num) return 0; - index = mlxsw_hwmon->module_sensor_count; - max_index = mlxsw_hwmon->module_sensor_count + gbox_num; + index = mlxsw_hwmon->module_sensor_max; + max_index = mlxsw_hwmon->module_sensor_max + gbox_num; while (index < max_index) { - sensor_index = index % mlxsw_hwmon->module_sensor_count + + sensor_index = index % mlxsw_hwmon->module_sensor_max + MLXSW_REG_MTMP_GBOX_INDEX_MIN; mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); err = mlxsw_reg_write(mlxsw_hwmon->core, -- cgit v1.2.3-59-g8ed1b From c5cb92d59b30229e22c286651640f55621586e84 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 6 Oct 2019 09:34:50 +0300 Subject: mlxsw: thermal: Provide optimization for QSFP modules number detection Use new field "num_of_modules" of MGPIR register for "thermal" interface in order to get the number of modules supported by system directly from the system configuration, instead of getting it from port to module mapping info. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 37 ++++++++++------------ 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c index b2c76a95f671..c721b171bd8d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c @@ -112,6 +112,7 @@ struct mlxsw_thermal { struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; enum thermal_device_mode mode; struct mlxsw_thermal_module *tz_module_arr; + u8 tz_module_num; struct mlxsw_thermal_module *tz_gearbox_arr; u8 tz_gearbox_num; unsigned int tz_highest_score; @@ -775,23 +776,10 @@ static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) static int mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, - struct mlxsw_thermal *thermal, u8 local_port) + struct mlxsw_thermal *thermal, u8 module) { struct mlxsw_thermal_module *module_tz; - char pmlp_pl[MLXSW_REG_PMLP_LEN]; - u8 width, module; - int err; - - mlxsw_reg_pmlp_pack(pmlp_pl, local_port); - err = mlxsw_reg_query(core, MLXSW_REG(pmlp), pmlp_pl); - if (err) - return err; - width = mlxsw_reg_pmlp_width_get(pmlp_pl); - if (!width) - return 0; - - module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); module_tz = &thermal->tz_module_arr[module]; /* Skip if parent is already set (case of port split). */ if (module_tz->parent) @@ -819,26 +807,34 @@ static int mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, struct mlxsw_thermal *thermal) { - unsigned int module_count = mlxsw_core_max_ports(core); struct mlxsw_thermal_module *module_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; int i, err; if (!mlxsw_core_res_query_enabled(core)) return 0; - thermal->tz_module_arr = kcalloc(module_count, + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, + &thermal->tz_module_num); + + thermal->tz_module_arr = kcalloc(thermal->tz_module_num, sizeof(*thermal->tz_module_arr), GFP_KERNEL); if (!thermal->tz_module_arr) return -ENOMEM; - for (i = 1; i < module_count; i++) { + for (i = 0; i < thermal->tz_module_num; i++) { err = mlxsw_thermal_module_init(dev, core, thermal, i); if (err) goto err_unreg_tz_module_arr; } - for (i = 0; i < module_count - 1; i++) { + for (i = 0; i < thermal->tz_module_num; i++) { module_tz = &thermal->tz_module_arr[i]; if (!module_tz->parent) continue; @@ -850,7 +846,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, return 0; err_unreg_tz_module_arr: - for (i = module_count - 1; i >= 0; i--) + for (i = thermal->tz_module_num - 1; i >= 0; i--) mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); kfree(thermal->tz_module_arr); return err; @@ -859,13 +855,12 @@ err_unreg_tz_module_arr: static void mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) { - unsigned int module_count = mlxsw_core_max_ports(thermal->core); int i; if (!mlxsw_core_res_query_enabled(thermal->core)) return; - for (i = module_count - 1; i >= 0; i--) + for (i = thermal->tz_module_num - 1; i >= 0; i--) mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); kfree(thermal->tz_module_arr); } -- cgit v1.2.3-59-g8ed1b From 762effaad63edca1d927bd6c98f21b870ee3f2a5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 6 Oct 2019 09:34:51 +0300 Subject: mlxsw: core: Push minor/subminor fw version check into helper Add new API for FW "minor" and "subminor" version validation for sharing it between "spectrum" and "minimal" drivers. Use it in "spectrum" driver. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 10 ++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 5 +++++ drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 +--- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 1c29522a2af3..2b59f84b14f9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -127,6 +127,16 @@ bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) } EXPORT_SYMBOL(mlxsw_core_res_query_enabled); +bool +mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + const struct mlxsw_fw_rev *req_rev) +{ + return rev->minor > req_rev->minor || + (rev->minor == req_rev->minor && + rev->subminor >= req_rev->subminor); +} +EXPORT_SYMBOL(mlxsw_core_fw_rev_minor_subminor_validate); + struct mlxsw_rx_listener_item { struct list_head list; struct mlxsw_rx_listener rxl; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 3377a1b39b03..f25037074e2d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -24,6 +24,7 @@ struct mlxsw_core_port; struct mlxsw_driver; struct mlxsw_bus; struct mlxsw_bus_info; +struct mlxsw_fw_rev; unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); @@ -31,6 +32,10 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); +bool +mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + const struct mlxsw_fw_rev *req_rev); + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index c91b8238c8c5..3c5154e559b2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -409,9 +409,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp) } if (MLXSW_SP_FWREV_MINOR_TO_BRANCH(rev->minor) == MLXSW_SP_FWREV_MINOR_TO_BRANCH(req_rev->minor) && - (rev->minor > req_rev->minor || - (rev->minor == req_rev->minor && - rev->subminor >= req_rev->subminor))) + mlxsw_core_fw_rev_minor_subminor_validate(rev, req_rev)) return 0; dev_info(mlxsw_sp->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver\n", -- cgit v1.2.3-59-g8ed1b From 6935af8073a02ffd11a7e495dc318c0a51e18012 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 6 Oct 2019 09:34:52 +0300 Subject: mlxsw: minimal: Add validation for FW version Add validation for FW version in order to prevent driver initialization in case FW version is older than expected. FW version validation is necessary, because use of a new field 'num_of_modules' in MGPIR register is not backward compatible. FW 'minor' and 'subminor' versions are expected to be greater than or equal to 2000 and 1886, respectively. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/minimal.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 5edd8de57a24..2b543911ae00 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -16,6 +16,14 @@ static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; +#define MLXSW_M_FWREV_MINOR 2000 +#define MLXSW_M_FWREV_SUBMINOR 1886 + +static const struct mlxsw_fw_rev mlxsw_m_fw_rev = { + .minor = MLXSW_M_FWREV_MINOR, + .subminor = MLXSW_M_FWREV_SUBMINOR, +}; + struct mlxsw_m_port; struct mlxsw_m { @@ -326,6 +334,24 @@ static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) kfree(mlxsw_m->ports); } +static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) +{ + const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; + + /* Validate driver and FW are compatible. + * Do not check major version, since it defines chip type, while + * driver is supposed to support any type. + */ + if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev)) + return 0; + + dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", + rev->major, rev->minor, rev->subminor, rev->major, + mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor); + + return -EINVAL; +} + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, const struct mlxsw_bus_info *mlxsw_bus_info, struct netlink_ext_ack *extack) @@ -336,6 +362,10 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, mlxsw_m->core = mlxsw_core; mlxsw_m->bus_info = mlxsw_bus_info; + err = mlxsw_m_fw_rev_validate(mlxsw_m); + if (err) + return err; + err = mlxsw_m_base_mac_get(mlxsw_m); if (err) { dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); -- cgit v1.2.3-59-g8ed1b From 59d55789def92c504784295be7980d5e63c90896 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sun, 6 Oct 2019 18:50:07 +0800 Subject: net: dsa: ksz9477: fix platform_no_drv_owner.cocci warning Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/dsa/microchip/ksz9477_i2c.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index 0b1e01f0873d..b0a1595d780d 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -85,7 +85,6 @@ MODULE_DEVICE_TABLE(of, ksz9477_dt_ids); static struct i2c_driver ksz9477_i2c_driver = { .driver = { .name = "ksz9477-switch", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ksz9477_dt_ids), }, .probe = ksz9477_i2c_probe, -- cgit v1.2.3-59-g8ed1b From c7ab0b8088d7f023f543013963f23aecc7e47efb Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Sun, 6 Oct 2019 13:17:12 +0200 Subject: net: stmmac: Fallback to VLAN Perfect filtering if HASH is not available If VLAN Hash Filtering is not available we can fallback to perfect filtering instead. Let's implement this in XGMAC and GMAC cores and let the user use this filter. VLAN VID=0 always passes filter so we check if more than 2 VLANs are created and return proper error code if so because perfect filtering only supports 1 VID at a time. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 12 +++++++++++- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 17 ++++++++++++++++- drivers/net/ethernet/stmicro/stmmac/hwif.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 18 ++++++++++++------ 4 files changed, 40 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 2cb9c53f93b8..2eadfb124fc7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -733,7 +733,7 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable) } static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash, - bool is_double) + u16 perfect_match, bool is_double) { void __iomem *ioaddr = hw->pcsr; @@ -748,6 +748,16 @@ static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash, } writel(value, ioaddr + GMAC_VLAN_TAG); + } else if (perfect_match) { + u32 value = GMAC_VLAN_ETV; + + if (is_double) { + value |= GMAC_VLAN_EDVLP; + value |= GMAC_VLAN_ESVL; + value |= GMAC_VLAN_DOVLTC; + } + + writel(value | perfect_match, ioaddr + GMAC_VLAN_TAG); } else { u32 value = readl(ioaddr + GMAC_VLAN_TAG); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 5031398e612c..5cda360d5d07 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -555,7 +555,7 @@ static int dwxgmac2_rss_configure(struct mac_device_info *hw, } static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash, - bool is_double) + u16 perfect_match, bool is_double) { void __iomem *ioaddr = hw->pcsr; @@ -576,6 +576,21 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash, } writel(value, ioaddr + XGMAC_VLAN_TAG); + } else if (perfect_match) { + u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); + + value |= XGMAC_FILTER_VTFE; + + writel(value, ioaddr + XGMAC_PACKET_FILTER); + + value = XGMAC_VLAN_ETV; + if (is_double) { + value |= XGMAC_VLAN_EDVLP; + value |= XGMAC_VLAN_ESVL; + value |= XGMAC_VLAN_DOVLTC; + } + + writel(value | perfect_match, ioaddr + XGMAC_VLAN_TAG); } else { u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index ddb851d99618..1303d1e9a18f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -357,7 +357,7 @@ struct stmmac_ops { struct stmmac_rss *cfg, u32 num_rxq); /* VLAN */ void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, - bool is_double); + u16 perfect_match, bool is_double); void (*enable_vlan)(struct mac_device_info *hw, u32 type); /* TX Timestamp */ int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b8ac1744950e..8b76745a7ec4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4207,15 +4207,25 @@ static u32 stmmac_vid_crc32_le(__le16 vid_le) static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double) { u32 crc, hash = 0; - u16 vid; + int count = 0; + u16 vid = 0; for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) { __le16 vid_le = cpu_to_le16(vid); crc = bitrev32(~stmmac_vid_crc32_le(vid_le)) >> 28; hash |= (1 << crc); + count++; + } + + if (!priv->dma_cap.vlhash) { + if (count > 2) /* VID = 0 always passes filter */ + return -EOPNOTSUPP; + + vid = cpu_to_le16(vid); + hash = 0; } - return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double); + return stmmac_update_vlan_hash(priv, priv->hw, hash, vid, is_double); } static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) @@ -4224,8 +4234,6 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid bool is_double = false; int ret; - if (!priv->dma_cap.vlhash) - return -EOPNOTSUPP; if (be16_to_cpu(proto) == ETH_P_8021AD) is_double = true; @@ -4244,8 +4252,6 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi struct stmmac_priv *priv = netdev_priv(ndev); bool is_double = false; - if (!priv->dma_cap.vlhash) - return -EOPNOTSUPP; if (be16_to_cpu(proto) == ETH_P_8021AD) is_double = true; -- cgit v1.2.3-59-g8ed1b From 1b2250a04c1f85253bd593bf28ddb48d396da7c6 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Sun, 6 Oct 2019 13:17:13 +0200 Subject: net: stmmac: selftests: Add tests for VLAN Perfect Filtering Add two new tests for VLAN Perfect Filtering. While at it, increase a little bit the tests strings lenght so that we can have more descriptive test names. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/stmmac_selftests.c | 114 ++++++++++++++------- 1 file changed, 77 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c index cc76a42c7466..68c59cfb8f70 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c @@ -816,16 +816,13 @@ out: return 0; } -static int stmmac_test_vlanfilt(struct stmmac_priv *priv) +static int __stmmac_test_vlanfilt(struct stmmac_priv *priv) { struct stmmac_packet_attrs attr = { }; struct stmmac_test_priv *tpriv; struct sk_buff *skb = NULL; int ret = 0, i; - if (!priv->dma_cap.vlhash) - return -EOPNOTSUPP; - tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); if (!tpriv) return -ENOMEM; @@ -891,16 +888,32 @@ cleanup: return ret; } -static int stmmac_test_dvlanfilt(struct stmmac_priv *priv) +static int stmmac_test_vlanfilt(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.vlhash) + return -EOPNOTSUPP; + + return __stmmac_test_vlanfilt(priv); +} + +static int stmmac_test_vlanfilt_perfect(struct stmmac_priv *priv) +{ + int ret, prev_cap = priv->dma_cap.vlhash; + + priv->dma_cap.vlhash = 0; + ret = __stmmac_test_vlanfilt(priv); + priv->dma_cap.vlhash = prev_cap; + + return ret; +} + +static int __stmmac_test_dvlanfilt(struct stmmac_priv *priv) { struct stmmac_packet_attrs attr = { }; struct stmmac_test_priv *tpriv; struct sk_buff *skb = NULL; int ret = 0, i; - if (!priv->dma_cap.vlhash) - return -EOPNOTSUPP; - tpriv = kzalloc(sizeof(*tpriv), GFP_KERNEL); if (!tpriv) return -ENOMEM; @@ -967,6 +980,25 @@ cleanup: return ret; } +static int stmmac_test_dvlanfilt(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.vlhash) + return -EOPNOTSUPP; + + return __stmmac_test_dvlanfilt(priv); +} + +static int stmmac_test_dvlanfilt_perfect(struct stmmac_priv *priv) +{ + int ret, prev_cap = priv->dma_cap.vlhash; + + priv->dma_cap.vlhash = 0; + ret = __stmmac_test_dvlanfilt(priv); + priv->dma_cap.vlhash = prev_cap; + + return ret; +} + #ifdef CONFIG_NET_CLS_ACT static int stmmac_test_rxp(struct stmmac_priv *priv) { @@ -1641,119 +1673,127 @@ static const struct stmmac_test { int (*fn)(struct stmmac_priv *priv); } stmmac_selftests[] = { { - .name = "MAC Loopback ", + .name = "MAC Loopback ", .lb = STMMAC_LOOPBACK_MAC, .fn = stmmac_test_mac_loopback, }, { - .name = "PHY Loopback ", + .name = "PHY Loopback ", .lb = STMMAC_LOOPBACK_NONE, /* Test will handle it */ .fn = stmmac_test_phy_loopback, }, { - .name = "MMC Counters ", + .name = "MMC Counters ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_mmc, }, { - .name = "EEE ", + .name = "EEE ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_eee, }, { - .name = "Hash Filter MC ", + .name = "Hash Filter MC ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_hfilt, }, { - .name = "Perfect Filter UC ", + .name = "Perfect Filter UC ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_pfilt, }, { - .name = "MC Filter ", + .name = "MC Filter ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_mcfilt, }, { - .name = "UC Filter ", + .name = "UC Filter ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_ucfilt, }, { - .name = "Flow Control ", + .name = "Flow Control ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_flowctrl, }, { - .name = "RSS ", + .name = "RSS ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_rss, }, { - .name = "VLAN Filtering ", + .name = "VLAN Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_vlanfilt, }, { - .name = "Double VLAN Filtering", + .name = "VLAN Filtering (perf) ", + .lb = STMMAC_LOOPBACK_PHY, + .fn = stmmac_test_vlanfilt_perfect, + }, { + .name = "Double VLAN Filter ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_dvlanfilt, }, { - .name = "Flexible RX Parser ", + .name = "Double VLAN Filter (perf) ", + .lb = STMMAC_LOOPBACK_PHY, + .fn = stmmac_test_dvlanfilt_perfect, + }, { + .name = "Flexible RX Parser ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_rxp, }, { - .name = "SA Insertion (desc) ", + .name = "SA Insertion (desc) ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_desc_sai, }, { - .name = "SA Replacement (desc)", + .name = "SA Replacement (desc) ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_desc_sar, }, { - .name = "SA Insertion (reg) ", + .name = "SA Insertion (reg) ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_reg_sai, }, { - .name = "SA Replacement (reg)", + .name = "SA Replacement (reg) ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_reg_sar, }, { - .name = "VLAN TX Insertion ", + .name = "VLAN TX Insertion ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_vlanoff, }, { - .name = "SVLAN TX Insertion ", + .name = "SVLAN TX Insertion ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_svlanoff, }, { - .name = "L3 DA Filtering ", + .name = "L3 DA Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l3filt_da, }, { - .name = "L3 SA Filtering ", + .name = "L3 SA Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l3filt_sa, }, { - .name = "L4 DA TCP Filtering ", + .name = "L4 DA TCP Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l4filt_da_tcp, }, { - .name = "L4 SA TCP Filtering ", + .name = "L4 SA TCP Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l4filt_sa_tcp, }, { - .name = "L4 DA UDP Filtering ", + .name = "L4 DA UDP Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l4filt_da_udp, }, { - .name = "L4 SA UDP Filtering ", + .name = "L4 SA UDP Filtering ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_l4filt_sa_udp, }, { - .name = "ARP Offload ", + .name = "ARP Offload ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_arpoffload, }, { - .name = "Jumbo Frame ", + .name = "Jumbo Frame ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_jumbo, }, { - .name = "Multichannel Jumbo ", + .name = "Multichannel Jumbo ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_mjumbo, }, { - .name = "Split Header ", + .name = "Split Header ", .lb = STMMAC_LOOPBACK_PHY, .fn = stmmac_test_sph, }, -- cgit v1.2.3-59-g8ed1b From dc07f5fdef9bbd6981800904551d86c8ffc3c993 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Sun, 6 Oct 2019 13:17:14 +0200 Subject: net: stmmac: Implement L3/L4 Filters in GMAC4+ GMAC4+ cores support Layer 3 and Layer 4 filtering. Add the corresponding callbacks in these cores. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 21 +++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 106 ++++++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 1 + 3 files changed, 128 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 2fe45fa3c482..07e97f45755d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -43,6 +43,10 @@ #define GMAC_ARP_ADDR 0x00000210 #define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) #define GMAC_ADDR_LOW(reg) (0x304 + reg * 8) +#define GMAC_L3L4_CTRL(reg) (0x900 + (reg) * 0x30) +#define GMAC_L4_ADDR(reg) (0x904 + (reg) * 0x30) +#define GMAC_L3_ADDR0(reg) (0x910 + (reg) * 0x30) +#define GMAC_L3_ADDR1(reg) (0x914 + (reg) * 0x30) /* RX Queues Routing */ #define GMAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0) @@ -67,6 +71,7 @@ #define GMAC_PACKET_FILTER_PCF BIT(7) #define GMAC_PACKET_FILTER_HPF BIT(10) #define GMAC_PACKET_FILTER_VTFE BIT(16) +#define GMAC_PACKET_FILTER_IPFE BIT(20) #define GMAC_MAX_PERFECT_ADDRESSES 128 @@ -202,6 +207,7 @@ enum power_event { #define GMAC_HW_FEAT_MIISEL BIT(0) /* MAC HW features1 bitmap */ +#define GMAC_HW_FEAT_L3L4FNUM GENMASK(30, 27) #define GMAC_HW_HASH_TB_SZ GENMASK(25, 24) #define GMAC_HW_FEAT_AVSEL BIT(20) #define GMAC_HW_TSOEN BIT(18) @@ -228,6 +234,21 @@ enum power_event { #define GMAC_HI_DCS_SHIFT 16 #define GMAC_HI_REG_AE BIT(31) +/* L3/L4 Filters regs */ +#define GMAC_L4DPIM0 BIT(21) +#define GMAC_L4DPM0 BIT(20) +#define GMAC_L4SPIM0 BIT(19) +#define GMAC_L4SPM0 BIT(18) +#define GMAC_L4PEN0 BIT(16) +#define GMAC_L3DAIM0 BIT(5) +#define GMAC_L3DAM0 BIT(4) +#define GMAC_L3SAIM0 BIT(3) +#define GMAC_L3SAM0 BIT(2) +#define GMAC_L3PEN0 BIT(0) +#define GMAC_L4DP0 GENMASK(31, 16) +#define GMAC_L4DP0_SHIFT 16 +#define GMAC_L4SP0 GENMASK(15, 0) + /* MTL registers */ #define MTL_OPERATION_MODE 0x00000c00 #define MTL_FRPE BIT(15) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 2eadfb124fc7..df11376ee735 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -809,6 +809,106 @@ static void dwmac4_set_arp_offload(struct mac_device_info *hw, bool en, writel(value, ioaddr + GMAC_CONFIG); } +static int dwmac4_config_l3_filter(struct mac_device_info *hw, u32 filter_no, + bool en, bool ipv6, bool sa, bool inv, + u32 match) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + value = readl(ioaddr + GMAC_PACKET_FILTER); + value |= GMAC_PACKET_FILTER_IPFE; + writel(value, ioaddr + GMAC_PACKET_FILTER); + + value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no)); + + /* For IPv6 not both SA/DA filters can be active */ + if (ipv6) { + value |= GMAC_L3PEN0; + value &= ~(GMAC_L3SAM0 | GMAC_L3SAIM0); + value &= ~(GMAC_L3DAM0 | GMAC_L3DAIM0); + if (sa) { + value |= GMAC_L3SAM0; + if (inv) + value |= GMAC_L3SAIM0; + } else { + value |= GMAC_L3DAM0; + if (inv) + value |= GMAC_L3DAIM0; + } + } else { + value &= ~GMAC_L3PEN0; + if (sa) { + value |= GMAC_L3SAM0; + if (inv) + value |= GMAC_L3SAIM0; + } else { + value |= GMAC_L3DAM0; + if (inv) + value |= GMAC_L3DAIM0; + } + } + + writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no)); + + if (sa) { + writel(match, ioaddr + GMAC_L3_ADDR0(filter_no)); + } else { + writel(match, ioaddr + GMAC_L3_ADDR1(filter_no)); + } + + if (!en) + writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no)); + + return 0; +} + +static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, + bool en, bool udp, bool sa, bool inv, + u32 match) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + value = readl(ioaddr + GMAC_PACKET_FILTER); + value |= GMAC_PACKET_FILTER_IPFE; + writel(value, ioaddr + GMAC_PACKET_FILTER); + + value = readl(ioaddr + GMAC_L3L4_CTRL(filter_no)); + if (udp) { + value |= GMAC_L4PEN0; + } else { + value &= ~GMAC_L4PEN0; + } + + value &= ~(GMAC_L4SPM0 | GMAC_L4SPIM0); + value &= ~(GMAC_L4DPM0 | GMAC_L4DPIM0); + if (sa) { + value |= GMAC_L4SPM0; + if (inv) + value |= GMAC_L4SPIM0; + } else { + value |= GMAC_L4DPM0; + if (inv) + value |= GMAC_L4DPIM0; + } + + writel(value, ioaddr + GMAC_L3L4_CTRL(filter_no)); + + if (sa) { + value = match & GMAC_L4SP0; + } else { + value = (match << GMAC_L4DP0_SHIFT) & GMAC_L4DP0; + } + + writel(value, ioaddr + GMAC_L4_ADDR(filter_no)); + + if (!en) + writel(0, ioaddr + GMAC_L3L4_CTRL(filter_no)); + + return 0; +} + const struct stmmac_ops dwmac4_ops = { .core_init = dwmac4_core_init, .set_mac = stmmac_set_mac, @@ -843,6 +943,8 @@ const struct stmmac_ops dwmac4_ops = { .sarc_configure = dwmac4_sarc_configure, .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, + .config_l3_filter = dwmac4_config_l3_filter, + .config_l4_filter = dwmac4_config_l4_filter, }; const struct stmmac_ops dwmac410_ops = { @@ -879,6 +981,8 @@ const struct stmmac_ops dwmac410_ops = { .sarc_configure = dwmac4_sarc_configure, .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, + .config_l3_filter = dwmac4_config_l3_filter, + .config_l4_filter = dwmac4_config_l4_filter, }; const struct stmmac_ops dwmac510_ops = { @@ -920,6 +1024,8 @@ const struct stmmac_ops dwmac510_ops = { .sarc_configure = dwmac4_sarc_configure, .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, + .config_l3_filter = dwmac4_config_l3_filter, + .config_l4_filter = dwmac4_config_l4_filter, }; int dwmac4_setup(struct stmmac_priv *priv) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 229059cef949..b24c89572745 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -364,6 +364,7 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr, /* MAC HW feature1 */ hw_cap = readl(ioaddr + GMAC_HW_FEATURE1); + dma_cap->l3l4fnum = (hw_cap & GMAC_HW_FEAT_L3L4FNUM) >> 27; dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24; dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20; dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18; -- cgit v1.2.3-59-g8ed1b From 8e23cc0319b185de49e35ed4fec174552bdf2f9a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 7 Oct 2019 10:27:08 +0200 Subject: netdevsim: implement devlink dev_info op Do simple dev_info devlink operation implementation which only fills up the driver name. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 31d1752c703a..a3d7d39f231a 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -510,6 +510,13 @@ static int nsim_dev_reload_up(struct devlink *devlink, return nsim_dev_reload_create(nsim_dev, extack); } +static int nsim_dev_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + return devlink_info_driver_name_put(req, DRV_NAME); +} + #define NSIM_DEV_FLASH_SIZE 500000 #define NSIM_DEV_FLASH_CHUNK_SIZE 1000 #define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 @@ -603,6 +610,7 @@ nsim_dev_devlink_trap_action_set(struct devlink *devlink, static const struct devlink_ops nsim_dev_devlink_ops = { .reload_down = nsim_dev_reload_down, .reload_up = nsim_dev_reload_up, + .info_get = nsim_dev_info_get, .flash_update = nsim_dev_flash_update, .trap_init = nsim_dev_devlink_trap_init, .trap_action_set = nsim_dev_devlink_trap_action_set, -- cgit v1.2.3-59-g8ed1b From faa615f9da5d79937756363ff0628d04b61015a1 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:23 +0300 Subject: net: ena: change num_queues to num_io_queues for clarity and consistency Most places in the code refer to the IO queues as io_queues and not simply queues. Examples - max_io_queues_per_vf, ENA_MAX_NUM_IO_QUEUES, ena_destroy_all_io_queues() etc.. We are also adding the new max_num_io_queues field to struct ena_adapter in the following commit. The changes included in this commit are: struct ena_adapter->num_queues => struct ena_adapter->num_io_queues Signed-off-by: Arthur Kiyanovski Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 20 ++++---- drivers/net/ethernet/amazon/ena/ena_netdev.c | 66 +++++++++++++-------------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 2 +- 3 files changed, 44 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 16553d92fad2..3ad661fd986c 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -133,7 +133,7 @@ static void ena_queue_stats(struct ena_adapter *adapter, u64 **data) u64 *ptr; int i, j; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { /* Tx stats */ ring = &adapter->tx_ring[i]; @@ -205,7 +205,7 @@ int ena_get_sset_count(struct net_device *netdev, int sset) if (sset != ETH_SS_STATS) return -EOPNOTSUPP; - return adapter->num_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX) + return adapter->num_io_queues * (ENA_STATS_ARRAY_TX + ENA_STATS_ARRAY_RX) + ENA_STATS_ARRAY_GLOBAL + ENA_STATS_ARRAY_ENA_COM; } @@ -214,7 +214,7 @@ static void ena_queue_strings(struct ena_adapter *adapter, u8 **data) const struct ena_stats *ena_stats; int i, j; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { /* Tx stats */ for (j = 0; j < ENA_STATS_ARRAY_TX; j++) { ena_stats = &ena_stats_tx_strings[j]; @@ -333,7 +333,7 @@ static void ena_update_tx_rings_intr_moderation(struct ena_adapter *adapter) val = ena_com_get_nonadaptive_moderation_interval_tx(adapter->ena_dev); - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) adapter->tx_ring[i].smoothed_interval = val; } @@ -344,7 +344,7 @@ static void ena_update_rx_rings_intr_moderation(struct ena_adapter *adapter) val = ena_com_get_nonadaptive_moderation_interval_rx(adapter->ena_dev); - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) adapter->rx_ring[i].smoothed_interval = val; } @@ -612,7 +612,7 @@ static int ena_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info, switch (info->cmd) { case ETHTOOL_GRXRINGS: - info->data = adapter->num_queues; + info->data = adapter->num_io_queues; rc = 0; break; case ETHTOOL_GRXFH: @@ -734,12 +734,12 @@ static void ena_get_channels(struct net_device *netdev, { struct ena_adapter *adapter = netdev_priv(netdev); - channels->max_rx = adapter->num_queues; - channels->max_tx = adapter->num_queues; + channels->max_rx = adapter->num_io_queues; + channels->max_tx = adapter->num_io_queues; channels->max_other = 0; channels->max_combined = 0; - channels->rx_count = adapter->num_queues; - channels->tx_count = adapter->num_queues; + channels->rx_count = adapter->num_io_queues; + channels->tx_count = adapter->num_io_queues; channels->other_count = 0; channels->combined_count = 0; } diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index c487d2a7d6dd..c18d5bce8fbb 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -101,7 +101,7 @@ static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) adapter->rx_ring[i].mtu = mtu; } @@ -129,10 +129,10 @@ static int ena_init_rx_cpu_rmap(struct ena_adapter *adapter) u32 i; int rc; - adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_queues); + adapter->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(adapter->num_io_queues); if (!adapter->netdev->rx_cpu_rmap) return -ENOMEM; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { int irq_idx = ENA_IO_IRQ_IDX(i); rc = irq_cpu_rmap_add(adapter->netdev->rx_cpu_rmap, @@ -172,7 +172,7 @@ static void ena_init_io_rings(struct ena_adapter *adapter) ena_dev = adapter->ena_dev; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { txr = &adapter->tx_ring[i]; rxr = &adapter->rx_ring[i]; @@ -294,7 +294,7 @@ static int ena_setup_all_tx_resources(struct ena_adapter *adapter) { int i, rc = 0; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rc = ena_setup_tx_resources(adapter, i); if (rc) goto err_setup_tx; @@ -322,7 +322,7 @@ static void ena_free_all_io_tx_resources(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) ena_free_tx_resources(adapter, i); } @@ -428,7 +428,7 @@ static int ena_setup_all_rx_resources(struct ena_adapter *adapter) { int i, rc = 0; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rc = ena_setup_rx_resources(adapter, i); if (rc) goto err_setup_rx; @@ -456,7 +456,7 @@ static void ena_free_all_io_rx_resources(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) ena_free_rx_resources(adapter, i); } @@ -600,7 +600,7 @@ static void ena_refill_all_rx_bufs(struct ena_adapter *adapter) struct ena_ring *rx_ring; int i, rc, bufs_num; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rx_ring = &adapter->rx_ring[i]; bufs_num = rx_ring->ring_size - 1; rc = ena_refill_rx_bufs(rx_ring, bufs_num); @@ -616,7 +616,7 @@ static void ena_free_all_rx_bufs(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) ena_free_rx_bufs(adapter, i); } @@ -688,7 +688,7 @@ static void ena_free_all_tx_bufs(struct ena_adapter *adapter) struct ena_ring *tx_ring; int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { tx_ring = &adapter->tx_ring[i]; ena_free_tx_bufs(tx_ring); } @@ -699,7 +699,7 @@ static void ena_destroy_all_tx_queues(struct ena_adapter *adapter) u16 ena_qid; int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { ena_qid = ENA_IO_TXQ_IDX(i); ena_com_destroy_io_queue(adapter->ena_dev, ena_qid); } @@ -710,7 +710,7 @@ static void ena_destroy_all_rx_queues(struct ena_adapter *adapter) u16 ena_qid; int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { ena_qid = ENA_IO_RXQ_IDX(i); cancel_work_sync(&adapter->ena_napi[i].dim.work); ena_com_destroy_io_queue(adapter->ena_dev, ena_qid); @@ -1359,7 +1359,7 @@ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) netif_notice(adapter, probe, adapter->netdev, "enable only %d MSI-X (out of %d), reduce the number of queues\n", irq_cnt, msix_vecs); - adapter->num_queues = irq_cnt - ENA_ADMIN_MSIX_VEC; + adapter->num_io_queues = irq_cnt - ENA_ADMIN_MSIX_VEC; } if (ena_init_rx_cpu_rmap(adapter)) @@ -1397,7 +1397,7 @@ static void ena_setup_io_intr(struct ena_adapter *adapter) netdev = adapter->netdev; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { irq_idx = ENA_IO_IRQ_IDX(i); cpu = i % num_online_cpus(); @@ -1529,7 +1529,7 @@ static void ena_del_napi(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) netif_napi_del(&adapter->ena_napi[i].napi); } @@ -1538,7 +1538,7 @@ static void ena_init_napi(struct ena_adapter *adapter) struct ena_napi *napi; int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { napi = &adapter->ena_napi[i]; netif_napi_add(adapter->netdev, @@ -1555,7 +1555,7 @@ static void ena_napi_disable_all(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) napi_disable(&adapter->ena_napi[i].napi); } @@ -1563,7 +1563,7 @@ static void ena_napi_enable_all(struct ena_adapter *adapter) { int i; - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) napi_enable(&adapter->ena_napi[i].napi); } @@ -1673,7 +1673,7 @@ static int ena_create_all_io_tx_queues(struct ena_adapter *adapter) struct ena_com_dev *ena_dev = adapter->ena_dev; int rc, i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rc = ena_create_io_tx_queue(adapter, i); if (rc) goto create_err; @@ -1741,7 +1741,7 @@ static int ena_create_all_io_rx_queues(struct ena_adapter *adapter) struct ena_com_dev *ena_dev = adapter->ena_dev; int rc, i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rc = ena_create_io_rx_queue(adapter, i); if (rc) goto create_err; @@ -1764,7 +1764,7 @@ static void set_io_rings_size(struct ena_adapter *adapter, { int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { adapter->tx_ring[i].ring_size = new_tx_size; adapter->rx_ring[i].ring_size = new_rx_size; } @@ -1902,14 +1902,14 @@ static int ena_up(struct ena_adapter *adapter) set_bit(ENA_FLAG_DEV_UP, &adapter->flags); /* Enable completion queues interrupt */ - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) ena_unmask_interrupt(&adapter->tx_ring[i], &adapter->rx_ring[i]); /* schedule napi in case we had pending packets * from the last time we disable napi */ - for (i = 0; i < adapter->num_queues; i++) + for (i = 0; i < adapter->num_io_queues; i++) napi_schedule(&adapter->ena_napi[i].napi); return rc; @@ -1984,13 +1984,13 @@ static int ena_open(struct net_device *netdev) int rc; /* Notify the stack of the actual queue counts. */ - rc = netif_set_real_num_tx_queues(netdev, adapter->num_queues); + rc = netif_set_real_num_tx_queues(netdev, adapter->num_io_queues); if (rc) { netif_err(adapter, ifup, netdev, "Can't set num tx queues\n"); return rc; } - rc = netif_set_real_num_rx_queues(netdev, adapter->num_queues); + rc = netif_set_real_num_rx_queues(netdev, adapter->num_io_queues); if (rc) { netif_err(adapter, ifup, netdev, "Can't set num rx queues\n"); return rc; @@ -2495,7 +2495,7 @@ static void ena_get_stats64(struct net_device *netdev, if (!test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) return; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { u64 bytes, packets; tx_ring = &adapter->tx_ring[i]; @@ -2783,7 +2783,7 @@ static int ena_restore_device(struct ena_adapter *adapter) } rc = ena_enable_msix_and_set_admin_interrupts(adapter, - adapter->num_queues); + adapter->num_io_queues); if (rc) { dev_err(&pdev->dev, "Enable MSI-X failed\n"); goto err_device_destroy; @@ -2948,7 +2948,7 @@ static void check_for_missing_completions(struct ena_adapter *adapter) budget = ENA_MONITORED_TX_QUEUES; - for (i = adapter->last_monitored_tx_qid; i < adapter->num_queues; i++) { + for (i = adapter->last_monitored_tx_qid; i < adapter->num_io_queues; i++) { tx_ring = &adapter->tx_ring[i]; rx_ring = &adapter->rx_ring[i]; @@ -2965,7 +2965,7 @@ static void check_for_missing_completions(struct ena_adapter *adapter) break; } - adapter->last_monitored_tx_qid = i % adapter->num_queues; + adapter->last_monitored_tx_qid = i % adapter->num_io_queues; } /* trigger napi schedule after 2 consecutive detections */ @@ -2995,7 +2995,7 @@ static void check_for_empty_rx_ring(struct ena_adapter *adapter) if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) return; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_io_queues; i++) { rx_ring = &adapter->rx_ring[i]; refill_required = @@ -3302,7 +3302,7 @@ static int ena_rss_init_default(struct ena_adapter *adapter) } for (i = 0; i < ENA_RX_RSS_TABLE_SIZE; i++) { - val = ethtool_rxfh_indir_default(i, adapter->num_queues); + val = ethtool_rxfh_indir_default(i, adapter->num_io_queues); rc = ena_com_indirect_table_fill_entry(ena_dev, i, ENA_IO_RXQ_IDX(val)); if (unlikely(rc && (rc != -EOPNOTSUPP))) { @@ -3545,7 +3545,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size; adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size; - adapter->num_queues = io_queue_num; + adapter->num_io_queues = io_queue_num; adapter->last_monitored_tx_qid = 0; adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 72ee51a82ec7..7e8e51e323e9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -324,7 +324,7 @@ struct ena_adapter { u32 rx_copybreak; u32 max_mtu; - int num_queues; + int num_io_queues; int msix_vecs; -- cgit v1.2.3-59-g8ed1b From 4d19266022ec4814add8d5f02f49cb493294c674 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:24 +0300 Subject: net: ena: multiple queue creation related cleanups - Rename ena_calc_queue_size() to ena_calc_io_queue_size() for clarity and consistency - Remove redundant number of io queues parameter in functions ena_enable_msix() and ena_enable_msix_and_set_admin_interrupts(), which already get adapter parameter, so use adapter->num_io_queues in the function instead. - Use the local variable ena_dev instead of ctx->ena_dev in ena_calc_io_queue_size - Fix multi row comment alignments Signed-off-by: Arthur Kiyanovski Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 31 ++++++++++------------------ 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index c18d5bce8fbb..a4e95fe2b6e5 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1331,7 +1331,7 @@ static irqreturn_t ena_intr_msix_io(int irq, void *data) * the number of potential io queues is the minimum of what the device * supports and the number of vCPUs. */ -static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) +static int ena_enable_msix(struct ena_adapter *adapter) { int msix_vecs, irq_cnt; @@ -1342,7 +1342,7 @@ static int ena_enable_msix(struct ena_adapter *adapter, int num_queues) } /* Reserved the max msix vectors we might need */ - msix_vecs = ENA_MAX_MSIX_VEC(num_queues); + msix_vecs = ENA_MAX_MSIX_VEC(adapter->num_io_queues); netif_dbg(adapter, probe, adapter->netdev, "trying to enable MSI-X, vectors %d\n", msix_vecs); @@ -2682,14 +2682,13 @@ err_mmio_read_less: return rc; } -static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter, - int io_vectors) +static int ena_enable_msix_and_set_admin_interrupts(struct ena_adapter *adapter) { struct ena_com_dev *ena_dev = adapter->ena_dev; struct device *dev = &adapter->pdev->dev; int rc; - rc = ena_enable_msix(adapter, io_vectors); + rc = ena_enable_msix(adapter); if (rc) { dev_err(dev, "Can not reserve msix vectors\n"); return rc; @@ -2782,8 +2781,7 @@ static int ena_restore_device(struct ena_adapter *adapter) goto err_device_destroy; } - rc = ena_enable_msix_and_set_admin_interrupts(adapter, - adapter->num_io_queues); + rc = ena_enable_msix_and_set_admin_interrupts(adapter); if (rc) { dev_err(&pdev->dev, "Enable MSI-X failed\n"); goto err_device_destroy; @@ -3349,7 +3347,7 @@ static void set_default_llq_configurations(struct ena_llq_configurations *llq_co llq_config->llq_ring_entry_size_value = 128; } -static int ena_calc_queue_size(struct ena_calc_queue_size_ctx *ctx) +static int ena_calc_io_queue_size(struct ena_calc_queue_size_ctx *ctx) { struct ena_admin_feature_llq_desc *llq = &ctx->get_feat_ctx->llq; struct ena_com_dev *ena_dev = ctx->ena_dev; @@ -3358,7 +3356,7 @@ static int ena_calc_queue_size(struct ena_calc_queue_size_ctx *ctx) u32 max_tx_queue_size; u32 max_rx_queue_size; - if (ctx->ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) { + if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) { struct ena_admin_queue_ext_feature_fields *max_queue_ext = &ctx->get_feat_ctx->max_queue_ext.max_queue_ext; max_rx_queue_size = min_t(u32, max_queue_ext->max_rx_cq_depth, @@ -3497,25 +3495,18 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) calc_queue_ctx.pdev = pdev; /* Initial Tx and RX interrupt delay. Assumes 1 usec granularity. - * Updated during device initialization with the real granularity - */ + * Updated during device initialization with the real granularity + */ ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS; ena_dev->intr_moder_rx_interval = ENA_INTR_INITIAL_RX_INTERVAL_USECS; ena_dev->intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION; io_queue_num = ena_calc_io_queue_num(pdev, ena_dev, &get_feat_ctx); - rc = ena_calc_queue_size(&calc_queue_ctx); + rc = ena_calc_io_queue_size(&calc_queue_ctx); if (rc || io_queue_num <= 0) { rc = -EFAULT; goto err_device_destroy; } - dev_info(&pdev->dev, "creating %d io queues. rx queue size: %d tx queue size. %d LLQ is %s\n", - io_queue_num, - calc_queue_ctx.rx_queue_size, - calc_queue_ctx.tx_queue_size, - (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) ? - "ENABLED" : "DISABLED"); - /* dev zeroed in init_etherdev */ netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), io_queue_num); if (!netdev) { @@ -3569,7 +3560,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u64_stats_init(&adapter->syncp); - rc = ena_enable_msix_and_set_admin_interrupts(adapter, io_queue_num); + rc = ena_enable_msix_and_set_admin_interrupts(adapter); if (rc) { dev_err(&pdev->dev, "Failed to enable and set the admin interrupts\n"); -- cgit v1.2.3-59-g8ed1b From 9a037b06137b46bea6ed2fade2537cb820c1fd7c Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:25 +0300 Subject: net: ena: ethtool: get_channels: use combined only Since we use the same IRQ and NAPI to service RX and TX then we need to use a combined channel instead of rx and tx channels. Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 3ad661fd986c..03b4ae7baf01 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -734,14 +734,8 @@ static void ena_get_channels(struct net_device *netdev, { struct ena_adapter *adapter = netdev_priv(netdev); - channels->max_rx = adapter->num_io_queues; - channels->max_tx = adapter->num_io_queues; - channels->max_other = 0; - channels->max_combined = 0; - channels->rx_count = adapter->num_io_queues; - channels->tx_count = adapter->num_io_queues; - channels->other_count = 0; - channels->combined_count = 0; + channels->max_combined = adapter->num_io_queues; + channels->combined_count = adapter->num_io_queues; } static int ena_get_tunable(struct net_device *netdev, -- cgit v1.2.3-59-g8ed1b From 736ce3f414ccc005e86bdd920e35bf4ddaa65d68 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:26 +0300 Subject: net: ena: make ethtool -l show correct max number of queues - Update ena_ethtool:ena_get_channels() to return adapter->max_io_queues so that ethtool -l returns the correct maximum queue number. - Change the name of ena_calc_io_queue_num() to ena_calc_max_io_queue_num() as it returns the maximum number of io queues and actual number of queues can be smaller if changed by ethtool -L which is implemented in a later commit. - Change variable name from io_queue_num to max_num_io_queues in ena_calc_max_io_queue_num() and ena_probe(). - Make all types of variables that convey the number and sizeof queues to be u32, for consistency with the API between the driver and the device. Signed-off-by: Arthur Kiyanovski Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 2 +- drivers/net/ethernet/amazon/ena/ena_netdev.c | 41 ++++++++++++++------------- drivers/net/ethernet/amazon/ena/ena_netdev.h | 11 +++---- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index 03b4ae7baf01..b75dafb793f7 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -734,7 +734,7 @@ static void ena_get_channels(struct net_device *netdev, { struct ena_adapter *adapter = netdev_priv(netdev); - channels->max_combined = adapter->num_io_queues; + channels->max_combined = adapter->max_num_io_queues; channels->combined_count = adapter->num_io_queues; } diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index a4e95fe2b6e5..e715681597d0 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3135,16 +3135,16 @@ static void ena_timer_service(struct timer_list *t) mod_timer(&adapter->timer_service, jiffies + HZ); } -static int ena_calc_io_queue_num(struct pci_dev *pdev, - struct ena_com_dev *ena_dev, - struct ena_com_dev_get_features_ctx *get_feat_ctx) +static int ena_calc_max_io_queue_num(struct pci_dev *pdev, + struct ena_com_dev *ena_dev, + struct ena_com_dev_get_features_ctx *get_feat_ctx) { - int io_tx_sq_num, io_tx_cq_num, io_rx_num, io_queue_num; + int io_tx_sq_num, io_tx_cq_num, io_rx_num, max_num_io_queues; if (ena_dev->supported_features & BIT(ENA_ADMIN_MAX_QUEUES_EXT)) { struct ena_admin_queue_ext_feature_fields *max_queue_ext = &get_feat_ctx->max_queue_ext.max_queue_ext; - io_rx_num = min_t(int, max_queue_ext->max_rx_sq_num, + io_rx_num = min_t(u32, max_queue_ext->max_rx_sq_num, max_queue_ext->max_rx_cq_num); io_tx_sq_num = max_queue_ext->max_tx_sq_num; @@ -3154,25 +3154,25 @@ static int ena_calc_io_queue_num(struct pci_dev *pdev, &get_feat_ctx->max_queues; io_tx_sq_num = max_queues->max_sq_num; io_tx_cq_num = max_queues->max_cq_num; - io_rx_num = min_t(int, io_tx_sq_num, io_tx_cq_num); + io_rx_num = min_t(u32, io_tx_sq_num, io_tx_cq_num); } /* In case of LLQ use the llq fields for the tx SQ/CQ */ if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) io_tx_sq_num = get_feat_ctx->llq.max_llq_num; - io_queue_num = min_t(int, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES); - io_queue_num = min_t(int, io_queue_num, io_rx_num); - io_queue_num = min_t(int, io_queue_num, io_tx_sq_num); - io_queue_num = min_t(int, io_queue_num, io_tx_cq_num); + max_num_io_queues = min_t(u32, num_online_cpus(), ENA_MAX_NUM_IO_QUEUES); + max_num_io_queues = min_t(u32, max_num_io_queues, io_rx_num); + max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_sq_num); + max_num_io_queues = min_t(u32, max_num_io_queues, io_tx_cq_num); /* 1 IRQ for for mgmnt and 1 IRQs for each IO direction */ - io_queue_num = min_t(int, io_queue_num, pci_msix_vec_count(pdev) - 1); - if (unlikely(!io_queue_num)) { + max_num_io_queues = min_t(u32, max_num_io_queues, pci_msix_vec_count(pdev) - 1); + if (unlikely(!max_num_io_queues)) { dev_err(&pdev->dev, "The device doesn't have io queues\n"); return -EFAULT; } - return io_queue_num; + return max_num_io_queues; } static int ena_set_queues_placement_policy(struct pci_dev *pdev, @@ -3430,11 +3430,12 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct ena_llq_configurations llq_config; struct ena_com_dev *ena_dev = NULL; struct ena_adapter *adapter; - int io_queue_num, bars, rc; struct net_device *netdev; static int adapters_found; + u32 max_num_io_queues; char *queue_type_str; bool wd_state; + int bars, rc; dev_dbg(&pdev->dev, "%s\n", __func__); @@ -3500,15 +3501,15 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ena_dev->intr_moder_tx_interval = ENA_INTR_INITIAL_TX_INTERVAL_USECS; ena_dev->intr_moder_rx_interval = ENA_INTR_INITIAL_RX_INTERVAL_USECS; ena_dev->intr_delay_resolution = ENA_DEFAULT_INTR_DELAY_RESOLUTION; - io_queue_num = ena_calc_io_queue_num(pdev, ena_dev, &get_feat_ctx); + max_num_io_queues = ena_calc_max_io_queue_num(pdev, ena_dev, &get_feat_ctx); rc = ena_calc_io_queue_size(&calc_queue_ctx); - if (rc || io_queue_num <= 0) { + if (rc || !max_num_io_queues) { rc = -EFAULT; goto err_device_destroy; } /* dev zeroed in init_etherdev */ - netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), io_queue_num); + netdev = alloc_etherdev_mq(sizeof(struct ena_adapter), max_num_io_queues); if (!netdev) { dev_err(&pdev->dev, "alloc_etherdev_mq failed\n"); rc = -ENOMEM; @@ -3536,7 +3537,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->max_tx_sgl_size = calc_queue_ctx.max_tx_sgl_size; adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size; - adapter->num_io_queues = io_queue_num; + adapter->num_io_queues = max_num_io_queues; + adapter->max_num_io_queues = max_num_io_queues; + adapter->last_monitored_tx_qid = 0; adapter->rx_copybreak = ENA_DEFAULT_RX_COPYBREAK; @@ -3604,7 +3607,7 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "%s found at mem %lx, mac addr %pM Queues %d, Placement policy: %s\n", DEVICE_NAME, (long)pci_resource_start(pdev, 0), - netdev->dev_addr, io_queue_num, queue_type_str); + netdev->dev_addr, max_num_io_queues, queue_type_str); set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 7e8e51e323e9..7499afb586a6 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -161,10 +161,10 @@ struct ena_calc_queue_size_ctx { struct ena_com_dev_get_features_ctx *get_feat_ctx; struct ena_com_dev *ena_dev; struct pci_dev *pdev; - u16 tx_queue_size; - u16 rx_queue_size; - u16 max_tx_queue_size; - u16 max_rx_queue_size; + u32 tx_queue_size; + u32 rx_queue_size; + u32 max_tx_queue_size; + u32 max_rx_queue_size; u16 max_tx_sgl_size; u16 max_rx_sgl_size; }; @@ -324,7 +324,8 @@ struct ena_adapter { u32 rx_copybreak; u32 max_mtu; - int num_io_queues; + u32 num_io_queues; + u32 max_num_io_queues; int msix_vecs; -- cgit v1.2.3-59-g8ed1b From 9f648f7b712461f0aafbbc896a4e5df68dacafa9 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:27 +0300 Subject: net: ena: remove redundant print of number of queues The number of queues can be derived using ethtool, no need to print it in ena_probe() Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index e715681597d0..6386554b14b2 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -3605,9 +3605,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) queue_type_str = "Low Latency"; dev_info(&pdev->dev, - "%s found at mem %lx, mac addr %pM Queues %d, Placement policy: %s\n", + "%s found at mem %lx, mac addr %pM, Placement policy: %s\n", DEVICE_NAME, (long)pci_resource_start(pdev, 0), - netdev->dev_addr, max_num_io_queues, queue_type_str); + netdev->dev_addr, queue_type_str); set_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags); -- cgit v1.2.3-59-g8ed1b From 2413ea97157d6116b3abf432e36c2228f6428f02 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Sun, 6 Oct 2019 15:33:28 +0300 Subject: net: ena: ethtool: support set_channels callback Set channels callback enables the user to change the count of queues used by the driver using ethtool. We decided to currently support only equal number of rx and tx queues, this might change in the future. Also rename dev_up to dev_was_up in ena_update_queue_count() to make it clearer. Signed-off-by: Sameeh Jubran Signed-off-by: David S. Miller --- drivers/net/ethernet/amazon/ena/ena_ethtool.c | 13 +++++++++++++ drivers/net/ethernet/amazon/ena/ena_netdev.c | 22 +++++++++++++++++++--- drivers/net/ethernet/amazon/ena/ena_netdev.h | 3 +++ 3 files changed, 35 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/amazon/ena/ena_ethtool.c b/drivers/net/ethernet/amazon/ena/ena_ethtool.c index b75dafb793f7..a3250dcf7d53 100644 --- a/drivers/net/ethernet/amazon/ena/ena_ethtool.c +++ b/drivers/net/ethernet/amazon/ena/ena_ethtool.c @@ -738,6 +738,18 @@ static void ena_get_channels(struct net_device *netdev, channels->combined_count = adapter->num_io_queues; } +static int ena_set_channels(struct net_device *netdev, + struct ethtool_channels *channels) +{ + struct ena_adapter *adapter = netdev_priv(netdev); + u32 count = channels->combined_count; + /* The check for max value is already done in ethtool */ + if (count < ENA_MIN_NUM_IO_QUEUES) + return -EINVAL; + + return ena_update_queue_count(adapter, count); +} + static int ena_get_tunable(struct net_device *netdev, const struct ethtool_tunable *tuna, void *data) { @@ -801,6 +813,7 @@ static const struct ethtool_ops ena_ethtool_ops = { .get_rxfh = ena_get_rxfh, .set_rxfh = ena_set_rxfh, .get_channels = ena_get_channels, + .set_channels = ena_set_channels, .get_tunable = ena_get_tunable, .set_tunable = ena_set_tunable, }; diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 6386554b14b2..d46a912002ff 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2043,14 +2043,30 @@ int ena_update_queue_sizes(struct ena_adapter *adapter, u32 new_tx_size, u32 new_rx_size) { - bool dev_up; + bool dev_was_up; - dev_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags); + dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags); ena_close(adapter->netdev); adapter->requested_tx_ring_size = new_tx_size; adapter->requested_rx_ring_size = new_rx_size; ena_init_io_rings(adapter); - return dev_up ? ena_up(adapter) : 0; + return dev_was_up ? ena_up(adapter) : 0; +} + +int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count) +{ + struct ena_com_dev *ena_dev = adapter->ena_dev; + bool dev_was_up; + + dev_was_up = test_bit(ENA_FLAG_DEV_UP, &adapter->flags); + ena_close(adapter->netdev); + adapter->num_io_queues = new_channel_count; + /* We need to destroy the rss table so that the indirection + * table will be reinitialized by ena_up() + */ + ena_com_rss_destroy(ena_dev); + ena_init_io_rings(adapter); + return dev_was_up ? ena_open(adapter->netdev) : 0; } static void ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct sk_buff *skb) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.h b/drivers/net/ethernet/amazon/ena/ena_netdev.h index 7499afb586a6..bffd778f2ce3 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.h +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.h @@ -82,6 +82,8 @@ #define ENA_DEFAULT_RING_SIZE (1024) #define ENA_MIN_RING_SIZE (256) +#define ENA_MIN_NUM_IO_QUEUES (1) + #define ENA_TX_WAKEUP_THRESH (MAX_SKB_FRAGS + 2) #define ENA_DEFAULT_RX_COPYBREAK (256 - NET_IP_ALIGN) @@ -388,6 +390,7 @@ void ena_dump_stats_to_buf(struct ena_adapter *adapter, u8 *buf); int ena_update_queue_sizes(struct ena_adapter *adapter, u32 new_tx_size, u32 new_rx_size); +int ena_update_queue_count(struct ena_adapter *adapter, u32 new_channel_count); int ena_get_sset_count(struct net_device *netdev, int sset); -- cgit v1.2.3-59-g8ed1b From 99d895729f5d438518c8223d7ce81615cb9a88e9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 11:55:10 +0100 Subject: net: hns: make arrays static, makes object smaller Don't populate the arrays port_map and sl_map on the stack but instead make them static. Makes the object code smaller by 64 bytes. Before: text data bss dec hex filename 49575 6872 64 56511 dcbf hisilicon/hns/hns_dsaf_main.o After: text data bss dec hex filename 49350 7032 64 56446 dc7e hisilicon/hns/hns_dsaf_main.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 3a14bbc26ea2..1c5243cc1dc6 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -3049,7 +3049,7 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset) u32 sl; u32 credit; int i; - const u32 port_map[DSAF_ROCE_CREDIT_CHN][DSAF_ROCE_CHAN_MODE_NUM] = { + static const u32 port_map[DSAF_ROCE_CREDIT_CHN][DSAF_ROCE_CHAN_MODE_NUM] = { {DSAF_ROCE_PORT_0, DSAF_ROCE_PORT_0, DSAF_ROCE_PORT_0}, {DSAF_ROCE_PORT_1, DSAF_ROCE_PORT_0, DSAF_ROCE_PORT_0}, {DSAF_ROCE_PORT_2, DSAF_ROCE_PORT_1, DSAF_ROCE_PORT_0}, @@ -3059,7 +3059,7 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset) {DSAF_ROCE_PORT_5, DSAF_ROCE_PORT_3, DSAF_ROCE_PORT_1}, {DSAF_ROCE_PORT_5, DSAF_ROCE_PORT_3, DSAF_ROCE_PORT_1}, }; - const u32 sl_map[DSAF_ROCE_CREDIT_CHN][DSAF_ROCE_CHAN_MODE_NUM] = { + static const u32 sl_map[DSAF_ROCE_CREDIT_CHN][DSAF_ROCE_CHAN_MODE_NUM] = { {DSAF_ROCE_SL_0, DSAF_ROCE_SL_0, DSAF_ROCE_SL_0}, {DSAF_ROCE_SL_0, DSAF_ROCE_SL_1, DSAF_ROCE_SL_1}, {DSAF_ROCE_SL_0, DSAF_ROCE_SL_0, DSAF_ROCE_SL_2}, -- cgit v1.2.3-59-g8ed1b From 3ea7af9e2caaec13a455974b04bfa357faf18baf Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 12:09:35 +0100 Subject: net: hns3: make array tick_array static, makes object smaller Don't populate the array tick_array on the stack but instead make it static. Makes the object code smaller by 29 bytes. Before: text data bss dec hex filename 19191 432 0 19623 4ca7 hisilicon/hns3/hns3pf/hclge_tm.o After: text data bss dec hex filename 19098 496 0 19594 4c8a hisilicon/hns3/hns3pf/hclge_tm.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 9f0e35f27789..5cce9b7f1d3d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -46,7 +46,7 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level, #define DIVISOR_CLK (1000 * 8) #define DIVISOR_IR_B_126 (126 * DIVISOR_CLK) - const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = { + static const u16 tick_array[HCLGE_SHAPER_LVL_CNT] = { 6 * 256, /* Prioriy level */ 6 * 32, /* Prioriy group level */ 6 * 8, /* Port level */ -- cgit v1.2.3-59-g8ed1b From 219684a58d7226cd66438f9a72c35679d4cabadd Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 7 Oct 2019 14:38:26 +0300 Subject: dpaa2-eth: Cleanup dead code Remove one function call whose result was not used anywhere. Signed-off-by: Ioana Radulescu Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 162d7d8fb295..2c5072fa9aa0 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -2043,7 +2043,6 @@ static struct fsl_mc_device *setup_dpcon(struct dpaa2_eth_priv *priv) { struct fsl_mc_device *dpcon; struct device *dev = priv->net_dev->dev.parent; - struct dpcon_attr attrs; int err; err = fsl_mc_object_allocate(to_fsl_mc_device(dev), @@ -2068,12 +2067,6 @@ static struct fsl_mc_device *setup_dpcon(struct dpaa2_eth_priv *priv) goto close; } - err = dpcon_get_attributes(priv->mc_io, 0, dpcon->mc_handle, &attrs); - if (err) { - dev_err(dev, "dpcon_get_attributes() failed\n"); - goto close; - } - err = dpcon_enable(priv->mc_io, 0, dpcon->mc_handle); if (err) { dev_err(dev, "dpcon_enable() failed\n"); -- cgit v1.2.3-59-g8ed1b From 4b177f065e7ec37399b18e18412a8c7b75f8f299 Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 7 Oct 2019 14:38:27 +0300 Subject: dpaa2-eth: Fix minor bug in ethtool stats reporting Don't print error message for a successful return value. Fixes: d84c3a4ded96 ("dpaa2-eth: Add new DPNI statistics counters") Signed-off-by: Ioana Radulescu Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index 0aa1c34019bb..dc9a6c36cac0 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -216,7 +216,7 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, if (err == -EINVAL) /* Older firmware versions don't support all pages */ memset(&dpni_stats, 0, sizeof(dpni_stats)); - else + else if (err) netdev_warn(net_dev, "dpni_get_stats(%d) failed\n", j); num_cnt = dpni_stats_page_size[j] / sizeof(u64); -- cgit v1.2.3-59-g8ed1b From ef17bd7cc0c8bb14ea532fb66a708b02c5a4297e Mon Sep 17 00:00:00 2001 From: Ioana Radulescu Date: Mon, 7 Oct 2019 14:38:28 +0300 Subject: dpaa2-eth: Avoid unbounded while loops Throughout the driver there are several places where we wait indefinitely for DPIO portal commands to be executed, while the portal returns a busy response code. Even though in theory we are guaranteed the portals become available eventually, in practice the QBMan hardware module may become unresponsive in various corner cases. Make sure we can never get stuck in an infinite while loop by adding a retry counter for all portal commands. Signed-off-by: Ioana Radulescu Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 32 +++++++++++++++++++----- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 8 ++++++ 2 files changed, 34 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 2c5072fa9aa0..1b959d7ec923 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -221,6 +221,7 @@ static void xdp_release_buf(struct dpaa2_eth_priv *priv, struct dpaa2_eth_channel *ch, dma_addr_t addr) { + int retries = 0; int err; ch->xdp.drop_bufs[ch->xdp.drop_cnt++] = addr; @@ -229,8 +230,11 @@ static void xdp_release_buf(struct dpaa2_eth_priv *priv, while ((err = dpaa2_io_service_release(ch->dpio, priv->bpid, ch->xdp.drop_bufs, - ch->xdp.drop_cnt)) == -EBUSY) + ch->xdp.drop_cnt)) == -EBUSY) { + if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) + break; cpu_relax(); + } if (err) { free_bufs(priv, ch->xdp.drop_bufs, ch->xdp.drop_cnt); @@ -458,7 +462,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch, struct dpaa2_eth_fq *fq = NULL; struct dpaa2_dq *dq; const struct dpaa2_fd *fd; - int cleaned = 0; + int cleaned = 0, retries = 0; int is_last; do { @@ -469,6 +473,11 @@ static int consume_frames(struct dpaa2_eth_channel *ch, * the store until we get some sort of valid response * token (either a valid frame or an "empty dequeue") */ + if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) { + netdev_err_once(priv->net_dev, + "Unable to read a valid dequeue response\n"); + return -ETIMEDOUT; + } continue; } @@ -477,6 +486,7 @@ static int consume_frames(struct dpaa2_eth_channel *ch, fq->consume(priv, ch, fd, fq); cleaned++; + retries = 0; } while (!is_last); if (!cleaned) @@ -949,6 +959,7 @@ static int add_bufs(struct dpaa2_eth_priv *priv, u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; struct page *page; dma_addr_t addr; + int retries = 0; int i, err; for (i = 0; i < DPAA2_ETH_BUFS_PER_CMD; i++) { @@ -980,8 +991,11 @@ static int add_bufs(struct dpaa2_eth_priv *priv, release_bufs: /* In case the portal is busy, retry until successful */ while ((err = dpaa2_io_service_release(ch->dpio, bpid, - buf_array, i)) == -EBUSY) + buf_array, i)) == -EBUSY) { + if (retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) + break; cpu_relax(); + } /* If release command failed, clean up and bail out; * not much else we can do about it @@ -1032,16 +1046,21 @@ static int seed_pool(struct dpaa2_eth_priv *priv, u16 bpid) static void drain_bufs(struct dpaa2_eth_priv *priv, int count) { u64 buf_array[DPAA2_ETH_BUFS_PER_CMD]; + int retries = 0; int ret; do { ret = dpaa2_io_service_acquire(NULL, priv->bpid, buf_array, count); if (ret < 0) { + if (ret == -EBUSY && + retries++ >= DPAA2_ETH_SWP_BUSY_RETRIES) + continue; netdev_err(priv->net_dev, "dpaa2_io_service_acquire() failed\n"); return; } free_bufs(priv, buf_array, ret); + retries = 0; } while (ret); } @@ -1094,7 +1113,7 @@ static int pull_channel(struct dpaa2_eth_channel *ch) ch->store); dequeues++; cpu_relax(); - } while (err == -EBUSY); + } while (err == -EBUSY && dequeues < DPAA2_ETH_SWP_BUSY_RETRIES); ch->stats.dequeue_portal_busy += dequeues; if (unlikely(err)) @@ -1118,6 +1137,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) struct netdev_queue *nq; int store_cleaned, work_done; struct list_head rx_list; + int retries = 0; int err; ch = container_of(napi, struct dpaa2_eth_channel, napi); @@ -1136,7 +1156,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) refill_pool(priv, ch, priv->bpid); store_cleaned = consume_frames(ch, &fq); - if (!store_cleaned) + if (store_cleaned <= 0) break; if (fq->type == DPAA2_RX_FQ) { rx_cleaned += store_cleaned; @@ -1163,7 +1183,7 @@ static int dpaa2_eth_poll(struct napi_struct *napi, int budget) do { err = dpaa2_io_service_rearm(ch->dpio, &ch->nctx); cpu_relax(); - } while (err == -EBUSY); + } while (err == -EBUSY && retries++ < DPAA2_ETH_SWP_BUSY_RETRIES); WARN_ONCE(err, "CDAN notifications rearm failed on core %d", ch->nctx.desired_cpu); diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 8a0e65b3267f..686b651edcb2 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -245,6 +245,14 @@ static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa) */ #define DPAA2_ETH_ENQUEUE_RETRIES 10 +/* Number of times to retry DPIO portal operations while waiting + * for portal to finish executing current command and become + * available. We want to avoid being stuck in a while loop in case + * hardware becomes unresponsive, but not give up too easily if + * the portal really is busy for valid reasons + */ +#define DPAA2_ETH_SWP_BUSY_RETRIES 1000 + /* Driver statistics, other than those in struct rtnl_link_stats64. * These are usually collected per-CPU and aggregated by ethtool. */ -- cgit v1.2.3-59-g8ed1b From 155283c3ac5e272f0178efba08ac62366ffdb86b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 12:52:39 +0100 Subject: nfp: bpf: make array exp_mask static, makes object smaller Don't populate the array exp_mask on the stack but instead make it static. Makes the object code smaller by 224 bytes. Before: text data bss dec hex filename 77832 2290 0 80122 138fa ethernet/netronome/nfp/bpf/jit.o After: text data bss dec hex filename 77544 2354 0 79898 1381a ethernet/netronome/nfp/bpf/jit.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Acked-by: Jakub Kicinski Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/netronome/nfp/bpf/jit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c index 5afcb3c4c2ef..c80bb83c8ac9 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c @@ -3952,7 +3952,7 @@ static void nfp_bpf_opt_neg_add_sub(struct nfp_prog *nfp_prog) static void nfp_bpf_opt_ld_mask(struct nfp_prog *nfp_prog) { struct nfp_insn_meta *meta1, *meta2; - const s32 exp_mask[] = { + static const s32 exp_mask[] = { [BPF_B] = 0x000000ffU, [BPF_H] = 0x0000ffffU, [BPF_W] = 0xffffffffU, -- cgit v1.2.3-59-g8ed1b From c4256794dfdc429d61494a0d1fe1e8212e00803f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 13:03:08 +0100 Subject: net: phy: mscc: make arrays static, makes object smaller Don't populate const arrays on the stack but instead make them static. Makes the object code smaller by 1058 bytes. Before: text data bss dec hex filename 29879 6144 0 36023 8cb7 drivers/net/phy/mscc.o After: text data bss dec hex filename 28437 6528 0 34965 8895 drivers/net/phy/mscc.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: Jakub Kicinski --- drivers/net/phy/mscc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 7ada1fd9ca71..805cda3465d7 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -895,7 +895,7 @@ static void vsc85xx_tr_write(struct phy_device *phydev, u16 addr, u32 val) static int vsc8531_pre_init_seq_set(struct phy_device *phydev) { int rc; - const struct reg_val init_seq[] = { + static const struct reg_val init_seq[] = { {0x0f90, 0x00688980}, {0x0696, 0x00000003}, {0x07fa, 0x0050100f}, @@ -939,7 +939,7 @@ out_unlock: static int vsc85xx_eee_init_seq_set(struct phy_device *phydev) { - const struct reg_val init_eee[] = { + static const struct reg_val init_eee[] = { {0x0f82, 0x0012b00a}, {0x1686, 0x00000004}, {0x168c, 0x00d2c46f}, @@ -1224,7 +1224,7 @@ out: /* bus->mdio_lock should be locked when using this function */ static int vsc8574_config_pre_init(struct phy_device *phydev) { - const struct reg_val pre_init1[] = { + static const struct reg_val pre_init1[] = { {0x0fae, 0x000401bd}, {0x0fac, 0x000f000f}, {0x17a0, 0x00a0f147}, @@ -1272,7 +1272,7 @@ static int vsc8574_config_pre_init(struct phy_device *phydev) {0x0fee, 0x0004a6a1}, {0x0ffe, 0x00b01807}, }; - const struct reg_val pre_init2[] = { + static const struct reg_val pre_init2[] = { {0x0486, 0x0008a518}, {0x0488, 0x006dc696}, {0x048a, 0x00000912}, @@ -1427,7 +1427,7 @@ out: /* bus->mdio_lock should be locked when using this function */ static int vsc8584_config_pre_init(struct phy_device *phydev) { - const struct reg_val pre_init1[] = { + static const struct reg_val pre_init1[] = { {0x07fa, 0x0050100f}, {0x1688, 0x00049f81}, {0x0f90, 0x00688980}, @@ -1451,7 +1451,7 @@ static int vsc8584_config_pre_init(struct phy_device *phydev) {0x16b2, 0x00007000}, {0x16b4, 0x00000814}, }; - const struct reg_val pre_init2[] = { + static const struct reg_val pre_init2[] = { {0x0486, 0x0008a518}, {0x0488, 0x006dc696}, {0x048a, 0x00000912}, @@ -1786,7 +1786,7 @@ static int vsc8514_config_pre_init(struct phy_device *phydev) * values to handle hardware performance of PHY. They * are set at Power-On state and remain until PHY Reset. */ - const struct reg_val pre_init1[] = { + static const struct reg_val pre_init1[] = { {0x0f90, 0x00688980}, {0x0786, 0x00000003}, {0x07fa, 0x0050100f}, -- cgit v1.2.3-59-g8ed1b From f9867b51d268d6fabcc4477d877f04aaad9299ae Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 8 Oct 2019 09:17:47 +0100 Subject: netdevsim: fix spelling mistake "forbidded" -> "forbid" There is a spelling mistake in a NL_SET_ERR_MSG_MOD message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Jakub Kicinski --- drivers/net/netdevsim/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index a3d7d39f231a..e47fa7b6ca7c 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -486,7 +486,7 @@ static int nsim_dev_reload_down(struct devlink *devlink, bool netns_change, /* For testing purposes, user set debugfs dont_allow_reload * value to true. So forbid it. */ - NL_SET_ERR_MSG_MOD(extack, "User forbidded reload for testing purposes"); + NL_SET_ERR_MSG_MOD(extack, "User forbid the reload for testing purposes"); return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From 11fc7d5a0a2d458cae8ce5d5ee3ebfdabe2cb35a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 7 Oct 2019 12:21:05 -0700 Subject: tun: fix memory leak in error path syzbot reported a warning [1] that triggered after recent Jiri patch. This exposes a bug that we hit already in the past (see commit ff244c6b29b1 ("tun: handle register_netdevice() failures properly") for details) tun uses priv->destructor without an ndo_init() method. register_netdevice() can return an error, but will not call priv->destructor() in some cases. Jiri recent patch added one more. A long term fix would be to transfer the initialization of what we destroy in ->destructor() in the ndo_init() This looks a bit risky given the complexity of tun driver. A simpler fix is to detect after the failed register_netdevice() if the tun_free_netdev() function was called already. [1] ODEBUG: free active (active state 0) object type: timer_list hint: tun_flow_cleanup+0x0/0x280 drivers/net/tun.c:457 WARNING: CPU: 0 PID: 8653 at lib/debugobjects.c:481 debug_print_object+0x168/0x250 lib/debugobjects.c:481 Kernel panic - not syncing: panic_on_warn set ... CPU: 0 PID: 8653 Comm: syz-executor976 Not tainted 5.4.0-rc1-next-20191004 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x172/0x1f0 lib/dump_stack.c:113 panic+0x2dc/0x755 kernel/panic.c:220 __warn.cold+0x2f/0x3c kernel/panic.c:581 report_bug+0x289/0x300 lib/bug.c:195 fixup_bug arch/x86/kernel/traps.c:174 [inline] fixup_bug arch/x86/kernel/traps.c:169 [inline] do_error_trap+0x11b/0x200 arch/x86/kernel/traps.c:267 do_invalid_op+0x37/0x50 arch/x86/kernel/traps.c:286 invalid_op+0x23/0x30 arch/x86/entry/entry_64.S:1028 RIP: 0010:debug_print_object+0x168/0x250 lib/debugobjects.c:481 Code: dd 80 b9 e6 87 48 89 fa 48 c1 ea 03 80 3c 02 00 0f 85 b5 00 00 00 48 8b 14 dd 80 b9 e6 87 48 c7 c7 e0 ae e6 87 e8 80 84 ff fd <0f> 0b 83 05 e3 ee 80 06 01 48 83 c4 20 5b 41 5c 41 5d 41 5e 5d c3 RSP: 0018:ffff888095997a28 EFLAGS: 00010082 RAX: 0000000000000000 RBX: 0000000000000003 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffffffff815cb526 RDI: ffffed1012b32f37 RBP: ffff888095997a68 R08: ffff8880a92ac580 R09: ffffed1015d04101 R10: ffffed1015d04100 R11: ffff8880ae820807 R12: 0000000000000001 R13: ffffffff88fb5340 R14: ffffffff81627110 R15: ffff8880aa41eab8 __debug_check_no_obj_freed lib/debugobjects.c:963 [inline] debug_check_no_obj_freed+0x2d4/0x43f lib/debugobjects.c:994 kfree+0xf8/0x2c0 mm/slab.c:3755 kvfree+0x61/0x70 mm/util.c:593 netdev_freemem net/core/dev.c:9384 [inline] free_netdev+0x39d/0x450 net/core/dev.c:9533 tun_set_iff drivers/net/tun.c:2871 [inline] __tun_chr_ioctl+0x317b/0x3f30 drivers/net/tun.c:3075 tun_chr_ioctl+0x2b/0x40 drivers/net/tun.c:3355 vfs_ioctl fs/ioctl.c:47 [inline] file_ioctl fs/ioctl.c:539 [inline] do_vfs_ioctl+0xdb6/0x13e0 fs/ioctl.c:726 ksys_ioctl+0xab/0xd0 fs/ioctl.c:743 __do_sys_ioctl fs/ioctl.c:750 [inline] __se_sys_ioctl fs/ioctl.c:748 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:748 do_syscall_64+0xfa/0x760 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x441439 Code: e8 9c ae 02 00 48 83 c4 18 c3 0f 1f 80 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 0f 83 3b 0a fc ff c3 66 2e 0f 1f 84 00 00 00 00 RSP: 002b:00007fff61c37438 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000441439 RDX: 0000000020000400 RSI: 00000000400454ca RDI: 0000000000000004 RBP: 00007fff61c37470 R08: 0000000000000001 R09: 0000000100000000 R10: 0000000000000000 R11: 0000000000000246 R12: ffffffffffffffff R13: 0000000000000005 R14: 0000000000000000 R15: 0000000000000000 Kernel Offset: disabled Rebooting in 86400 seconds.. Fixes: ff92741270bf ("net: introduce name_node struct to be used in hashlist") Signed-off-by: Eric Dumazet Cc: Jiri Pirko Reported-by: syzbot Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 812dc3a65efb..1e541b08b136 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2290,7 +2290,13 @@ static void tun_free_netdev(struct net_device *dev) struct tun_struct *tun = netdev_priv(dev); BUG_ON(!(list_empty(&tun->disabled))); + free_percpu(tun->pcpu_stats); + /* We clear pcpu_stats so that tun_set_iff() can tell if + * tun_free_netdev() has been called from register_netdevice(). + */ + tun->pcpu_stats = NULL; + tun_flow_uninit(tun); security_tun_dev_free_security(tun->security); __tun_set_ebpf(tun, &tun->steering_prog, NULL); @@ -2859,8 +2865,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) err_detach: tun_detach_all(dev); - /* register_netdevice() already called tun_free_netdev() */ - goto err_free_dev; + /* We are here because register_netdevice() has failed. + * If register_netdevice() already called tun_free_netdev() + * while dealing with the error, tun->pcpu_stats has been cleared. + */ + if (!tun->pcpu_stats) + goto err_free_dev; err_free_flow: tun_flow_uninit(tun); -- cgit v1.2.3-59-g8ed1b From 6430f744a45adb722dc51982a7df7ac1367dc90d Mon Sep 17 00:00:00 2001 From: Yufeng Mo Date: Tue, 8 Oct 2019 09:20:04 +0800 Subject: net: hns3: add support for setting VF link status on the host This patch adds support to configure VF link properties. The options are auto, enable, and disable. Even if the PF is down, the communication between VFs will be normal if the VFs are set to enable. The commands are as follows: 'ip link set vf state ' change the VF status 'ip link show' show the setting status Signed-off-by: Yufeng Mo Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 8 +++ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 24 +++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 57 ++++++++++++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 6 +++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 17 ++++++- 5 files changed, 111 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index c4b7bf851a28..1fc37281b058 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -364,6 +364,10 @@ struct hnae3_ae_dev { * Enable/disable HW GRO * add_arfs_entry * Check the 5-tuples of flow, and create flow director rule + * get_vf_config + * Get the VF configuration setting by the host + * set_vf_link_state + * Set VF link status */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -529,6 +533,10 @@ struct hnae3_ae_ops { int (*mac_connect_phy)(struct hnae3_handle *handle); void (*mac_disconnect_phy)(struct hnae3_handle *handle); void (*restore_vlan_table)(struct hnae3_handle *handle); + int (*get_vf_config)(struct hnae3_handle *handle, int vf, + struct ifla_vf_info *ivf); + int (*set_vf_link_state)(struct hnae3_handle *handle, int vf, + int link_state); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 616cad0faa21..2136323bd9b9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1805,6 +1805,28 @@ static int hns3_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } #endif +static int hns3_nic_get_vf_config(struct net_device *ndev, int vf, + struct ifla_vf_info *ivf) +{ + struct hnae3_handle *h = hns3_get_handle(ndev); + + if (!h->ae_algo->ops->get_vf_config) + return -EOPNOTSUPP; + + return h->ae_algo->ops->get_vf_config(h, vf, ivf); +} + +static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf, + int link_state) +{ + struct hnae3_handle *h = hns3_get_handle(ndev); + + if (!h->ae_algo->ops->set_vf_link_state) + return -EOPNOTSUPP; + + return h->ae_algo->ops->set_vf_link_state(h, vf, link_state); +} + static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -1823,6 +1845,8 @@ static const struct net_device_ops hns3_nic_netdev_ops = { #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = hns3_rx_flow_steer, #endif + .ndo_get_vf_config = hns3_nic_get_vf_config, + .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index fd7f94372ff0..931a3117ccf6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -55,6 +55,8 @@ #define HCLGE_LINK_STATUS_MS 10 +#define HCLGE_VF_VPORT_START_NUM 1 + static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps); static int hclge_init_vlan_config(struct hclge_dev *hdev); static void hclge_sync_vlan_filter(struct hclge_dev *hdev); @@ -1633,6 +1635,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) for (i = 0; i < num_vport; i++) { vport->back = hdev; vport->vport_id = i; + vport->vf_info.link_state = IFLA_VF_LINK_STATE_AUTO; vport->mps = HCLGE_MAC_DEFAULT_FRAME; vport->port_base_vlan_cfg.state = HNAE3_PORT_BASE_VLAN_DISABLE; vport->rxvlan_cfg.rx_vlan_offload_en = true; @@ -2853,6 +2856,58 @@ static int hclge_get_status(struct hnae3_handle *handle) return hdev->hw.mac.link; } +static struct hclge_vport *hclge_get_vf_vport(struct hclge_dev *hdev, int vf) +{ + if (pci_num_vf(hdev->pdev) == 0) { + dev_err(&hdev->pdev->dev, + "SRIOV is disabled, can not get vport(%d) info.\n", vf); + return NULL; + } + + if (vf < 0 || vf >= pci_num_vf(hdev->pdev)) { + dev_err(&hdev->pdev->dev, + "vf id(%d) is out of range(0 <= vfid < %d)\n", + vf, pci_num_vf(hdev->pdev)); + return NULL; + } + + /* VF start from 1 in vport */ + vf += HCLGE_VF_VPORT_START_NUM; + return &hdev->vport[vf]; +} + +static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, + struct ifla_vf_info *ivf) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + ivf->vf = vf; + ivf->linkstate = vport->vf_info.link_state; + ether_addr_copy(ivf->mac, vport->vf_info.mac); + + return 0; +} + +static int hclge_set_vf_link_state(struct hnae3_handle *handle, int vf, + int link_state) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + vport->vf_info.link_state = link_state; + + return 0; +} + static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) { u32 rst_src_reg, cmdq_src_reg, msix_src_reg; @@ -10152,6 +10207,8 @@ static const struct hnae3_ae_ops hclge_ops = { .mac_connect_phy = hclge_mac_connect_phy, .mac_disconnect_phy = hclge_mac_disconnect_phy, .restore_vlan_table = hclge_restore_vlan_table, + .get_vf_config = hclge_get_vf_config, + .set_vf_link_state = hclge_set_vf_link_state, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 3e9574a9e22d..6a3ccdac6aa8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -885,6 +885,11 @@ struct hclge_port_base_vlan_config { struct hclge_vlan_info vlan_info; }; +struct hclge_vf_info { + int link_state; + u8 mac[ETH_ALEN]; +}; + struct hclge_vport { u16 alloc_tqps; /* Allocated Tx/Rx queues */ @@ -916,6 +921,7 @@ struct hclge_vport { unsigned long state; unsigned long last_active_jiffies; u32 mps; /* Max packet size */ + struct hclge_vf_info vf_info; struct list_head uc_mac_list; /* Store VF unicast table */ struct list_head mc_mac_list; /* Store VF multicast table */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index f5da28a60d00..b842291861f5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -428,6 +428,9 @@ static int hclge_get_vf_media_type(struct hclge_vport *vport, static int hclge_get_link_info(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req) { +#define HCLGE_VF_LINK_STATE_UP 1U +#define HCLGE_VF_LINK_STATE_DOWN 0U + struct hclge_dev *hdev = vport->back; u16 link_status; u8 msg_data[8]; @@ -435,7 +438,19 @@ static int hclge_get_link_info(struct hclge_vport *vport, u16 duplex; /* mac.link can only be 0 or 1 */ - link_status = (u16)hdev->hw.mac.link; + switch (vport->vf_info.link_state) { + case IFLA_VF_LINK_STATE_ENABLE: + link_status = HCLGE_VF_LINK_STATE_UP; + break; + case IFLA_VF_LINK_STATE_DISABLE: + link_status = HCLGE_VF_LINK_STATE_DOWN; + break; + case IFLA_VF_LINK_STATE_AUTO: + default: + link_status = (u16)hdev->hw.mac.link; + break; + } + duplex = hdev->hw.mac.duplex; memcpy(&msg_data[0], &link_status, sizeof(u16)); memcpy(&msg_data[2], &hdev->hw.mac.speed, sizeof(u32)); -- cgit v1.2.3-59-g8ed1b From 22044f95faa05cb8ceb96101bfe18a42613914dc Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Tue, 8 Oct 2019 09:20:05 +0800 Subject: net: hns3: add support for spoof check setting This patch adds support for spoof check configuration for VFs. When it is enabled, "spoof checking" is done for both mac address and VLAN. For each VF, the HW ensures that the source MAC address (or VLAN) of every outgoing packet exists in the MAC-list (or VLAN-list) configured for RX filtering for that VF. If not, the packet is dropped. Signed-off-by: Jian Shen Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 +++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 125 +++++++++++++++++++-- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 1 + .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 3 + .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 2 +- 6 files changed, 140 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 1fc37281b058..b7b81697d906 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -368,6 +368,8 @@ struct hnae3_ae_dev { * Get the VF configuration setting by the host * set_vf_link_state * Set VF link status + * set_vf_spoofchk + * Enable/disable spoof check for specified vf */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -537,6 +539,8 @@ struct hnae3_ae_ops { struct ifla_vf_info *ivf); int (*set_vf_link_state)(struct hnae3_handle *handle, int vf, int link_state); + int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf, + bool enable); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 2136323bd9b9..4a5404ef39a6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1643,6 +1643,19 @@ static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, return ret; } +static int hns3_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable) +{ + struct hnae3_handle *handle = hns3_get_handle(netdev); + + if (hns3_nic_resetting(netdev)) + return -EBUSY; + + if (!handle->ae_algo->ops->set_vf_spoofchk) + return -EOPNOTSUPP; + + return handle->ae_algo->ops->set_vf_spoofchk(handle, vf, enable); +} + static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu) { struct hnae3_handle *h = hns3_get_handle(netdev); @@ -1842,6 +1855,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_vlan_rx_add_vid = hns3_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid, .ndo_set_vf_vlan = hns3_ndo_set_vf_vlan, + .ndo_set_vf_spoofchk = hns3_set_vf_spoofchk, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = hns3_rx_flow_steer, #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 931a3117ccf6..7c728623b4b0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2888,6 +2888,7 @@ static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, ivf->vf = vf; ivf->linkstate = vport->vf_info.link_state; + ivf->spoofchk = vport->vf_info.spoofchk; ether_addr_copy(ivf->mac, vport->vf_info.mac); return 0; @@ -7619,6 +7620,8 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, __be16 proto) { #define HCLGE_MAX_VF_BYTES 16 + + struct hclge_vport *vport = &hdev->vport[vfid]; struct hclge_vlan_filter_vf_cfg_cmd *req0; struct hclge_vlan_filter_vf_cfg_cmd *req1; struct hclge_desc desc[2]; @@ -7627,10 +7630,18 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, int ret; /* if vf vlan table is full, firmware will close vf vlan filter, it - * is unable and unnecessary to add new vlan id to vf vlan filter + * is unable and unnecessary to add new vlan id to vf vlan filter. + * If spoof check is enable, and vf vlan is full, it shouldn't add + * new vlan, because tx packets with these vlan id will be dropped. */ - if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) + if (test_bit(vfid, hdev->vf_vlan_full) && !is_kill) { + if (vport->vf_info.spoofchk && vlan) { + dev_err(&hdev->pdev->dev, + "Can't add vlan due to spoof check is on and vf vlan table is full\n"); + return -EPERM; + } return 0; + } hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_VLAN_FILTER_VF_CFG, false); @@ -8127,12 +8138,15 @@ static void hclge_restore_vlan_table(struct hnae3_handle *handle) } list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) { - if (vlan->hd_tbl_status) - hclge_set_vlan_filter_hw(hdev, - htons(ETH_P_8021Q), - vport->vport_id, - vlan->vlan_id, - false); + int ret; + + if (!vlan->hd_tbl_status) + continue; + ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q), + vport->vport_id, + vlan->vlan_id, false); + if (ret) + break; } } @@ -9374,6 +9388,97 @@ static void hclge_stats_clear(struct hclge_dev *hdev) memset(&hdev->hw_stats, 0, sizeof(hdev->hw_stats)); } +static int hclge_set_mac_spoofchk(struct hclge_dev *hdev, int vf, bool enable) +{ + return hclge_config_switch_param(hdev, vf, enable, + HCLGE_SWITCH_ANTI_SPOOF_MASK); +} + +static int hclge_set_vlan_spoofchk(struct hclge_dev *hdev, int vf, bool enable) +{ + return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_VF, + HCLGE_FILTER_FE_NIC_INGRESS_B, + enable, vf); +} + +static int hclge_set_vf_spoofchk_hw(struct hclge_dev *hdev, int vf, bool enable) +{ + int ret; + + ret = hclge_set_mac_spoofchk(hdev, vf, enable); + if (ret) { + dev_err(&hdev->pdev->dev, + "Set vf %d mac spoof check %s failed, ret=%d\n", + vf, enable ? "on" : "off", ret); + return ret; + } + + ret = hclge_set_vlan_spoofchk(hdev, vf, enable); + if (ret) + dev_err(&hdev->pdev->dev, + "Set vf %d vlan spoof check %s failed, ret=%d\n", + vf, enable ? "on" : "off", ret); + + return ret; +} + +static int hclge_set_vf_spoofchk(struct hnae3_handle *handle, int vf, + bool enable) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + u32 new_spoofchk = enable ? 1 : 0; + int ret; + + if (hdev->pdev->revision == 0x20) + return -EOPNOTSUPP; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + if (vport->vf_info.spoofchk == new_spoofchk) + return 0; + + if (enable && test_bit(vport->vport_id, hdev->vf_vlan_full)) + dev_warn(&hdev->pdev->dev, + "vf %d vlan table is full, enable spoof check may cause its packet send fail\n", + vf); + else if (enable && hclge_is_umv_space_full(vport)) + dev_warn(&hdev->pdev->dev, + "vf %d mac table is full, enable spoof check may cause its packet send fail\n", + vf); + + ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, enable); + if (ret) + return ret; + + vport->vf_info.spoofchk = new_spoofchk; + return 0; +} + +static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev) +{ + struct hclge_vport *vport = hdev->vport; + int ret; + int i; + + if (hdev->pdev->revision == 0x20) + return 0; + + /* resume the vf spoof check state after reset */ + for (i = 0; i < hdev->num_alloc_vport; i++) { + ret = hclge_set_vf_spoofchk_hw(hdev, vport->vport_id, + vport->vf_info.spoofchk); + if (ret) + return ret; + + vport++; + } + + return 0; +} + static void hclge_reset_vport_state(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; @@ -9473,6 +9578,9 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) } hclge_reset_vport_state(hdev); + ret = hclge_reset_vport_spoofchk(hdev); + if (ret) + return ret; dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n", HCLGE_DRIVER_NAME); @@ -10209,6 +10317,7 @@ static const struct hnae3_ae_ops hclge_ops = { .restore_vlan_table = hclge_restore_vlan_table, .get_vf_config = hclge_get_vf_config, .set_vf_link_state = hclge_set_vf_link_state, + .set_vf_spoofchk = hclge_set_vf_spoofchk, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 6a3ccdac6aa8..9483529606a3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -888,6 +888,7 @@ struct hclge_port_base_vlan_config { struct hclge_vf_info { int link_state; u8 mac[ETH_ALEN]; + u32 spoofchk; }; struct hclge_vport { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index b842291861f5..cad7029f360d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -324,6 +324,9 @@ static int hclge_set_vf_vlan_cfg(struct hclge_vport *vport, proto = msg_cmd->proto; status = hclge_set_vlan_filter(handle, cpu_to_be16(proto), vlan, is_kill); + if (mbx_req->mbx_need_resp) + return hclge_gen_resp_to_vf(vport, mbx_req, status, + NULL, 0); } else if (msg_cmd->subcode == HCLGE_MBX_VLAN_RX_OFF_CFG) { struct hnae3_handle *handle = &vport->nic; bool en = msg_cmd->is_kill ? true : false; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index e3090b3dab1d..2b87b70a5385 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1267,7 +1267,7 @@ static int hclgevf_set_vlan_filter(struct hnae3_handle *handle, memcpy(&msg_data[3], &proto, sizeof(proto)); ret = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_SET_VLAN, HCLGE_MBX_VLAN_FILTER, msg_data, - HCLGEVF_VLAN_MBX_MSG_LEN, false, NULL, 0); + HCLGEVF_VLAN_MBX_MSG_LEN, true, NULL, 0); /* when remove hw vlan filter failed, record the vlan id, * and try to remove it from hw later, to be consistence -- cgit v1.2.3-59-g8ed1b From e196ec75958e16f5a6d418a1296244f825109d8a Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Tue, 8 Oct 2019 09:20:06 +0800 Subject: net: hns3: add support for setting VF trust This patch adds supports for setting VF trust by host. If specified VF is trusted, then it can enable promisc(include allmulti mode). If a trusted VF enabled promisc, and being untrusted, host will disable promisc mode for this VF. For VF will update its promisc mode from set_rx_mode now, so it's unnecessary to set broadcst promisc mode when initialization or reset. Signed-off-by: Jian Shen Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 1 + drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 ++ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 11 ++++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 3 -- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 60 ++++++++++++++++++---- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 8 +-- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 36 +++++++++++-- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 34 +++++------- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c | 12 +++++ 9 files changed, 129 insertions(+), 40 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index f8a87f8ca983..0059d440e1f9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -45,6 +45,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_GET_LINK_MODE, /* (VF -> PF) get the link mode of pf */ HCLGE_MBX_PUSH_VLAN_INFO, /* (PF -> VF) push port base vlan */ HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */ + HCLGE_MBX_PUSH_PROMISC_INFO, /* (PF -> VF) push vf promisc info */ HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index b7b81697d906..ef56f3737855 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -370,6 +370,9 @@ struct hnae3_ae_dev { * Set VF link status * set_vf_spoofchk * Enable/disable spoof check for specified vf + * set_vf_trust + * Enable/disable trust for specified vf, if the vf being trusted, then + * it can enable promisc mode */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -541,6 +544,7 @@ struct hnae3_ae_ops { int link_state); int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf, bool enable); + int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4a5404ef39a6..5c50555fa28c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1656,6 +1656,16 @@ static int hns3_set_vf_spoofchk(struct net_device *netdev, int vf, bool enable) return handle->ae_algo->ops->set_vf_spoofchk(handle, vf, enable); } +static int hns3_set_vf_trust(struct net_device *netdev, int vf, bool enable) +{ + struct hnae3_handle *handle = hns3_get_handle(netdev); + + if (!handle->ae_algo->ops->set_vf_trust) + return -EOPNOTSUPP; + + return handle->ae_algo->ops->set_vf_trust(handle, vf, enable); +} + static int hns3_nic_change_mtu(struct net_device *netdev, int new_mtu) { struct hnae3_handle *h = hns3_get_handle(netdev); @@ -1856,6 +1866,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid, .ndo_set_vf_vlan = hns3_ndo_set_vf_vlan, .ndo_set_vf_spoofchk = hns3_set_vf_spoofchk, + .ndo_set_vf_trust = hns3_set_vf_trust, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = hns3_rx_flow_steer, #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 4821fe08b5e4..265695aaba5d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -1090,9 +1090,6 @@ void hclge_cmd_setup_basic_desc(struct hclge_desc *desc, enum hclge_opcode_type opcode, bool is_read); void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read); -int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev, - struct hclge_promisc_param *param); - enum hclge_cmd_status hclge_cmd_mdio_write(struct hclge_hw *hw, struct hclge_desc *desc); enum hclge_cmd_status hclge_cmd_mdio_read(struct hclge_hw *hw, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 7c728623b4b0..c63f723dc00e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2889,6 +2889,7 @@ static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, ivf->vf = vf; ivf->linkstate = vport->vf_info.link_state; ivf->spoofchk = vport->vf_info.spoofchk; + ivf->trusted = vport->vf_info.trusted; ether_addr_copy(ivf->mac, vport->vf_info.mac); return 0; @@ -4614,8 +4615,8 @@ static int hclge_unmap_ring_frm_vector(struct hnae3_handle *handle, int vector, return ret; } -int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev, - struct hclge_promisc_param *param) +static int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev, + struct hclge_promisc_param *param) { struct hclge_promisc_cfg_cmd *req; struct hclge_desc desc; @@ -4642,8 +4643,9 @@ int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev, return ret; } -void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc, - bool en_mc, bool en_bc, int vport_id) +static void hclge_promisc_param_init(struct hclge_promisc_param *param, + bool en_uc, bool en_mc, bool en_bc, + int vport_id) { if (!param) return; @@ -4658,12 +4660,21 @@ void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc, param->vf_id = vport_id; } +int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc, + bool en_mc_pmc, bool en_bc_pmc) +{ + struct hclge_dev *hdev = vport->back; + struct hclge_promisc_param param; + + hclge_promisc_param_init(¶m, en_uc_pmc, en_mc_pmc, en_bc_pmc, + vport->vport_id); + return hclge_cmd_set_promisc_mode(hdev, ¶m); +} + static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc, bool en_mc_pmc) { struct hclge_vport *vport = hclge_get_vport(handle); - struct hclge_dev *hdev = vport->back; - struct hclge_promisc_param param; bool en_bc_pmc = true; /* For revision 0x20, if broadcast promisc enabled, vlan filter is @@ -4673,9 +4684,8 @@ static int hclge_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc, if (handle->pdev->revision == 0x20) en_bc_pmc = handle->netdev_flags & HNAE3_BPE ? true : false; - hclge_promisc_param_init(¶m, en_uc_pmc, en_mc_pmc, en_bc_pmc, - vport->vport_id); - return hclge_cmd_set_promisc_mode(hdev, ¶m); + return hclge_set_vport_promisc_mode(vport, en_uc_pmc, en_mc_pmc, + en_bc_pmc); } static int hclge_get_fd_mode(struct hclge_dev *hdev, u8 *fd_mode) @@ -9479,6 +9489,37 @@ static int hclge_reset_vport_spoofchk(struct hclge_dev *hdev) return 0; } +static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + u32 new_trusted = enable ? 1 : 0; + bool en_bc_pmc; + int ret; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + if (vport->vf_info.trusted == new_trusted) + return 0; + + /* Disable promisc mode for VF if it is not trusted any more. */ + if (!enable && vport->vf_info.promisc_enable) { + en_bc_pmc = hdev->pdev->revision != 0x20; + ret = hclge_set_vport_promisc_mode(vport, false, false, + en_bc_pmc); + if (ret) + return ret; + vport->vf_info.promisc_enable = 0; + hclge_inform_vf_promisc_info(vport); + } + + vport->vf_info.trusted = new_trusted; + + return 0; +} + static void hclge_reset_vport_state(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; @@ -10318,6 +10359,7 @@ static const struct hnae3_ae_ops hclge_ops = { .get_vf_config = hclge_get_vf_config, .set_vf_link_state = hclge_set_vf_link_state, .set_vf_spoofchk = hclge_set_vf_spoofchk, + .set_vf_trust = hclge_set_vf_trust, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 9483529606a3..66e8833856e5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -889,6 +889,8 @@ struct hclge_vf_info { int link_state; u8 mac[ETH_ALEN]; u32 spoofchk; + u32 trusted; + u16 promisc_enable; }; struct hclge_vport { @@ -929,9 +931,8 @@ struct hclge_vport { struct list_head vlan_list; /* Store VF vlan table */ }; -void hclge_promisc_param_init(struct hclge_promisc_param *param, bool en_uc, - bool en_mc, bool en_bc, int vport_id); - +int hclge_set_vport_promisc_mode(struct hclge_vport *vport, bool en_uc_pmc, + bool en_mc_pmc, bool en_bc_pmc); int hclge_add_uc_addr_common(struct hclge_vport *vport, const unsigned char *addr); int hclge_rm_uc_addr_common(struct hclge_vport *vport, @@ -1000,4 +1001,5 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, struct hclge_desc *desc); void hclge_report_hw_error(struct hclge_dev *hdev, enum hnae3_hw_error_type type); +void hclge_inform_vf_promisc_info(struct hclge_vport *vport); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index cad7029f360d..131b47bac3a2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -205,12 +205,38 @@ static int hclge_map_unmap_ring_to_vf_vector(struct hclge_vport *vport, bool en, static int hclge_set_vf_promisc_mode(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *req) { - bool en_bc = req->msg[1] ? true : false; - struct hclge_promisc_param param; +#define HCLGE_MBX_BC_INDEX 1 +#define HCLGE_MBX_UC_INDEX 2 +#define HCLGE_MBX_MC_INDEX 3 - /* vf is not allowed to enable unicast/multicast broadcast */ - hclge_promisc_param_init(¶m, false, false, en_bc, vport->vport_id); - return hclge_cmd_set_promisc_mode(vport->back, ¶m); + bool en_bc = req->msg[HCLGE_MBX_BC_INDEX] ? true : false; + bool en_uc = req->msg[HCLGE_MBX_UC_INDEX] ? true : false; + bool en_mc = req->msg[HCLGE_MBX_MC_INDEX] ? true : false; + int ret; + + if (!vport->vf_info.trusted) { + en_uc = false; + en_mc = false; + } + + ret = hclge_set_vport_promisc_mode(vport, en_uc, en_mc, en_bc); + if (req->mbx_need_resp) + hclge_gen_resp_to_vf(vport, req, ret, NULL, 0); + + vport->vf_info.promisc_enable = (en_uc || en_mc) ? 1 : 0; + + return ret; +} + +void hclge_inform_vf_promisc_info(struct hclge_vport *vport) +{ + u8 dest_vfid = (u8)vport->vport_id; + u8 msg_data[2]; + + memcpy(&msg_data[0], &vport->vf_info.promisc_enable, sizeof(u16)); + + hclge_send_mbx_msg(vport, msg_data, sizeof(msg_data), + HCLGE_MBX_PUSH_PROMISC_INFO, dest_vfid); } static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 2b87b70a5385..17326681db6d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1105,6 +1105,7 @@ static int hclgevf_put_vector(struct hnae3_handle *handle, int vector) } static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev, + bool en_uc_pmc, bool en_mc_pmc, bool en_bc_pmc) { struct hclge_mbx_vf_to_pf_cmd *req; @@ -1112,10 +1113,11 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev, int ret; req = (struct hclge_mbx_vf_to_pf_cmd *)desc.data; - hclgevf_cmd_setup_basic_desc(&desc, HCLGEVF_OPC_MBX_VF_TO_PF, false); req->msg[0] = HCLGE_MBX_SET_PROMISC_MODE; req->msg[1] = en_bc_pmc ? 1 : 0; + req->msg[2] = en_uc_pmc ? 1 : 0; + req->msg[3] = en_mc_pmc ? 1 : 0; ret = hclgevf_cmd_send(&hdev->hw, &desc, 1); if (ret) @@ -1125,9 +1127,17 @@ static int hclgevf_cmd_set_promisc_mode(struct hclgevf_dev *hdev, return ret; } -static int hclgevf_set_promisc_mode(struct hclgevf_dev *hdev, bool en_bc_pmc) +static int hclgevf_set_promisc_mode(struct hnae3_handle *handle, bool en_uc_pmc, + bool en_mc_pmc) { - return hclgevf_cmd_set_promisc_mode(hdev, en_bc_pmc); + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + struct pci_dev *pdev = hdev->pdev; + bool en_bc_pmc; + + en_bc_pmc = pdev->revision != 0x20; + + return hclgevf_cmd_set_promisc_mode(hdev, en_uc_pmc, en_mc_pmc, + en_bc_pmc); } static int hclgevf_tqp_enable(struct hclgevf_dev *hdev, unsigned int tqp_id, @@ -2626,12 +2636,6 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) return ret; } - if (pdev->revision >= 0x21) { - ret = hclgevf_set_promisc_mode(hdev, true); - if (ret) - return ret; - } - dev_info(&hdev->pdev->dev, "Reset done\n"); return 0; @@ -2706,17 +2710,6 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) if (ret) goto err_config; - /* vf is not allowed to enable unicast/multicast promisc mode. - * For revision 0x20, default to disable broadcast promisc mode, - * firmware makes sure broadcast packets can be accepted. - * For revision 0x21, default to enable broadcast promisc mode. - */ - if (pdev->revision >= 0x21) { - ret = hclgevf_set_promisc_mode(hdev, true); - if (ret) - goto err_config; - } - /* Initialize RSS for this VF */ ret = hclgevf_rss_init_hw(hdev); if (ret) { @@ -3130,6 +3123,7 @@ static const struct hnae3_ae_ops hclgevf_ops = { .get_global_queue_id = hclgevf_get_qid_global, .set_timer_task = hclgevf_set_timer_task, .get_link_mode = hclgevf_get_link_mode, + .set_promisc_mode = hclgevf_set_promisc_mode, }; static struct hnae3_ae_algo ae_algovf = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index a108191c9e50..72bacf89f09c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -205,6 +205,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_ASSERTING_RESET: case HCLGE_MBX_LINK_STAT_MODE: case HCLGE_MBX_PUSH_VLAN_INFO: + case HCLGE_MBX_PUSH_PROMISC_INFO: /* set this mbx event as pending. This is required as we * might loose interrupt event when mbx task is busy * handling. This shall be cleared when mbx task just @@ -248,6 +249,14 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) crq->next_to_use); } +static void hclgevf_parse_promisc_info(struct hclgevf_dev *hdev, + u16 promisc_info) +{ + if (!promisc_info) + dev_info(&hdev->pdev->dev, + "Promisc mode is closed by host for being untrusted.\n"); +} + void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) { enum hnae3_reset_type reset_type; @@ -313,6 +322,9 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) hclgevf_update_port_base_vlan_info(hdev, state, (u8 *)vlan_info, 8); break; + case HCLGE_MBX_PUSH_PROMISC_INFO: + hclgevf_parse_promisc_info(hdev, msg_q[1]); + break; default: dev_err(&hdev->pdev->dev, "fetched unsupported(%d) message from arq\n", -- cgit v1.2.3-59-g8ed1b From ee9e44248f52b6f1425cd50b5941f491b4629456 Mon Sep 17 00:00:00 2001 From: Yonglong Liu Date: Tue, 8 Oct 2019 09:20:07 +0800 Subject: net: hns3: add support for configuring bandwidth of VF on the host This patch adds support for configuring bandwidth of VF on the host for HNS3 drivers. Signed-off-by: Yonglong Liu Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 4 + drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 ++- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 2 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 79 +++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 130 +++++++++++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 + .../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 43 +++++++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h | 8 ++ 8 files changed, 280 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index ef56f3737855..1202bbccf96c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -373,6 +373,8 @@ struct hnae3_ae_dev { * set_vf_trust * Enable/disable trust for specified vf, if the vf being trusted, then * it can enable promisc mode + * set_vf_rate + * Set the max tx rate of specified vf. */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -545,6 +547,8 @@ struct hnae3_ae_ops { int (*set_vf_spoofchk)(struct hnae3_handle *handle, int vf, bool enable); int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable); + int (*set_vf_rate)(struct hnae3_handle *handle, int vf, + int min_tx_rate, int max_tx_rate, bool force); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 5c50555fa28c..5a8c316fe431 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1850,6 +1850,18 @@ static int hns3_nic_set_vf_link_state(struct net_device *ndev, int vf, return h->ae_algo->ops->set_vf_link_state(h, vf, link_state); } +static int hns3_nic_set_vf_rate(struct net_device *ndev, int vf, + int min_tx_rate, int max_tx_rate) +{ + struct hnae3_handle *h = hns3_get_handle(ndev); + + if (!h->ae_algo->ops->set_vf_rate) + return -EOPNOTSUPP; + + return h->ae_algo->ops->set_vf_rate(h, vf, min_tx_rate, max_tx_rate, + false); +} + static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -1872,7 +1884,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = { #endif .ndo_get_vf_config = hns3_nic_get_vf_config, .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, - + .ndo_set_vf_rate = hns3_nic_set_vf_rate, }; bool hns3_is_phys_func(struct pci_dev *pdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 265695aaba5d..3578832067ff 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -244,7 +244,7 @@ enum hclge_opcode_type { /* QCN commands */ HCLGE_OPC_QCN_MOD_CFG = 0x1A01, HCLGE_OPC_QCN_GRP_TMPLT_CFG = 0x1A02, - HCLGE_OPC_QCN_SHAPPING_IR_CFG = 0x1A03, + HCLGE_OPC_QCN_SHAPPING_CFG = 0x1A03, HCLGE_OPC_QCN_SHAPPING_BS_CFG = 0x1A04, HCLGE_OPC_QCN_QSET_LINK_CFG = 0x1A05, HCLGE_OPC_QCN_RP_STATUS_GET = 0x1A06, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index d0128d792717..0ccc8e7b19d0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -1110,6 +1110,82 @@ static void hclge_dbg_dump_mac_tnl_status(struct hclge_dev *hdev) } } +static void hclge_dbg_dump_qs_shaper_single(struct hclge_dev *hdev, u16 qsid) +{ + struct hclge_qs_shapping_cmd *shap_cfg_cmd; + u8 ir_u, ir_b, ir_s, bs_b, bs_s; + struct hclge_desc desc; + u32 shapping_para; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, true); + + shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data; + shap_cfg_cmd->qs_id = cpu_to_le16(qsid); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "qs%u failed to get tx_rate, ret=%d\n", + qsid, ret); + return; + } + + shapping_para = le32_to_cpu(shap_cfg_cmd->qs_shapping_para); + ir_b = hclge_tm_get_field(shapping_para, IR_B); + ir_u = hclge_tm_get_field(shapping_para, IR_U); + ir_s = hclge_tm_get_field(shapping_para, IR_S); + bs_b = hclge_tm_get_field(shapping_para, BS_B); + bs_s = hclge_tm_get_field(shapping_para, BS_S); + + dev_info(&hdev->pdev->dev, + "qs%u ir_b:%u, ir_u:%u, ir_s:%u, bs_b:%u, bs_s:%u\n", + qsid, ir_b, ir_u, ir_s, bs_b, bs_s); +} + +static void hclge_dbg_dump_qs_shaper_all(struct hclge_dev *hdev) +{ + struct hnae3_knic_private_info *kinfo; + struct hclge_vport *vport; + int vport_id, i; + + for (vport_id = 0; vport_id <= pci_num_vf(hdev->pdev); vport_id++) { + vport = &hdev->vport[vport_id]; + kinfo = &vport->nic.kinfo; + + dev_info(&hdev->pdev->dev, "qs cfg of vport%d:\n", vport_id); + + for (i = 0; i < kinfo->num_tc; i++) { + u16 qsid = vport->qs_offset + i; + + hclge_dbg_dump_qs_shaper_single(hdev, qsid); + } + } +} + +static void hclge_dbg_dump_qs_shaper(struct hclge_dev *hdev, + const char *cmd_buf) +{ +#define HCLGE_MAX_QSET_NUM 1024 + + u16 qsid; + int ret; + + ret = kstrtou16(cmd_buf, 0, &qsid); + if (ret) { + hclge_dbg_dump_qs_shaper_all(hdev); + return; + } + + if (qsid >= HCLGE_MAX_QSET_NUM) { + dev_err(&hdev->pdev->dev, "qsid(%u) out of range[0-1023]\n", + qsid); + return; + } + + hclge_dbg_dump_qs_shaper_single(hdev, qsid); +} + int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) { #define DUMP_REG "dump reg" @@ -1145,6 +1221,9 @@ int hclge_dbg_run_cmd(struct hnae3_handle *handle, const char *cmd_buf) &cmd_buf[sizeof("dump ncl_config")]); } else if (strncmp(cmd_buf, "dump mac tnl status", 19) == 0) { hclge_dbg_dump_mac_tnl_status(hdev); + } else if (strncmp(cmd_buf, "dump qs shaper", 14) == 0) { + hclge_dbg_dump_qs_shaper(hdev, + &cmd_buf[sizeof("dump qs shaper")]); } else { dev_info(&hdev->pdev->dev, "unknown command\n"); return -EINVAL; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c63f723dc00e..b88c0aa9a7ff 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1184,6 +1184,35 @@ static void hclge_parse_link_mode(struct hclge_dev *hdev, u8 speed_ability) hclge_parse_backplane_link_mode(hdev, speed_ability); } +static u32 hclge_get_max_speed(u8 speed_ability) +{ + if (speed_ability & HCLGE_SUPPORT_100G_BIT) + return HCLGE_MAC_SPEED_100G; + + if (speed_ability & HCLGE_SUPPORT_50G_BIT) + return HCLGE_MAC_SPEED_50G; + + if (speed_ability & HCLGE_SUPPORT_40G_BIT) + return HCLGE_MAC_SPEED_40G; + + if (speed_ability & HCLGE_SUPPORT_25G_BIT) + return HCLGE_MAC_SPEED_25G; + + if (speed_ability & HCLGE_SUPPORT_10G_BIT) + return HCLGE_MAC_SPEED_10G; + + if (speed_ability & HCLGE_SUPPORT_1G_BIT) + return HCLGE_MAC_SPEED_1G; + + if (speed_ability & HCLGE_SUPPORT_100M_BIT) + return HCLGE_MAC_SPEED_100M; + + if (speed_ability & HCLGE_SUPPORT_10M_BIT) + return HCLGE_MAC_SPEED_10M; + + return HCLGE_MAC_SPEED_1G; +} + static void hclge_parse_cfg(struct hclge_cfg *cfg, struct hclge_desc *desc) { struct hclge_cfg_param_cmd *req; @@ -1354,6 +1383,8 @@ static int hclge_configure(struct hclge_dev *hdev) hclge_parse_link_mode(hdev, cfg.speed_ability); + hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability); + if ((hdev->tc_max > HNAE3_MAX_TC) || (hdev->tc_max < 1)) { dev_warn(&hdev->pdev->dev, "TC num = %d.\n", @@ -2890,6 +2921,8 @@ static int hclge_get_vf_config(struct hnae3_handle *handle, int vf, ivf->linkstate = vport->vf_info.link_state; ivf->spoofchk = vport->vf_info.spoofchk; ivf->trusted = vport->vf_info.trusted; + ivf->min_tx_rate = 0; + ivf->max_tx_rate = vport->vf_info.max_tx_rate; ether_addr_copy(ivf->mac, vport->vf_info.mac); return 0; @@ -9520,6 +9553,97 @@ static int hclge_set_vf_trust(struct hnae3_handle *handle, int vf, bool enable) return 0; } +static void hclge_reset_vf_rate(struct hclge_dev *hdev) +{ + int ret; + int vf; + + /* reset vf rate to default value */ + for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) { + struct hclge_vport *vport = &hdev->vport[vf]; + + vport->vf_info.max_tx_rate = 0; + ret = hclge_tm_qs_shaper_cfg(vport, vport->vf_info.max_tx_rate); + if (ret) + dev_err(&hdev->pdev->dev, + "vf%d failed to reset to default, ret=%d\n", + vf - HCLGE_VF_VPORT_START_NUM, ret); + } +} + +static int hclge_vf_rate_param_check(struct hclge_dev *hdev, int vf, + int min_tx_rate, int max_tx_rate) +{ + if (min_tx_rate != 0 || + max_tx_rate < 0 || max_tx_rate > hdev->hw.mac.max_speed) { + dev_err(&hdev->pdev->dev, + "min_tx_rate:%d [0], max_tx_rate:%d [0, %u]\n", + min_tx_rate, max_tx_rate, hdev->hw.mac.max_speed); + return -EINVAL; + } + + return 0; +} + +static int hclge_set_vf_rate(struct hnae3_handle *handle, int vf, + int min_tx_rate, int max_tx_rate, bool force) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + int ret; + + ret = hclge_vf_rate_param_check(hdev, vf, min_tx_rate, max_tx_rate); + if (ret) + return ret; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + if (!force && max_tx_rate == vport->vf_info.max_tx_rate) + return 0; + + ret = hclge_tm_qs_shaper_cfg(vport, max_tx_rate); + if (ret) + return ret; + + vport->vf_info.max_tx_rate = max_tx_rate; + + return 0; +} + +static int hclge_resume_vf_rate(struct hclge_dev *hdev) +{ + struct hnae3_handle *handle = &hdev->vport->nic; + struct hclge_vport *vport; + int ret; + int vf; + + /* resume the vf max_tx_rate after reset */ + for (vf = 0; vf < pci_num_vf(hdev->pdev); vf++) { + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + /* zero means max rate, after reset, firmware already set it to + * max rate, so just continue. + */ + if (!vport->vf_info.max_tx_rate) + continue; + + ret = hclge_set_vf_rate(handle, vf, 0, + vport->vf_info.max_tx_rate, true); + if (ret) { + dev_err(&hdev->pdev->dev, + "vf%d failed to resume tx_rate:%u, ret=%d\n", + vf, vport->vf_info.max_tx_rate, ret); + return ret; + } + } + + return 0; +} + static void hclge_reset_vport_state(struct hclge_dev *hdev) { struct hclge_vport *vport = hdev->vport; @@ -9623,6 +9747,10 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) if (ret) return ret; + ret = hclge_resume_vf_rate(hdev); + if (ret) + return ret; + dev_info(&pdev->dev, "Reset done, %s driver initialization finished.\n", HCLGE_DRIVER_NAME); @@ -9634,6 +9762,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev) struct hclge_dev *hdev = ae_dev->priv; struct hclge_mac *mac = &hdev->hw.mac; + hclge_reset_vf_rate(hdev); hclge_misc_affinity_teardown(hdev); hclge_state_uninit(hdev); @@ -10360,6 +10489,7 @@ static const struct hnae3_ae_ops hclge_ops = { .set_vf_link_state = hclge_set_vf_link_state, .set_vf_spoofchk = hclge_set_vf_spoofchk, .set_vf_trust = hclge_set_vf_trust, + .set_vf_rate = hclge_set_vf_rate, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 66e8833856e5..3153a96729d3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -258,6 +258,7 @@ struct hclge_mac { u8 support_autoneg; u8 speed_type; /* 0: sfp speed, 1: active speed */ u32 speed; + u32 max_speed; u32 speed_ability; /* speed ability supported by current media */ u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */ u32 fec_mode; /* active fec mode */ @@ -889,6 +890,7 @@ struct hclge_vf_info { int link_state; u8 mac[ETH_ALEN]; u32 spoofchk; + u32 max_tx_rate; u32 trusted; u16 promisc_enable; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index 5cce9b7f1d3d..09349545c473 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -511,6 +511,49 @@ static int hclge_tm_qs_bp_cfg(struct hclge_dev *hdev, u8 tc, u8 grp_id, return hclge_cmd_send(&hdev->hw, &desc, 1); } +int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate) +{ + struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; + struct hclge_qs_shapping_cmd *shap_cfg_cmd; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u8 ir_b, ir_u, ir_s; + u32 shaper_para; + int ret, i; + + if (!max_tx_rate) + max_tx_rate = HCLGE_ETHER_MAX_RATE; + + ret = hclge_shaper_para_calc(max_tx_rate, HCLGE_SHAPER_LVL_QSET, + &ir_b, &ir_u, &ir_s); + if (ret) + return ret; + + shaper_para = hclge_tm_get_shapping_para(ir_b, ir_u, ir_s, + HCLGE_SHAPER_BS_U_DEF, + HCLGE_SHAPER_BS_S_DEF); + + for (i = 0; i < kinfo->num_tc; i++) { + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_QCN_SHAPPING_CFG, + false); + + shap_cfg_cmd = (struct hclge_qs_shapping_cmd *)desc.data; + shap_cfg_cmd->qs_id = cpu_to_le16(vport->qs_offset + i); + shap_cfg_cmd->qs_shapping_para = cpu_to_le32(shaper_para); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "vf%d, qs%u failed to set tx_rate:%d, ret=%d\n", + vport->vport_id, shap_cfg_cmd->qs_id, + max_tx_rate, ret); + return ret; + } + } + + return 0; +} + static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport) { struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h index 818610988d34..95ef6e1204cf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h @@ -96,6 +96,12 @@ struct hclge_pg_shapping_cmd { __le32 pg_shapping_para; }; +struct hclge_qs_shapping_cmd { + __le16 qs_id; + u8 rsvd[2]; + __le32 qs_shapping_para; +}; + #define HCLGE_BP_GRP_NUM 32 #define HCLGE_BP_SUB_GRP_ID_S 0 #define HCLGE_BP_SUB_GRP_ID_M GENMASK(4, 0) @@ -154,4 +160,6 @@ int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx); int hclge_pause_addr_cfg(struct hclge_dev *hdev, const u8 *mac_addr); int hclge_pfc_rx_stats_get(struct hclge_dev *hdev, u64 *stats); int hclge_pfc_tx_stats_get(struct hclge_dev *hdev, u64 *stats); +int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate); + #endif -- cgit v1.2.3-59-g8ed1b From 8e6de441b8e663e33d457494f88860f269933317 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Tue, 8 Oct 2019 09:20:08 +0800 Subject: net: hns3: add support for configuring VF MAC from the host This patch adds support of configuring VF MAC from the host for the HNS3 driver. BTW, the parameter init in the hns3_init_mac_addr is unnecessary now, since the MAC address will not read from NCL_CONFIG when doing reset, so it should be removed, otherwise it will affect VF's MAC address initialization. Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 ++ drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 43 ++++++++++++--- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 62 ++++++++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 29 ++++++++++ .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 28 +++++++++- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 1 + 6 files changed, 158 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 1202bbccf96c..c15d7fc31bb8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -375,6 +375,8 @@ struct hnae3_ae_dev { * it can enable promisc mode * set_vf_rate * Set the max tx rate of specified vf. + * set_vf_mac + * Configure the default MAC for specified VF */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -549,6 +551,7 @@ struct hnae3_ae_ops { int (*set_vf_trust)(struct hnae3_handle *handle, int vf, bool enable); int (*set_vf_rate)(struct hnae3_handle *handle, int vf, int min_tx_rate, int max_tx_rate, bool force); + int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 5a8c316fe431..4e304b441678 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1413,6 +1413,16 @@ static int hns3_nic_net_set_mac_address(struct net_device *netdev, void *p) return 0; } + /* For VF device, if there is a perm_addr, then the user will not + * be allowed to change the address. + */ + if (!hns3_is_phys_func(h->pdev) && + !is_zero_ether_addr(netdev->perm_addr)) { + netdev_err(netdev, "has permanent MAC %pM, user MAC %pM not allow\n", + netdev->perm_addr, mac_addr->sa_data); + return -EPERM; + } + ret = h->ae_algo->ops->set_mac_addr(h, mac_addr->sa_data, false); if (ret) { netdev_err(netdev, "set_mac_address fail, ret=%d!\n", ret); @@ -1862,6 +1872,23 @@ static int hns3_nic_set_vf_rate(struct net_device *ndev, int vf, false); } +static int hns3_nic_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) +{ + struct hnae3_handle *h = hns3_get_handle(netdev); + + if (!h->ae_algo->ops->set_vf_mac) + return -EOPNOTSUPP; + + if (is_multicast_ether_addr(mac)) { + netdev_err(netdev, + "Invalid MAC:%pM specified. Could not set MAC\n", + mac); + return -EINVAL; + } + + return h->ae_algo->ops->set_vf_mac(h, vf_id, mac); +} + static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_open = hns3_nic_net_open, .ndo_stop = hns3_nic_net_stop, @@ -1885,6 +1912,7 @@ static const struct net_device_ops hns3_nic_netdev_ops = { .ndo_get_vf_config = hns3_nic_get_vf_config, .ndo_set_vf_link_state = hns3_nic_set_vf_link_state, .ndo_set_vf_rate = hns3_nic_set_vf_rate, + .ndo_set_vf_mac = hns3_nic_set_vf_mac, }; bool hns3_is_phys_func(struct pci_dev *pdev) @@ -3804,23 +3832,24 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv) } /* Set mac addr if it is configured. or leave it to the AE driver */ -static int hns3_init_mac_addr(struct net_device *netdev, bool init) +static int hns3_init_mac_addr(struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); struct hnae3_handle *h = priv->ae_handle; u8 mac_addr_temp[ETH_ALEN]; int ret = 0; - if (h->ae_algo->ops->get_mac_addr && init) { + if (h->ae_algo->ops->get_mac_addr) h->ae_algo->ops->get_mac_addr(h, mac_addr_temp); - ether_addr_copy(netdev->dev_addr, mac_addr_temp); - } /* Check if the MAC address is valid, if not get a random one */ - if (!is_valid_ether_addr(netdev->dev_addr)) { + if (!is_valid_ether_addr(mac_addr_temp)) { eth_hw_addr_random(netdev); dev_warn(priv->dev, "using random MAC address %pM\n", netdev->dev_addr); + } else { + ether_addr_copy(netdev->dev_addr, mac_addr_temp); + ether_addr_copy(netdev->perm_addr, mac_addr_temp); } if (h->ae_algo->ops->set_mac_addr) @@ -3924,7 +3953,7 @@ static int hns3_client_init(struct hnae3_handle *handle) handle->kinfo.netdev = netdev; handle->priv = (void *)priv; - hns3_init_mac_addr(netdev, true); + hns3_init_mac_addr(netdev); hns3_set_default_feature(netdev); @@ -4392,7 +4421,7 @@ static int hns3_reset_notify_restore_enet(struct hnae3_handle *handle) bool vlan_filter_enable; int ret; - ret = hns3_init_mac_addr(netdev, false); + ret = hns3_init_mac_addr(netdev); if (ret) return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index b88c0aa9a7ff..8a3a4fdc12ed 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7490,6 +7490,67 @@ static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev, return return_status; } +static bool hclge_check_vf_mac_exist(struct hclge_vport *vport, int vf_idx, + u8 *mac_addr) +{ + struct hclge_mac_vlan_tbl_entry_cmd req; + struct hclge_dev *hdev = vport->back; + struct hclge_desc desc; + u16 egress_port = 0; + int i; + + if (is_zero_ether_addr(mac_addr)) + return false; + + memset(&req, 0, sizeof(req)); + hnae3_set_field(egress_port, HCLGE_MAC_EPORT_VFID_M, + HCLGE_MAC_EPORT_VFID_S, vport->vport_id); + req.egress_port = cpu_to_le16(egress_port); + hclge_prepare_mac_addr(&req, mac_addr, false); + + if (hclge_lookup_mac_vlan_tbl(vport, &req, &desc, false) != -ENOENT) + return true; + + vf_idx += HCLGE_VF_VPORT_START_NUM; + for (i = hdev->num_vmdq_vport + 1; i < hdev->num_alloc_vport; i++) + if (i != vf_idx && + ether_addr_equal(mac_addr, hdev->vport[i].vf_info.mac)) + return true; + + return false; +} + +static int hclge_set_vf_mac(struct hnae3_handle *handle, int vf, + u8 *mac_addr) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + vport = hclge_get_vf_vport(hdev, vf); + if (!vport) + return -EINVAL; + + if (ether_addr_equal(mac_addr, vport->vf_info.mac)) { + dev_info(&hdev->pdev->dev, + "Specified MAC(=%pM) is same as before, no change committed!\n", + mac_addr); + return 0; + } + + if (hclge_check_vf_mac_exist(vport, vf, mac_addr)) { + dev_err(&hdev->pdev->dev, "Specified MAC(=%pM) exists!\n", + mac_addr); + return -EEXIST; + } + + ether_addr_copy(vport->vf_info.mac, mac_addr); + dev_info(&hdev->pdev->dev, + "MAC of VF %d has been set to %pM, and it will be reinitialized!\n", + vf, mac_addr); + + return hclge_inform_reset_assert_to_vf(vport); +} + static int hclge_add_mgr_tbl(struct hclge_dev *hdev, const struct hclge_mac_mgr_tbl_entry_cmd *req) { @@ -10490,6 +10551,7 @@ static const struct hnae3_ae_ops hclge_ops = { .set_vf_spoofchk = hclge_set_vf_spoofchk, .set_vf_trust = hclge_set_vf_trust, .set_vf_rate = hclge_set_vf_rate, + .set_vf_mac = hclge_set_vf_mac, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 131b47bac3a2..97463e11aca7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -249,6 +249,20 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, if (mbx_req->msg[1] == HCLGE_MBX_MAC_VLAN_UC_MODIFY) { const u8 *old_addr = (const u8 *)(&mbx_req->msg[8]); + /* If VF MAC has been configured by the host then it + * cannot be overridden by the MAC specified by the VM. + */ + if (!is_zero_ether_addr(vport->vf_info.mac) && + !ether_addr_equal(mac_addr, vport->vf_info.mac)) { + status = -EPERM; + goto out; + } + + if (!is_valid_ether_addr(mac_addr)) { + status = -EINVAL; + goto out; + } + hclge_rm_uc_addr_common(vport, old_addr); status = hclge_add_uc_addr_common(vport, mac_addr); if (status) { @@ -276,6 +290,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, return -EIO; } +out: if (mbx_req->mbx_need_resp & HCLGE_MBX_NEED_RESP_BIT) hclge_gen_resp_to_vf(vport, mbx_req, status, NULL, 0); @@ -427,6 +442,13 @@ static int hclge_get_vf_queue_info(struct hclge_vport *vport, HCLGE_TQPS_RSS_INFO_LEN); } +static int hclge_get_vf_mac_addr(struct hclge_vport *vport, + struct hclge_mbx_vf_to_pf_cmd *mbx_req) +{ + return hclge_gen_resp_to_vf(vport, mbx_req, 0, vport->vf_info.mac, + ETH_ALEN); +} + static int hclge_get_vf_queue_depth(struct hclge_vport *vport, struct hclge_mbx_vf_to_pf_cmd *mbx_req, bool gen_resp) @@ -793,6 +815,13 @@ void hclge_mbx_handler(struct hclge_dev *hdev) case HCLGE_MBX_PUSH_LINK_STATUS: hclge_handle_link_change_event(hdev, req); break; + case HCLGE_MBX_GET_MAC_ADDR: + ret = hclge_get_vf_mac_addr(vport, req); + if (ret) + dev_err(&hdev->pdev->dev, + "PF failed(%d) to get MAC for VF\n", + ret); + break; case HCLGE_MBX_NCSI_ERROR: hclge_handle_ncsi_error(hdev); break; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 17326681db6d..9c8fd971f9fd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1176,11 +1176,37 @@ static void hclgevf_reset_tqp_stats(struct hnae3_handle *handle) } } +static int hclgevf_get_host_mac_addr(struct hclgevf_dev *hdev, u8 *p) +{ + u8 host_mac[ETH_ALEN]; + int status; + + status = hclgevf_send_mbx_msg(hdev, HCLGE_MBX_GET_MAC_ADDR, 0, NULL, 0, + true, host_mac, ETH_ALEN); + if (status) { + dev_err(&hdev->pdev->dev, + "fail to get VF MAC from host %d", status); + return status; + } + + ether_addr_copy(p, host_mac); + + return 0; +} + static void hclgevf_get_mac_addr(struct hnae3_handle *handle, u8 *p) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + u8 host_mac_addr[ETH_ALEN]; - ether_addr_copy(p, hdev->hw.mac.mac_addr); + if (hclgevf_get_host_mac_addr(hdev, host_mac_addr)) + return; + + hdev->has_pf_mac = !is_zero_ether_addr(host_mac_addr); + if (hdev->has_pf_mac) + ether_addr_copy(p, host_mac_addr); + else + ether_addr_copy(p, hdev->hw.mac.mac_addr); } static int hclgevf_set_mac_addr(struct hnae3_handle *handle, void *p, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index bdde3afc286b..ed839408850e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -266,6 +266,7 @@ struct hclgevf_dev { u16 num_tx_desc; /* desc num of per tx queue */ u16 num_rx_desc; /* desc num of per rx queue */ u8 hw_tc_map; + u8 has_pf_mac; u16 num_msi; u16 num_msi_left; -- cgit v1.2.3-59-g8ed1b From 8ae10cfb508977c186c9d6e1ac873c4280b10fa3 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Tue, 8 Oct 2019 09:20:09 +0800 Subject: net: hns3: support tx-scatter-gather-fraglist feature The hardware supports up to 8 TX BD for non-tso skb and up to 63 TX BD for TSO skb. Currently, the hns3 driver supports RX skb with fraglist when HW GRO is enabled, when the stack forwards a RX skb with fraglist, the stack need to linearize the skb before sending to other interface without TX fraglist support. This patch adds support for TX fraglist. The performance increases from 1 GByte to 1.5 GByte for one iperf TCP stream during forwarding test after this patch. BTW, the minimum BD number of ring should be updated to 72 for supporting TX fraglist. This patch also changes the error handling of some function that called by hns3_fill_desc, which returns BD num when there is no error, change some macro to more meaningful name. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 249 +++++++++++++++--------- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 12 +- 2 files changed, 168 insertions(+), 93 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4e304b441678..6e0b2612d92d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -681,7 +681,7 @@ static int hns3_set_tso(struct sk_buff *skb, u32 *paylen, return 0; ret = skb_cow_head(skb, 0); - if (unlikely(ret)) + if (unlikely(ret < 0)) return ret; l3.hdr = skb_network_header(skb); @@ -962,14 +962,6 @@ static int hns3_set_l2l3l4(struct sk_buff *skb, u8 ol4_proto, return 0; } -static void hns3_set_txbd_baseinfo(u16 *bdtp_fe_sc_vld_ra_ri, int frag_end) -{ - /* Config bd buffer end */ - if (!!frag_end) - hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_FE_B, 1U); - hns3_set_field(*bdtp_fe_sc_vld_ra_ri, HNS3_TXD_VLD_B, 1U); -} - static int hns3_handle_vtags(struct hns3_enet_ring *tx_ring, struct sk_buff *skb) { @@ -1062,7 +1054,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, skb_reset_mac_len(skb); ret = hns3_get_l4_protocol(skb, &ol4_proto, &il4_proto); - if (unlikely(ret)) { + if (unlikely(ret < 0)) { u64_stats_update_begin(&ring->syncp); ring->stats.tx_l4_proto_err++; u64_stats_update_end(&ring->syncp); @@ -1072,7 +1064,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, ret = hns3_set_l2l3l4(skb, ol4_proto, il4_proto, &type_cs_vlan_tso, &ol_type_vlan_len_msec); - if (unlikely(ret)) { + if (unlikely(ret < 0)) { u64_stats_update_begin(&ring->syncp); ring->stats.tx_l2l3l4_err++; u64_stats_update_end(&ring->syncp); @@ -1081,7 +1073,7 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, ret = hns3_set_tso(skb, &paylen, &mss, &type_cs_vlan_tso); - if (unlikely(ret)) { + if (unlikely(ret < 0)) { u64_stats_update_begin(&ring->syncp); ring->stats.tx_tso_err++; u64_stats_update_end(&ring->syncp); @@ -1102,9 +1094,10 @@ static int hns3_fill_skb_desc(struct hns3_enet_ring *ring, } static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, - unsigned int size, int frag_end, - enum hns_desc_type type) + unsigned int size, enum hns_desc_type type) { +#define HNS3_LIKELY_BD_NUM 1 + struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use]; struct hns3_desc *desc = &ring->desc[ring->next_to_use]; struct device *dev = ring_to_dev(ring); @@ -1118,7 +1111,7 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, int ret; ret = hns3_fill_skb_desc(ring, skb, desc); - if (unlikely(ret)) + if (unlikely(ret < 0)) return ret; dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE); @@ -1137,19 +1130,16 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, desc_cb->length = size; if (likely(size <= HNS3_MAX_BD_SIZE)) { - u16 bdtp_fe_sc_vld_ra_ri = 0; - desc_cb->priv = priv; desc_cb->dma = dma; desc_cb->type = type; desc->addr = cpu_to_le64(dma); desc->tx.send_size = cpu_to_le16(size); - hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, frag_end); desc->tx.bdtp_fe_sc_vld_ra_ri = - cpu_to_le16(bdtp_fe_sc_vld_ra_ri); + cpu_to_le16(BIT(HNS3_TXD_VLD_B)); ring_ptr_move_fw(ring, next_to_use); - return 0; + return HNS3_LIKELY_BD_NUM; } frag_buf_num = hns3_tx_bd_count(size); @@ -1158,8 +1148,6 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, /* When frag size is bigger than hardware limit, split this frag */ for (k = 0; k < frag_buf_num; k++) { - u16 bdtp_fe_sc_vld_ra_ri = 0; - /* The txbd's baseinfo of DESC_TYPE_PAGE & DESC_TYPE_SKB */ desc_cb->priv = priv; desc_cb->dma = dma + HNS3_MAX_BD_SIZE * k; @@ -1170,11 +1158,8 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, desc->addr = cpu_to_le64(dma + HNS3_MAX_BD_SIZE * k); desc->tx.send_size = cpu_to_le16((k == frag_buf_num - 1) ? (u16)sizeoflast : (u16)HNS3_MAX_BD_SIZE); - hns3_set_txbd_baseinfo(&bdtp_fe_sc_vld_ra_ri, - frag_end && (k == frag_buf_num - 1) ? - 1 : 0); desc->tx.bdtp_fe_sc_vld_ra_ri = - cpu_to_le16(bdtp_fe_sc_vld_ra_ri); + cpu_to_le16(BIT(HNS3_TXD_VLD_B)); /* move ring pointer to next */ ring_ptr_move_fw(ring, next_to_use); @@ -1183,23 +1168,78 @@ static int hns3_fill_desc(struct hns3_enet_ring *ring, void *priv, desc = &ring->desc[ring->next_to_use]; } - return 0; + return frag_buf_num; } -static unsigned int hns3_nic_bd_num(struct sk_buff *skb) +static unsigned int hns3_skb_bd_num(struct sk_buff *skb, unsigned int *bd_size, + unsigned int bd_num) { - unsigned int bd_num; + unsigned int size; int i; - /* if the total len is within the max bd limit */ - if (likely(skb->len <= HNS3_MAX_BD_SIZE)) - return skb_shinfo(skb)->nr_frags + 1; + size = skb_headlen(skb); + while (size > HNS3_MAX_BD_SIZE) { + bd_size[bd_num++] = HNS3_MAX_BD_SIZE; + size -= HNS3_MAX_BD_SIZE; + + if (bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; + } - bd_num = hns3_tx_bd_count(skb_headlen(skb)); + if (size) { + bd_size[bd_num++] = size; + if (bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; + } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - bd_num += hns3_tx_bd_count(skb_frag_size(frag)); + size = skb_frag_size(frag); + if (!size) + continue; + + while (size > HNS3_MAX_BD_SIZE) { + bd_size[bd_num++] = HNS3_MAX_BD_SIZE; + size -= HNS3_MAX_BD_SIZE; + + if (bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; + } + + bd_size[bd_num++] = size; + if (bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; + } + + return bd_num; +} + +static unsigned int hns3_tx_bd_num(struct sk_buff *skb, unsigned int *bd_size) +{ + struct sk_buff *frag_skb; + unsigned int bd_num = 0; + + /* If the total len is within the max bd limit */ + if (likely(skb->len <= HNS3_MAX_BD_SIZE && !skb_has_frag_list(skb) && + skb_shinfo(skb)->nr_frags < HNS3_MAX_NON_TSO_BD_NUM)) + return skb_shinfo(skb)->nr_frags + 1U; + + /* The below case will always be linearized, return + * HNS3_MAX_BD_NUM_TSO + 1U to make sure it is linearized. + */ + if (unlikely(skb->len > HNS3_MAX_TSO_SIZE || + (!skb_is_gso(skb) && skb->len > HNS3_MAX_NON_TSO_SIZE))) + return HNS3_MAX_TSO_BD_NUM + 1U; + + bd_num = hns3_skb_bd_num(skb, bd_size, bd_num); + + if (!skb_has_frag_list(skb) || bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; + + skb_walk_frags(skb, frag_skb) { + bd_num = hns3_skb_bd_num(frag_skb, bd_size, bd_num); + if (bd_num > HNS3_MAX_TSO_BD_NUM) + return bd_num; } return bd_num; @@ -1218,26 +1258,26 @@ static unsigned int hns3_gso_hdr_len(struct sk_buff *skb) * 7 frags to to be larger than gso header len + mss, and the remaining * continuous 7 frags to be larger than MSS except the last 7 frags. */ -static bool hns3_skb_need_linearized(struct sk_buff *skb) +static bool hns3_skb_need_linearized(struct sk_buff *skb, unsigned int *bd_size, + unsigned int bd_num) { - int bd_limit = HNS3_MAX_BD_NUM_NORMAL - 1; unsigned int tot_len = 0; int i; - for (i = 0; i < bd_limit; i++) - tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i]); + for (i = 0; i < HNS3_MAX_NON_TSO_BD_NUM - 1U; i++) + tot_len += bd_size[i]; - /* ensure headlen + the first 7 frags is greater than mss + header - * and the first 7 frags is greater than mss. - */ - if (((tot_len + skb_headlen(skb)) < (skb_shinfo(skb)->gso_size + - hns3_gso_hdr_len(skb))) || (tot_len < skb_shinfo(skb)->gso_size)) + /* ensure the first 8 frags is greater than mss + header */ + if (tot_len + bd_size[HNS3_MAX_NON_TSO_BD_NUM - 1U] < + skb_shinfo(skb)->gso_size + hns3_gso_hdr_len(skb)) return true; - /* ensure the remaining continuous 7 buffer is greater than mss */ - for (i = 0; i < (skb_shinfo(skb)->nr_frags - bd_limit - 1); i++) { - tot_len -= skb_frag_size(&skb_shinfo(skb)->frags[i]); - tot_len += skb_frag_size(&skb_shinfo(skb)->frags[i + bd_limit]); + /* ensure every continuous 7 buffer is greater than mss + * except the last one. + */ + for (i = 0; i < bd_num - HNS3_MAX_NON_TSO_BD_NUM; i++) { + tot_len -= bd_size[i]; + tot_len += bd_size[i + HNS3_MAX_NON_TSO_BD_NUM - 1U]; if (tot_len < skb_shinfo(skb)->gso_size) return true; @@ -1249,15 +1289,16 @@ static bool hns3_skb_need_linearized(struct sk_buff *skb) static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring, struct sk_buff **out_skb) { + unsigned int bd_size[HNS3_MAX_TSO_BD_NUM + 1U]; struct sk_buff *skb = *out_skb; unsigned int bd_num; - bd_num = hns3_nic_bd_num(skb); - if (unlikely(bd_num > HNS3_MAX_BD_NUM_NORMAL)) { + bd_num = hns3_tx_bd_num(skb, bd_size); + if (unlikely(bd_num > HNS3_MAX_NON_TSO_BD_NUM)) { struct sk_buff *new_skb; - if (skb_is_gso(skb) && bd_num <= HNS3_MAX_BD_NUM_TSO && - !hns3_skb_need_linearized(skb)) + if (bd_num <= HNS3_MAX_TSO_BD_NUM && skb_is_gso(skb) && + !hns3_skb_need_linearized(skb, bd_size, bd_num)) goto out; /* manual split the send packet */ @@ -1267,9 +1308,10 @@ static int hns3_nic_maybe_stop_tx(struct hns3_enet_ring *ring, dev_kfree_skb_any(skb); *out_skb = new_skb; - bd_num = hns3_nic_bd_num(new_skb); - if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_TSO) || - (!skb_is_gso(new_skb) && bd_num > HNS3_MAX_BD_NUM_NORMAL)) + bd_num = hns3_tx_bd_count(new_skb->len); + if ((skb_is_gso(new_skb) && bd_num > HNS3_MAX_TSO_BD_NUM) || + (!skb_is_gso(new_skb) && + bd_num > HNS3_MAX_NON_TSO_BD_NUM)) return -ENOMEM; u64_stats_update_begin(&ring->syncp); @@ -1314,6 +1356,37 @@ static void hns3_clear_desc(struct hns3_enet_ring *ring, int next_to_use_orig) } } +static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring, + struct sk_buff *skb, enum hns_desc_type type) +{ + unsigned int size = skb_headlen(skb); + int i, ret, bd_num = 0; + + if (size) { + ret = hns3_fill_desc(ring, skb, size, type); + if (unlikely(ret < 0)) + return ret; + + bd_num += ret; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + size = skb_frag_size(frag); + if (!size) + continue; + + ret = hns3_fill_desc(ring, frag, size, DESC_TYPE_PAGE); + if (unlikely(ret < 0)) + return ret; + + bd_num += ret; + } + + return bd_num; +} + netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); @@ -1321,58 +1394,54 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) &tx_ring_data(priv, skb->queue_mapping); struct hns3_enet_ring *ring = ring_data->ring; struct netdev_queue *dev_queue; - skb_frag_t *frag; - int next_to_use_head; - int buf_num; - int seg_num; - int size; + int pre_ntu, next_to_use_head; + struct sk_buff *frag_skb; + int bd_num = 0; int ret; - int i; /* Prefetch the data used later */ prefetch(skb->data); - buf_num = hns3_nic_maybe_stop_tx(ring, &skb); - if (unlikely(buf_num <= 0)) { - if (buf_num == -EBUSY) { + ret = hns3_nic_maybe_stop_tx(ring, &skb); + if (unlikely(ret <= 0)) { + if (ret == -EBUSY) { u64_stats_update_begin(&ring->syncp); ring->stats.tx_busy++; u64_stats_update_end(&ring->syncp); goto out_net_tx_busy; - } else if (buf_num == -ENOMEM) { + } else if (ret == -ENOMEM) { u64_stats_update_begin(&ring->syncp); ring->stats.sw_err_cnt++; u64_stats_update_end(&ring->syncp); } - hns3_rl_err(netdev, "xmit error: %d!\n", buf_num); + hns3_rl_err(netdev, "xmit error: %d!\n", ret); goto out_err_tx_ok; } - /* No. of segments (plus a header) */ - seg_num = skb_shinfo(skb)->nr_frags + 1; - /* Fill the first part */ - size = skb_headlen(skb); - next_to_use_head = ring->next_to_use; - ret = hns3_fill_desc(ring, skb, size, seg_num == 1 ? 1 : 0, - DESC_TYPE_SKB); - if (unlikely(ret)) + ret = hns3_fill_skb_to_desc(ring, skb, DESC_TYPE_SKB); + if (unlikely(ret < 0)) goto fill_err; - /* Fill the fragments */ - for (i = 1; i < seg_num; i++) { - frag = &skb_shinfo(skb)->frags[i - 1]; - size = skb_frag_size(frag); + bd_num += ret; - ret = hns3_fill_desc(ring, frag, size, - seg_num - 1 == i ? 1 : 0, - DESC_TYPE_PAGE); + if (!skb_has_frag_list(skb)) + goto out; - if (unlikely(ret)) + skb_walk_frags(skb, frag_skb) { + ret = hns3_fill_skb_to_desc(ring, frag_skb, DESC_TYPE_PAGE); + if (unlikely(ret < 0)) goto fill_err; + + bd_num += ret; } +out: + pre_ntu = ring->next_to_use ? (ring->next_to_use - 1) : + (ring->desc_num - 1); + ring->desc[pre_ntu].tx.bdtp_fe_sc_vld_ra_ri |= + cpu_to_le16(BIT(HNS3_TXD_FE_B)); /* Complete translate all packets */ dev_queue = netdev_get_tx_queue(netdev, ring_data->queue_index); @@ -1380,7 +1449,7 @@ netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) wmb(); /* Commit all data before submit */ - hnae3_queue_xmit(ring->tqp, buf_num); + hnae3_queue_xmit(ring->tqp, bd_num); return NETDEV_TX_OK; @@ -2158,9 +2227,8 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; - - netdev->hw_enc_features |= NETIF_F_TSO_MANGLEID; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_TSO_MANGLEID | NETIF_F_FRAGLIST; netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM; @@ -2170,21 +2238,24 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_FRAGLIST; netdev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_FRAGLIST; netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL | - NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC; + NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_FRAGLIST; if (pdev->revision >= 0x21) { netdev->hw_features |= NETIF_F_GRO_HW; @@ -2447,7 +2518,7 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring) netdev_tx_completed_queue(dev_queue, pkts, bytes); if (unlikely(pkts && netif_carrier_ok(netdev) && - (ring_space(ring) > HNS3_MAX_BD_PER_PKT))) { + ring_space(ring) > HNS3_MAX_TSO_BD_NUM)) { /* Make sure that anybody stopping the queue after this * sees the new next_to_clean. */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 2110fa3b4479..c5b7c22263b1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -76,7 +76,7 @@ enum hns3_nic_state { #define HNS3_RING_NAME_LEN 16 #define HNS3_BUFFER_SIZE_2048 2048 #define HNS3_RING_MAX_PENDING 32760 -#define HNS3_RING_MIN_PENDING 24 +#define HNS3_RING_MIN_PENDING 72 #define HNS3_RING_BD_MULTIPLE 8 /* max frame size of mac */ #define HNS3_MAC_MAX_FRAME 9728 @@ -195,9 +195,13 @@ enum hns3_nic_state { #define HNS3_VECTOR_INITED 1 #define HNS3_MAX_BD_SIZE 65535 -#define HNS3_MAX_BD_NUM_NORMAL 8 -#define HNS3_MAX_BD_NUM_TSO 63 -#define HNS3_MAX_BD_PER_PKT MAX_SKB_FRAGS +#define HNS3_MAX_NON_TSO_BD_NUM 8U +#define HNS3_MAX_TSO_BD_NUM 63U +#define HNS3_MAX_TSO_SIZE \ + (HNS3_MAX_BD_SIZE * HNS3_MAX_TSO_BD_NUM) + +#define HNS3_MAX_NON_TSO_SIZE \ + (HNS3_MAX_BD_SIZE * HNS3_MAX_NON_TSO_BD_NUM) #define HNS3_VECTOR_GL0_OFFSET 0x100 #define HNS3_VECTOR_GL1_OFFSET 0x200 -- cgit v1.2.3-59-g8ed1b From bacb7e1855969bba78b32302453d2cc8ba0bc403 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 8 Oct 2019 14:20:34 -0700 Subject: Revert "tun: call dev_get_valid_name() before register_netdevice()" This reverts commit 0ad646c81b2182f7fa67ec0c8c825e0ee165696d. As noticed by Jakub, this is no longer needed after commit 11fc7d5a0a2d ("tun: fix memory leak in error path") This no longer exports dev_get_valid_name() for the exclusive use of tun driver. Suggested-by: Jakub Kicinski Signed-off-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/tun.c | 3 --- include/linux/netdevice.h | 3 --- net/core/dev.c | 5 ++--- 3 files changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 1e541b08b136..0413d182d782 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -2788,9 +2788,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) if (!dev) return -ENOMEM; - err = dev_get_valid_name(net, dev, name); - if (err < 0) - goto err_free_dev; dev_net_set(dev, net); dev->rtnl_link_ops = &tun_link_ops; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index fe45b2c72315..3207e0b9ec4e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -4113,9 +4113,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, unsigned char name_assign_type, void (*setup)(struct net_device *), unsigned int txqs, unsigned int rxqs); -int dev_get_valid_name(struct net *net, struct net_device *dev, - const char *name); - #define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \ alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1) diff --git a/net/core/dev.c b/net/core/dev.c index 7d05e042c6ba..8bc3dce71fc0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1249,8 +1249,8 @@ int dev_alloc_name(struct net_device *dev, const char *name) } EXPORT_SYMBOL(dev_alloc_name); -int dev_get_valid_name(struct net *net, struct net_device *dev, - const char *name) +static int dev_get_valid_name(struct net *net, struct net_device *dev, + const char *name) { BUG_ON(!net); @@ -1266,7 +1266,6 @@ int dev_get_valid_name(struct net *net, struct net_device *dev, return 0; } -EXPORT_SYMBOL(dev_get_valid_name); /** * dev_change_name - change name of a device -- cgit v1.2.3-59-g8ed1b From a9bb0b51577835d26054d080c59935be8b7e44f4 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 2 Oct 2019 20:18:07 +0800 Subject: rtl8xxxu: Improve TX performance of RTL8723BU on rtl8xxxu driver We have 3 laptops which connect the wifi by the same RTL8723BU. The PCI VID/PID of the wifi chip is 10EC:B720 which is supported. They have the same problem with the in-kernel rtl8xxxu driver, the iperf (as a client to an ethernet-connected server) gets ~1Mbps. Nevertheless, the signal strength is reported as around -40dBm, which is quite good. From the wireshark capture, the tx rate for each data and qos data packet is only 1Mbps. Compare to the Realtek driver at https://github.com/lwfinger/rtl8723bu, the same iperf test gets ~12Mbps or better. The signal strength is reported similarly around -40dBm. That's why we want to improve. After reading the source code of the rtl8xxxu driver and Realtek's, the major difference is that Realtek's driver has a watchdog which will keep monitoring the signal quality and updating the rate mask just like the rtl8xxxu_gen2_update_rate_mask() does if signal quality changes. And this kind of watchdog also exists in rtlwifi driver of some specific chips, ex rtl8192ee, rtl8188ee, rtl8723ae, rtl8821ae...etc. They have the same member function named dm_watchdog and will invoke the corresponding dm_refresh_rate_adaptive_mask to adjust the tx rate mask. With this commit, the tx rate of each data and qos data packet will be 39Mbps (MCS4) with the 0xF00000 as the tx rate mask. The 20th bit to 23th bit means MCS4 to MCS7. It means that the firmware still picks the lowest rate from the rate mask and explains why the tx rate of data and qos data is always lowest 1Mbps because the default rate mask passed is always 0xFFFFFFF ranges from the basic CCK rate, OFDM rate, and MCS rate. However, with Realtek's driver, the tx rate observed from wireshark under the same condition is almost 65Mbps or 72Mbps, which indicating that rtl8xxxu could still be further improved. Signed-off-by: Chris Chiu Reviewed-by: Daniel Drake Acked-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 55 ++++- .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 230 ++++++++++++++++++++- 2 files changed, 278 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index ade057d868f7..582c2a346cec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1187,6 +1187,48 @@ struct rtl8723bu_c2h { struct rtl8xxxu_fileops; +/*mlme related.*/ +enum wireless_mode { + WIRELESS_MODE_UNKNOWN = 0, + /* Sub-Element */ + WIRELESS_MODE_B = BIT(0), + WIRELESS_MODE_G = BIT(1), + WIRELESS_MODE_A = BIT(2), + WIRELESS_MODE_N_24G = BIT(3), + WIRELESS_MODE_N_5G = BIT(4), + WIRELESS_AUTO = BIT(5), + WIRELESS_MODE_AC = BIT(6), + WIRELESS_MODE_MAX = 0x7F, +}; + +/* from rtlwifi/wifi.h */ +enum ratr_table_mode_new { + RATEID_IDX_BGN_40M_2SS = 0, + RATEID_IDX_BGN_40M_1SS = 1, + RATEID_IDX_BGN_20M_2SS_BN = 2, + RATEID_IDX_BGN_20M_1SS_BN = 3, + RATEID_IDX_GN_N2SS = 4, + RATEID_IDX_GN_N1SS = 5, + RATEID_IDX_BG = 6, + RATEID_IDX_G = 7, + RATEID_IDX_B = 8, + RATEID_IDX_VHT_2SS = 9, + RATEID_IDX_VHT_1SS = 10, + RATEID_IDX_MIX1 = 11, + RATEID_IDX_MIX2 = 12, + RATEID_IDX_VHT_3SS = 13, + RATEID_IDX_BGN_3SS = 14, +}; + +#define RTL8XXXU_RATR_STA_INIT 0 +#define RTL8XXXU_RATR_STA_HIGH 1 +#define RTL8XXXU_RATR_STA_MID 2 +#define RTL8XXXU_RATR_STA_LOW 3 + +#define RTL8XXXU_NOISE_FLOOR_MIN -100 +#define RTL8XXXU_SNR_THRESH_HIGH 50 +#define RTL8XXXU_SNR_THRESH_LOW 20 + struct rtl8xxxu_priv { struct ieee80211_hw *hw; struct usb_device *udev; @@ -1291,6 +1333,13 @@ struct rtl8xxxu_priv { u8 pi_enabled:1; u8 no_pape:1; u8 int_buf[USB_INTR_CONTENT_LENGTH]; + u8 rssi_level; + /* + * Only one virtual interface permitted because only STA mode + * is supported and no iface_combinations are provided. + */ + struct ieee80211_vif *vif; + struct delayed_work ra_watchdog; }; struct rtl8xxxu_rx_urb { @@ -1326,7 +1375,7 @@ 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, int sgi); + u32 ramask, u8 rateid, int sgi); void (*report_connect) (struct rtl8xxxu_priv *priv, u8 macid, bool connect); void (*fill_txdesc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, @@ -1411,9 +1460,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, int sgi); + u32 ramask, u8 rateid, int sgi); void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi); + u32 ramask, u8 rateid, int sgi); void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv, u8 macid, bool connect); void rtl8xxxu_gen2_report_connect(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 776bbae14a8d..bd5ccb3aa5d7 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4304,7 +4304,8 @@ static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw, rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); } -void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, int sgi) +void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, + u32 ramask, u8 rateid, int sgi) { struct h2c_cmd h2c; @@ -4324,7 +4325,7 @@ void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv, u32 ramask, int sgi) } void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, - u32 ramask, int sgi) + u32 ramask, u8 rateid, int sgi) { struct h2c_cmd h2c; u8 bw = 0; @@ -4338,7 +4339,7 @@ void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv, h2c.b_macid_cfg.ramask3 = (ramask >> 24) & 0xff; h2c.ramask.arg = 0x80; - h2c.b_macid_cfg.data1 = 0; + h2c.b_macid_cfg.data1 = rateid; if (sgi) h2c.b_macid_cfg.data1 |= BIT(7); @@ -4478,6 +4479,40 @@ static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); } +static u16 +rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) +{ + u16 network_type = WIRELESS_MODE_UNKNOWN; + u32 rate_mask; + + rate_mask = (sta->supp_rates[0] & 0xfff) | + (sta->ht_cap.mcs.rx_mask[0] << 12) | + (sta->ht_cap.mcs.rx_mask[0] << 20); + + if (hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) { + if (sta->vht_cap.vht_supported) + network_type = WIRELESS_MODE_AC; + else if (sta->ht_cap.ht_supported) + network_type = WIRELESS_MODE_N_5G; + + network_type |= WIRELESS_MODE_A; + } else { + if (sta->vht_cap.vht_supported) + network_type = WIRELESS_MODE_AC; + else if (sta->ht_cap.ht_supported) + network_type = WIRELESS_MODE_N_24G; + + if (sta->supp_rates[0] <= 0xf) + network_type |= WIRELESS_MODE_B; + else if (sta->supp_rates[0] & 0xf) + network_type |= (WIRELESS_MODE_B | WIRELESS_MODE_G); + else + network_type |= WIRELESS_MODE_G; + } + + return network_type; +} + static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -4520,7 +4555,10 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, sgi = 1; rcu_read_unlock(); - priv->fops->update_rate_mask(priv, ramask, sgi); + priv->vif = vif; + priv->rssi_level = RTL8XXXU_RATR_STA_INIT; + + priv->fops->update_rate_mask(priv, ramask, 0, sgi); rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); @@ -5465,6 +5503,10 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, 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); @@ -5488,6 +5530,9 @@ static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, struct rtl8xxxu_priv *priv = hw->priv; dev_dbg(&priv->udev->dev, "%s\n", __func__); + + if (priv->vif) + priv->vif = NULL; } static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) @@ -5773,6 +5818,178 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } +static u8 rtl8xxxu_signal_to_snr(int signal) +{ + if (signal < RTL8XXXU_NOISE_FLOOR_MIN) + signal = RTL8XXXU_NOISE_FLOOR_MIN; + else if (signal > 0) + signal = 0; + return (u8)(signal - RTL8XXXU_NOISE_FLOOR_MIN); +} + +static void rtl8xxxu_refresh_rate_mask(struct rtl8xxxu_priv *priv, + int signal, struct ieee80211_sta *sta) +{ + struct ieee80211_hw *hw = priv->hw; + u16 wireless_mode; + u8 rssi_level, ratr_idx; + u8 txbw_40mhz; + u8 snr, snr_thresh_high, snr_thresh_low; + u8 go_up_gap = 5; + + rssi_level = priv->rssi_level; + snr = rtl8xxxu_signal_to_snr(signal); + snr_thresh_high = RTL8XXXU_SNR_THRESH_HIGH; + snr_thresh_low = RTL8XXXU_SNR_THRESH_LOW; + txbw_40mhz = (hw->conf.chandef.width == NL80211_CHAN_WIDTH_40) ? 1 : 0; + + switch (rssi_level) { + case RTL8XXXU_RATR_STA_MID: + snr_thresh_high += go_up_gap; + break; + case RTL8XXXU_RATR_STA_LOW: + snr_thresh_high += go_up_gap; + snr_thresh_low += go_up_gap; + break; + default: + break; + } + + if (snr > snr_thresh_high) + rssi_level = RTL8XXXU_RATR_STA_HIGH; + else if (snr > snr_thresh_low) + rssi_level = RTL8XXXU_RATR_STA_MID; + else + rssi_level = RTL8XXXU_RATR_STA_LOW; + + if (rssi_level != priv->rssi_level) { + int sgi = 0; + u32 rate_bitmap = 0; + + rcu_read_lock(); + rate_bitmap = (sta->supp_rates[0] & 0xfff) | + (sta->ht_cap.mcs.rx_mask[0] << 12) | + (sta->ht_cap.mcs.rx_mask[1] << 20); + if (sta->ht_cap.cap & + (IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20)) + sgi = 1; + rcu_read_unlock(); + + wireless_mode = rtl8xxxu_wireless_mode(hw, sta); + switch (wireless_mode) { + case WIRELESS_MODE_B: + ratr_idx = RATEID_IDX_B; + if (rate_bitmap & 0x0000000c) + rate_bitmap &= 0x0000000d; + else + rate_bitmap &= 0x0000000f; + break; + case WIRELESS_MODE_A: + case WIRELESS_MODE_G: + ratr_idx = RATEID_IDX_G; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else + rate_bitmap &= 0x00000ff0; + break; + case (WIRELESS_MODE_B | WIRELESS_MODE_G): + ratr_idx = RATEID_IDX_BG; + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) + rate_bitmap &= 0x00000f00; + else if (rssi_level == RTL8XXXU_RATR_STA_MID) + rate_bitmap &= 0x00000ff0; + else + rate_bitmap &= 0x00000ff5; + break; + case WIRELESS_MODE_N_24G: + case WIRELESS_MODE_N_5G: + case (WIRELESS_MODE_G | WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_A | WIRELESS_MODE_N_5G): + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_GN_N2SS; + else + ratr_idx = RATEID_IDX_GN_N1SS; + break; + case (WIRELESS_MODE_B | WIRELESS_MODE_G | WIRELESS_MODE_N_24G): + case (WIRELESS_MODE_B | WIRELESS_MODE_N_24G): + if (txbw_40mhz) { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_BGN_40M_2SS; + else + ratr_idx = RATEID_IDX_BGN_40M_1SS; + } else { + if (priv->tx_paths == 2 && priv->rx_paths == 2) + ratr_idx = RATEID_IDX_BGN_20M_2SS_BN; + else + ratr_idx = RATEID_IDX_BGN_20M_1SS_BN; + } + + if (priv->tx_paths == 2 && priv->rx_paths == 2) { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { + rate_bitmap &= 0x0f8f0000; + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { + rate_bitmap &= 0x0f8ff000; + } else { + if (txbw_40mhz) + rate_bitmap &= 0x0f8ff015; + else + rate_bitmap &= 0x0f8ff005; + } + } else { + if (rssi_level == RTL8XXXU_RATR_STA_HIGH) { + rate_bitmap &= 0x000f0000; + } else if (rssi_level == RTL8XXXU_RATR_STA_MID) { + rate_bitmap &= 0x000ff000; + } else { + if (txbw_40mhz) + rate_bitmap &= 0x000ff015; + else + rate_bitmap &= 0x000ff005; + } + } + break; + default: + ratr_idx = RATEID_IDX_BGN_40M_2SS; + rate_bitmap &= 0x0fffffff; + break; + } + + priv->rssi_level = rssi_level; + priv->fops->update_rate_mask(priv, rate_bitmap, ratr_idx, sgi); + } +} + +static void rtl8xxxu_watchdog_callback(struct work_struct *work) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_priv *priv; + + priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); + vif = priv->vif; + + if (vif && vif->type == NL80211_IFTYPE_STATION) { + int signal; + struct ieee80211_sta *sta; + + rcu_read_lock(); + sta = ieee80211_find_sta(vif, vif->bss_conf.bssid); + if (!sta) { + struct device *dev = &priv->udev->dev; + + dev_dbg(dev, "%s: no sta found\n", __func__); + rcu_read_unlock(); + goto out; + } + rcu_read_unlock(); + + signal = ieee80211_ave_rssi(vif); + rtl8xxxu_refresh_rate_mask(priv, signal, sta); + } + +out: + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); +} + static int rtl8xxxu_start(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; @@ -5829,6 +6046,8 @@ static int rtl8xxxu_start(struct ieee80211_hw *hw) ret = rtl8xxxu_submit_rx_urb(priv, rx_urb); } + + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); exit: /* * Accept all data and mgmt frames @@ -5880,6 +6099,8 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) if (priv->usb_interrupts) rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + cancel_delayed_work_sync(&priv->ra_watchdog); + rtl8xxxu_free_rx_resources(priv); rtl8xxxu_free_tx_resources(priv); } @@ -6052,6 +6273,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, INIT_LIST_HEAD(&priv->rx_urb_pending_list); 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); usb_set_intfdata(interface, hw); -- cgit v1.2.3-59-g8ed1b From 0fc44cd4c480bf10c8c530ee043849346999225d Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:48 +0800 Subject: rtlwifi: rtl8821ae: Remove set but not used variables 'rtstatus','bd' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c: In function rtl8812ae_phy_config_rf_with_headerfile: drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c:2079:7: warning: variable rtstatus set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c: In function rtl8821ae_phy_config_rf_with_headerfile: drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c:2114:7: warning: variable rtstatus set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c: In function _rtl8812ae_phy_get_txpower_limit: drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c:2354:6: warning: variable bd set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index 979e434a4e73..c54b80de25d3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -2076,7 +2076,6 @@ static bool _rtl8821ae_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { - bool rtstatus = true; u32 *radioa_array_table_a, *radioa_array_table_b; u16 radioa_arraylen_a, radioa_arraylen_b; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -2088,7 +2087,6 @@ bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen_a); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: return __rtl8821ae_phy_config_with_headerfile(hw, @@ -2111,7 +2109,6 @@ bool rtl8812ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -2121,7 +2118,6 @@ bool rtl8821ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8821AE_RADIOA_ARRAY %d\n", radioa_arraylen); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: return __rtl8821ae_phy_config_with_headerfile(hw, @@ -2351,7 +2347,7 @@ static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, struct rtl_phy *rtlphy = &rtlpriv->phy; short band_temp = -1, regulation = -1, bandwidth_temp = -1, rate_section = -1, channel_temp = -1; - u16 bd, regu, bdwidth, sec, chnl; + u16 regu, bdwidth, sec, chnl; s8 power_limit = MAX_POWER_INDEX; if (rtlefuse->eeprom_regulatory == 2) @@ -2472,7 +2468,6 @@ static s8 _rtl8812ae_phy_get_txpower_limit(struct ieee80211_hw *hw, return MAX_POWER_INDEX; } - bd = band_temp; regu = regulation; bdwidth = bandwidth_temp; sec = rate_section; -- cgit v1.2.3-59-g8ed1b From a3e017fd8932ee4e01a01fea3cda63b451bc0558 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:49 +0800 Subject: rtlwifi: rtl8723ae: Remove set but not used variables 'reg_ecc','reg_ec4','reg_eac','b_pathb_ok' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c: In function rtl8723e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c:1346:6: warning: variable reg_ecc set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c: In function rtl8723e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c:1345:61: warning: variable reg_ec4 set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c: In function rtl8723e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c:1345:34: warning: variable reg_eac set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c: In function rtl8723e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c:1344:19: warning: variable b_pathb_ok set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c index 22441dd5fdac..1385e5a2e0b0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c @@ -1338,9 +1338,9 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; - bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + bool b_patha_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[10] = { ROFDM0_XARXIQIMBALANCE, @@ -1369,7 +1369,6 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) } final_candidate = 0xff; b_patha_ok = false; - b_pathb_ok = false; is12simular = false; is23simular = false; is13simular = false; @@ -1409,23 +1408,16 @@ void rtl8723e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; - reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; - reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; - b_pathb_ok = true; } else { rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100; rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0; -- cgit v1.2.3-59-g8ed1b From a003aec306c8175b31ecc06d5c7d9decd4a82797 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:50 +0800 Subject: rtlwifi: rtl8192c: Remove set but not used variables 'reg_ecc','reg_eac' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c: In function rtl92c_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c:1373:6: warning: variable reg_ecc set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c: In function rtl92c_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c:1372:34: warning: variable reg_eac set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c index 0efd19aa4fe5..661249d618c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c @@ -1369,8 +1369,8 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) long result[4][8]; u8 i, final_candidate; bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[10] = { ROFDM0_XARXIQIMBALANCE, @@ -1445,21 +1445,17 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { rtlphy->reg_e94 = reg_e94 = result[final_candidate][0]; rtlphy->reg_e9c = reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4]; rtlphy->reg_ebc = reg_ebc = result[final_candidate][5]; reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; b_patha_ok = true; b_pathb_ok = true; } else { -- cgit v1.2.3-59-g8ed1b From 925942b5da0959c7e3a56e6651f2e38999fa3293 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:51 +0800 Subject: rtlwifi: rtl8188ee: Remove set but not used variables 'v3','rtstatus','reg_ecc','reg_ec4','reg_eac','b_pathb_ok' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function phy_config_bb_with_pghdr: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:652:22: warning: variable v3 set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function rtl88e_phy_config_rf_with_headerfile: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:772:7: warning: variable rtstatus set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function rtl88e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:1945:6: warning: variable reg_ecc set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function rtl88e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:1944:61: warning: variable reg_ec4 set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function rtl88e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:1944:34: warning: variable reg_eac set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c: In function rtl88e_phy_iq_calibrate: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c:1943:19: warning: variable b_pathb_ok set but not used [-Wunused-but-set-variable] They are not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8188ee/phy.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c index 96d8f25b120f..978e6a169654 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c @@ -649,7 +649,7 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) int i; u32 *phy_reg_page; u16 phy_reg_page_len; - u32 v1 = 0, v2 = 0, v3 = 0; + u32 v1 = 0, v2 = 0; phy_reg_page_len = RTL8188EEPHY_REG_ARRAY_PGLEN; phy_reg_page = RTL8188EEPHY_REG_ARRAY_PG; @@ -658,7 +658,6 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) for (i = 0; i < phy_reg_page_len; i = i + 3) { v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; if (v1 < 0xcdcdcdcd) { if (phy_reg_page[i] == 0xfe) @@ -689,13 +688,11 @@ static bool phy_config_bb_with_pghdr(struct ieee80211_hw *hw, u8 configtype) v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; while (v2 != 0xDEAD && i < phy_reg_page_len - 5) { i += 3; v1 = phy_reg_page[i]; v2 = phy_reg_page[i+1]; - v3 = phy_reg_page[i+2]; } } } @@ -769,7 +766,6 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { struct rtl_priv *rtlpriv = rtl_priv(hw); - bool rtstatus = true; u32 *radioa_array_table; u16 radioa_arraylen; @@ -778,7 +774,6 @@ bool rtl88e_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio_A:RTL8188EE_RADIOA_1TARRAY %d\n", radioa_arraylen); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Radio No %x\n", rfpath); - rtstatus = true; switch (rfpath) { case RF90_PATH_A: process_path_a(hw, radioa_arraylen, radioa_array_table); @@ -1940,9 +1935,9 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) struct rtl_phy *rtlphy = &rtlpriv->phy; long result[4][8]; u8 i, final_candidate; - bool b_patha_ok, b_pathb_ok; - long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, - reg_ecc, reg_tmp = 0; + bool b_patha_ok; + long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, + reg_tmp = 0; bool is12simular, is13simular, is23simular; u32 iqk_bb_reg[9] = { ROFDM0_XARXIQIMBALANCE, @@ -1971,7 +1966,6 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) } final_candidate = 0xff; b_patha_ok = false; - b_pathb_ok = false; is12simular = false; is23simular = false; is13simular = false; @@ -2014,27 +2008,20 @@ void rtl88e_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery) reg_e94 = result[i][0]; reg_e9c = result[i][1]; reg_ea4 = result[i][2]; - reg_eac = result[i][3]; reg_eb4 = result[i][4]; reg_ebc = result[i][5]; - reg_ec4 = result[i][6]; - reg_ecc = result[i][7]; } if (final_candidate != 0xff) { reg_e94 = result[final_candidate][0]; reg_e9c = result[final_candidate][1]; reg_ea4 = result[final_candidate][2]; - reg_eac = result[final_candidate][3]; reg_eb4 = result[final_candidate][4]; reg_ebc = result[final_candidate][5]; - reg_ec4 = result[final_candidate][6]; - reg_ecc = result[final_candidate][7]; rtlphy->reg_eb4 = reg_eb4; rtlphy->reg_ebc = reg_ebc; rtlphy->reg_e94 = reg_e94; rtlphy->reg_e9c = reg_e9c; b_patha_ok = true; - b_pathb_ok = true; } else { rtlphy->reg_e94 = 0x100; rtlphy->reg_eb4 = 0x100; -- cgit v1.2.3-59-g8ed1b From 073f8138f598433e7bf8b79a312b2f0d71c16141 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:52 +0800 Subject: rtlwifi: rtl8188ee: Remove set but not used variable 'h2c_parameter' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c: In function rtl88e_dm_pwdb_monitor: drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c:763:6: warning: variable h2c_parameter set but not used [-Wunused-but-set-variable] It is not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c index 333e355c9281..dceb04a9b3f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/dm.c @@ -759,14 +759,8 @@ static void rtl88e_dm_pwdb_monitor(struct ieee80211_hw *hw) rtlpriv->dm.entry_min_undec_sm_pwdb = 0; } /* Indicate Rx signal strength to FW. */ - if (rtlpriv->dm.useramask) { - u8 h2c_parameter[3] = { 0 }; - - h2c_parameter[2] = (u8)(rtlpriv->dm.undec_sm_pwdb & 0xFF); - h2c_parameter[0] = 0x20; - } else { + if (!rtlpriv->dm.useramask) rtl_write_byte(rtlpriv, 0x4fe, rtlpriv->dm.undec_sm_pwdb); - } } void rtl88e_dm_init_edca_turbo(struct ieee80211_hw *hw) -- cgit v1.2.3-59-g8ed1b From e25076070201b826fbbcdb0e3fe554e905601d8f Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:53 +0800 Subject: rtlwifi: btcoex: Remove set but not used variable 'result' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c: In function btc8192e2ant_tdma_duration_adjust: drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c:1584:6: warning: variable result set but not used [-Wunused-but-set-variable] It is not used since commit 27a31a60a4de ("rtlwifi: btcoex: remove unused functions") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c index 3ebc7c93b1e9..3c96c320236c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8192e2ant.c @@ -1578,10 +1578,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, { struct rtl_priv *rtlpriv = btcoexist->adapter; static int up, dn, m, n, wait_cnt; - /* 0: no change, +1: increase WiFi duration, - * -1: decrease WiFi duration - */ - int result; u8 retry_cnt = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, @@ -1669,7 +1665,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, dn = 0; m = 1; n = 3; - result = 0; wait_cnt = 0; } else { /* accquire the BT TRx retry count from BT_Info byte2 */ @@ -1679,7 +1674,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], up=%d, dn=%d, m=%d, n=%d, wait_cnt=%d\n", up, dn, m, n, wait_cnt); - result = 0; wait_cnt++; /* no retry in the last 2-second duration */ if (retry_cnt == 0) { @@ -1694,7 +1688,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, n = 3; up = 0; dn = 0; - result = 1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex]Increase wifi duration!!\n"); } @@ -1718,7 +1711,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, up = 0; dn = 0; wait_cnt = 0; - result = -1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "Reduce wifi duration for retry<3\n"); } @@ -1735,7 +1727,6 @@ static void btc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, up = 0; dn = 0; wait_cnt = 0; - result = -1; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "Decrease wifi duration for retryCounter>3!!\n"); } -- cgit v1.2.3-59-g8ed1b From aab7541a5a8b85ee2f46dc4d5d4ace6174bb9c5d Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:54 +0800 Subject: rtlwifi: btcoex: Remove set but not used variables 'wifi_busy','bt_info_ext' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c: In function btc8723b1ant_tdma_dur_adj_for_acl: drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c:1428:7: warning: variable wifi_busy set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c: In function btc8723b1ant_tdma_dur_adj_for_acl: drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c:1427:22: warning: variable bt_info_ext set but not used [-Wunused-but-set-variable] 'wifi_busy' is not used since commit 158707f9584c ("rtlwifi: btcoex: Restore 23b 1ant routine for tdma adjustment") 'bt_info_ext' is not used since commit 2622d7d86a57 ("rtlwifi: btcoex: 23b 1ant: TDMA duration for ACL busy") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 5f5739904edf..528e442f25a4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1424,17 +1424,11 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, * -1: decrease WiFi duration */ s32 result; - u8 retry_count = 0, bt_info_ext; - bool wifi_busy = false; + u8 retry_count = 0; RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD, "[BTCoex], TdmaDurationAdjustForAcl()\n"); - if (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_BUSY) - wifi_busy = true; - else - wifi_busy = false; - if ((wifi_status == BT_8723B_1ANT_WIFI_STATUS_NON_CONNECTED_ASSO_AUTH_SCAN) || (wifi_status == BT_8723B_1ANT_WIFI_STATUS_CONNECTED_SCAN) || @@ -1472,7 +1466,6 @@ void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, } else { /* acquire the BT TRx retry count from BT_Info byte2 */ retry_count = coex_sta->bt_retry_cnt; - bt_info_ext = coex_sta->bt_info_ext; if ((coex_sta->low_priority_tx) > 1050 || (coex_sta->low_priority_rx) > 1250) -- cgit v1.2.3-59-g8ed1b From 4614239cba34b28cb2d95d60c6f4498f39e533dd Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 16:43:55 +0800 Subject: rtlwifi: rtl8723: Remove set but not used variable 'own' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c: In function rtl8723_cmd_send_packet: drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c:226:5: warning: variable own set but not used [-Wunused-but-set-variable] It is not used since commit f1d2b4d338bf ("rtlwifi: rtl818x: Move drivers into new realtek directory") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c index 18ce2856a91b..37036e653e56 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c @@ -223,7 +223,6 @@ bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; struct sk_buff *pskb = NULL; - u8 own; unsigned long flags; ring = &rtlpci->tx_ring[BEACON_QUEUE]; @@ -233,9 +232,6 @@ bool rtl8723_cmd_send_packet(struct ieee80211_hw *hw, spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); pdesc = &ring->desc[0]; - own = (u8)rtlpriv->cfg->ops->get_desc(hw, (u8 *)pdesc, true, - HW_DESC_OWN); - rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb); __skb_queue_tail(&ring->queue, skb); -- cgit v1.2.3-59-g8ed1b From c5dcf8f0e850a504235a0af51f73d51b6ddc0933 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 4 Oct 2019 16:44:21 +0200 Subject: Revert "rsi: fix potential null dereference in rsi_probe()" This reverts commit f170d44bc4ec2feae5f6206980e7ae7fbf0432a0. USB core will never call a USB-driver probe function with a NULL device-id pointer. Reverting before removing the existing checks in order to document this and prevent the offending commit from being "autoselected" for stable. Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 23a1d00b5f38..760eaffeebd6 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -793,7 +793,7 @@ static int rsi_probe(struct usb_interface *pfunction, adapter->device_model = RSI_DEV_9116; } else { rsi_dbg(ERR_ZONE, "%s: Unsupported RSI device id 0x%x\n", - __func__, id ? id->idProduct : 0x0); + __func__, id->idProduct); goto err1; } -- cgit v1.2.3-59-g8ed1b From 39e50f5ce26c0aa413cf2a680a401a35ec6508bf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 4 Oct 2019 16:44:22 +0200 Subject: rsi: drop bogus device-id checks from probe USB core will never call a USB-driver probe function with a NULL device-id pointer. Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index 760eaffeebd6..53f41fc2cadf 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -785,10 +785,10 @@ static int rsi_probe(struct usb_interface *pfunction, rsi_dbg(ERR_ZONE, "%s: Initialized os intf ops\n", __func__); - if (id && id->idProduct == RSI_USB_PID_9113) { + if (id->idProduct == RSI_USB_PID_9113) { rsi_dbg(INIT_ZONE, "%s: 9113 module detected\n", __func__); adapter->device_model = RSI_DEV_9113; - } else if (id && id->idProduct == RSI_USB_PID_9116) { + } else if (id->idProduct == RSI_USB_PID_9116) { rsi_dbg(INIT_ZONE, "%s: 9116 module detected\n", __func__); adapter->device_model = RSI_DEV_9116; } else { -- cgit v1.2.3-59-g8ed1b From db8fd2cde93227e566a412cf53173ffa227998bc Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 4 Oct 2019 15:08:52 -0500 Subject: mwifiex: pcie: Fix memory leak in mwifiex_pcie_alloc_cmdrsp_buf In mwifiex_pcie_alloc_cmdrsp_buf, a new skb is allocated which should be released if mwifiex_map_pci_memory() fails. The release is added. Fixes: fc3314609047 ("mwifiex: use pci_alloc/free_consistent APIs for PCIe") Signed-off-by: Navid Emamdoost Acked-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index eff06d59e9df..1578eaa071bd 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1029,8 +1029,10 @@ static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) } skb_put(skb, MWIFIEX_UPLD_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); return -1; + } card->cmdrsp_buf = skb; -- cgit v1.2.3-59-g8ed1b From d10dcb615c8e29d403a24d35f8310a7a53e3050c Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Fri, 4 Oct 2019 15:16:48 -0500 Subject: mwifiex: pcie: Fix memory leak in mwifiex_pcie_init_evt_ring In mwifiex_pcie_init_evt_ring, a new skb is allocated which should be released if mwifiex_map_pci_memory() fails. The release for skb and card->evtbd_ring_vbase is added. Fixes: 0732484b47b5 ("mwifiex: separate ring initialization and ring creation routines") Signed-off-by: Navid Emamdoost Acked-by: Ganapathi Bhat Signed-off-by: Kalle Valo --- drivers/net/wireless/marvell/mwifiex/pcie.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index 1578eaa071bd..fc1706d0647d 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -687,8 +687,11 @@ static int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter) skb_put(skb, MAX_EVENT_SIZE); if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE, - PCI_DMA_FROMDEVICE)) + PCI_DMA_FROMDEVICE)) { + kfree_skb(skb); + kfree(card->evtbd_ring_vbase); return -1; + } buf_pa = MWIFIEX_SKB_DMA_ADDR(skb); -- cgit v1.2.3-59-g8ed1b From e542e66b7c2ee2adeefdbb7f259f2f60cadf2819 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Sat, 5 Oct 2019 17:48:26 +0800 Subject: rtl8xxxu: add bluetooth co-existence support for single antenna The RTL8723BU suffers the wifi disconnection problem while bluetooth device connected. While wifi is doing tx/rx, the bluetooth will scan without results. This is due to the wifi and bluetooth share the same single antenna for RF communication and they need to have a mechanism to collaborate. BT information is provided via the packet sent from co-processor to host (C2H). It contains the status of BT but the rtl8723bu_handle_c2h dose not really handle it. And there's no bluetooth coexistence mechanism to deal with it. This commit adds a workqueue to set the tdma configurations and coefficient table per the parsed bluetooth link status and given wifi connection state. The tdma/coef table comes from the vendor driver code of the RTL8192EU and RTL8723BU. However, this commit is only for single antenna scenario which RTL8192EU is default dual antenna. The rtl8xxxu_parse_rxdesc24 which invokes the handle_c2h is only for 8723b and 8192e so the mechanism is expected to work on both chips with single antenna. Note RTL8192EU dual antenna is not supported. Signed-off-by: Chris Chiu Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 37 +++ .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 2 - .../net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 269 ++++++++++++++++++++- 3 files changed, 301 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 582c2a346cec..22e95b11bfbb 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1220,6 +1220,37 @@ enum ratr_table_mode_new { RATEID_IDX_BGN_3SS = 14, }; +#define BT_INFO_8723B_1ANT_B_FTP BIT(7) +#define BT_INFO_8723B_1ANT_B_A2DP BIT(6) +#define BT_INFO_8723B_1ANT_B_HID BIT(5) +#define BT_INFO_8723B_1ANT_B_SCO_BUSY BIT(4) +#define BT_INFO_8723B_1ANT_B_ACL_BUSY BIT(3) +#define BT_INFO_8723B_1ANT_B_INQ_PAGE BIT(2) +#define BT_INFO_8723B_1ANT_B_SCO_ESCO BIT(1) +#define BT_INFO_8723B_1ANT_B_CONNECTION BIT(0) + +enum _BT_8723B_1ANT_STATUS { + BT_8723B_1ANT_STATUS_NON_CONNECTED_IDLE = 0x0, + BT_8723B_1ANT_STATUS_CONNECTED_IDLE = 0x1, + BT_8723B_1ANT_STATUS_INQ_PAGE = 0x2, + BT_8723B_1ANT_STATUS_ACL_BUSY = 0x3, + BT_8723B_1ANT_STATUS_SCO_BUSY = 0x4, + BT_8723B_1ANT_STATUS_ACL_SCO_BUSY = 0x5, + BT_8723B_1ANT_STATUS_MAX +}; + +struct rtl8xxxu_btcoex { + u8 bt_status; + bool bt_busy; + bool has_sco; + bool has_a2dp; + bool has_hid; + bool has_pan; + bool hid_only; + bool a2dp_only; + bool c2h_bt_inquiry; +}; + #define RTL8XXXU_RATR_STA_INIT 0 #define RTL8XXXU_RATR_STA_HIGH 1 #define RTL8XXXU_RATR_STA_MID 2 @@ -1340,6 +1371,10 @@ struct rtl8xxxu_priv { */ struct ieee80211_vif *vif; struct delayed_work ra_watchdog; + struct work_struct c2hcmd_work; + struct sk_buff_head c2hcmd_queue; + spinlock_t c2hcmd_lock; + struct rtl8xxxu_btcoex bt_coex; }; struct rtl8xxxu_rx_urb { @@ -1486,6 +1521,8 @@ void rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, struct rtl8xxxu_txdesc32 *tx_desc32, bool sgi, bool short_preamble, bool ampdu_enable, u32 rts_rate); +void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5); extern struct rtl8xxxu_fileops rtl8192cu_fops; extern struct rtl8xxxu_fileops rtl8192eu_fops; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index ceffe05bd65b..9ba661b3d767 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1580,9 +1580,7 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv) /* * Software control, antenna at WiFi side */ -#ifdef NEED_PS_TDMA rtl8723bu_set_ps_tdma(priv, 0x08, 0x00, 0x00, 0x00, 0x00); -#endif rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index bd5ccb3aa5d7..8c47fdf2fdef 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3820,9 +3820,8 @@ void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_RSV_CTRL, 0x0e); } -#ifdef NEED_PS_TDMA -static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, - u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) +void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, + u8 arg1, u8 arg2, u8 arg3, u8 arg4, u8 arg5) { struct h2c_cmd h2c; @@ -3835,7 +3834,6 @@ static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv, h2c.b_type_dma.data5 = arg5; rtl8xxxu_gen2_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma)); } -#endif void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv) { @@ -5186,12 +5184,265 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) } } +/* + * The RTL8723BU/RTL8192EU vendor driver use coexistence table type + * 0-7 to represent writing different combinations of register values + * to REG_BT_COEX_TABLEs. It's for different kinds of coexistence use + * cases which Realtek doesn't provide detail for these settings. Keep + * this aligned with vendor driver for easier maintenance. + */ +void rtl8723bu_set_coex_with_type(struct rtl8xxxu_priv *priv, u8 type) +{ + switch (type) { + case 0: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 1: + case 3: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 2: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 4: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaa5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 5: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x5a5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaa5a5a5a); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 6: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0x55555555); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + case 7: + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE1, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE2, 0xaaaaaaaa); + rtl8xxxu_write32(priv, REG_BT_COEX_TABLE3, 0x00ffffff); + rtl8xxxu_write8(priv, REG_BT_COEX_TABLE4, 0x03); + break; + default: + break; + } +} + +void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) +{ + struct rtl8xxxu_btcoex *btcoex = &priv->bt_coex; + + if (bt_info & BT_INFO_8723B_1ANT_B_INQ_PAGE) + btcoex->c2h_bt_inquiry = true; + else + btcoex->c2h_bt_inquiry = false; + + if (!(bt_info & BT_INFO_8723B_1ANT_B_CONNECTION)) { + btcoex->bt_status = BT_8723B_1ANT_STATUS_NON_CONNECTED_IDLE; + btcoex->has_sco = false; + btcoex->has_hid = false; + btcoex->has_pan = false; + btcoex->has_a2dp = false; + } else { + if ((bt_info & 0x1f) == BT_INFO_8723B_1ANT_B_CONNECTION) + btcoex->bt_status = BT_8723B_1ANT_STATUS_CONNECTED_IDLE; + else if ((bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) || + (bt_info & BT_INFO_8723B_1ANT_B_SCO_BUSY)) + btcoex->bt_status = BT_8723B_1ANT_STATUS_SCO_BUSY; + else if (bt_info & BT_INFO_8723B_1ANT_B_ACL_BUSY) + btcoex->bt_status = BT_8723B_1ANT_STATUS_ACL_BUSY; + else + btcoex->bt_status = BT_8723B_1ANT_STATUS_MAX; + + if (bt_info & BT_INFO_8723B_1ANT_B_FTP) + btcoex->has_pan = true; + else + btcoex->has_pan = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_A2DP) + btcoex->has_a2dp = true; + else + btcoex->has_a2dp = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_HID) + btcoex->has_hid = true; + else + btcoex->has_hid = false; + + if (bt_info & BT_INFO_8723B_1ANT_B_SCO_ESCO) + btcoex->has_sco = true; + else + btcoex->has_sco = false; + } + + if (!btcoex->has_a2dp && !btcoex->has_sco && + !btcoex->has_pan && btcoex->has_hid) + btcoex->hid_only = true; + else + btcoex->hid_only = false; + + if (!btcoex->has_sco && !btcoex->has_pan && + !btcoex->has_hid && btcoex->has_a2dp) + btcoex->has_a2dp = true; + else + btcoex->has_a2dp = false; + + if (btcoex->bt_status == BT_8723B_1ANT_STATUS_SCO_BUSY || + btcoex->bt_status == BT_8723B_1ANT_STATUS_ACL_BUSY) + btcoex->bt_busy = true; + else + btcoex->bt_busy = false; +} + +void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_btcoex *btcoex; + bool wifi_connected; + + vif = priv->vif; + btcoex = &priv->bt_coex; + wifi_connected = (vif && vif->bss_conf.assoc); + + if (!wifi_connected) { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 0); + } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else if (btcoex->has_pan) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x3f, 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 7); + } +} + +void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) +{ + struct ieee80211_vif *vif; + struct rtl8xxxu_btcoex *btcoex; + bool wifi_connected; + + vif = priv->vif; + btcoex = &priv->bt_coex; + wifi_connected = (vif && vif->bss_conf.assoc); + + if (wifi_connected) { + u32 val32 = 0; + u32 high_prio_tx = 0, high_prio_rx = 0; + + val32 = rtl8xxxu_read32(priv, 0x770); + high_prio_tx = val32 & 0x0000ffff; + high_prio_rx = (val32 & 0xffff0000) >> 16; + + if (btcoex->bt_busy) { + if (btcoex->hid_only) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x20, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 5); + } else if (btcoex->a2dp_only) { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } else if ((btcoex->has_a2dp && btcoex->has_pan) || + (btcoex->has_hid && btcoex->has_a2dp && + btcoex->has_pan)) { + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, + 0x3, 0x10, 0x10); + rtl8723bu_set_coex_with_type(priv, 4); + } else if (btcoex->has_hid && btcoex->has_a2dp) { + rtl8723bu_set_ps_tdma(priv, 0x51, 0x21, + 0x3, 0x10, 0x10); + rtl8723bu_set_coex_with_type(priv, 3); + } else { + rtl8723bu_set_ps_tdma(priv, 0x61, 0x35, + 0x3, 0x11, 0x11); + rtl8723bu_set_coex_with_type(priv, 4); + } + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + if (high_prio_tx + high_prio_rx <= 60) + rtl8723bu_set_coex_with_type(priv, 2); + else + rtl8723bu_set_coex_with_type(priv, 7); + } + } else { + rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); + rtl8723bu_set_coex_with_type(priv, 0); + } +} + +static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) +{ + struct rtl8xxxu_priv *priv; + struct rtl8723bu_c2h *c2h; + struct ieee80211_vif *vif; + struct device *dev; + struct sk_buff *skb = NULL; + unsigned long flags; + int len; + u8 bt_info = 0; + struct rtl8xxxu_btcoex *btcoex; + + priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); + vif = priv->vif; + btcoex = &priv->bt_coex; + dev = &priv->udev->dev; + + if (priv->rf_paths > 1) + goto out; + + while (!skb_queue_empty(&priv->c2hcmd_queue)) { + spin_lock_irqsave(&priv->c2hcmd_lock, flags); + skb = __skb_dequeue(&priv->c2hcmd_queue); + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); + + c2h = (struct rtl8723bu_c2h *)skb->data; + len = skb->len - 2; + + switch (c2h->id) { + case C2H_8723B_BT_INFO: + bt_info = c2h->bt_info.bt_info; + + rtl8723bu_update_bt_link_info(priv, bt_info); + if (btcoex->c2h_bt_inquiry) { + rtl8723bu_handle_bt_inquiry(priv); + break; + } + rtl8723bu_handle_bt_info(priv); + break; + default: + break; + } + } + +out: + dev_kfree_skb(skb); +} + static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, struct sk_buff *skb) { struct rtl8723bu_c2h *c2h = (struct rtl8723bu_c2h *)skb->data; struct device *dev = &priv->udev->dev; int len; + unsigned long flags; len = skb->len - 2; @@ -5229,6 +5480,12 @@ static void rtl8723bu_handle_c2h(struct rtl8xxxu_priv *priv, 16, 1, c2h->raw.payload, len, false); break; } + + spin_lock_irqsave(&priv->c2hcmd_lock, flags); + __skb_queue_tail(&priv->c2hcmd_queue, skb); + spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); + + schedule_work(&priv->c2hcmd_work); } int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv, struct sk_buff *skb) @@ -5353,7 +5610,6 @@ int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv, struct sk_buff *skb) struct device *dev = &priv->udev->dev; dev_dbg(dev, "%s: C2H packet\n", __func__); rtl8723bu_handle_c2h(priv, skb); - dev_kfree_skb(skb); return RX_TYPE_C2H; } @@ -6274,6 +6530,9 @@ 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); + spin_lock_init(&priv->c2hcmd_lock); + INIT_WORK(&priv->c2hcmd_work, rtl8xxxu_c2hcmd_callback); + skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); -- cgit v1.2.3-59-g8ed1b From be10b09b278fcd64e79e232c88d9152c6f5c2923 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 7 Oct 2019 11:48:05 +0300 Subject: rtw88: Fix an error message The WARN_ON() macro doesn't take an error message, the argument is a condition so this won't display the warning message. Fixes: 27e117e4b01b ("rtw88: add deep power save support") Signed-off-by: Dan Carpenter Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index bf149956b04e..e81de3ddc8c5 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -109,7 +109,7 @@ retry: * read/write. It should be treated as fatal error and * requires an entire analysis about the firmware/hardware */ - WARN_ON("Hardware power state locked\n"); + WARN(1, "Hardware power state locked\n"); } } EXPORT_SYMBOL(rtw_power_mode_change); -- cgit v1.2.3-59-g8ed1b From 55047fb783e0f5b13fc79653f09a06782c3ffe18 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 14:41:13 +0100 Subject: iwlegacy: make array interval static, makes object smaller Don't populate the array interval on the stack but instead make it static. Makes the object code smaller by 121 bytes. Before: text data bss dec hex filename 167797 29676 448 197921 30521 wireless/intel/iwlegacy/common.o After: text data bss dec hex filename 167580 29772 448 197800 304a8 wireless/intel/iwlegacy/common.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlegacy/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 73f7bbf742bc..e4ea734e58d8 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -1072,7 +1072,7 @@ EXPORT_SYMBOL(il_get_channel_info); static void il_build_powertable_cmd(struct il_priv *il, struct il_powertable_cmd *cmd) { - const __le32 interval[3][IL_POWER_VEC_SIZE] = { + static const __le32 interval[3][IL_POWER_VEC_SIZE] = { SLP_VEC(2, 2, 4, 6, 0xFF), SLP_VEC(2, 4, 7, 10, 10), SLP_VEC(4, 7, 10, 10, 0xFF) -- cgit v1.2.3-59-g8ed1b From 314bf64d1266abe7aaccffb24f876ff7de261bf5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Oct 2019 14:53:13 +0100 Subject: rtl8xxxu: make arrays static, makes object smaller Don't populate const arrays on the stack but instead make them static. Makes the object code smaller by 60 bytes. Before: text data bss dec hex filename 15133 8768 0 23901 5d5d realtek/rtl8xxxu/rtl8xxxu_8192e.o 15209 6392 0 21601 5461 realtek/rtl8xxxu/rtl8xxxu_8723b.o 103254 31202 576 135032 20f78 realtek/rtl8xxxu/rtl8xxxu_core.o After: text data bss dec hex filename 14861 9024 0 23885 5d4d realtek/rtl8xxxu/rtl8xxxu_8192e.o 14953 6616 0 21569 5441 realtek/rtl8xxxu/rtl8xxxu_8723b.o 102986 31458 576 135020 20f6c realtek/rtl8xxxu/rtl8xxxu_core.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c | 6 +++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 6 +++--- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index c747f6a1922d..9f1f93d04145 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1011,7 +1011,7 @@ static void rtl8192eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok, path_b_ok; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -1021,11 +1021,11 @@ static void rtl8192eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + 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_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 9ba661b3d767..d15dde388435 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -882,7 +882,7 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok /*, path_b_ok */; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -892,11 +892,11 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + 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_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 8c47fdf2fdef..1e3b71626f1b 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3115,7 +3115,7 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, u32 i, val32; int path_a_ok, path_b_ok; int retry = 2; - const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { + static const u32 adda_regs[RTL8XXXU_ADDA_REGS] = { REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH, REG_RX_WAIT_CCA, REG_TX_CCK_RFON, REG_TX_CCK_BBON, REG_TX_OFDM_RFON, @@ -3125,11 +3125,11 @@ static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv, REG_RX_TO_RX, REG_STANDBY, REG_SLEEP, REG_PMPD_ANAEN }; - const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { + static const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = { REG_TXPAUSE, REG_BEACON_CTRL, REG_BEACON_CTRL_1, REG_GPIO_MUXCFG }; - const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = { + 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_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE, -- cgit v1.2.3-59-g8ed1b From ac8efe4f4a84c6bf59237f77a5db65410bf20241 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 8 Oct 2019 10:01:40 +0800 Subject: rtlwifi: rtl8192ee: Remove set but not used variable 'cur_tx_wp' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c: In function rtl92ee_is_tx_desc_closed: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c:1005:18: warning: variable cur_tx_wp set but not used [-Wunused-but-set-variable] It is not used since commit cf54622c8076 ("rtlwifi: cleanup the code that check whether TX ring is available") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c index 36a8a51e6096..dc7b515bdc85 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/trx.c @@ -1002,14 +1002,13 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index) struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; { - u16 cur_tx_rp, cur_tx_wp; + u16 cur_tx_rp; u32 tmpu32; tmpu32 = rtl_read_dword(rtlpriv, get_desc_addr_fr_q_idx(hw_queue)); cur_tx_rp = (u16)((tmpu32 >> 16) & 0x0fff); - cur_tx_wp = (u16)(tmpu32 & 0x0fff); /* don't need to update ring->cur_tx_wp */ ring->cur_tx_rp = cur_tx_rp; -- cgit v1.2.3-59-g8ed1b From 75792624783659b6712b8cacb01fc0f04150eebb Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 7 Oct 2019 17:43:06 +0200 Subject: net: stmmac: add flexible PPS to dwmac 4.10a All the registers and the functionalities used in the callback dwmac5_flex_pps_config() are common between dwmac 4.10a [1] and 5.00a [2]. Reuse the same callback for dwmac 4.10a too. Tested on STM32MP15x, based on dwmac 4.10a. [1] DWC Ethernet QoS Databook 4.10a October 2014 [2] DWC Ethernet QoS Databook 5.00a September 2017 Signed-off-by: Antonio Borneo Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index df11376ee735..e552d7958114 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -938,6 +938,7 @@ const struct stmmac_ops dwmac4_ops = { .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, + .flex_pps_config = dwmac5_flex_pps_config, .set_mac_loopback = dwmac4_set_mac_loopback, .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, -- cgit v1.2.3-59-g8ed1b From 0ea1671f26204ee8ef138651707dace886fb9df4 Mon Sep 17 00:00:00 2001 From: Biao Huang Date: Wed, 9 Oct 2019 15:33:48 +0800 Subject: net: stmmac: dwmac-mediatek: fix wrong delay value issue when resume back mac_delay value will be divided by 550/170 in mt2712_delay_ps2stage(), which is invoked at the beginning of mt2712_set_delay(), and the value should be restored at the end of mt2712_set_delay(). Or, mac_delay will be divided again when invoking mt2712_set_delay() when resume back. So, add mt2712_delay_stage2ps() to mt2712_set_delay() to recovery the original mac_delay value. Signed-off-by: Biao Huang Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index 79f2ee37afed..cea7a0c7ce68 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -130,6 +130,31 @@ static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat) } } +static void mt2712_delay_stage2ps(struct mediatek_dwmac_plat_data *plat) +{ + struct mac_delay_struct *mac_delay = &plat->mac_delay; + + switch (plat->phy_mode) { + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_RMII: + /* 550ps per stage for MII/RMII */ + mac_delay->tx_delay *= 550; + mac_delay->rx_delay *= 550; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + /* 170ps per stage for RGMII */ + mac_delay->tx_delay *= 170; + mac_delay->rx_delay *= 170; + break; + default: + dev_err(plat->dev, "phy interface not supported\n"); + break; + } +} + static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat) { struct mac_delay_struct *mac_delay = &plat->mac_delay; @@ -199,6 +224,8 @@ static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat) regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val); regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val); + mt2712_delay_stage2ps(plat); + return 0; } -- cgit v1.2.3-59-g8ed1b From 7573822883bdbec33a9f79dd90edbf0c3fa22c1a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 9 Oct 2019 14:26:27 +0100 Subject: net/ethernet: xgmac don't set .driver twice Cleanup the .driver setup to just do it once, to avoid the following sparse warning: drivers/net/ethernet/calxeda/xgmac.c:1914:10: warning: Initializer entry defined twice drivers/net/ethernet/calxeda/xgmac.c:1920:10: also defined here Signed-off-by: Ben Dooks Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/calxeda/xgmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index f96a42af1014..af04a2c81adb 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -1914,10 +1914,10 @@ static struct platform_driver xgmac_driver = { .driver = { .name = "calxedaxgmac", .of_match_table = xgmac_of_match, + .pm = &xgmac_pm_ops, }, .probe = xgmac_probe, .remove = xgmac_remove, - .driver.pm = &xgmac_pm_ops, }; module_platform_driver(xgmac_driver); -- cgit v1.2.3-59-g8ed1b From 5e96cd3302bd62b8cbfc1a7f8f8f1396d6f5e0b0 Mon Sep 17 00:00:00 2001 From: Tiezhu Yang Date: Wed, 9 Oct 2019 22:29:00 +0800 Subject: net: stmmac: Remove break after a return Since break is not useful after a return, remove it. Signed-off-by: Tiezhu Yang Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 3d69da112625..d0356fbd1e43 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -130,7 +130,6 @@ static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, writel(mcfilterbits[0], ioaddr + GMAC_HASH_LOW); writel(mcfilterbits[1], ioaddr + GMAC_HASH_HIGH); return; - break; case 7: numhashregs = 4; break; @@ -140,7 +139,6 @@ static void dwmac1000_set_mchash(void __iomem *ioaddr, u32 *mcfilterbits, default: pr_debug("STMMAC: err in setting multicast filter\n"); return; - break; } for (regs = 0; regs < numhashregs; regs++) writel(mcfilterbits[regs], -- cgit v1.2.3-59-g8ed1b From c17e26ddc79596230834345be80fcad6c619e9ec Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Wed, 9 Oct 2019 20:18:28 +0800 Subject: team: call RCU read lock when walking the port_list Before reading the team port list, we need to acquire the RCU read lock. Also change list_for_each_entry() to list_for_each_entry_rcu(). v2: repost the patch to net-next and remove fixes flag as this is a cosmetic change. Suggested-by: Paolo Abeni Signed-off-by: Hangbin Liu Acked-by: Paolo Abeni Acked-by: Jiri Pirko Signed-off-by: Jakub Kicinski --- drivers/net/team/team.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index e8089def5a46..cb1d5fe60c31 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2066,7 +2066,8 @@ static int team_ethtool_get_link_ksettings(struct net_device *dev, cmd->base.duplex = DUPLEX_UNKNOWN; cmd->base.port = PORT_OTHER; - list_for_each_entry(port, &team->port_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(port, &team->port_list, list) { if (team_port_txable(port)) { if (port->state.speed != SPEED_UNKNOWN) speed += port->state.speed; @@ -2075,6 +2076,8 @@ static int team_ethtool_get_link_ksettings(struct net_device *dev, cmd->base.duplex = port->state.duplex; } } + rcu_read_unlock(); + cmd->base.speed = speed ? : SPEED_UNKNOWN; return 0; -- cgit v1.2.3-59-g8ed1b From 41441d85b671ee8d096e8a316dc8e072c210a62f Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Wed, 9 Oct 2019 16:20:11 -0700 Subject: ipvlan: consolidate TSO flags using NETIF_F_ALL_TSO This will ensure that any new TSO related flags added (which would be part of ALL_TSO mask and IPvlan driver doesn't need to update every time new flag gets added. Signed-off-by: Mahesh Bandewar Suggested-by: Eric Dumazet Signed-off-by: Jakub Kicinski --- drivers/net/ipvlan/ipvlan_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 887bbba4631e..b0ac557f8e60 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -108,8 +108,8 @@ static void ipvlan_port_destroy(struct net_device *dev) #define IPVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_CSUM_MASK | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ - NETIF_F_GSO | NETIF_F_TSO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \ + NETIF_F_GSO | NETIF_F_ALL_TSO | NETIF_F_GSO_ROBUST | \ + NETIF_F_GRO | NETIF_F_RXCSUM | \ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER) #define IPVLAN_STATE_MASK \ -- cgit v1.2.3-59-g8ed1b From cc78dc3b790619aa05f22a86a9152986bd73698c Mon Sep 17 00:00:00 2001 From: Abhishek Ambure Date: Thu, 3 Oct 2019 16:45:22 +0300 Subject: ath10k: enable transmit data ack RSSI for QCA9884 For all data packets transmitted, host gets htt tx completion event. Some QCA9984 firmware releases support WMI_SERVICE_TX_DATA_ACK_RSSI, which gives data ack rssi values to host through htt event of data tx completion. Data ack rssi values are valid if A0 bit is set in HTT rx message. So enable the feature also for QCA9884. Tested HW: QCA9984 Tested FW: 10.4-3.9.0.2-00044 Signed-off-by: Abhishek Ambure Signed-off-by: Balaji Pothunoori [kvalo@codeaurora.org: improve commit log] Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 55849173e55d..2451e0fb8ee5 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -1148,6 +1148,7 @@ static bool ath10k_qca99x0_rx_desc_msdu_limit_error(struct htt_rx_desc *rxd) const struct ath10k_hw_ops qca99x0_ops = { .rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes, .rx_desc_get_msdu_limit_error = ath10k_qca99x0_rx_desc_msdu_limit_error, + .is_rssi_enable = ath10k_htt_tx_rssi_enable, }; const struct ath10k_hw_ops qca6174_ops = { -- cgit v1.2.3-59-g8ed1b From b5764696ac409523414f70421c13b7e7a9309454 Mon Sep 17 00:00:00 2001 From: Ramon Fontes Date: Thu, 10 Oct 2019 15:13:06 -0300 Subject: mac80211_hwsim: add more 5GHz channels, 5/10 MHz support These new 5GHz channels and 5/10 MHz support should be available for OCB usage (802.11p). Signed-off-by: Ramon Fontes Link: https://lore.kernel.org/r/20191010181307.11821-1-ramonreisfontes@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1aeb38296ec3..e638553d3c82 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -148,23 +148,25 @@ static const char *hwsim_alpha2s[] = { }; static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = { - .n_reg_rules = 4, + .n_reg_rules = 5, .alpha2 = "99", .reg_rules = { REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), REG_RULE(2484-10, 2484+10, 40, 0, 20, 0), REG_RULE(5150-10, 5240+10, 40, 0, 30, 0), REG_RULE(5745-10, 5825+10, 40, 0, 30, 0), + REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), } }; static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = { - .n_reg_rules = 2, + .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { REG_RULE(2412-10, 2462+10, 40, 0, 20, 0), REG_RULE(5725-10, 5850+10, 40, 0, 30, NL80211_RRF_NO_IR), + REG_RULE(5855-10, 5925+10, 40, 0, 33, 0), } }; @@ -354,6 +356,24 @@ static const struct ieee80211_channel hwsim_channels_5ghz[] = { CHAN5G(5805), /* Channel 161 */ CHAN5G(5825), /* Channel 165 */ CHAN5G(5845), /* Channel 169 */ + + CHAN5G(5855), /* Channel 171 */ + CHAN5G(5860), /* Channel 172 */ + CHAN5G(5865), /* Channel 173 */ + CHAN5G(5870), /* Channel 174 */ + + CHAN5G(5875), /* Channel 175 */ + CHAN5G(5880), /* Channel 176 */ + CHAN5G(5885), /* Channel 177 */ + CHAN5G(5890), /* Channel 178 */ + CHAN5G(5895), /* Channel 179 */ + CHAN5G(5900), /* Channel 180 */ + CHAN5G(5905), /* Channel 181 */ + + CHAN5G(5910), /* Channel 182 */ + CHAN5G(5915), /* Channel 183 */ + CHAN5G(5920), /* Channel 184 */ + CHAN5G(5925), /* Channel 185 */ }; static const struct ieee80211_rate hwsim_rates[] = { @@ -1604,6 +1624,8 @@ mac80211_hwsim_beacon(struct hrtimer *timer) } static const char * const hwsim_chanwidths[] = { + [NL80211_CHAN_WIDTH_5] = "ht5", + [NL80211_CHAN_WIDTH_10] = "ht10", [NL80211_CHAN_WIDTH_20_NOHT] = "noht", [NL80211_CHAN_WIDTH_20] = "ht20", [NL80211_CHAN_WIDTH_40] = "ht40", @@ -2846,6 +2868,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, } else { data->if_combination.num_different_channels = 1; data->if_combination.radar_detect_widths = + BIT(NL80211_CHAN_WIDTH_5) | + BIT(NL80211_CHAN_WIDTH_10) | BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | -- cgit v1.2.3-59-g8ed1b From 7dfd8ac327301f302b03072066c66eb32578e940 Mon Sep 17 00:00:00 2001 From: Ramon Fontes Date: Thu, 10 Oct 2019 15:13:07 -0300 Subject: mac80211_hwsim: add support for OCB OCB (Outside the Context of a BSS) interfaces are the implementation of 802.11p, support that. Signed-off-by: Ramon Fontes Link: https://lore.kernel.org/r/20191010181307.11821-2-ramonreisfontes@gmail.com Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index e638553d3c82..9dfa354eb1cb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1570,7 +1570,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, if (vif->type != NL80211_IFTYPE_AP && vif->type != NL80211_IFTYPE_MESH_POINT && - vif->type != NL80211_IFTYPE_ADHOC) + vif->type != NL80211_IFTYPE_ADHOC && + vif->type != NL80211_IFTYPE_OCB) return; skb = ieee80211_beacon_get(hw, vif); @@ -2744,7 +2745,8 @@ static void mac80211_hwsim_he_capab(struct ieee80211_supported_band *sband) BIT(NL80211_IFTYPE_P2P_CLIENT) | \ BIT(NL80211_IFTYPE_P2P_GO) | \ BIT(NL80211_IFTYPE_ADHOC) | \ - BIT(NL80211_IFTYPE_MESH_POINT)) + BIT(NL80211_IFTYPE_MESH_POINT) | \ + BIT(NL80211_IFTYPE_OCB)) static int mac80211_hwsim_new_radio(struct genl_info *info, struct hwsim_new_radio_params *param) -- cgit v1.2.3-59-g8ed1b From a69d3bdd4d40c8f780c94b5e1983adb1cd389b59 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 4 Oct 2019 17:02:27 +0100 Subject: ath10k: fix null dereference on pointer crash_data Currently when pointer crash_data is null the present null check will also check that crash_data->ramdump_buf is null and will cause a null pointer dereference on crash_data. Fix this by using the || operator instead of &&. Fixes: 3f14b73c3843 ("ath10k: Enable MSA region dump support for WCN3990") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/snoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index cd22c8654aa9..16177497bba7 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1400,7 +1400,7 @@ static void ath10k_msa_dump_memory(struct ath10k *ar, size_t buf_len; u8 *buf; - if (!crash_data && !crash_data->ramdump_buf) + if (!crash_data || !crash_data->ramdump_buf) return; mem_layout = ath10k_coredump_get_mem_layout(ar); -- cgit v1.2.3-59-g8ed1b From 59f4567d228f7f5686e0f91d30e6aeaca999e2fd Mon Sep 17 00:00:00 2001 From: zhengbin Date: Wed, 9 Oct 2019 17:08:27 +0800 Subject: rtlwifi: rtl8192ee: Remove set but not used variable 'err' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c: In function rtl92ee_download_fw: drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c:111:6: warning: variable err set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: zhengbin Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c index 67305ce915ec..05462422d247 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c @@ -108,7 +108,6 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) struct rtlwifi_firmware_header *pfwheader; u8 *pfwdata; u32 fwsize; - int err; enum version_8192e version = rtlhal->version; if (!rtlhal->pfirmware) @@ -146,9 +145,7 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw) _rtl92ee_write_fw(hw, version, pfwdata, fwsize); _rtl92ee_enable_fw_download(hw, false); - err = _rtl92ee_fw_free_to_go(hw); - - return 0; + return _rtl92ee_fw_free_to_go(hw); } static bool _rtl92ee_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum) -- cgit v1.2.3-59-g8ed1b From 4633d30b61ac1415817b954c3d4d241ca7439a7c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 9 Oct 2019 09:50:06 -0700 Subject: wlcore: clean-up clearing of WL1271_FLAG_IRQ_RUNNING We set WL1271_FLAG_IRQ_RUNNING in the beginning of wlcore_irq(), but clear it before interrupt handling is done in wlcore_irq_locked(). Let's move the clearing to the end of wlcore_irq() where it gets set, and remove the old comments about hardirq. That's no longer the case as we're using request_threaded_irq(). Note that the WL1271_FLAG_IRQ_RUNNING should never race between the interrupt handler and wlcore_runtime_resume() as because of autosuspend timeout we cannot enter idle between wlcore_irq_locked() and the end of wlcore_irq(). Cc: Anders Roxell Cc: Eyal Reizer Cc: Guy Mishol Cc: John Stultz Cc: Ulf Hansson Signed-off-by: Tony Lindgren Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 123afbe10f44..e994995d79ab 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -544,11 +544,6 @@ static int wlcore_irq_locked(struct wl1271 *wl) } while (!done && loopcount--) { - /* - * In order to avoid a race with the hardirq, clear the flag - * before acknowledging the chip. - */ - clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_atomic(); ret = wlcore_fw_status(wl, wl->fw_status); @@ -668,7 +663,7 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) disable_irq_nosync(wl->irq); pm_wakeup_event(wl->dev, 0); spin_unlock_irqrestore(&wl->wl_lock, flags); - return IRQ_HANDLED; + goto out_handled; } spin_unlock_irqrestore(&wl->wl_lock, flags); @@ -692,6 +687,11 @@ static irqreturn_t wlcore_irq(int irq, void *cookie) mutex_unlock(&wl->mutex); +out_handled: + spin_lock_irqsave(&wl->wl_lock, flags); + clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From c2fca7d083f78aad632fb99fd24acb082c58a495 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 9 Oct 2019 12:37:08 -0500 Subject: rtlwifi: rtl8192se: Remove unused GET_XXX and SET_XXX As the first step in converting from macros that get/set information in the RX and TX descriptors, unused macros are being removed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8192se/def.h | 223 --------------------- 1 file changed, 223 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h index bb6b60814762..44b2b4e3c151 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h @@ -53,18 +53,12 @@ SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) #define SET_TX_DESC_OFFSET(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) -#define SET_TX_DESC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) #define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) #define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) #define SET_TX_DESC_LINIP(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) -#define SET_TX_DESC_AMSDU(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) -#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) #define SET_TX_DESC_OWN(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) @@ -74,76 +68,26 @@ /* Dword 1 */ #define SET_TX_DESC_MACID(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) -#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val) -#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val) -#define SET_TX_DESC_PIFS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val) #define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) -#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val) -#define SET_TX_DESC_NO_ACM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) #define SET_TX_DESC_NON_QOS(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) -#define SET_TX_DESC_KEY_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val) -#define SET_TX_DESC_OUI(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val) -#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val) -#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val) #define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) -#define SET_TX_DESC_WDS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) -#define SET_TX_DESC_HTC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) -#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val) -#define SET_TX_DESC_HWPC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) /* Dword 2 */ -#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val) -#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val) -#define SET_TX_DESC_TSFL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val) -#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val) -#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val) #define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) #define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) -#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) -#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val) /* Dword 3 */ -#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val) -#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val) #define SET_TX_DESC_SEQ(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) -#define SET_TX_DESC_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val) /* Dword 4 */ #define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) -#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val) -#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val) #define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) #define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ @@ -158,12 +102,6 @@ SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) #define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) -#define SET_TX_DESC_TX_STBC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val) -#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val) -#define SET_TX_DESC_RTS_HT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val) #define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) #define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ @@ -180,26 +118,12 @@ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) #define SET_TX_DESC_TX_RATE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) -#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val) #define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) -#define SET_TX_DESC_TX_AGC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val) - -/* Dword 6 */ -#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val) -#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val) /* Dword 7 */ #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) -#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val) -#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val) /* Dword 8 */ #define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ @@ -228,26 +152,6 @@ /* DWORD 0 */ #define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) -#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val) -#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val) -#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val) -#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val) -#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val) -#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val) -#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) -#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) -#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) -#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val) #define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) #define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ @@ -261,159 +165,32 @@ SHIFT_AND_MASK_LE(__pdesc, 15, 1) #define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc, 16, 4) -#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 20, 3) -#define GET_RX_STATUS_DESC_QOS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 23, 1) #define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc, 24, 2) #define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc, 26, 1) #define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc, 27, 1) -#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 28, 1) -#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 29, 1) -#define GET_RX_STATUS_DESC_EOR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 30, 1) #define GET_RX_STATUS_DESC_OWN(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc, 31, 1) /* DWORD 1 */ -#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) -#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val) -#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val) -#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val) -#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val) -#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val) -#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val) -#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val) -#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val) -#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val) -#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val) -#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val) -#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val) - -#define GET_RX_STATUS_DEC_MACID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5) -#define GET_RX_STATUS_DESC_TID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4) #define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) #define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) -#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4) -#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4) -#define GET_RX_STATUS_DESC_PAM(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1) -#define GET_RX_STATUS_DESC_PWR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1) -#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1) -#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1) -#define GET_RX_STATUS_DESC_TYPE(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2) -#define GET_RX_STATUS_DESC_MC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1) -#define GET_RX_STATUS_DESC_BC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1) - -/* DWORD 2 */ -#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val) -#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val) -#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val) -#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val) - -#define GET_RX_STATUS_DESC_SEQ(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12) -#define GET_RX_STATUS_DESC_FRAG(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4) -#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8) -#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1) /* DWORD 3 */ -#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val) -#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val) -#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val) -#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val) -#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val) -#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val) -#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val) -#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val) -#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val) -#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val) -#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val) -#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val) - #define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) #define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) -#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1) #define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) #define GET_RX_STATUS_DESC_BW(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) -#define GET_RX_STATUS_DESC_HTC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1) -#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1) -#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1) -#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1) -#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1) -#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1) -#define GET_RX_STATUS_DESC_IV0(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16) - -/* DWORD 4 */ -#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val) -#define GET_RX_STATUS_DESC_IV1(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32) /* DWORD 5 */ -#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val) #define GET_RX_STATUS_DESC_TSFL(__pdesc) \ SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) -- cgit v1.2.3-59-g8ed1b From c3f997f0c3b2c46776304a482571cdee5f182de2 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 9 Oct 2019 12:37:09 -0500 Subject: rtlwifi: rtl8192se: Replace local bit manipulation macros This driver uses a set of local macros to manipulate the RX and TX descriptors, which are all little-endian quantities. These macros are replaced by the bitfield macros le32p_replace_bits() and le32_get_bits(). In several places, the macros operated on an entire 32-bit word. In these cases, a direct read or replacement is used. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8192se/def.h | 130 +++++++++------------ .../net/wireless/realtek/rtlwifi/rtl8192se/fw.c | 31 ++--- .../net/wireless/realtek/rtlwifi/rtl8192se/trx.c | 4 +- 3 files changed, 74 insertions(+), 91 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h index 44b2b4e3c151..19db124fbdda 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h @@ -24,116 +24,94 @@ #define TX_DESC_SIZE_RTL8192S (16 * 4) #define TX_CMDDESC_SIZE_RTL8192S (16 * 4) -/* Define a macro that takes a le32 word, converts it to host ordering, - * right shifts by a specified count, creates a mask of the specified - * bit count, and extracts that number of bits. - */ - -#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \ - ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \ - BIT_LEN_MASK_32(__mask)) - -/* Define a macro that clears a bit field in an le32 word and - * sets the specified value into that bit field. The resulting - * value remains in le32 ordering; however, it is properly converted - * to host ordering for the clear and set operations before conversion - * back to le32. - */ - -#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \ - (*(__le32 *)(__pdesc) = \ - (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \ - (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \ - (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift))))); - /* macros to read/write various fields in RX or TX descriptors */ /* Dword 0 */ #define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(15, 0)) #define SET_TX_DESC_OFFSET(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(23, 16)) #define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(26)) #define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(27)) #define SET_TX_DESC_LINIP(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(28)) #define SET_TX_DESC_OWN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)) #define GET_TX_DESC_OWN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 31, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(31)) /* Dword 1 */ #define SET_TX_DESC_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val) + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(4, 0)) #define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val) + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(12, 8)) #define SET_TX_DESC_NON_QOS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, BIT(16)) #define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val) + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(23, 22)) /* Dword 2 */ #define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val) + le32p_replace_bits((__le32 *)(__pdesc + 8), __val, GENMASK(28, 24)) #define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 8), __val, BIT(29)) /* Dword 3 */ #define SET_TX_DESC_SEQ(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val) + le32p_replace_bits((__le32 *)(__pdesc + 12), __val, GENMASK(27, 16)) /* Dword 4 */ #define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(5, 0)) #define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(11)) #define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(12)) #define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(15, 13)) #define SET_TX_DESC_TXHT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(16)) #define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(17)) #define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(18)) #define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(20, 19)) #define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(25)) #define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(26)) #define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(28, 27)) #define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(30, 29)) #define SET_TX_DESC_USER_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val) + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(31)) /* Dword 5 */ #define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val) + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(8, 0)) #define SET_TX_DESC_TX_RATE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val) + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(14, 9)) #define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val) + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(20, 16)) /* Dword 7 */ #define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val) + le32p_replace_bits((__le32 *)(__pdesc + 28), __val, GENMASK(15, 0)) /* Dword 8 */ #define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val) + *(__le32 *)(__pdesc + 32) = cpu_to_le32(__val) #define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32) + le32_to_cpu(*((__le32 *)(__pdesc + 32))) /* Dword 9 */ #define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val) + *(__le32 *)(__pdesc + 36) = cpu_to_le32(__val) /* Because the PCI Tx descriptors are chaied at the * initialization and all the NextDescAddresses in @@ -151,54 +129,54 @@ /* DWORD 0 */ #define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(13, 0)) #define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(30)) #define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val) + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)) #define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 0, 14) + le32_get_bits(*((__le32 *)__pdesc), GENMASK(13, 0)) #define GET_RX_STATUS_DESC_CRC32(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 14, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(14)) #define GET_RX_STATUS_DESC_ICV(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 15, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(15)) #define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 16, 4) + le32_get_bits(*((__le32 *)__pdesc), GENMASK(19, 16)) #define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 24, 2) + le32_get_bits(*((__le32 *)__pdesc), GENMASK(25, 24)) #define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 26, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(26)) #define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 27, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(27)) #define GET_RX_STATUS_DESC_OWN(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc, 31, 1) + le32_get_bits(*((__le32 *)__pdesc), BIT(31)) /* DWORD 1 */ #define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1) + le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(14)) #define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1) + le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(15)) /* DWORD 3 */ #define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6) + le32_get_bits(*(__le32 *)(__pdesc + 12), GENMASK(5, 0)) #define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1) + le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(6)) #define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1) + le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(8)) #define GET_RX_STATUS_DESC_BW(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1) + le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(9)) /* DWORD 5 */ #define GET_RX_STATUS_DESC_TSFL(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32) + le32_to_cpu(*((__le32 *)(__pdesc + 20))) /* DWORD 6 */ #define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ - SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) + *(__le32 *)(__pdesc + 24) = cpu_to_le32(__val) #define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \ - SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32) + le32_to_cpu(*(__le32 *)(__pdesc + 24)) #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c index 541b7881735e..47a5b95ca2b9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/fw.c @@ -442,17 +442,20 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, memset((ph2c_buffer + totallen + tx_desclen), 0, len); /* CMD len */ - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 0, 16, pcmd_len[i]); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), pcmd_len[i], + GENMASK(15, 0)); /* CMD ID */ - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 16, 8, pelement_id[i]); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), pelement_id[i], + GENMASK(23, 16)); /* CMD Sequence */ *cmd_start_seq = *cmd_start_seq % 0x80; - SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen), - 24, 7, *cmd_start_seq); + le32p_replace_bits((__le32 *)(ph2c_buffer + totallen + + tx_desclen), *cmd_start_seq, + GENMASK(30, 24)); ++*cmd_start_seq; /* Copy memory */ @@ -462,8 +465,9 @@ static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen, /* CMD continue */ /* set the continue in prevoius cmd. */ if (i < cmd_num - 1) - SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset), - 31, 1, 1); + le32p_replace_bits((__le32 *)(ph2c_buffer + + pre_continueoffset), + 1, BIT(31)); pre_continueoffset = totallen; @@ -559,8 +563,8 @@ void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) pwrmode.flag_dps_en = 0; pwrmode.bcn_rx_en = 0; pwrmode.bcn_to = 0; - SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16, - mac->vif->bss_conf.beacon_int); + le16p_replace_bits((__le16 *)(((u8 *)(&pwrmode) + 8)), + mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); pwrmode.app_itv = 0; pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl; pwrmode.smart_ps = 1; @@ -602,9 +606,10 @@ void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, joinbss_rpt.bssid[3] = mac->bssid[3]; joinbss_rpt.bssid[4] = mac->bssid[4]; joinbss_rpt.bssid[5] = mac->bssid[5]; - SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16, - mac->vif->bss_conf.beacon_int); - SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id); + le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 8)), + mac->vif->bss_conf.beacon_int, GENMASK(15, 0)); + le16p_replace_bits((__le16 *)(((u8 *)(&joinbss_rpt) + 10)), + mac->assoc_id, GENMASK(15, 0)); _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index efb432c6d785..2cab31334a6a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -537,8 +537,8 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, /* Fixed queue of H2C command */ SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); - SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq); - + le32p_replace_bits((__le32 *)skb->data, rtlhal->h2c_txcmd_seq, + GENMASK(30, 24)); SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); -- cgit v1.2.3-59-g8ed1b From 06aae1b02285fd144ff1f1c50a7824f09dc8d778 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 9 Oct 2019 12:37:10 -0500 Subject: rtlwifi: rtl8192se: Convert macros that set descriptor As a first step in the conversion, the macros that set the RX and TX descriptors are converted to static inline routines, and the names are changed from upper to lower case. To minimize the changes in a given step, the input descriptor information is left as as a byte array (u8 *), even though it should be a little-endian word array (__le32 *). That will be changed in the next patch. Several places where checkpatch.pl complains about a space after a cast and other warnings are fixed. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8192se/def.h | 374 ++++++++++++++------- .../net/wireless/realtek/rtlwifi/rtl8192se/trx.c | 161 ++++----- 2 files changed, 341 insertions(+), 194 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h index 19db124fbdda..09baa74709ea 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h @@ -27,91 +27,183 @@ /* macros to read/write various fields in RX or TX descriptors */ /* Dword 0 */ -#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(15, 0)) -#define SET_TX_DESC_OFFSET(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(23, 16)) -#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(26)) -#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(27)) -#define SET_TX_DESC_LINIP(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(28)) -#define SET_TX_DESC_OWN(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)) - -#define GET_TX_DESC_OWN(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(31)) +static inline void set_tx_desc_pkt_size(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(15, 0)); +} + +static inline void set_tx_desc_offset(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(23, 16)); +} + +static inline void set_tx_desc_last_seg(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(26)); +} + +static inline void set_tx_desc_first_seg(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(27)); +} + +static inline void set_tx_desc_linip(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(28)); +} + +static inline void set_tx_desc_own(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)); +} + +static inline u32 get_tx_desc_own(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(31)); +} /* Dword 1 */ -#define SET_TX_DESC_MACID(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(4, 0)) -#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(12, 8)) -#define SET_TX_DESC_NON_QOS(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, BIT(16)) -#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(23, 22)) +static inline void set_tx_desc_macid(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(4, 0)); +} + +static inline void set_tx_desc_queue_sel(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(12, 8)); +} + +static inline void set_tx_desc_non_qos(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, BIT(16)); +} + +static inline void set_tx_desc_sec_type(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(23, 22)); +} /* Dword 2 */ -#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 8), __val, GENMASK(28, 24)) -#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 8), __val, BIT(29)) +static inline void set_tx_desc_rsvd_macid(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 8), __val, GENMASK(28, 24)); +} + +static inline void set_tx_desc_agg_enable(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 8), __val, BIT(29)); +} /* Dword 3 */ -#define SET_TX_DESC_SEQ(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 12), __val, GENMASK(27, 16)) +static inline void set_tx_desc_seq(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 12), __val, GENMASK(27, 16)); +} /* Dword 4 */ -#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(5, 0)) -#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(11)) -#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(12)) -#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(15, 13)) -#define SET_TX_DESC_TXHT(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(16)) -#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(17)) -#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(18)) -#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(20, 19)) -#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(25)) -#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(26)) -#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(28, 27)) -#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(30, 29)) -#define SET_TX_DESC_USER_RATE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(31)) +static inline void set_tx_desc_rts_rate(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(5, 0)); +} + +static inline void set_tx_desc_cts_enable(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(11)); +} + +static inline void set_tx_desc_rts_enable(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(12)); +} + +static inline void set_tx_desc_ra_brsr_id(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(15, 13)); +} + +static inline void set_tx_desc_txht(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(16)); +} + +static inline void set_tx_desc_tx_short(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(17)); +} + +static inline void set_tx_desc_tx_bandwidth(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(18)); +} + +static inline void set_tx_desc_tx_sub_carrier(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(20, 19)); +} + +static inline void set_tx_desc_rts_short(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(25)); +} + +static inline void set_tx_desc_rts_bandwidth(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(26)); +} + +static inline void set_tx_desc_rts_sub_carrier(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(28, 27)); +} + +static inline void set_tx_desc_rts_stbc(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(30, 29)); +} + +static inline void set_tx_desc_user_rate(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(31)); +} /* Dword 5 */ -#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(8, 0)) -#define SET_TX_DESC_TX_RATE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(14, 9)) -#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(20, 16)) +static inline void set_tx_desc_packet_id(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(8, 0)); +} + +static inline void set_tx_desc_tx_rate(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(14, 9)); +} + +static inline void set_tx_desc_data_rate_fb_limit(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(20, 16)); +} /* Dword 7 */ -#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \ - le32p_replace_bits((__le32 *)(__pdesc + 28), __val, GENMASK(15, 0)) +static inline void set_tx_desc_tx_buffer_size(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)(__pdesc + 28), __val, GENMASK(15, 0)); +} /* Dword 8 */ -#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \ - *(__le32 *)(__pdesc + 32) = cpu_to_le32(__val) -#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \ - le32_to_cpu(*((__le32 *)(__pdesc + 32))) +static inline void set_tx_desc_tx_buffer_address(u8 *__pdesc, u32 __val) +{ + *(__le32 *)(__pdesc + 32) = cpu_to_le32(__val); +} + +static inline u32 get_tx_desc_tx_buffer_address(u8 *__pdesc) +{ + return le32_to_cpu(*((__le32 *)(__pdesc + 32))); +} /* Dword 9 */ -#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \ - *(__le32 *)(__pdesc + 36) = cpu_to_le32(__val) +static inline void set_tx_desc_next_desc_address(u8 *__pdesc, u32 __val) +{ + *(__le32 *)(__pdesc + 36) = cpu_to_le32(__val); +} /* Because the PCI Tx descriptors are chaied at the * initialization and all the NextDescAddresses in @@ -128,61 +220,115 @@ #define RX_DRV_INFO_SIZE_UNIT 8 /* DWORD 0 */ -#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(13, 0)) -#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(30)) -#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \ - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)) - -#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), GENMASK(13, 0)) -#define GET_RX_STATUS_DESC_CRC32(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(14)) -#define GET_RX_STATUS_DESC_ICV(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(15)) -#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), GENMASK(19, 16)) -#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), GENMASK(25, 24)) -#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(26)) -#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(27)) -#define GET_RX_STATUS_DESC_OWN(__pdesc) \ - le32_get_bits(*((__le32 *)__pdesc), BIT(31)) +static inline void set_rx_status_desc_pkt_len(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(13, 0)); +} + +static inline void set_rx_status_desc_eor(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(30)); +} + +static inline void set_rx_status_desc_own(u8 *__pdesc, u32 __val) +{ + le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)); +} + +static inline u32 get_rx_status_desc_pkt_len(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), GENMASK(13, 0)); +} + +static inline u32 get_rx_status_desc_crc32(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(14)); +} + +static inline u32 get_rx_status_desc_icv(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(15)); +} + +static inline u32 get_rx_status_desc_drvinfo_size(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), GENMASK(19, 16)); +} + +static inline u32 get_rx_status_desc_shift(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), GENMASK(25, 24)); +} + +static inline u32 get_rx_status_desc_phy_status(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(26)); +} + +static inline u32 get_rx_status_desc_swdec(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(27)); +} + +static inline u32 get_rx_status_desc_own(u8 *__pdesc) +{ + return le32_get_bits(*((__le32 *)__pdesc), BIT(31)); +} /* DWORD 1 */ -#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(14)) -#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(15)) +static inline u32 get_rx_status_desc_paggr(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(14)); +} + +static inline u32 get_rx_status_desc_faggr(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(15)); +} /* DWORD 3 */ -#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 12), GENMASK(5, 0)) -#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(6)) -#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(8)) -#define GET_RX_STATUS_DESC_BW(__pdesc) \ - le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(9)) +static inline u32 get_rx_status_desc_rx_mcs(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 12), GENMASK(5, 0)); +} + +static inline u32 get_rx_status_desc_rx_ht(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(6)); +} + +static inline u32 get_rx_status_desc_splcp(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(8)); +} + +static inline u32 get_rx_status_desc_bw(u8 *__pdesc) +{ + return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(9)); +} /* DWORD 5 */ -#define GET_RX_STATUS_DESC_TSFL(__pdesc) \ - le32_to_cpu(*((__le32 *)(__pdesc + 20))) +static inline u32 get_rx_status_desc_tsfl(u8 *__pdesc) +{ + return le32_to_cpu(*((__le32 *)(__pdesc + 20))); +} /* DWORD 6 */ -#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ - *(__le32 *)(__pdesc + 24) = cpu_to_le32(__val) -#define GET_RX_STATUS_DESC_BUFF_ADDR(__pdesc) \ - le32_to_cpu(*(__le32 *)(__pdesc + 24)) +static inline void set_rx_status__desc_buff_addr(u8 *__pdesc, u32 __val) +{ + *(__le32 *)(__pdesc + 24) = cpu_to_le32(__val); +} + +static inline u32 get_rx_status_desc_buff_addr(u8 *__pdesc) +{ + return le32_to_cpu(*(__le32 *)(__pdesc + 24)); +} #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE2M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE5_5M ||\ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE11M) + (get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE1M || \ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE2M || \ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE5_5M ||\ + get_rx_status_desc_rx_mcs(_pdesc) == DESC_RATE11M) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index 2cab31334a6a..911bca8233e6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -236,25 +236,25 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct sk_buff *skb) { struct rx_fwinfo *p_drvinfo; - u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + u32 phystatus = (u32)get_rx_status_desc_phy_status(pdesc); struct ieee80211_hdr *hdr; - stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); - stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; - stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03); - stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc); - stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc); + stats->length = (u16)get_rx_status_desc_pkt_len(pdesc); + stats->rx_drvinfo_size = (u8)get_rx_status_desc_drvinfo_size(pdesc) * 8; + stats->rx_bufshift = (u8)(get_rx_status_desc_shift(pdesc) & 0x03); + stats->icv = (u16)get_rx_status_desc_icv(pdesc); + stats->crc = (u16)get_rx_status_desc_crc32(pdesc); stats->hwerror = (u16)(stats->crc | stats->icv); - stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc); - - stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); - stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); - stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); - stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1) - && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1)); - stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); - stats->rx_is40mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); - stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc); + stats->decrypted = !get_rx_status_desc_swdec(pdesc); + + stats->rate = (u8)get_rx_status_desc_rx_mcs(pdesc); + stats->shortpreamble = (u16)get_rx_status_desc_splcp(pdesc); + stats->isampdu = (bool)(get_rx_status_desc_paggr(pdesc) == 1); + stats->isfirst_ampdu = (bool)((get_rx_status_desc_paggr(pdesc) == 1) && + (get_rx_status_desc_faggr(pdesc) == 1)); + stats->timestamp_low = get_rx_status_desc_tsfl(pdesc); + stats->rx_is40mhzpacket = (bool)get_rx_status_desc_bw(pdesc); + stats->is_ht = (bool)get_rx_status_desc_rx_ht(pdesc); stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc); if (stats->hwerror) @@ -360,13 +360,13 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, if (rtlpriv->dm.useramask) { /* set txdesc macId */ if (ptcb_desc->mac_id < 32) { - SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id); + set_tx_desc_macid(pdesc, ptcb_desc->mac_id); reserved_macid |= ptcb_desc->mac_id; } } - SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); + set_tx_desc_rsvd_macid(pdesc, reserved_macid); - SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= + set_tx_desc_txht(pdesc, ((ptcb_desc->hw_rate >= DESC_RATEMCS0) ? 1 : 0)); if (rtlhal->version == VERSION_8192S_ACUT) { @@ -378,31 +378,32 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, } } - SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); + set_tx_desc_tx_rate(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) - SET_TX_DESC_TX_SHORT(pdesc, 0); + set_tx_desc_tx_short(pdesc, 0); /* Aggregation related */ if (info->flags & IEEE80211_TX_CTL_AMPDU) - SET_TX_DESC_AGG_ENABLE(pdesc, 1); + set_tx_desc_agg_enable(pdesc, 1); /* For AMPDU, we must insert SSN into TX_DESC */ - SET_TX_DESC_SEQ(pdesc, seq_number); + set_tx_desc_seq(pdesc, seq_number); /* Protection mode related */ /* For 92S, if RTS/CTS are set, HW will execute RTS. */ /* We choose only one protection mode to execute */ - SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable && - !ptcb_desc->cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ? + set_tx_desc_rts_enable(pdesc, ((ptcb_desc->rts_enable && + !ptcb_desc->cts_enable) ? + 1 : 0)); + set_tx_desc_cts_enable(pdesc, ((ptcb_desc->cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); + set_tx_desc_rts_stbc(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); - SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); - SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); - SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= + set_tx_desc_rts_rate(pdesc, ptcb_desc->rts_rate); + set_tx_desc_rts_bandwidth(pdesc, 0); + set_tx_desc_rts_sub_carrier(pdesc, ptcb_desc->rts_sc); + set_tx_desc_rts_short(pdesc, ((ptcb_desc->rts_rate <= DESC_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); @@ -411,27 +412,27 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, /* Set Bandwidth and sub-channel settings. */ if (bw_40) { if (ptcb_desc->packet_bw) { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 1); + set_tx_desc_tx_bandwidth(pdesc, 1); /* use duplicated mode */ - SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, 0); } else { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); - SET_TX_DESC_TX_SUB_CARRIER(pdesc, + set_tx_desc_tx_bandwidth(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, mac->cur_40_prime_sc); } } else { - SET_TX_DESC_TX_BANDWIDTH(pdesc, 0); - SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0); + set_tx_desc_tx_bandwidth(pdesc, 0); + set_tx_desc_tx_sub_carrier(pdesc, 0); } /* 3 Fill necessary field in First Descriptor */ /*DWORD 0*/ - SET_TX_DESC_LINIP(pdesc, 0); - SET_TX_DESC_OFFSET(pdesc, 32); - SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); + set_tx_desc_linip(pdesc, 0); + set_tx_desc_offset(pdesc, 32); + set_tx_desc_pkt_size(pdesc, (u16)skb->len); /*DWORD 1*/ - SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index); + set_tx_desc_ra_brsr_id(pdesc, ptcb_desc->ratr_index); /* Fill security related */ if (info->control.hw_key) { @@ -441,51 +442,51 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: - SET_TX_DESC_SEC_TYPE(pdesc, 0x1); + set_tx_desc_sec_type(pdesc, 0x1); break; case WLAN_CIPHER_SUITE_TKIP: - SET_TX_DESC_SEC_TYPE(pdesc, 0x2); + set_tx_desc_sec_type(pdesc, 0x2); break; case WLAN_CIPHER_SUITE_CCMP: - SET_TX_DESC_SEC_TYPE(pdesc, 0x3); + set_tx_desc_sec_type(pdesc, 0x3); break; default: - SET_TX_DESC_SEC_TYPE(pdesc, 0x0); + set_tx_desc_sec_type(pdesc, 0x0); break; } } /* Set Packet ID */ - SET_TX_DESC_PACKET_ID(pdesc, 0); + set_tx_desc_packet_id(pdesc, 0); /* We will assign magement queue to BK. */ - SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel); + set_tx_desc_queue_sel(pdesc, fw_qsel); /* Alwasy enable all rate fallback range */ - SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); + set_tx_desc_data_rate_fb_limit(pdesc, 0x1F); /* Fix: I don't kown why hw use 6.5M to tx when set it */ - SET_TX_DESC_USER_RATE(pdesc, + set_tx_desc_user_rate(pdesc, ptcb_desc->use_driver_rate ? 1 : 0); /* Set NON_QOS bit. */ if (!ieee80211_is_data_qos(fc)) - SET_TX_DESC_NON_QOS(pdesc, 1); + set_tx_desc_non_qos(pdesc, 1); } /* Fill fields that are required to be initialized * in all of the descriptors */ /*DWORD 0 */ - SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); - SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); + set_tx_desc_first_seg(pdesc, (firstseg ? 1 : 0)); + set_tx_desc_last_seg(pdesc, (lastseg ? 1 : 0)); /* DWORD 7 */ - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); + set_tx_desc_tx_buffer_size(pdesc, (u16)skb->len); /* DOWRD 8 */ - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + set_tx_desc_tx_buffer_address(pdesc, mapping); RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); } @@ -512,38 +513,38 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, /* This bit indicate this packet is used for FW download. */ if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) { /* For firmware downlaod we only need to set LINIP */ - SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt); + set_tx_desc_linip(pdesc, tcb_desc->last_inipkt); /* 92SE must set as 1 for firmware download HW DMA error */ - SET_TX_DESC_FIRST_SEG(pdesc, 1); - SET_TX_DESC_LAST_SEG(pdesc, 1); + set_tx_desc_first_seg(pdesc, 1); + set_tx_desc_last_seg(pdesc, 1); /* 92SE need not to set TX packet size when firmware download */ - SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + set_tx_desc_pkt_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_address(pdesc, mapping); wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); } else { /* H2C Command Desc format (Host TXCMD) */ /* 92SE must set as 1 for firmware download HW DMA error */ - SET_TX_DESC_FIRST_SEG(pdesc, 1); - SET_TX_DESC_LAST_SEG(pdesc, 1); + set_tx_desc_first_seg(pdesc, 1); + set_tx_desc_last_seg(pdesc, 1); - SET_TX_DESC_OFFSET(pdesc, 0x20); + set_tx_desc_offset(pdesc, 0x20); /* Buffer size + command header */ - SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len)); + set_tx_desc_pkt_size(pdesc, (u16)(skb->len)); /* Fixed queue of H2C command */ - SET_TX_DESC_QUEUE_SEL(pdesc, 0x13); + set_tx_desc_queue_sel(pdesc, 0x13); le32p_replace_bits((__le32 *)skb->data, rtlhal->h2c_txcmd_seq, GENMASK(30, 24)); - SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); + set_tx_desc_tx_buffer_size(pdesc, (u16)(skb->len)); + set_tx_desc_tx_buffer_address(pdesc, mapping); wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); } } @@ -555,10 +556,10 @@ void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, switch (desc_name) { case HW_DESC_OWN: wmb(); - SET_TX_DESC_OWN(pdesc, 1); + set_tx_desc_own(pdesc, 1); break; case HW_DESC_TX_NEXTDESC_ADDR: - SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val); + set_tx_desc_next_desc_address(pdesc, *(u32 *)val); break; default: WARN_ONCE(true, "rtl8192se: ERR txdesc :%d not processed\n", @@ -569,16 +570,16 @@ void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, switch (desc_name) { case HW_DESC_RXOWN: wmb(); - SET_RX_STATUS_DESC_OWN(pdesc, 1); + set_rx_status_desc_own(pdesc, 1); break; case HW_DESC_RXBUFF_ADDR: - SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val); + set_rx_status__desc_buff_addr(pdesc, *(u32 *)val); break; case HW_DESC_RXPKT_LEN: - SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val); + set_rx_status_desc_pkt_len(pdesc, *(u32 *)val); break; case HW_DESC_RXERO: - SET_RX_STATUS_DESC_EOR(pdesc, 1); + set_rx_status_desc_eor(pdesc, 1); break; default: WARN_ONCE(true, "rtl8192se: ERR rxdesc :%d not processed\n", @@ -596,10 +597,10 @@ u64 rtl92se_get_desc(struct ieee80211_hw *hw, if (istx) { switch (desc_name) { case HW_DESC_OWN: - ret = GET_TX_DESC_OWN(desc); + ret = get_tx_desc_own(desc); break; case HW_DESC_TXBUFF_ADDR: - ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc); + ret = get_tx_desc_tx_buffer_address(desc); break; default: WARN_ONCE(true, "rtl8192se: ERR txdesc :%d not processed\n", @@ -609,13 +610,13 @@ u64 rtl92se_get_desc(struct ieee80211_hw *hw, } else { switch (desc_name) { case HW_DESC_OWN: - ret = GET_RX_STATUS_DESC_OWN(desc); + ret = get_rx_status_desc_own(desc); break; case HW_DESC_RXPKT_LEN: - ret = GET_RX_STATUS_DESC_PKT_LEN(desc); + ret = get_rx_status_desc_pkt_len(desc); break; case HW_DESC_RXBUFF_ADDR: - ret = GET_RX_STATUS_DESC_BUFF_ADDR(desc); + ret = get_rx_status_desc_buff_addr(desc); break; default: WARN_ONCE(true, "rtl8192se: ERR rxdesc :%d not processed\n", -- cgit v1.2.3-59-g8ed1b From 1dce7eb37333a5e1b155a381d8b517c5e2d2bc39 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 9 Oct 2019 12:37:11 -0500 Subject: rtlwifi: rtl8192se: Convert inline routines to little-endian words In this step, the read/write routines for the descriptors are converted to use __le32 quantities, thus a lot of casts can be removed. Callback routines still use the 8-bit arrays, but these are changed within the specified routine. Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- .../net/wireless/realtek/rtlwifi/rtl8192se/def.h | 216 ++++++++++----------- .../net/wireless/realtek/rtlwifi/rtl8192se/trx.c | 24 ++- 2 files changed, 122 insertions(+), 118 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h index 09baa74709ea..f43331224851 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/def.h @@ -27,182 +27,182 @@ /* macros to read/write various fields in RX or TX descriptors */ /* Dword 0 */ -static inline void set_tx_desc_pkt_size(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_pkt_size(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(15, 0)); + le32p_replace_bits(__pdesc, __val, GENMASK(15, 0)); } -static inline void set_tx_desc_offset(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_offset(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(23, 16)); + le32p_replace_bits(__pdesc, __val, GENMASK(23, 16)); } -static inline void set_tx_desc_last_seg(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_last_seg(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(26)); + le32p_replace_bits(__pdesc, __val, BIT(26)); } -static inline void set_tx_desc_first_seg(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_first_seg(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(27)); + le32p_replace_bits(__pdesc, __val, BIT(27)); } -static inline void set_tx_desc_linip(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_linip(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(28)); + le32p_replace_bits(__pdesc, __val, BIT(28)); } -static inline void set_tx_desc_own(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_own(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)); + le32p_replace_bits(__pdesc, __val, BIT(31)); } -static inline u32 get_tx_desc_own(u8 *__pdesc) +static inline u32 get_tx_desc_own(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(31)); + return le32_get_bits(*(__pdesc), BIT(31)); } /* Dword 1 */ -static inline void set_tx_desc_macid(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_macid(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(4, 0)); + le32p_replace_bits((__pdesc + 1), __val, GENMASK(4, 0)); } -static inline void set_tx_desc_queue_sel(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_queue_sel(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(12, 8)); + le32p_replace_bits((__pdesc + 1), __val, GENMASK(12, 8)); } -static inline void set_tx_desc_non_qos(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_non_qos(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, BIT(16)); + le32p_replace_bits((__pdesc + 1), __val, BIT(16)); } -static inline void set_tx_desc_sec_type(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_sec_type(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 4), __val, GENMASK(23, 22)); + le32p_replace_bits((__pdesc + 1), __val, GENMASK(23, 22)); } /* Dword 2 */ -static inline void set_tx_desc_rsvd_macid(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rsvd_macid(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 8), __val, GENMASK(28, 24)); + le32p_replace_bits((__pdesc + 2), __val, GENMASK(28, 24)); } -static inline void set_tx_desc_agg_enable(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_agg_enable(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 8), __val, BIT(29)); + le32p_replace_bits((__pdesc + 2), __val, BIT(29)); } /* Dword 3 */ -static inline void set_tx_desc_seq(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_seq(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 12), __val, GENMASK(27, 16)); + le32p_replace_bits((__pdesc + 3), __val, GENMASK(27, 16)); } /* Dword 4 */ -static inline void set_tx_desc_rts_rate(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_rate(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(5, 0)); + le32p_replace_bits((__pdesc + 4), __val, GENMASK(5, 0)); } -static inline void set_tx_desc_cts_enable(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_cts_enable(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(11)); + le32p_replace_bits((__pdesc + 4), __val, BIT(11)); } -static inline void set_tx_desc_rts_enable(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_enable(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(12)); + le32p_replace_bits((__pdesc + 4), __val, BIT(12)); } -static inline void set_tx_desc_ra_brsr_id(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_ra_brsr_id(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(15, 13)); + le32p_replace_bits((__pdesc + 4), __val, GENMASK(15, 13)); } -static inline void set_tx_desc_txht(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_txht(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(16)); + le32p_replace_bits((__pdesc + 4), __val, BIT(16)); } -static inline void set_tx_desc_tx_short(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_short(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(17)); + le32p_replace_bits((__pdesc + 4), __val, BIT(17)); } -static inline void set_tx_desc_tx_bandwidth(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_bandwidth(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(18)); + le32p_replace_bits((__pdesc + 4), __val, BIT(18)); } -static inline void set_tx_desc_tx_sub_carrier(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_sub_carrier(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(20, 19)); + le32p_replace_bits((__pdesc + 4), __val, GENMASK(20, 19)); } -static inline void set_tx_desc_rts_short(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_short(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(25)); + le32p_replace_bits((__pdesc + 4), __val, BIT(25)); } -static inline void set_tx_desc_rts_bandwidth(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_bandwidth(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(26)); + le32p_replace_bits((__pdesc + 4), __val, BIT(26)); } -static inline void set_tx_desc_rts_sub_carrier(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_sub_carrier(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(28, 27)); + le32p_replace_bits((__pdesc + 4), __val, GENMASK(28, 27)); } -static inline void set_tx_desc_rts_stbc(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_rts_stbc(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, GENMASK(30, 29)); + le32p_replace_bits((__pdesc + 4), __val, GENMASK(30, 29)); } -static inline void set_tx_desc_user_rate(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_user_rate(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 16), __val, BIT(31)); + le32p_replace_bits((__pdesc + 4), __val, BIT(31)); } /* Dword 5 */ -static inline void set_tx_desc_packet_id(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_packet_id(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(8, 0)); + le32p_replace_bits((__pdesc + 5), __val, GENMASK(8, 0)); } -static inline void set_tx_desc_tx_rate(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_rate(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(14, 9)); + le32p_replace_bits((__pdesc + 5), __val, GENMASK(14, 9)); } -static inline void set_tx_desc_data_rate_fb_limit(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_data_rate_fb_limit(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 20), __val, GENMASK(20, 16)); + le32p_replace_bits((__pdesc + 5), __val, GENMASK(20, 16)); } /* Dword 7 */ -static inline void set_tx_desc_tx_buffer_size(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_buffer_size(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)(__pdesc + 28), __val, GENMASK(15, 0)); + le32p_replace_bits((__pdesc + 7), __val, GENMASK(15, 0)); } /* Dword 8 */ -static inline void set_tx_desc_tx_buffer_address(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_tx_buffer_address(__le32 *__pdesc, u32 __val) { - *(__le32 *)(__pdesc + 32) = cpu_to_le32(__val); + *(__pdesc + 8) = cpu_to_le32(__val); } -static inline u32 get_tx_desc_tx_buffer_address(u8 *__pdesc) +static inline u32 get_tx_desc_tx_buffer_address(__le32 *__pdesc) { - return le32_to_cpu(*((__le32 *)(__pdesc + 32))); + return le32_to_cpu(*((__pdesc + 8))); } /* Dword 9 */ -static inline void set_tx_desc_next_desc_address(u8 *__pdesc, u32 __val) +static inline void set_tx_desc_next_desc_address(__le32 *__pdesc, u32 __val) { - *(__le32 *)(__pdesc + 36) = cpu_to_le32(__val); + *(__pdesc + 9) = cpu_to_le32(__val); } /* Because the PCI Tx descriptors are chaied at the @@ -220,108 +220,108 @@ static inline void set_tx_desc_next_desc_address(u8 *__pdesc, u32 __val) #define RX_DRV_INFO_SIZE_UNIT 8 /* DWORD 0 */ -static inline void set_rx_status_desc_pkt_len(u8 *__pdesc, u32 __val) +static inline void set_rx_status_desc_pkt_len(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, GENMASK(13, 0)); + le32p_replace_bits(__pdesc, __val, GENMASK(13, 0)); } -static inline void set_rx_status_desc_eor(u8 *__pdesc, u32 __val) +static inline void set_rx_status_desc_eor(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(30)); + le32p_replace_bits(__pdesc, __val, BIT(30)); } -static inline void set_rx_status_desc_own(u8 *__pdesc, u32 __val) +static inline void set_rx_status_desc_own(__le32 *__pdesc, u32 __val) { - le32p_replace_bits((__le32 *)__pdesc, __val, BIT(31)); + le32p_replace_bits(__pdesc, __val, BIT(31)); } -static inline u32 get_rx_status_desc_pkt_len(u8 *__pdesc) +static inline u32 get_rx_status_desc_pkt_len(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), GENMASK(13, 0)); + return le32_get_bits(*(__pdesc), GENMASK(13, 0)); } -static inline u32 get_rx_status_desc_crc32(u8 *__pdesc) +static inline u32 get_rx_status_desc_crc32(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(14)); + return le32_get_bits(*(__pdesc), BIT(14)); } -static inline u32 get_rx_status_desc_icv(u8 *__pdesc) +static inline u32 get_rx_status_desc_icv(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(15)); + return le32_get_bits(*(__pdesc), BIT(15)); } -static inline u32 get_rx_status_desc_drvinfo_size(u8 *__pdesc) +static inline u32 get_rx_status_desc_drvinfo_size(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), GENMASK(19, 16)); + return le32_get_bits(*(__pdesc), GENMASK(19, 16)); } -static inline u32 get_rx_status_desc_shift(u8 *__pdesc) +static inline u32 get_rx_status_desc_shift(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), GENMASK(25, 24)); + return le32_get_bits(*(__pdesc), GENMASK(25, 24)); } -static inline u32 get_rx_status_desc_phy_status(u8 *__pdesc) +static inline u32 get_rx_status_desc_phy_status(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(26)); + return le32_get_bits(*(__pdesc), BIT(26)); } -static inline u32 get_rx_status_desc_swdec(u8 *__pdesc) +static inline u32 get_rx_status_desc_swdec(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(27)); + return le32_get_bits(*(__pdesc), BIT(27)); } -static inline u32 get_rx_status_desc_own(u8 *__pdesc) +static inline u32 get_rx_status_desc_own(__le32 *__pdesc) { - return le32_get_bits(*((__le32 *)__pdesc), BIT(31)); + return le32_get_bits(*(__pdesc), BIT(31)); } /* DWORD 1 */ -static inline u32 get_rx_status_desc_paggr(u8 *__pdesc) +static inline u32 get_rx_status_desc_paggr(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(14)); + return le32_get_bits(*(__pdesc + 1), BIT(14)); } -static inline u32 get_rx_status_desc_faggr(u8 *__pdesc) +static inline u32 get_rx_status_desc_faggr(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 4), BIT(15)); + return le32_get_bits(*(__pdesc + 1), BIT(15)); } /* DWORD 3 */ -static inline u32 get_rx_status_desc_rx_mcs(u8 *__pdesc) +static inline u32 get_rx_status_desc_rx_mcs(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 12), GENMASK(5, 0)); + return le32_get_bits(*(__pdesc + 3), GENMASK(5, 0)); } -static inline u32 get_rx_status_desc_rx_ht(u8 *__pdesc) +static inline u32 get_rx_status_desc_rx_ht(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(6)); + return le32_get_bits(*(__pdesc + 3), BIT(6)); } -static inline u32 get_rx_status_desc_splcp(u8 *__pdesc) +static inline u32 get_rx_status_desc_splcp(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(8)); + return le32_get_bits(*(__pdesc + 3), BIT(8)); } -static inline u32 get_rx_status_desc_bw(u8 *__pdesc) +static inline u32 get_rx_status_desc_bw(__le32 *__pdesc) { - return le32_get_bits(*(__le32 *)(__pdesc + 12), BIT(9)); + return le32_get_bits(*(__pdesc + 3), BIT(9)); } /* DWORD 5 */ -static inline u32 get_rx_status_desc_tsfl(u8 *__pdesc) +static inline u32 get_rx_status_desc_tsfl(__le32 *__pdesc) { - return le32_to_cpu(*((__le32 *)(__pdesc + 20))); + return le32_to_cpu(*((__pdesc + 5))); } /* DWORD 6 */ -static inline void set_rx_status__desc_buff_addr(u8 *__pdesc, u32 __val) +static inline void set_rx_status__desc_buff_addr(__le32 *__pdesc, u32 __val) { - *(__le32 *)(__pdesc + 24) = cpu_to_le32(__val); + *(__pdesc + 6) = cpu_to_le32(__val); } -static inline u32 get_rx_status_desc_buff_addr(u8 *__pdesc) +static inline u32 get_rx_status_desc_buff_addr(__le32 *__pdesc) { - return le32_to_cpu(*(__le32 *)(__pdesc + 24)); + return le32_to_cpu(*(__pdesc + 6)); } #define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c index 911bca8233e6..9eaa5348b556 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/trx.c @@ -33,7 +33,7 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) } static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, - struct rtl_stats *pstats, u8 *pdesc, + struct rtl_stats *pstats, __le32 *pdesc, struct rx_fwinfo *p_drvinfo, bool packet_match_bssid, bool packet_toself, @@ -193,11 +193,10 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_stats *pstats, - u8 *pdesc, struct rx_fwinfo *p_drvinfo) + __le32 *pdesc, struct rx_fwinfo *p_drvinfo) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - struct ieee80211_hdr *hdr; u8 *tmp_buf; u8 *praddr; @@ -232,10 +231,11 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw, } bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, - struct ieee80211_rx_status *rx_status, u8 *pdesc, + struct ieee80211_rx_status *rx_status, u8 *pdesc8, struct sk_buff *skb) { struct rx_fwinfo *p_drvinfo; + __le32 *pdesc = (__le32 *)pdesc8; u32 phystatus = (u32)get_rx_status_desc_phy_status(pdesc); struct ieee80211_hdr *hdr; @@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, } void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, - struct ieee80211_hdr *hdr, u8 *pdesc_tx, + struct ieee80211_hdr *hdr, u8 *pdesc8, u8 *pbd_desc_tx, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, struct sk_buff *skb, @@ -320,7 +320,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - u8 *pdesc = pdesc_tx; + __le32 *pdesc = (__le32 *)pdesc8; u16 seq_number; __le16 fc = hdr->frame_control; u8 reserved_macid = 0; @@ -491,13 +491,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n"); } -void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, - bool firstseg, bool lastseg, struct sk_buff *skb) +void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc8, + bool firstseg, bool lastseg, struct sk_buff *skb) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb); + __le32 *pdesc = (__le32 *)pdesc8; dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); @@ -549,9 +550,11 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, } } -void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, +void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc8, bool istx, u8 desc_name, u8 *val) { + __le32 *pdesc = (__le32 *)pdesc8; + if (istx) { switch (desc_name) { case HW_DESC_OWN: @@ -590,9 +593,10 @@ void rtl92se_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, } u64 rtl92se_get_desc(struct ieee80211_hw *hw, - u8 *desc, bool istx, u8 desc_name) + u8 *desc8, bool istx, u8 desc_name) { u32 ret = 0; + __le32 *desc = (__le32 *)desc8; if (istx) { switch (desc_name) { -- cgit v1.2.3-59-g8ed1b From 9bce4b27f3ecd4b81648cb02ce8fd6d319676eb7 Mon Sep 17 00:00:00 2001 From: Andrew Jeffery Date: Thu, 10 Oct 2019 12:37:56 +1030 Subject: net: ftgmac100: Ungate RCLK for RMII on ASPEED MACs The 50MHz RCLK has to be enabled before the RMII interface will function. Signed-off-by: Andrew Jeffery Reviewed-by: Joel Stanley Signed-off-by: David S. Miller --- drivers/net/ethernet/faraday/ftgmac100.c | 50 +++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 9b7af94a40bb..824310253099 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -90,6 +90,9 @@ struct ftgmac100 { struct mii_bus *mii_bus; struct clk *clk; + /* AST2500/AST2600 RMII ref clock gate */ + struct clk *rclk; + /* Link management */ int cur_speed; int cur_duplex; @@ -1718,20 +1721,41 @@ static void ftgmac100_ncsi_handler(struct ncsi_dev *nd) nd->link_up ? "up" : "down"); } -static void ftgmac100_setup_clk(struct ftgmac100 *priv) +static int ftgmac100_setup_clk(struct ftgmac100 *priv) { - priv->clk = devm_clk_get(priv->dev, NULL); - if (IS_ERR(priv->clk)) - return; + struct clk *clk; + int rc; - clk_prepare_enable(priv->clk); + clk = devm_clk_get(priv->dev, NULL /* MACCLK */); + if (IS_ERR(clk)) + return PTR_ERR(clk); + priv->clk = clk; + rc = clk_prepare_enable(priv->clk); + if (rc) + return rc; /* Aspeed specifies a 100MHz clock is required for up to * 1000Mbit link speeds. As NCSI is limited to 100Mbit, 25MHz * is sufficient */ - clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ : - FTGMAC_100MHZ); + rc = clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ : + FTGMAC_100MHZ); + if (rc) + goto cleanup_clk; + + /* RCLK is for RMII, typically used for NCSI. Optional because its not + * necessary if it's the AST2400 MAC, or the MAC is configured for + * RGMII, or the controller is not an ASPEED-based controller. + */ + priv->rclk = devm_clk_get_optional(priv->dev, "RCLK"); + rc = clk_prepare_enable(priv->rclk); + if (!rc) + return 0; + +cleanup_clk: + clk_disable_unprepare(priv->clk); + + return rc; } static int ftgmac100_probe(struct platform_device *pdev) @@ -1853,8 +1877,11 @@ static int ftgmac100_probe(struct platform_device *pdev) goto err_setup_mdio; } - if (priv->is_aspeed) - ftgmac100_setup_clk(priv); + if (priv->is_aspeed) { + err = ftgmac100_setup_clk(priv); + if (err) + goto err_ncsi_dev; + } /* Default ring sizes */ priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES; @@ -1886,8 +1913,10 @@ static int ftgmac100_probe(struct platform_device *pdev) return 0; -err_ncsi_dev: err_register_netdev: + clk_disable_unprepare(priv->rclk); + clk_disable_unprepare(priv->clk); +err_ncsi_dev: ftgmac100_destroy_mdio(netdev); err_setup_mdio: iounmap(priv->base); @@ -1909,6 +1938,7 @@ static int ftgmac100_remove(struct platform_device *pdev) unregister_netdev(netdev); + clk_disable_unprepare(priv->rclk); clk_disable_unprepare(priv->clk); /* There's a small chance the reset task will have been re-queued, -- cgit v1.2.3-59-g8ed1b From 1635520aefc1056604ad60d042a64f43898c7108 Mon Sep 17 00:00:00 2001 From: Peter Fink Date: Thu, 10 Oct 2019 15:00:22 +0200 Subject: net: usb: ax88179_178a: write mac to hardware in get_mac_addr When the MAC address is supplied via device tree or a random MAC is generated it has to be written to the asix chip in order to receive any data. Previously in 9fb137aef34e ("net: usb: ax88179_178a: allow optionally getting mac address from device tree") this line was omitted because it seemed to work perfectly fine without it. But it was simply not detected because the chip keeps the mac stored even beyond a reset and it was tested on a hardware with an integrated UPS where the asix chip was permanently powered on even throughout power cycles. Fixes: 9fb137aef34e ("net: usb: ax88179_178a: allow optionally getting mac address from device tree") Signed-off-by: Peter Fink Signed-off-by: David S. Miller --- drivers/net/usb/ax88179_178a.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 5a587663e7dc..c5a6e75c24e3 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1235,6 +1235,9 @@ static void ax88179_get_mac_addr(struct usbnet *dev) netdev_info(dev->net, "invalid MAC address, using random\n"); eth_hw_addr_random(dev->net); } + + ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN, ETH_ALEN, + dev->net->dev_addr); } static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf) -- cgit v1.2.3-59-g8ed1b From e7a981050a7fb9a14b652365c00d9c5a025704ce Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 10 Oct 2019 15:18:49 +0200 Subject: devlink: propagate extack down to health reporter ops During health reporter operations, driver might want to fill-up the extack message, so propagate extack down to the health reporter ops. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 9 ++++++--- .../net/ethernet/mellanox/mlx5/core/en/reporter_rx.c | 6 ++++-- .../net/ethernet/mellanox/mlx5/core/en/reporter_tx.c | 6 ++++-- drivers/net/ethernet/mellanox/mlx5/core/health.c | 12 ++++++++---- include/net/devlink.h | 8 +++++--- net/core/devlink.c | 20 +++++++++++--------- 6 files changed, 38 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index e664392dccc0..ff1bc0ec2e7c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -16,7 +16,8 @@ #include "bnxt_devlink.h" static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct bnxt *bp = devlink_health_reporter_priv(reporter); struct bnxt_fw_health *health = bp->fw_health; @@ -66,7 +67,8 @@ static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = { }; static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, + struct netlink_ext_ack *extack) { struct bnxt *bp = devlink_health_reporter_priv(reporter); @@ -84,7 +86,8 @@ struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = { }; static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, + struct netlink_ext_ack *extack) { struct bnxt *bp = devlink_health_reporter_priv(reporter); struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c index b860569d4247..6c72b592315b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c @@ -222,7 +222,8 @@ static int mlx5e_rx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx) } static int mlx5e_rx_reporter_recover(struct devlink_health_reporter *reporter, - void *context) + void *context, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_err_ctx *err_ctx = context; @@ -301,7 +302,8 @@ static int mlx5e_rx_reporter_build_diagnose_output(struct mlx5e_rq *rq, } static int mlx5e_rx_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_params *params = &priv->channels.params; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c index bfed558637c2..b468549e96ff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c @@ -135,7 +135,8 @@ static int mlx5e_tx_reporter_recover_from_ctx(struct mlx5e_err_ctx *err_ctx) } static int mlx5e_tx_reporter_recover(struct devlink_health_reporter *reporter, - void *context) + void *context, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_err_ctx *err_ctx = context; @@ -205,7 +206,8 @@ mlx5e_tx_reporter_build_diagnose_output(struct devlink_fmsg *fmsg, } static int mlx5e_tx_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5e_priv *priv = devlink_health_reporter_priv(reporter); struct mlx5e_txqsq *generic_sq = priv->txq2sq[0]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index d685122d9ff7..be3c3c704bfc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -390,7 +390,8 @@ static void print_health_info(struct mlx5_core_dev *dev) static int mlx5_fw_reporter_diagnose(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg) + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); struct mlx5_core_health *health = &dev->priv.health; @@ -491,7 +492,8 @@ mlx5_fw_reporter_heath_buffer_data_put(struct mlx5_core_dev *dev, static int mlx5_fw_reporter_dump(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg, void *priv_ctx) + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); int err; @@ -545,7 +547,8 @@ static const struct devlink_health_reporter_ops mlx5_fw_reporter_ops = { static int mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); @@ -555,7 +558,8 @@ mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter, #define MLX5_CR_DUMP_CHUNK_SIZE 256 static int mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg, void *priv_ctx) + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) { struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); u32 crdump_size = dev->priv.health.crdump_size; diff --git a/include/net/devlink.h b/include/net/devlink.h index 4095657fc23f..6bf3b9e0595a 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -507,11 +507,13 @@ enum devlink_health_reporter_state { struct devlink_health_reporter_ops { char *name; int (*recover)(struct devlink_health_reporter *reporter, - void *priv_ctx); + void *priv_ctx, struct netlink_ext_ack *extack); int (*dump)(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg, void *priv_ctx); + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack); int (*diagnose)(struct devlink_health_reporter *reporter, - struct devlink_fmsg *fmsg); + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack); }; /** diff --git a/net/core/devlink.c b/net/core/devlink.c index 95887462eecf..97e9a2246929 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -4847,7 +4847,7 @@ EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update); static int devlink_health_reporter_recover(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, struct netlink_ext_ack *extack) { int err; @@ -4857,7 +4857,7 @@ devlink_health_reporter_recover(struct devlink_health_reporter *reporter, if (!reporter->ops->recover) return -EOPNOTSUPP; - err = reporter->ops->recover(reporter, priv_ctx); + err = reporter->ops->recover(reporter, priv_ctx, extack); if (err) return err; @@ -4878,7 +4878,8 @@ devlink_health_dump_clear(struct devlink_health_reporter *reporter) } static int devlink_health_do_dump(struct devlink_health_reporter *reporter, - void *priv_ctx) + void *priv_ctx, + struct netlink_ext_ack *extack) { int err; @@ -4899,7 +4900,7 @@ static int devlink_health_do_dump(struct devlink_health_reporter *reporter, goto dump_err; err = reporter->ops->dump(reporter, reporter->dump_fmsg, - priv_ctx); + priv_ctx, extack); if (err) goto dump_err; @@ -4946,11 +4947,12 @@ int devlink_health_report(struct devlink_health_reporter *reporter, mutex_lock(&reporter->dump_lock); /* store current dump of current error, for later analysis */ - devlink_health_do_dump(reporter, priv_ctx); + devlink_health_do_dump(reporter, priv_ctx, NULL); mutex_unlock(&reporter->dump_lock); if (reporter->auto_recover) - return devlink_health_reporter_recover(reporter, priv_ctx); + return devlink_health_reporter_recover(reporter, + priv_ctx, NULL); return 0; } @@ -5188,7 +5190,7 @@ static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb, if (!reporter) return -EINVAL; - err = devlink_health_reporter_recover(reporter, NULL); + err = devlink_health_reporter_recover(reporter, NULL, info->extack); devlink_health_reporter_put(reporter); return err; @@ -5221,7 +5223,7 @@ static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb, if (err) goto out; - err = reporter->ops->diagnose(reporter, fmsg); + err = reporter->ops->diagnose(reporter, fmsg, info->extack); if (err) goto out; @@ -5256,7 +5258,7 @@ devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb, } mutex_lock(&reporter->dump_lock); if (!start) { - err = devlink_health_do_dump(reporter, NULL); + err = devlink_health_do_dump(reporter, NULL, cb->extack); if (err) goto unlock; cb->args[1] = reporter->dump_ts; -- cgit v1.2.3-59-g8ed1b From 82c93a87bf8bc0cdb5ec2ab99da7d87715ff889f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 10 Oct 2019 15:18:50 +0200 Subject: netdevsim: implement couple of testing devlink health reporters Implement "empty" and "dummy" reporters. The first one is really simple and does nothing. The other one has debugfs files to trigger breakage and it is able to do recovery. The ops also implement dummy fmsg content. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/Makefile | 2 +- drivers/net/netdevsim/dev.c | 17 +- drivers/net/netdevsim/health.c | 325 ++++++++++++++++++++++++++++++++++++++ drivers/net/netdevsim/netdevsim.h | 13 ++ 4 files changed, 354 insertions(+), 3 deletions(-) create mode 100644 drivers/net/netdevsim/health.c (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/Makefile b/drivers/net/netdevsim/Makefile index 09f1315d2f2a..f4d8f62f28c2 100644 --- a/drivers/net/netdevsim/Makefile +++ b/drivers/net/netdevsim/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_NETDEVSIM) += netdevsim.o netdevsim-objs := \ - netdev.o dev.o fib.o bus.o + netdev.o dev.o fib.o bus.o health.o ifeq ($(CONFIG_BPF_SYSCALL),y) netdevsim-objs += \ diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index e47fa7b6ca7c..468e157a7cb1 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -730,12 +730,18 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, if (err) goto err_dummy_region_exit; - err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + err = nsim_dev_health_init(nsim_dev, devlink); if (err) goto err_traps_exit; + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + if (err) + goto err_health_exit; + return 0; +err_health_exit: + nsim_dev_health_exit(nsim_dev); err_traps_exit: nsim_dev_traps_exit(devlink); err_dummy_region_exit: @@ -797,10 +803,14 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) if (err) goto err_traps_exit; - err = nsim_bpf_dev_init(nsim_dev); + err = nsim_dev_health_init(nsim_dev, devlink); if (err) goto err_debugfs_exit; + err = nsim_bpf_dev_init(nsim_dev); + if (err) + goto err_health_exit; + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); if (err) goto err_bpf_dev_exit; @@ -810,6 +820,8 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) err_bpf_dev_exit: nsim_bpf_dev_exit(nsim_dev); +err_health_exit: + nsim_dev_health_exit(nsim_dev); err_debugfs_exit: nsim_dev_debugfs_exit(nsim_dev); err_traps_exit: @@ -837,6 +849,7 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) if (devlink_is_reload_failed(devlink)) return; nsim_dev_port_del_all(nsim_dev); + nsim_dev_health_exit(nsim_dev); nsim_dev_traps_exit(devlink); nsim_dev_dummy_region_exit(nsim_dev); mutex_destroy(&nsim_dev->port_list_lock); diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c new file mode 100644 index 000000000000..2716235a0336 --- /dev/null +++ b/drivers/net/netdevsim/health.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */ + +#include +#include +#include +#include + +#include "netdevsim.h" + +static int +nsim_dev_empty_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int +nsim_dev_empty_reporter_diagnose(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static const +struct devlink_health_reporter_ops nsim_dev_empty_reporter_ops = { + .name = "empty", + .dump = nsim_dev_empty_reporter_dump, + .diagnose = nsim_dev_empty_reporter_diagnose, +}; + +struct nsim_dev_dummy_reporter_ctx { + char *break_msg; +}; + +static int +nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter, + void *priv_ctx, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; + + if (health->fail_recover) { + /* For testing purposes, user set debugfs fail_recover + * value to true. Fail right away. + */ + NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes"); + return -EINVAL; + } + if (ctx) { + kfree(health->recovered_break_msg); + health->recovered_break_msg = kstrdup(ctx->break_msg, + GFP_KERNEL); + if (!health->recovered_break_msg) + return -ENOMEM; + } + return 0; +} + +static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len) +{ + char *binary; + int err; + int i; + + err = devlink_fmsg_bool_pair_put(fmsg, "test_bool", true); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, "test_u8", 1); + if (err) + return err; + err = devlink_fmsg_u32_pair_put(fmsg, "test_u32", 3); + if (err) + return err; + err = devlink_fmsg_u64_pair_put(fmsg, "test_u64", 4); + if (err) + return err; + err = devlink_fmsg_string_pair_put(fmsg, "test_string", "somestring"); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_binary"); + if (err) + return err; + binary = kmalloc(binary_len, GFP_KERNEL); + if (!binary) + return -ENOMEM; + get_random_bytes(binary, binary_len); + err = devlink_fmsg_binary_put(fmsg, binary, binary_len); + kfree(binary); + if (err) + return err; + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_pair_nest_start(fmsg, "test_nest"); + if (err) + return err; + err = devlink_fmsg_obj_nest_start(fmsg); + if (err) + return err; + err = devlink_fmsg_bool_pair_put(fmsg, "nested_test_bool", false); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, "nested_test_u8", false); + if (err) + return err; + err = devlink_fmsg_obj_nest_end(fmsg); + if (err) + return err; + err = devlink_fmsg_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_bool_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_bool_put(fmsg, true); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u8_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u8_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u32_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u32_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u64_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u64_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_array_of_objects"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_obj_nest_start(fmsg); + if (err) + return err; + err = devlink_fmsg_bool_pair_put(fmsg, + "in_array_nested_test_bool", + false); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, + "in_array_nested_test_u8", + i); + if (err) + return err; + err = devlink_fmsg_obj_nest_end(fmsg); + if (err) + return err; + } + return devlink_fmsg_arr_pair_nest_end(fmsg); +} + +static int +nsim_dev_dummy_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; + int err; + + if (ctx) { + err = devlink_fmsg_string_pair_put(fmsg, "break_message", + ctx->break_msg); + if (err) + return err; + } + return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len); +} + +static int +nsim_dev_dummy_reporter_diagnose(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + int err; + + if (health->recovered_break_msg) { + err = devlink_fmsg_string_pair_put(fmsg, + "recovered_break_message", + health->recovered_break_msg); + if (err) + return err; + } + return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len); +} + +static const +struct devlink_health_reporter_ops nsim_dev_dummy_reporter_ops = { + .name = "dummy", + .recover = nsim_dev_dummy_reporter_recover, + .dump = nsim_dev_dummy_reporter_dump, + .diagnose = nsim_dev_dummy_reporter_diagnose, +}; + +static ssize_t nsim_dev_health_break_write(struct file *file, + const char __user *data, + size_t count, loff_t *ppos) +{ + struct nsim_dev_health *health = file->private_data; + struct nsim_dev_dummy_reporter_ctx ctx; + char *break_msg; + int err; + + break_msg = kmalloc(count + 1, GFP_KERNEL); + if (!break_msg) + return -ENOMEM; + + if (copy_from_user(break_msg, data, count)) { + err = -EFAULT; + goto out; + } + break_msg[count] = '\0'; + if (break_msg[count - 1] == '\n') + break_msg[count - 1] = '\0'; + + ctx.break_msg = break_msg; + err = devlink_health_report(health->dummy_reporter, break_msg, &ctx); + if (err) + goto out; + +out: + kfree(break_msg); + return err ?: count; +} + +static const struct file_operations nsim_dev_health_break_fops = { + .open = simple_open, + .write = nsim_dev_health_break_write, + .llseek = generic_file_llseek, +}; + +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink) +{ + struct nsim_dev_health *health = &nsim_dev->health; + int err; + + health->empty_reporter = + devlink_health_reporter_create(devlink, + &nsim_dev_empty_reporter_ops, + 0, false, health); + if (IS_ERR(health->empty_reporter)) + return PTR_ERR(health->empty_reporter); + + health->dummy_reporter = + devlink_health_reporter_create(devlink, + &nsim_dev_dummy_reporter_ops, + 0, false, health); + if (IS_ERR(health->dummy_reporter)) { + err = PTR_ERR(health->dummy_reporter); + goto err_empty_reporter_destroy; + } + + health->ddir = debugfs_create_dir("health", nsim_dev->ddir); + if (IS_ERR_OR_NULL(health->ddir)) { + err = PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL; + goto err_dummy_reporter_destroy; + } + + health->recovered_break_msg = NULL; + debugfs_create_file("break_health", 0200, health->ddir, health, + &nsim_dev_health_break_fops); + health->binary_len = 16; + debugfs_create_u32("binary_len", 0600, health->ddir, + &health->binary_len); + health->fail_recover = false; + debugfs_create_bool("fail_recover", 0600, health->ddir, + &health->fail_recover); + return 0; + +err_dummy_reporter_destroy: + devlink_health_reporter_destroy(health->dummy_reporter); +err_empty_reporter_destroy: + devlink_health_reporter_destroy(health->empty_reporter); + return err; +} + +void nsim_dev_health_exit(struct nsim_dev *nsim_dev) +{ + struct nsim_dev_health *health = &nsim_dev->health; + + debugfs_remove_recursive(health->ddir); + kfree(health->recovered_break_msg); + devlink_health_reporter_destroy(health->dummy_reporter); + devlink_health_reporter_destroy(health->empty_reporter); +} diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 24358385d869..94df795ef4d3 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -134,6 +134,18 @@ enum nsim_resource_id { NSIM_RESOURCE_IPV6_FIB_RULES, }; +struct nsim_dev_health { + struct devlink_health_reporter *empty_reporter; + struct devlink_health_reporter *dummy_reporter; + struct dentry *ddir; + char *recovered_break_msg; + u32 binary_len; + bool fail_recover; +}; + +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink); +void nsim_dev_health_exit(struct nsim_dev *nsim_dev); + struct nsim_dev_port { struct list_head list; struct devlink_port devlink_port; @@ -164,6 +176,7 @@ struct nsim_dev { bool dont_allow_reload; bool fail_reload; struct devlink_region *dummy_region; + struct nsim_dev_health health; }; static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev) -- cgit v1.2.3-59-g8ed1b From c5329b2d5b8b4e41be14d31ee8505b4f5607bf9b Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 9 Oct 2019 16:18:08 +0800 Subject: ath10k: fix array out-of-bounds access If firmware reports rate_max > WMI_TPC_RATE_MAX(WMI_TPC_FINAL_RATE_MAX) or num_tx_chain > WMI_TPC_TX_N_CHAIN, it will cause array out-of-bounds access, so print a warning and reset to avoid memory corruption. Tested HW: QCA9984 Tested FW: 10.4-3.9.0.2-00035 Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 2 +- drivers/net/wireless/ath/ath10k/wmi.c | 49 +++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index bd2b5628f850..40baf25ac99f 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1516,7 +1516,7 @@ static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, *len += scnprintf(buf + *len, buf_len - *len, "No. Preamble Rate_code "); - for (i = 0; i < WMI_TPC_TX_N_CHAIN; i++) + for (i = 0; i < tpc_stats->num_tx_chain; i++) *len += scnprintf(buf + *len, buf_len - *len, "tpc_value%d ", i); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f0ab11556dc2..4473b13d1d48 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4681,16 +4681,13 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar, } pream_idx = 0; - for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) { + for (i = 0; i < tpc_stats->rate_max; i++) { memset(tpc_value, 0, sizeof(tpc_value)); memset(buff, 0, sizeof(buff)); if (i == pream_table[pream_idx]) pream_idx++; - for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) { - if (j >= __le32_to_cpu(ev->num_tx_chain)) - break; - + for (j = 0; j < tpc_stats->num_tx_chain; j++) { tpc[j] = ath10k_tpc_config_get_rate(ar, ev, i, j + 1, rate_code[i], type); @@ -4803,7 +4800,7 @@ void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table, void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) { - u32 num_tx_chain; + u32 num_tx_chain, rate_max; u8 rate_code[WMI_TPC_RATE_MAX]; u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; struct wmi_pdev_tpc_config_event *ev; @@ -4819,6 +4816,13 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) return; } + rate_max = __le32_to_cpu(ev->rate_max); + if (rate_max > WMI_TPC_RATE_MAX) { + ath10k_warn(ar, "number of rate is %d greater than TPC configured rate %d\n", + rate_max, WMI_TPC_RATE_MAX); + rate_max = WMI_TPC_RATE_MAX; + } + tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); if (!tpc_stats) return; @@ -4835,8 +4839,8 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(ev->twice_antenna_reduction); tpc_stats->power_limit = __le32_to_cpu(ev->power_limit); tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power); - tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain); - tpc_stats->rate_max = __le32_to_cpu(ev->rate_max); + tpc_stats->num_tx_chain = num_tx_chain; + tpc_stats->rate_max = rate_max; ath10k_tpc_config_disp_tables(ar, ev, tpc_stats, rate_code, pream_table, @@ -5031,16 +5035,13 @@ ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar, } pream_idx = 0; - for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) { + for (i = 0; i < tpc_stats->rate_max; i++) { memset(tpc_value, 0, sizeof(tpc_value)); memset(buff, 0, sizeof(buff)); if (i == pream_table[pream_idx]) pream_idx++; - for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) { - if (j >= __le32_to_cpu(ev->num_tx_chain)) - break; - + for (j = 0; j < tpc_stats->num_tx_chain; j++) { tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1, rate_code[i], type, pream_idx); @@ -5056,7 +5057,7 @@ ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar, void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb) { - u32 num_tx_chain; + u32 num_tx_chain, rate_max; u8 rate_code[WMI_TPC_FINAL_RATE_MAX]; u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; struct wmi_pdev_tpc_final_table_event *ev; @@ -5064,12 +5065,24 @@ void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb) ev = (struct wmi_pdev_tpc_final_table_event *)skb->data; + num_tx_chain = __le32_to_cpu(ev->num_tx_chain); + if (num_tx_chain > WMI_TPC_TX_N_CHAIN) { + ath10k_warn(ar, "number of tx chain is %d greater than TPC final configured tx chain %d\n", + num_tx_chain, WMI_TPC_TX_N_CHAIN); + return; + } + + rate_max = __le32_to_cpu(ev->rate_max); + if (rate_max > WMI_TPC_FINAL_RATE_MAX) { + ath10k_warn(ar, "number of rate is %d greater than TPC final configured rate %d\n", + rate_max, WMI_TPC_FINAL_RATE_MAX); + rate_max = WMI_TPC_FINAL_RATE_MAX; + } + tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); if (!tpc_stats) return; - num_tx_chain = __le32_to_cpu(ev->num_tx_chain); - ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table, num_tx_chain); @@ -5082,8 +5095,8 @@ void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(ev->twice_antenna_reduction); tpc_stats->power_limit = __le32_to_cpu(ev->power_limit); tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power); - tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain); - tpc_stats->rate_max = __le32_to_cpu(ev->rate_max); + tpc_stats->num_tx_chain = num_tx_chain; + tpc_stats->rate_max = rate_max; ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats, rate_code, pream_table, -- cgit v1.2.3-59-g8ed1b From 486a8849843455298d49e694cca9968336ce2327 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 9 Oct 2019 16:18:09 +0800 Subject: ath10k: fix memory leak for tpc_stats_final The memory of ar->debug.tpc_stats_final is reallocated every debugfs reading, it should be freed in ath10k_debug_destroy() for the last allocation. Tested HW: QCA9984 Tested FW: 10.4-3.9.0.2-00035 Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 40baf25ac99f..04c50a26a4f4 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -2532,6 +2532,7 @@ void ath10k_debug_destroy(struct ath10k *ar) ath10k_debug_fw_stats_reset(ar); kfree(ar->debug.tpc_stats); + kfree(ar->debug.tpc_stats_final); } int ath10k_debug_register(struct ath10k *ar) -- cgit v1.2.3-59-g8ed1b From f433abfc2f76b7ebf9a7211351bd2ee021daed17 Mon Sep 17 00:00:00 2001 From: Tomislav Požega Date: Thu, 10 Oct 2019 22:53:15 +0200 Subject: ath: rename regulatory rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regulatory rule defines in regd.c are used not only by ath9k but also ath10k driver (haven't test other drivers) and thus should be renamed from ATH9K* to ATH*. Signed-off-by: Tomislav Požega Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/regd.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index e25bfdf78c2e..20f4f8ea9f89 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -33,33 +33,33 @@ static int __ath_regd_init(struct ath_regulatory *reg); */ /* Only these channels all allow active scan on all world regulatory domains */ -#define ATH9K_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) +#define ATH_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) /* We enable active scan on these a case by case basis by regulatory domain */ -#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ +#define ATH_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ NL80211_RRF_NO_IR) -#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ +#define ATH_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ NL80211_RRF_NO_IR | \ NL80211_RRF_NO_OFDM) /* We allow IBSS on these on a case by case basis by regulatory domain */ -#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ +#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ NL80211_RRF_NO_IR) -#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ +#define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ NL80211_RRF_NO_IR) -#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ +#define ATH_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ NL80211_RRF_NO_IR) -#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \ - ATH9K_2GHZ_CH12_13, \ - ATH9K_2GHZ_CH14 +#define ATH_2GHZ_ALL ATH_2GHZ_CH01_11, \ + ATH_2GHZ_CH12_13, \ + ATH_2GHZ_CH14 -#define ATH9K_5GHZ_ALL ATH9K_5GHZ_5150_5350, \ - ATH9K_5GHZ_5470_5850 +#define ATH_5GHZ_ALL ATH_5GHZ_5150_5350, \ + ATH_5GHZ_5470_5850 /* This one skips what we call "mid band" */ -#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ - ATH9K_5GHZ_5725_5850 +#define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \ + ATH_5GHZ_5725_5850 /* Can be used for: * 0x60, 0x61, 0x62 */ @@ -67,8 +67,8 @@ static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { .n_reg_rules = 5, .alpha2 = "99", .reg_rules = { - ATH9K_2GHZ_ALL, - ATH9K_5GHZ_ALL, + ATH_2GHZ_ALL, + ATH_5GHZ_ALL, } }; @@ -77,9 +77,9 @@ static const struct ieee80211_regdomain ath_world_regdom_63_65 = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_NO_MIDBAND, + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_NO_MIDBAND, } }; @@ -88,8 +88,8 @@ static const struct ieee80211_regdomain ath_world_regdom_64 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_NO_MIDBAND, + ATH_2GHZ_CH01_11, + ATH_5GHZ_NO_MIDBAND, } }; @@ -98,8 +98,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_ALL, + ATH_2GHZ_CH01_11, + ATH_5GHZ_ALL, } }; @@ -108,9 +108,9 @@ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_ALL, + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_ALL, } }; -- cgit v1.2.3-59-g8ed1b From d43810b2c1808ac865aa1a2a2c291644bf95345c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 11 Oct 2019 11:28:17 -0700 Subject: ath10k: Correct error handling of dma_map_single() The return value of dma_map_single() should be checked for errors using dma_mapping_error() and the skb has been dequeued so it needs to be freed. This was found when enabling CONFIG_DMA_API_DEBUG and it warned about the missing dma_mapping_error() call. Fixes: 1807da49733e ("ath10k: wmi: add management tx by reference support over wmi") Reported-by: Niklas Cassel Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 3d2c8fcba952..e8bdb2ba9b18 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3904,8 +3904,10 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ar->running_fw->fw_file.fw_features)) { paddr = dma_map_single(ar->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (!paddr) + if (dma_mapping_error(ar->dev, paddr)) { + ieee80211_free_txskb(ar->hw, skb); continue; + } ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr); if (ret) { ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n", -- cgit v1.2.3-59-g8ed1b From 27c65bfc434fb18db001c3ade07dbdb189eda7ec Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Tue, 8 Oct 2019 16:20:54 +0800 Subject: rtw88: config 8822c multicast address in MAC init flow Multicast address should be congiured in the initialization flow. The value is created by a hashed calculation that is also implemented by the hardware for multicast address filtering. Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8822c.c | 3 +++ 2 files changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index bd04c3fad1ee..330574a9f55a 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -310,6 +310,7 @@ #define REG_RX_PKT_LIMIT 0x060C #define REG_RX_DRVINFO_SZ 0x060F #define BIT_APP_PHYSTS BIT(28) +#define REG_MAR 0x0620 #define REG_USTIME_EDCA 0x0638 #define REG_ACKTO_CCK 0x0639 #define REG_RESP_SIFS_CCK 0x063C diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 5075c7045b8f..690934386b85 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1112,6 +1112,7 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) #define WLAN_RTS_RATE_FB_RATE4_H 0x400003E0 #define WLAN_RTS_RATE_FB_RATE5 0x0600F015 #define WLAN_RTS_RATE_FB_RATE5_H 0x000000E0 +#define WLAN_MULTI_ADDR 0xFFFFFFFF #define WLAN_TX_FUNC_CFG1 0x30 #define WLAN_TX_FUNC_CFG2 0x30 @@ -1221,6 +1222,8 @@ static int rtw8822c_mac_init(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_BCN_MAX_ERR, WLAN_BCN_MAX_ERR); /* WMAC configuration */ + rtw_write32(rtwdev, REG_MAR, WLAN_MULTI_ADDR); + rtw_write32(rtwdev, REG_MAR + 4, WLAN_MULTI_ADDR); rtw_write8(rtwdev, REG_BBPSF_CTRL + 2, WLAN_RESP_TXRATE); rtw_write8(rtwdev, REG_ACKTO, WLAN_ACK_TO); rtw_write8(rtwdev, REG_ACKTO_CCK, WLAN_ACK_TO_CCK); -- cgit v1.2.3-59-g8ed1b From 5dc32b8ace3754fab7f1c504e6e5dac6d0f7686d Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Tue, 8 Oct 2019 16:20:57 +0800 Subject: rtw88: add NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 support Add support for NL80211_EXT_FEATURE_CAN_REPLACE_PTK0 feature. According to the "Hardware crypto acceleration" documentation section, when set_key() is called with %DISABLE_KEY command, for outgoing frames, we flush out frames in the queues with the old key; for incoming frames, no frames will be passed to mac80211 decrypted with the old key due to rtw_sec_clear_cam(). Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.h | 5 +++++ drivers/net/wireless/realtek/rtw88/mac80211.c | 1 + drivers/net/wireless/realtek/rtw88/main.c | 2 ++ 3 files changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index a67fa82973e4..592dc830160c 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -33,4 +33,9 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); +static inline void rtw_mac_flush_all_queues(struct rtw_dev *rtwdev, bool drop) +{ + rtw_mac_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, drop); +} + #endif diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index d03b0b7a0e70..8d7a3429ea06 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -533,6 +533,7 @@ static int rtw_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, hw_key_type, hw_key_idx); break; case DISABLE_KEY: + rtw_mac_flush_all_queues(rtwdev, false); rtw_sec_clear_cam(rtwdev, sec, key->hw_key_idx); break; } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index e0cc4c11e513..5343d860189b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1324,6 +1324,8 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); + rtw_set_supported_band(hw, rtwdev->chip); SET_IEEE80211_PERM_ADDR(hw, rtwdev->efuse.addr); -- cgit v1.2.3-59-g8ed1b From a4835410995e0a15b40cd4ab13d19e680f5a2602 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 8 Oct 2019 16:20:58 +0800 Subject: rtw88: Use rtw_write8_set to set SYS_FUNC rtw_write8 could modify the values that we do not want to change, use rtw_write8_set instead to only enable the bits of sys_func_en Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index aa1f15e18c7a..8d72825ed3a7 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -261,7 +261,7 @@ static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) value |= BIT_WL_PLATFORM_RST | BIT_DDMA_EN; rtw_write32(rtwdev, REG_CPU_DMEM_CON, value); - rtw_write8(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); + rtw_write8_set(rtwdev, REG_SYS_FUNC_EN + 1, sys_func_en); value8 = (rtw_read8(rtwdev, REG_CR_EXT + 3) & 0xF0) | 0x0C; rtw_write8(rtwdev, REG_CR_EXT + 3, value8); -- cgit v1.2.3-59-g8ed1b From 474264d5a6b7db4d6c1a1ba1464812addbb7f974 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 8 Oct 2019 16:20:59 +0800 Subject: rtw88: pci: config phy after chip info is setup Chip info such as cut_version is required to configure PCI phy. Move rtw_pci_phy_config after rtw_chip_info_setup. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 772a14d851fc..17b9cdf9cb05 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1190,8 +1190,6 @@ static int rtw_pci_setup_resource(struct rtw_dev *rtwdev, struct pci_dev *pdev) goto err_io_unmap; } - rtw_pci_phy_cfg(rtwdev); - return 0; err_io_unmap: @@ -1304,6 +1302,8 @@ static int rtw_pci_probe(struct pci_dev *pdev, goto err_destroy_pci; } + rtw_pci_phy_cfg(rtwdev); + ret = rtw_register_hw(rtwdev, hw); if (ret) { rtw_err(rtwdev, "failed to register hw\n"); -- cgit v1.2.3-59-g8ed1b From 12078aae453556a88fb46777b7cc5fc97f867b7c Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 8 Oct 2019 16:21:00 +0800 Subject: rtw88: coex: Set 4 slot mode for A2DP With shallow buffer size, certain BT devices have active A2DP flow control to fill buffer frequently. If the slot is not at BT side, data can't be sent successfully to BT devices, and will cause audio glitch. To resolve this issue, this commit splits TUs into 4-slots instead of 2-slot for all of the A2DP related coexistence strategies. That makes BT have higher opportunity to fill the A2DP buffer in time, and the audio quality could be more stable and smooth. Signed-off-by: Ping-Ke Shih Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/coex.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 9d8cbd91e5ff..4dfb2ec395ee 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1302,6 +1302,7 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) struct rtw_chip_info *chip = rtwdev->chip; bool wl_hi_pri = false; u8 table_case, tdma_case; + u32 slot_type = 0; if (coex_stat->wl_linkscan_proc || coex_stat->wl_hi_pri_task1 || coex_stat->wl_hi_pri_task2) @@ -1312,14 +1313,16 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) if (wl_hi_pri) { table_case = 15; if (coex_stat->bt_a2dp_exist && - !coex_stat->bt_pan_exist) + !coex_stat->bt_pan_exist) { + slot_type = TDMA_4SLOT; tdma_case = 11; - else if (coex_stat->wl_hi_pri_task1) + } else if (coex_stat->wl_hi_pri_task1) { tdma_case = 6; - else if (!coex_stat->bt_page) + } else if (!coex_stat->bt_page) { tdma_case = 8; - else + } else { tdma_case = 9; + } } else if (coex_stat->wl_connected) { table_case = 10; tdma_case = 10; @@ -1355,7 +1358,7 @@ static void rtw_coex_action_bt_inquiry(struct rtw_dev *rtwdev) rtw_coex_set_ant_path(rtwdev, false, COEX_SET_ANT_2G); rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); rtw_coex_table(rtwdev, table_case); - rtw_coex_tdma(rtwdev, false, tdma_case); + rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); } static void rtw_coex_action_bt_hfp(struct rtw_dev *rtwdev) @@ -1469,13 +1472,13 @@ static void rtw_coex_action_bt_a2dp(struct rtw_dev *rtwdev) if (efuse->share_ant) { /* Shared-Ant */ + slot_type = TDMA_4SLOT; + if (coex_stat->wl_gl_busy && coex_stat->wl_noisy_level == 0) table_case = 10; else table_case = 9; - slot_type = TDMA_4SLOT; - if (coex_stat->wl_gl_busy) tdma_case = 13; else @@ -1579,13 +1582,14 @@ static void rtw_coex_action_bt_a2dp_hid(struct rtw_dev *rtwdev) if (efuse->share_ant) { /* Shared-Ant */ + slot_type = TDMA_4SLOT; + if (coex_stat->bt_ble_exist) table_case = 26; else table_case = 9; if (coex_stat->wl_gl_busy) { - slot_type = TDMA_4SLOT; tdma_case = 13; } else { tdma_case = 14; @@ -1788,10 +1792,12 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_chip_info *chip = rtwdev->chip; u8 table_case, tdma_case; + u32 slot_type = 0; if (efuse->share_ant) { /* Shared-Ant */ if (coex_stat->bt_a2dp_exist) { + slot_type = TDMA_4SLOT; table_case = 9; tdma_case = 11; } else { @@ -1812,7 +1818,7 @@ static void rtw_coex_action_wl_linkscan(struct rtw_dev *rtwdev) rtw_coex_set_ant_path(rtwdev, true, COEX_SET_ANT_2G); rtw_coex_set_rf_para(rtwdev, chip->wl_rf_para_rx[0]); rtw_coex_table(rtwdev, table_case); - rtw_coex_tdma(rtwdev, false, tdma_case); + rtw_coex_tdma(rtwdev, false, tdma_case | slot_type); } static void rtw_coex_action_wl_not_connected(struct rtw_dev *rtwdev) -- cgit v1.2.3-59-g8ed1b From 4ee2f342669991b733cceec53300407da555924d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 11 Oct 2019 18:27:20 -0700 Subject: rtw88: use a for loop in rtw_power_mode_change(), not goto No change in logic. Signed-off-by: Brian Norris Acked-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 61 ++++++++++++++++----------------- 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index e81de3ddc8c5..820e0a3a141c 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -69,24 +69,26 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter) u8 polling_cnt; u8 retry_cnt = 0; -retry: - request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); - confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); - - /* toggle to request power mode, others remain 0 */ - request ^= request | BIT_RPWM_TOGGLE; - if (!enter) { - request |= POWER_MODE_ACK; - } else { - request |= POWER_MODE_LCLK; - if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) - request |= POWER_MODE_PG; - } + for (retry_cnt = 0; retry_cnt < 3; retry_cnt++) { + request = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); + confirm = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); + + /* toggle to request power mode, others remain 0 */ + request ^= request | BIT_RPWM_TOGGLE; + if (!enter) { + request |= POWER_MODE_ACK; + } else { + request |= POWER_MODE_LCLK; + if (rtw_fw_lps_deep_mode == LPS_DEEP_MODE_PG) + request |= POWER_MODE_PG; + } - rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); + rtw_write8(rtwdev, rtwdev->hci.rpwm_addr, request); + + if (enter) + return; - /* check confirm power mode has left power save state */ - if (!enter) { + /* check confirm power mode has left power save state */ for (polling_cnt = 0; polling_cnt < 3; polling_cnt++) { polling = rtw_read8(rtwdev, rtwdev->hci.cpwm_addr); if ((polling ^ confirm) & BIT_RPWM_TOGGLE) @@ -94,23 +96,18 @@ retry: mdelay(20); } - /* in case of fw/hw missed the request, retry 3 times */ - if (retry_cnt < 3) { - rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", - retry_cnt); - retry_cnt++; - goto retry; - } - - /* Hit here means that driver failed to change hardware - * power mode to active state after retry 3 times. - * If the power state is locked at Deep sleep, most of - * the hardware circuits is not working, even register - * read/write. It should be treated as fatal error and - * requires an entire analysis about the firmware/hardware - */ - WARN(1, "Hardware power state locked\n"); + /* in case of fw/hw missed the request, retry */ + rtw_warn(rtwdev, "failed to leave deep PS, retry=%d\n", + retry_cnt); } + + /* Hit here means that driver failed to change hardware power mode to + * active state after retry 3 times. If the power state is locked at + * Deep sleep, most of the hardware circuits is not working, even + * register read/write. It should be treated as fatal error and + * requires an entire analysis about the firmware/hardware + */ + WARN(1, "Hardware power state locked\n"); } EXPORT_SYMBOL(rtw_power_mode_change); -- cgit v1.2.3-59-g8ed1b From c3226d93f85c27170abac78dbe233c0a0ad12d35 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 11 Oct 2019 18:44:21 -0700 Subject: rtw88: include interrupt.h for tasklet_struct Depending on implicit header includes, we might see this compilation error: .../main.h:1391:24: error: field has incomplete type 'struct tasklet_struct' struct tasklet_struct tx_tasklet; ^ Fixes: 3745d3e550d1 ("rtw88: add driver TX queue support") Signed-off-by: Brian Norris Acked-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index f3eab96dba86..4759d6a0ca6e 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "util.h" -- cgit v1.2.3-59-g8ed1b From 5b3ae43ab18acb8979541ce914b339db3af92364 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 02:18:13 +0300 Subject: net: dsa: sja1105: Get rid of global declaration of struct ptp_clock_info We need priv->ptp_caps to hold a structure and not just a pointer, because we use container_of in the various PTP callbacks. Therefore, the sja1105_ptp_caps structure declared in the global memory of the driver serves no further purpose after copying it into priv->ptp_caps. So just populate priv->ptp_caps with the needed operations and remove sja1105_ptp_caps. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_ptp.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 0df1bbec475a..6b0bfa0444a2 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -344,29 +344,28 @@ static void sja1105_ptp_overflow_check(struct work_struct *work) schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); } -static const struct ptp_clock_info sja1105_ptp_caps = { - .owner = THIS_MODULE, - .name = "SJA1105 PHC", - .adjfine = sja1105_ptp_adjfine, - .adjtime = sja1105_ptp_adjtime, - .gettime64 = sja1105_ptp_gettime, - .settime64 = sja1105_ptp_settime, - .max_adj = SJA1105_MAX_ADJ_PPB, -}; - int sja1105_ptp_clock_register(struct sja1105_private *priv) { struct dsa_switch *ds = priv->ds; /* Set up the cycle counter */ priv->tstamp_cc = (struct cyclecounter) { - .read = sja1105_ptptsclk_read, - .mask = CYCLECOUNTER_MASK(64), - .shift = SJA1105_CC_SHIFT, - .mult = SJA1105_CC_MULT, + .read = sja1105_ptptsclk_read, + .mask = CYCLECOUNTER_MASK(64), + .shift = SJA1105_CC_SHIFT, + .mult = SJA1105_CC_MULT, }; + priv->ptp_caps = (struct ptp_clock_info) { + .owner = THIS_MODULE, + .name = "SJA1105 PHC", + .adjfine = sja1105_ptp_adjfine, + .adjtime = sja1105_ptp_adjtime, + .gettime64 = sja1105_ptp_gettime, + .settime64 = sja1105_ptp_settime, + .max_adj = SJA1105_MAX_ADJ_PPB, + }; + mutex_init(&priv->ptp_lock); - priv->ptp_caps = sja1105_ptp_caps; priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev); if (IS_ERR_OR_NULL(priv->clock)) -- cgit v1.2.3-59-g8ed1b From 61c77126278eb950010d2ed944c3bc09d10e0eb4 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 02:18:14 +0300 Subject: net: dsa: sja1105: Make all public PTP functions take dsa_switch as argument The new rule (as already started for sja1105_tas.h) is for functions of optional driver components (ones which may be disabled via Kconfig - PTP and TAS) to take struct dsa_switch *ds instead of struct sja1105_private *priv as first argument. This is so that forward-declarations of struct sja1105_private can be avoided. So make sja1105_ptp.h the second user of this rule. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 2 +- drivers/net/dsa/sja1105/sja1105_main.c | 11 ++++++----- drivers/net/dsa/sja1105/sja1105_ptp.c | 30 +++++++++++++++++------------- drivers/net/dsa/sja1105/sja1105_ptp.h | 28 ++++++++++++---------------- drivers/net/dsa/sja1105/sja1105_spi.c | 2 +- 5 files changed, 37 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 8681ff9d1a76..c12e24fce575 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -71,7 +71,7 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - int (*ptp_cmd)(const void *ctx, const void *data); + int (*ptp_cmd)(const struct dsa_switch *ds, const void *data); int (*reset_cmd)(const void *ctx, const void *data); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 6ce46d7e971a..586974687ba2 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1686,7 +1686,7 @@ static int sja1105_setup(struct dsa_switch *ds) return rc; } - rc = sja1105_ptp_clock_register(priv); + rc = sja1105_ptp_clock_register(ds); if (rc < 0) { dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc); return rc; @@ -1730,7 +1730,7 @@ static void sja1105_teardown(struct dsa_switch *ds) sja1105_tas_teardown(ds); cancel_work_sync(&priv->tagger_data.rxtstamp_work); skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); - sja1105_ptp_clock_unregister(priv); + sja1105_ptp_clock_unregister(ds); sja1105_static_config_free(&priv->static_config); } @@ -1852,14 +1852,14 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, now = priv->tstamp_cc.read(&priv->tstamp_cc); - rc = sja1105_ptpegr_ts_poll(priv, slot, &ts); + rc = sja1105_ptpegr_ts_poll(ds, slot, &ts); if (rc < 0) { dev_err(ds->dev, "xmit: timed out polling for tstamp\n"); kfree_skb(clone); goto out_unlock_ptp; } - ts = sja1105_tstamp_reconstruct(priv, now, ts); + ts = sja1105_tstamp_reconstruct(ds, now, ts); ts = timecounter_cyc2time(&priv->tstamp_tc, ts); shwt.hwtstamp = ns_to_ktime(ts); @@ -2002,6 +2002,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) { struct sja1105_tagger_data *data = to_tagger(work); struct sja1105_private *priv = to_sja1105(data); + struct dsa_switch *ds = priv->ds; struct sk_buff *skb; u64 now; @@ -2016,7 +2017,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) *shwt = (struct skb_shared_hwtstamps) {0}; ts = SJA1105_SKB_CB(skb)->meta_tstamp; - ts = sja1105_tstamp_reconstruct(priv, now, ts); + ts = sja1105_tstamp_reconstruct(ds, now, ts); ts = timecounter_cyc2time(&priv->tstamp_tc, ts); shwt->hwtstamp = ns_to_ktime(ts); diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 6b0bfa0444a2..d9cae68d544c 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -78,10 +78,10 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, return 0; } -int sja1105et_ptp_cmd(const void *ctx, const void *data) +int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data) { + const struct sja1105_private *priv = ds->priv; const struct sja1105_ptp_cmd *cmd = data; - const struct sja1105_private *priv = ctx; const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; @@ -95,10 +95,10 @@ int sja1105et_ptp_cmd(const void *ctx, const void *data) SJA1105_SIZE_PTP_CMD); } -int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) +int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data) { + const struct sja1105_private *priv = ds->priv; const struct sja1105_ptp_cmd *cmd = data; - const struct sja1105_private *priv = ctx; const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; @@ -126,9 +126,10 @@ int sja1105pqrs_ptp_cmd(const void *ctx, const void *data) * Must be called within one wraparound period of the partial timestamp since * it was generated by the MAC. */ -u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now, +u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, u64 ts_partial) { + struct sja1105_private *priv = ds->priv; u64 partial_tstamp_mask = CYCLECOUNTER_MASK(priv->info->ptp_ts_bits); u64 ts_reconstructed; @@ -170,8 +171,9 @@ u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now, * To have common code for E/T and P/Q/R/S for reading the timestamp, * we need to juggle with the offset and the bit indices. */ -int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) +int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) { + struct sja1105_private *priv = ds->priv; const struct sja1105_regs *regs = priv->info->regs; int tstamp_bit_start, tstamp_bit_end; int timeout = 10; @@ -214,9 +216,9 @@ int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) return 0; } -int sja1105_ptp_reset(struct sja1105_private *priv) +int sja1105_ptp_reset(struct dsa_switch *ds) { - struct dsa_switch *ds = priv->ds; + struct sja1105_private *priv = ds->priv; struct sja1105_ptp_cmd cmd = {0}; int rc; @@ -224,7 +226,7 @@ int sja1105_ptp_reset(struct sja1105_private *priv) cmd.resptp = 1; dev_dbg(ds->dev, "Resetting PTP clock\n"); - rc = priv->info->ptp_cmd(priv, &cmd); + rc = priv->info->ptp_cmd(ds, &cmd); timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, ktime_to_ns(ktime_get_real())); @@ -344,9 +346,9 @@ static void sja1105_ptp_overflow_check(struct work_struct *work) schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); } -int sja1105_ptp_clock_register(struct sja1105_private *priv) +int sja1105_ptp_clock_register(struct dsa_switch *ds) { - struct dsa_switch *ds = priv->ds; + struct sja1105_private *priv = ds->priv; /* Set up the cycle counter */ priv->tstamp_cc = (struct cyclecounter) { @@ -374,11 +376,13 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv) INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check); schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); - return sja1105_ptp_reset(priv); + return sja1105_ptp_reset(ds); } -void sja1105_ptp_clock_unregister(struct sja1105_private *priv) +void sja1105_ptp_clock_unregister(struct dsa_switch *ds) { + struct sja1105_private *priv = ds->priv; + if (IS_ERR_OR_NULL(priv->clock)) return; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index af456b0a4d27..65d3d51da9ad 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -6,49 +6,45 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) -int sja1105_ptp_clock_register(struct sja1105_private *priv); +int sja1105_ptp_clock_register(struct dsa_switch *ds); -void sja1105_ptp_clock_unregister(struct sja1105_private *priv); +void sja1105_ptp_clock_unregister(struct dsa_switch *ds); -int sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts); +int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts); -int sja1105et_ptp_cmd(const void *ctx, const void *data); +int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data); -int sja1105pqrs_ptp_cmd(const void *ctx, const void *data); +int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data); int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); -u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, u64 now, - u64 ts_partial); +u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, u64 ts_partial); -int sja1105_ptp_reset(struct sja1105_private *priv); +int sja1105_ptp_reset(struct dsa_switch *ds); #else -static inline int sja1105_ptp_clock_register(struct sja1105_private *priv) +static inline int sja1105_ptp_clock_register(struct dsa_switch *ds) { return 0; } -static inline void sja1105_ptp_clock_unregister(struct sja1105_private *priv) -{ - return; -} +static inline void sja1105_ptp_clock_unregister(struct dsa_switch *ds) { } static inline int -sja1105_ptpegr_ts_poll(struct sja1105_private *priv, int port, u64 *ts) +sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) { return 0; } -static inline u64 sja1105_tstamp_reconstruct(struct sja1105_private *priv, +static inline u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, u64 ts_partial) { return 0; } -static inline int sja1105_ptp_reset(struct sja1105_private *priv) +static inline int sja1105_ptp_reset(struct dsa_switch *ds) { return 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index b224b1a55695..007688440f6c 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -495,7 +495,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv) dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); } - rc = sja1105_ptp_reset(priv); + rc = sja1105_ptp_reset(priv->ds); if (rc < 0) dev_err(dev, "Failed to reset PTP clock: %d\n", rc); -- cgit v1.2.3-59-g8ed1b From a9d6ed7a8bd0f3091b9fe6d0b9facc9392c1ec21 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 02:18:15 +0300 Subject: net: dsa: sja1105: Move PTP data to its own private structure This is a non-functional change with 2 goals (both for the case when CONFIG_NET_DSA_SJA1105_PTP is not enabled): - Reduce the size of the sja1105_private structure. - Make the PTP code more self-contained. Leaving priv->ptp_data.lock to be initialized in sja1105_main.c is not a leftover: it will be used in a future patch "net: dsa: sja1105: Restore PTP time after switch reset". Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 13 +- drivers/net/dsa/sja1105/sja1105_main.c | 231 +---------------------- drivers/net/dsa/sja1105/sja1105_ptp.c | 332 ++++++++++++++++++++++++++++----- drivers/net/dsa/sja1105/sja1105_ptp.h | 55 ++++-- 4 files changed, 335 insertions(+), 296 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index c12e24fce575..722a0f4d1c88 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -21,6 +21,7 @@ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) #include "sja1105_tas.h" +#include "sja1105_ptp.h" /* Keeps the different addresses between E/T and P/Q/R/S */ struct sja1105_regs { @@ -91,26 +92,16 @@ struct sja1105_private { struct spi_device *spidev; struct dsa_switch *ds; struct sja1105_port ports[SJA1105_NUM_PORTS]; - struct ptp_clock_info ptp_caps; - struct ptp_clock *clock; - /* The cycle counter translates the PTP timestamps (based on - * a free-running counter) into a software time domain. - */ - struct cyclecounter tstamp_cc; - struct timecounter tstamp_tc; - struct delayed_work refresh_work; - /* Serializes all operations on the cycle counter */ - struct mutex ptp_lock; /* Serializes transmission of management frames so that * the switch doesn't confuse them with one another. */ struct mutex mgmt_lock; struct sja1105_tagger_data tagger_data; + struct sja1105_ptp_data ptp_data; struct sja1105_tas_data tas_data; }; #include "sja1105_dynamic_config.h" -#include "sja1105_ptp.h" struct sja1105_spi_message { u64 access; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 586974687ba2..2ffe642cf54b 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -506,39 +506,6 @@ static int sja1105_init_l2_policing(struct sja1105_private *priv) return 0; } -static int sja1105_init_avb_params(struct sja1105_private *priv, - bool on) -{ - struct sja1105_avb_params_entry *avb; - struct sja1105_table *table; - - table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS]; - - /* Discard previous AVB Parameters Table */ - if (table->entry_count) { - kfree(table->entries); - table->entry_count = 0; - } - - /* Configure the reception of meta frames only if requested */ - if (!on) - return 0; - - table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT, - table->ops->unpacked_entry_size, GFP_KERNEL); - if (!table->entries) - return -ENOMEM; - - table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT; - - avb = table->entries; - - avb->destmeta = SJA1105_META_DMAC; - avb->srcmeta = SJA1105_META_SMAC; - - return 0; -} - static int sja1105_static_config_load(struct sja1105_private *priv, struct sja1105_dt_port *ports) { @@ -577,9 +544,6 @@ static int sja1105_static_config_load(struct sja1105_private *priv, if (rc < 0) return rc; rc = sja1105_init_general_params(priv); - if (rc < 0) - return rc; - rc = sja1105_init_avb_params(priv, false); if (rc < 0) return rc; @@ -1728,8 +1692,6 @@ static void sja1105_teardown(struct dsa_switch *ds) struct sja1105_private *priv = ds->priv; sja1105_tas_teardown(ds); - cancel_work_sync(&priv->tagger_data.rxtstamp_work); - skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); sja1105_ptp_clock_unregister(ds); sja1105_static_config_free(&priv->static_config); } @@ -1816,11 +1778,8 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, { struct sja1105_private *priv = ds->priv; struct sja1105_port *sp = &priv->ports[port]; - struct skb_shared_hwtstamps shwt = {0}; int slot = sp->mgmt_slot; struct sk_buff *clone; - u64 now, ts; - int rc; /* The tragic fact about the switch having 4x2 slots for installing * management routes is that all of them except one are actually @@ -1846,27 +1805,8 @@ static netdev_tx_t sja1105_port_deferred_xmit(struct dsa_switch *ds, int port, if (!clone) goto out; - skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS; - - mutex_lock(&priv->ptp_lock); - - now = priv->tstamp_cc.read(&priv->tstamp_cc); - - rc = sja1105_ptpegr_ts_poll(ds, slot, &ts); - if (rc < 0) { - dev_err(ds->dev, "xmit: timed out polling for tstamp\n"); - kfree_skb(clone); - goto out_unlock_ptp; - } - - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&priv->tstamp_tc, ts); - - shwt.hwtstamp = ns_to_ktime(ts); - skb_complete_tx_timestamp(clone, &shwt); + sja1105_ptp_txtstamp_skb(ds, slot, clone); -out_unlock_ptp: - mutex_unlock(&priv->ptp_lock); out: mutex_unlock(&priv->mgmt_lock); return NETDEV_TX_OK; @@ -1896,171 +1836,6 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds, return sja1105_static_config_reload(priv); } -/* Must be called only with priv->tagger_data.state bit - * SJA1105_HWTS_RX_EN cleared - */ -static int sja1105_change_rxtstamping(struct sja1105_private *priv, - bool on) -{ - struct sja1105_general_params_entry *general_params; - struct sja1105_table *table; - int rc; - - table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; - general_params = table->entries; - general_params->send_meta1 = on; - general_params->send_meta0 = on; - - rc = sja1105_init_avb_params(priv, on); - if (rc < 0) - return rc; - - /* Initialize the meta state machine to a known state */ - if (priv->tagger_data.stampable_skb) { - kfree_skb(priv->tagger_data.stampable_skb); - priv->tagger_data.stampable_skb = NULL; - } - - return sja1105_static_config_reload(priv); -} - -static int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, - struct ifreq *ifr) -{ - struct sja1105_private *priv = ds->priv; - struct hwtstamp_config config; - bool rx_on; - int rc; - - if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) - return -EFAULT; - - switch (config.tx_type) { - case HWTSTAMP_TX_OFF: - priv->ports[port].hwts_tx_en = false; - break; - case HWTSTAMP_TX_ON: - priv->ports[port].hwts_tx_en = true; - break; - default: - return -ERANGE; - } - - switch (config.rx_filter) { - case HWTSTAMP_FILTER_NONE: - rx_on = false; - break; - default: - rx_on = true; - break; - } - - if (rx_on != test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state)) { - clear_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state); - - rc = sja1105_change_rxtstamping(priv, rx_on); - if (rc < 0) { - dev_err(ds->dev, - "Failed to change RX timestamping: %d\n", rc); - return rc; - } - if (rx_on) - set_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state); - } - - if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) - return -EFAULT; - return 0; -} - -static int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, - struct ifreq *ifr) -{ - struct sja1105_private *priv = ds->priv; - struct hwtstamp_config config; - - config.flags = 0; - if (priv->ports[port].hwts_tx_en) - config.tx_type = HWTSTAMP_TX_ON; - else - config.tx_type = HWTSTAMP_TX_OFF; - if (test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state)) - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; - else - config.rx_filter = HWTSTAMP_FILTER_NONE; - - return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? - -EFAULT : 0; -} - -#define to_tagger(d) \ - container_of((d), struct sja1105_tagger_data, rxtstamp_work) -#define to_sja1105(d) \ - container_of((d), struct sja1105_private, tagger_data) - -static void sja1105_rxtstamp_work(struct work_struct *work) -{ - struct sja1105_tagger_data *data = to_tagger(work); - struct sja1105_private *priv = to_sja1105(data); - struct dsa_switch *ds = priv->ds; - struct sk_buff *skb; - u64 now; - - mutex_lock(&priv->ptp_lock); - - while ((skb = skb_dequeue(&data->skb_rxtstamp_queue)) != NULL) { - struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); - u64 ts; - - now = priv->tstamp_cc.read(&priv->tstamp_cc); - - *shwt = (struct skb_shared_hwtstamps) {0}; - - ts = SJA1105_SKB_CB(skb)->meta_tstamp; - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&priv->tstamp_tc, ts); - - shwt->hwtstamp = ns_to_ktime(ts); - netif_rx_ni(skb); - } - - mutex_unlock(&priv->ptp_lock); -} - -/* Called from dsa_skb_defer_rx_timestamp */ -static bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, - struct sk_buff *skb, unsigned int type) -{ - struct sja1105_private *priv = ds->priv; - struct sja1105_tagger_data *data = &priv->tagger_data; - - if (!test_bit(SJA1105_HWTS_RX_EN, &data->state)) - return false; - - /* We need to read the full PTP clock to reconstruct the Rx - * timestamp. For that we need a sleepable context. - */ - skb_queue_tail(&data->skb_rxtstamp_queue, skb); - schedule_work(&data->rxtstamp_work); - return true; -} - -/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone - * the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit - * callback, where we will timestamp it synchronously. - */ -static bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, - struct sk_buff *skb, unsigned int type) -{ - struct sja1105_private *priv = ds->priv; - struct sja1105_port *sp = &priv->ports[port]; - - if (!sp->hwts_tx_en) - return false; - - return true; -} - static int sja1105_port_setup_tc(struct dsa_switch *ds, int port, enum tc_setup_type type, void *type_data) @@ -2281,9 +2056,6 @@ static int sja1105_probe(struct spi_device *spi) priv->ds = ds; tagger_data = &priv->tagger_data; - skb_queue_head_init(&tagger_data->skb_rxtstamp_queue); - INIT_WORK(&tagger_data->rxtstamp_work, sja1105_rxtstamp_work); - spin_lock_init(&tagger_data->meta_lock); /* Connections between dsa_port and sja1105_port */ for (i = 0; i < SJA1105_NUM_PORTS; i++) { @@ -2293,6 +2065,7 @@ static int sja1105_probe(struct spi_device *spi) sp->dp = &ds->ports[i]; sp->data = tagger_data; } + mutex_init(&priv->ptp_data.lock); mutex_init(&priv->mgmt_lock); sja1105_tas_setup(ds); diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index d9cae68d544c..625411f59627 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -50,21 +50,155 @@ #define SJA1105_CC_MULT_NUM (1 << 9) #define SJA1105_CC_MULT_DEM 15625 -#define ptp_to_sja1105(d) container_of((d), struct sja1105_private, ptp_caps) -#define cc_to_sja1105(d) container_of((d), struct sja1105_private, tstamp_cc) -#define dw_to_sja1105(d) container_of((d), struct sja1105_private, refresh_work) +#define ptp_caps_to_data(d) \ + container_of((d), struct sja1105_ptp_data, caps) +#define cc_to_ptp_data(d) \ + container_of((d), struct sja1105_ptp_data, tstamp_cc) +#define dw_to_ptp_data(d) \ + container_of((d), struct sja1105_ptp_data, refresh_work) +#define ptp_data_to_sja1105(d) \ + container_of((d), struct sja1105_private, ptp_data) struct sja1105_ptp_cmd { u64 resptp; /* reset */ }; +static int sja1105_init_avb_params(struct sja1105_private *priv, + bool on) +{ + struct sja1105_avb_params_entry *avb; + struct sja1105_table *table; + + table = &priv->static_config.tables[BLK_IDX_AVB_PARAMS]; + + /* Discard previous AVB Parameters Table */ + if (table->entry_count) { + kfree(table->entries); + table->entry_count = 0; + } + + /* Configure the reception of meta frames only if requested */ + if (!on) + return 0; + + table->entries = kcalloc(SJA1105_MAX_AVB_PARAMS_COUNT, + table->ops->unpacked_entry_size, GFP_KERNEL); + if (!table->entries) + return -ENOMEM; + + table->entry_count = SJA1105_MAX_AVB_PARAMS_COUNT; + + avb = table->entries; + + avb->destmeta = SJA1105_META_DMAC; + avb->srcmeta = SJA1105_META_SMAC; + + return 0; +} + +/* Must be called only with priv->tagger_data.state bit + * SJA1105_HWTS_RX_EN cleared + */ +static int sja1105_change_rxtstamping(struct sja1105_private *priv, + bool on) +{ + struct sja1105_general_params_entry *general_params; + struct sja1105_table *table; + int rc; + + table = &priv->static_config.tables[BLK_IDX_GENERAL_PARAMS]; + general_params = table->entries; + general_params->send_meta1 = on; + general_params->send_meta0 = on; + + rc = sja1105_init_avb_params(priv, on); + if (rc < 0) + return rc; + + /* Initialize the meta state machine to a known state */ + if (priv->tagger_data.stampable_skb) { + kfree_skb(priv->tagger_data.stampable_skb); + priv->tagger_data.stampable_skb = NULL; + } + + return sja1105_static_config_reload(priv); +} + +int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct sja1105_private *priv = ds->priv; + struct hwtstamp_config config; + bool rx_on; + int rc; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv->ports[port].hwts_tx_en = false; + break; + case HWTSTAMP_TX_ON: + priv->ports[port].hwts_tx_en = true; + break; + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + rx_on = false; + break; + default: + rx_on = true; + break; + } + + if (rx_on != test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state)) { + clear_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state); + + rc = sja1105_change_rxtstamping(priv, rx_on); + if (rc < 0) { + dev_err(ds->dev, + "Failed to change RX timestamping: %d\n", rc); + return rc; + } + if (rx_on) + set_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state); + } + + if (copy_to_user(ifr->ifr_data, &config, sizeof(config))) + return -EFAULT; + return 0; +} + +int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr) +{ + struct sja1105_private *priv = ds->priv; + struct hwtstamp_config config; + + config.flags = 0; + if (priv->ports[port].hwts_tx_en) + config.tx_type = HWTSTAMP_TX_ON; + else + config.tx_type = HWTSTAMP_TX_OFF; + if (test_bit(SJA1105_HWTS_RX_EN, &priv->tagger_data.state)) + config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT; + else + config.rx_filter = HWTSTAMP_FILTER_NONE; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *info) { struct sja1105_private *priv = ds->priv; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; /* Called during cleanup */ - if (!priv->clock) + if (!ptp_data->clock) return -ENODEV; info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | @@ -74,7 +208,7 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, (1 << HWTSTAMP_TX_ON); info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT); - info->phc_index = ptp_clock_index(priv->clock); + info->phc_index = ptp_clock_index(ptp_data->clock); return 0; } @@ -126,8 +260,8 @@ int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data) * Must be called within one wraparound period of the partial timestamp since * it was generated by the MAC. */ -u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, - u64 ts_partial) +static u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, + u64 ts_partial) { struct sja1105_private *priv = ds->priv; u64 partial_tstamp_mask = CYCLECOUNTER_MASK(priv->info->ptp_ts_bits); @@ -171,7 +305,7 @@ u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, * To have common code for E/T and P/Q/R/S for reading the timestamp, * we need to juggle with the offset and the bit indices. */ -int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) +static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) { struct sja1105_private *priv = ds->priv; const struct sja1105_regs *regs = priv->info->regs; @@ -216,22 +350,91 @@ int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) return 0; } +#define rxtstamp_to_tagger(d) \ + container_of((d), struct sja1105_tagger_data, rxtstamp_work) +#define tagger_to_sja1105(d) \ + container_of((d), struct sja1105_private, tagger_data) + +static void sja1105_rxtstamp_work(struct work_struct *work) +{ + struct sja1105_tagger_data *tagger_data = rxtstamp_to_tagger(work); + struct sja1105_private *priv = tagger_to_sja1105(tagger_data); + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + struct dsa_switch *ds = priv->ds; + struct sk_buff *skb; + + mutex_lock(&ptp_data->lock); + + while ((skb = skb_dequeue(&tagger_data->skb_rxtstamp_queue)) != NULL) { + struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); + u64 now, ts; + + now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + + *shwt = (struct skb_shared_hwtstamps) {0}; + + ts = SJA1105_SKB_CB(skb)->meta_tstamp; + ts = sja1105_tstamp_reconstruct(ds, now, ts); + ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + + shwt->hwtstamp = ns_to_ktime(ts); + netif_rx_ni(skb); + } + + mutex_unlock(&ptp_data->lock); +} + +/* Called from dsa_skb_defer_rx_timestamp */ +bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb, unsigned int type) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_tagger_data *tagger_data = &priv->tagger_data; + + if (!test_bit(SJA1105_HWTS_RX_EN, &tagger_data->state)) + return false; + + /* We need to read the full PTP clock to reconstruct the Rx + * timestamp. For that we need a sleepable context. + */ + skb_queue_tail(&tagger_data->skb_rxtstamp_queue, skb); + schedule_work(&tagger_data->rxtstamp_work); + return true; +} + +/* Called from dsa_skb_tx_timestamp. This callback is just to make DSA clone + * the skb and have it available in DSA_SKB_CB in the .port_deferred_xmit + * callback, where we will timestamp it synchronously. + */ +bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb, unsigned int type) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_port *sp = &priv->ports[port]; + + if (!sp->hwts_tx_en) + return false; + + return true; +} + int sja1105_ptp_reset(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; struct sja1105_ptp_cmd cmd = {0}; int rc; - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); cmd.resptp = 1; dev_dbg(ds->dev, "Resetting PTP clock\n"); rc = priv->info->ptp_cmd(ds, &cmd); - timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, + timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, ktime_to_ns(ktime_get_real())); - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return rc; } @@ -239,12 +442,12 @@ int sja1105_ptp_reset(struct dsa_switch *ds) static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); u64 ns; - mutex_lock(&priv->ptp_lock); - ns = timecounter_read(&priv->tstamp_tc); - mutex_unlock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); + ns = timecounter_read(&ptp_data->tstamp_tc); + mutex_unlock(&ptp_data->lock); *ts = ns_to_timespec64(ns); @@ -254,25 +457,25 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); u64 ns = timespec64_to_ns(ts); - mutex_lock(&priv->ptp_lock); - timecounter_init(&priv->tstamp_tc, &priv->tstamp_cc, ns); - mutex_unlock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); + timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, ns); + mutex_unlock(&ptp_data->lock); return 0; } static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); s64 clkrate; clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM; clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM); - mutex_lock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); /* Force a readout to update the timer *before* changing its frequency. * @@ -300,29 +503,30 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) * instead of a compound function made of two segments (one at the old * and the other at the new rate) - introducing some inaccuracy. */ - timecounter_read(&priv->tstamp_tc); + timecounter_read(&ptp_data->tstamp_tc); - priv->tstamp_cc.mult = SJA1105_CC_MULT + clkrate; + ptp_data->tstamp_cc.mult = SJA1105_CC_MULT + clkrate; - mutex_unlock(&priv->ptp_lock); + mutex_unlock(&ptp_data->lock); return 0; } static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); + struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - mutex_lock(&priv->ptp_lock); - timecounter_adjtime(&priv->tstamp_tc, delta); - mutex_unlock(&priv->ptp_lock); + mutex_lock(&ptp_data->lock); + timecounter_adjtime(&ptp_data->tstamp_tc, delta); + mutex_unlock(&ptp_data->lock); return 0; } static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) { - struct sja1105_private *priv = cc_to_sja1105(cc); + struct sja1105_ptp_data *ptp_data = cc_to_ptp_data(cc); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); const struct sja1105_regs *regs = priv->info->regs; u64 ptptsclk = 0; int rc; @@ -338,26 +542,29 @@ static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) static void sja1105_ptp_overflow_check(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); - struct sja1105_private *priv = dw_to_sja1105(dw); + struct sja1105_ptp_data *ptp_data = dw_to_ptp_data(dw); struct timespec64 ts; - sja1105_ptp_gettime(&priv->ptp_caps, &ts); + sja1105_ptp_gettime(&ptp_data->caps, &ts); - schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); + schedule_delayed_work(&ptp_data->refresh_work, + SJA1105_REFRESH_INTERVAL); } int sja1105_ptp_clock_register(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; + struct sja1105_tagger_data *tagger_data = &priv->tagger_data; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; /* Set up the cycle counter */ - priv->tstamp_cc = (struct cyclecounter) { + ptp_data->tstamp_cc = (struct cyclecounter) { .read = sja1105_ptptsclk_read, .mask = CYCLECOUNTER_MASK(64), .shift = SJA1105_CC_SHIFT, .mult = SJA1105_CC_MULT, }; - priv->ptp_caps = (struct ptp_clock_info) { + ptp_data->caps = (struct ptp_clock_info) { .owner = THIS_MODULE, .name = "SJA1105 PHC", .adjfine = sja1105_ptp_adjfine, @@ -367,14 +574,16 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) .max_adj = SJA1105_MAX_ADJ_PPB, }; - mutex_init(&priv->ptp_lock); + skb_queue_head_init(&tagger_data->skb_rxtstamp_queue); + INIT_WORK(&tagger_data->rxtstamp_work, sja1105_rxtstamp_work); + spin_lock_init(&tagger_data->meta_lock); - priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev); - if (IS_ERR_OR_NULL(priv->clock)) - return PTR_ERR(priv->clock); + ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev); + if (IS_ERR_OR_NULL(ptp_data->clock)) + return PTR_ERR(ptp_data->clock); - INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check); - schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL); + INIT_DELAYED_WORK(&ptp_data->refresh_work, sja1105_ptp_overflow_check); + schedule_delayed_work(&ptp_data->refresh_work, SJA1105_REFRESH_INTERVAL); return sja1105_ptp_reset(ds); } @@ -382,11 +591,46 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) void sja1105_ptp_clock_unregister(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; - if (IS_ERR_OR_NULL(priv->clock)) + if (IS_ERR_OR_NULL(ptp_data->clock)) return; - cancel_delayed_work_sync(&priv->refresh_work); - ptp_clock_unregister(priv->clock); - priv->clock = NULL; + cancel_work_sync(&priv->tagger_data.rxtstamp_work); + skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); + cancel_delayed_work_sync(&ptp_data->refresh_work); + ptp_clock_unregister(ptp_data->clock); + ptp_data->clock = NULL; +} + +void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, + struct sk_buff *skb) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + struct skb_shared_hwtstamps shwt = {0}; + u64 now, ts; + int rc; + + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + mutex_lock(&ptp_data->lock); + + now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + + rc = sja1105_ptpegr_ts_poll(ds, slot, &ts); + if (rc < 0) { + dev_err(ds->dev, "timed out polling for tstamp\n"); + kfree_skb(skb); + goto out; + } + + ts = sja1105_tstamp_reconstruct(ds, now, ts); + ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + + shwt.hwtstamp = ns_to_ktime(ts); + skb_complete_tx_timestamp(skb, &shwt); + +out: + mutex_unlock(&ptp_data->lock); } diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 65d3d51da9ad..0b6b0e262a02 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -6,12 +6,23 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) +struct sja1105_ptp_data { + struct ptp_clock_info caps; + struct ptp_clock *clock; + /* The cycle counter translates the PTP timestamps (based on + * a free-running counter) into a software time domain. + */ + struct cyclecounter tstamp_cc; + struct timecounter tstamp_tc; + struct delayed_work refresh_work; + /* Serializes all operations on the cycle counter */ + struct mutex lock; +}; + int sja1105_ptp_clock_register(struct dsa_switch *ds); void sja1105_ptp_clock_unregister(struct dsa_switch *ds); -int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts); - int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data); int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data); @@ -19,12 +30,31 @@ int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data); int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); -u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now, u64 ts_partial); +void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, + struct sk_buff *clone); int sja1105_ptp_reset(struct dsa_switch *ds); +bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb, unsigned int type); + +bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb, unsigned int type); + +int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); + +int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); + #else +/* Structures cannot be empty in C. Bah! + * Keep the mutex as the only element, which is a bit more difficult to + * refactor out of sja1105_main.c anyway. + */ +struct sja1105_ptp_data { + struct mutex lock; +}; + static inline int sja1105_ptp_clock_register(struct dsa_switch *ds) { return 0; @@ -32,16 +62,9 @@ static inline int sja1105_ptp_clock_register(struct dsa_switch *ds) static inline void sja1105_ptp_clock_unregister(struct dsa_switch *ds) { } -static inline int -sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) +static inline void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, + struct sk_buff *clone) { - return 0; -} - -static inline u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, - u64 now, u64 ts_partial) -{ - return 0; } static inline int sja1105_ptp_reset(struct dsa_switch *ds) @@ -55,6 +78,14 @@ static inline int sja1105_ptp_reset(struct dsa_switch *ds) #define sja1105_get_ts_info NULL +#define sja1105_port_rxtstamp NULL + +#define sja1105_port_txtstamp NULL + +#define sja1105_hwtstamp_get NULL + +#define sja1105_hwtstamp_set NULL + #endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) */ #endif /* _SJA1105_PTP_H */ -- cgit v1.2.3-59-g8ed1b From 664277781c4cb312971c5a2e2df3290bd990ac14 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 02:18:16 +0300 Subject: net: dsa: sja1105: Change the PTP command access pattern The PTP command register contains enable bits for: - Putting the 64-bit PTPCLKVAL register in add/subtract or write mode - Taking timestamps off of the corrected vs free-running clock - Starting/stopping the TTEthernet scheduling - Starting/stopping PPS output - Resetting the switch When a command needs to be issued (e.g. "change the PTPCLKVAL from write mode to add/subtract mode"), one cannot simply write to the command register setting the PTPCLKADD bit to 1, because that would zeroize the other settings. One also cannot do a read-modify-write (that would be too easy for this hardware) because not all bits of the command register are readable over SPI. So this leaves us with the only option of keeping the value of the PTP command register in the driver, and operating on that. Actually there are 2 types of PTP operations now: - Operations that modify the cached PTP command. These operate on ptp_data->cmd as a pointer. - Operations that apply all previously cached PTP settings, but don't otherwise cache what they did themselves. The sja1105_ptp_reset function is such an example. It copies the ptp_data->cmd on stack before modifying and writing it to SPI. This practically means that struct sja1105_ptp_cmd is no longer an implementation detail, since it needs to be stored in full into struct sja1105_ptp_data, and hence in struct sja1105_private. So the (*ptp_cmd) function prototype can change and take struct sja1105_ptp_cmd as second argument now. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 3 ++- drivers/net/dsa/sja1105/sja1105_ptp.c | 14 +++++--------- drivers/net/dsa/sja1105/sja1105_ptp.h | 13 +++++++++++-- 3 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 722a0f4d1c88..657c492d39a0 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -72,7 +72,8 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - int (*ptp_cmd)(const struct dsa_switch *ds, const void *data); + int (*ptp_cmd)(const struct dsa_switch *ds, + const struct sja1105_ptp_cmd *cmd); int (*reset_cmd)(const void *ctx, const void *data); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 625411f59627..b43096063cf4 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -59,10 +59,6 @@ #define ptp_data_to_sja1105(d) \ container_of((d), struct sja1105_private, ptp_data) -struct sja1105_ptp_cmd { - u64 resptp; /* reset */ -}; - static int sja1105_init_avb_params(struct sja1105_private *priv, bool on) { @@ -212,10 +208,10 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, return 0; } -int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data) +int sja1105et_ptp_cmd(const struct dsa_switch *ds, + const struct sja1105_ptp_cmd *cmd) { const struct sja1105_private *priv = ds->priv; - const struct sja1105_ptp_cmd *cmd = data; const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; @@ -229,10 +225,10 @@ int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data) SJA1105_SIZE_PTP_CMD); } -int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data) +int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, + const struct sja1105_ptp_cmd *cmd) { const struct sja1105_private *priv = ds->priv; - const struct sja1105_ptp_cmd *cmd = data; const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; @@ -422,7 +418,7 @@ int sja1105_ptp_reset(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; - struct sja1105_ptp_cmd cmd = {0}; + struct sja1105_ptp_cmd cmd = ptp_data->cmd; int rc; mutex_lock(&ptp_data->lock); diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 0b6b0e262a02..507107ffd6a3 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -6,9 +6,14 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) +struct sja1105_ptp_cmd { + u64 resptp; /* reset */ +}; + struct sja1105_ptp_data { struct ptp_clock_info caps; struct ptp_clock *clock; + struct sja1105_ptp_cmd cmd; /* The cycle counter translates the PTP timestamps (based on * a free-running counter) into a software time domain. */ @@ -23,9 +28,11 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds); void sja1105_ptp_clock_unregister(struct dsa_switch *ds); -int sja1105et_ptp_cmd(const struct dsa_switch *ds, const void *data); +int sja1105et_ptp_cmd(const struct dsa_switch *ds, + const struct sja1105_ptp_cmd *cmd); -int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, const void *data); +int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, + const struct sja1105_ptp_cmd *cmd); int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); @@ -47,6 +54,8 @@ int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); #else +struct sja1105_ptp_cmd; + /* Structures cannot be empty in C. Bah! * Keep the mutex as the only element, which is a bit more difficult to * refactor out of sja1105_main.c anyway. -- cgit v1.2.3-59-g8ed1b From 52d4261862ec140cda09ec9cf4d6dc388fd83f59 Mon Sep 17 00:00:00 2001 From: Fuqian Huang Date: Mon, 15 Jul 2019 11:19:41 +0800 Subject: wireless: Remove call to memset after dma_alloc_coherent In commit 518a2f1925c3 ("dma-mapping: zero memory returned from dma_alloc_*"), dma_alloc_coherent has already zeroed the memory. So memset is not needed. Signed-off-by: Fuqian Huang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 5 ----- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 -- drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c | 2 -- drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c | 2 -- 4 files changed, 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index eca87f7c5b6c..294fbc1e89ab 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1704,9 +1704,6 @@ ath10k_ce_alloc_dest_ring_64(struct ath10k *ar, unsigned int ce_id, /* Correctly initialize memory to 0 to prevent garbage * data crashing system when download firmware */ - memset(dest_ring->base_addr_owner_space_unaligned, 0, - nentries * sizeof(struct ce_desc_64) + CE_DESC_RING_ALIGN); - dest_ring->base_addr_owner_space = PTR_ALIGN(dest_ring->base_addr_owner_space_unaligned, CE_DESC_RING_ALIGN); @@ -2019,8 +2016,6 @@ void ath10k_ce_alloc_rri(struct ath10k *ar) value |= ar->hw_ce_regs->upd->mask; ath10k_ce_write32(ar, ce_base_addr + ctrl1_regs, value); } - - memset(ce->vaddr_rri, 0, CE_COUNT * sizeof(u32)); } EXPORT_SYMBOL(ath10k_ce_alloc_rri); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 6c463475e90b..3184dab41a5e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1024,8 +1024,6 @@ brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo, address & 0xffffffff); brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32); - memset(ring, 0, size); - return (ring); } diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 3aa3714d4dfd..5ec1c9bc1612 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -244,8 +244,6 @@ static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps) /* tx bd */ - memset(vaddr, 0, len); - ps->bd_table_vaddr = vaddr; ps->bd_table_paddr = paddr; ps->bd_table_len = len; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index 9a4380ed7f1b..1f91088e3dff 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -199,8 +199,6 @@ static int topaz_alloc_bd_table(struct qtnf_pcie_topaz_state *ts, if (!vaddr) return -ENOMEM; - memset(vaddr, 0, len); - /* tx bd */ ts->tx_bd_vbase = vaddr; -- cgit v1.2.3-59-g8ed1b From 868ad21496020ef83d41fdeed3b0a63de2a3caa5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 22 Aug 2019 10:20:10 +0200 Subject: net/wireless: Delete unnecessary checks before the macro call “dev_kfree_skb” MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dev_kfree_skb() function performs also input parameter validation. Thus the test around the shown calls is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 +--- drivers/net/wireless/intel/iwlegacy/3945-mac.c | 8 ++------ drivers/net/wireless/intel/iwlegacy/common.c | 8 ++------ drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c | 5 +---- drivers/net/wireless/st/cw1200/scan.c | 3 +-- 5 files changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index f0ab11556dc2..74ad60a71a1f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -9481,7 +9481,5 @@ void ath10k_wmi_detach(struct ath10k *ar) } cancel_work_sync(&ar->svc_rdy_work); - - if (ar->svc_rdy_skb) - dev_kfree_skb(ar->svc_rdy_skb); + dev_kfree_skb(ar->svc_rdy_skb); } diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 4fbcc7fba3cc..1168055da182 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -2301,9 +2301,7 @@ __il3945_down(struct il_priv *il) il3945_hw_txq_ctx_free(il); exit: memset(&il->card_alive, 0, sizeof(struct il_alive_resp)); - - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); + dev_kfree_skb(il->beacon_skb); il->beacon_skb = NULL; /* clear out any free frames */ @@ -3846,9 +3844,7 @@ il3945_pci_remove(struct pci_dev *pdev) il_free_channel_map(il); il_free_geos(il); kfree(il->scan_cmd); - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); - + dev_kfree_skb(il->beacon_skb); ieee80211_free_hw(il->hw); } diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index e4ea734e58d8..d966b29b45ee 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -5182,8 +5182,7 @@ il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) memset(&il->current_ht_config, 0, sizeof(struct il_ht_config)); /* new association get rid of ibss beacon skb */ - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); + dev_kfree_skb(il->beacon_skb); il->beacon_skb = NULL; il->timestamp = 0; @@ -5302,10 +5301,7 @@ il_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } spin_lock_irqsave(&il->lock, flags); - - if (il->beacon_skb) - dev_kfree_skb(il->beacon_skb); - + dev_kfree_skb(il->beacon_skb); il->beacon_skb = skb; timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index 92305bd31aa1..4209209ac940 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -77,10 +77,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { if (vif_idx == i) { force_update = !!dev->beacons[i] ^ !!skb; - - if (dev->beacons[i]) - dev_kfree_skb(dev->beacons[i]); - + dev_kfree_skb(dev->beacons[i]); dev->beacons[i] = skb; __mt76x02_mac_set_beacon(dev, bcn_idx, skb); } else if (force_update && dev->beacons[i]) { diff --git a/drivers/net/wireless/st/cw1200/scan.c b/drivers/net/wireless/st/cw1200/scan.c index c46b044b7f7b..988581cc134b 100644 --- a/drivers/net/wireless/st/cw1200/scan.c +++ b/drivers/net/wireless/st/cw1200/scan.c @@ -120,8 +120,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw, ++priv->scan.n_ssids; } - if (frame.skb) - dev_kfree_skb(frame.skb); + dev_kfree_skb(frame.skb); mutex_unlock(&priv->conf_mutex); queue_work(priv->workqueue, &priv->scan.work); return 0; -- cgit v1.2.3-59-g8ed1b From f58a887ebc990b4d01a5a53330be06c384e089c4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 11 Oct 2019 18:22:32 +0100 Subject: net: b44: remove redundant assignment to variable reg The variable reg is being assigned a value that is never read and is being re-assigned in the following for-loop. The assignment is redundant and hence can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/b44.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 97ab0dd25552..035dbb1b2c98 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -511,9 +511,6 @@ static void b44_stats_update(struct b44 *bp) *val++ += br32(bp, reg); } - /* Pad */ - reg += 8*4UL; - for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) { *val++ += br32(bp, reg); } -- cgit v1.2.3-59-g8ed1b From 8a559400da42abd9e1a5f6232b0f57d6dd374f64 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 01:31:14 +0300 Subject: net: dsa: sja1105: Move sja1105_spi_transfer into sja1105_xfer This is a cosmetic patch that reduces some boilerplate in the SPI interaction of the driver. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_spi.c | 48 +++++++++++------------------------ 1 file changed, 15 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 007688440f6c..a7532fb3c162 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -13,36 +13,6 @@ #define SJA1105_SIZE_SPI_TRANSFER_MAX \ (SJA1105_SIZE_SPI_MSG_HEADER + SJA1105_SIZE_SPI_MSG_MAXLEN) -static int sja1105_spi_transfer(const struct sja1105_private *priv, - const void *tx, void *rx, int size) -{ - struct spi_device *spi = priv->spidev; - struct spi_transfer transfer = { - .tx_buf = tx, - .rx_buf = rx, - .len = size, - }; - struct spi_message msg; - int rc; - - if (size > SJA1105_SIZE_SPI_TRANSFER_MAX) { - dev_err(&spi->dev, "SPI message (%d) longer than max of %d\n", - size, SJA1105_SIZE_SPI_TRANSFER_MAX); - return -EMSGSIZE; - } - - spi_message_init(&msg); - spi_message_add_tail(&transfer, &msg); - - rc = spi_sync(spi, &msg); - if (rc < 0) { - dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); - return rc; - } - - return rc; -} - static void sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) { @@ -69,10 +39,17 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, void *packed_buf, size_t size_bytes) { + const int msg_len = size_bytes + SJA1105_SIZE_SPI_MSG_HEADER; u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; - const int msg_len = size_bytes + SJA1105_SIZE_SPI_MSG_HEADER; + struct spi_device *spi = priv->spidev; struct sja1105_spi_message msg = {0}; + struct spi_transfer xfer = { + .tx_buf = tx_buf, + .rx_buf = rx_buf, + .len = msg_len, + }; + struct spi_message m; int rc; if (msg_len > SJA1105_SIZE_SPI_TRANSFER_MAX) @@ -89,9 +66,14 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, memcpy(tx_buf + SJA1105_SIZE_SPI_MSG_HEADER, packed_buf, size_bytes); - rc = sja1105_spi_transfer(priv, tx_buf, rx_buf, msg_len); - if (rc < 0) + spi_message_init(&m); + spi_message_add_tail(&xfer, &m); + + rc = spi_sync(spi, &m); + if (rc < 0) { + dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); return rc; + } if (rw == SPI_READ) memcpy(packed_buf, rx_buf + SJA1105_SIZE_SPI_MSG_HEADER, -- cgit v1.2.3-59-g8ed1b From 08839c06e96f1a88e7c30011708727430fd78c3d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 12 Oct 2019 01:31:15 +0300 Subject: net: dsa: sja1105: Switch to scatter/gather API for SPI This reworks the SPI transfer implementation to make use of more of the SPI core features. The main benefit is to avoid the memcpy in sja1105_xfer_buf(). The memcpy was only needed because the function was transferring a single buffer at a time. So it needed to copy the caller-provided buffer at buf + 4, to store the SPI message header in the "headroom" area. But the SPI core supports scatter-gather messages, comprised of multiple transfers. We can actually use those to break apart every SPI message into 2 transfers: one for the header and one for the actual payload. To keep the behavior the same regarding the chip select signal, it is necessary to tell the SPI core to de-assert the chip select after each chunk. This was not needed before, because each spi_message contained only 1 single transfer. The meaning of the per-transfer cs_change=1 is: - If the transfer is the last one of the message, keep CS asserted - Otherwise, deassert CS We need to deassert CS in the "otherwise" case, which was implicit before. Avoiding the memcpy creates yet another opportunity. The device can't process more than 256 bytes of SPI payload at a time, so the sja1105_xfer_long_buf() function used to exist, to split the larger caller buffer into chunks. But these chunks couldn't be used as scatter/gather buffers for spi_message until now, because of that memcpy (we would have needed more memory for each chunk). So we can now remove the sja1105_xfer_long_buf() function and have a single implementation for long and short buffers. Another benefit is lower usage of stack memory. Previously we had to store 2 SPI buffers for each chunk. Due to the elimination of the memcpy, we can now send pointers to the actual chunks from the caller-supplied buffer to the SPI core. Since the patch merges two functions into a rewritten implementation, the function prototype was also changed, mainly for cosmetic consistency with the structures used within it. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 2 +- drivers/net/dsa/sja1105/sja1105_spi.c | 164 +++++++++++++++++----------------- 2 files changed, 85 insertions(+), 81 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 657c492d39a0..0ef97a916707 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -121,7 +121,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv); /* From sja1105_spi.c */ int sja1105_xfer_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, - void *packed_buf, size_t size_bytes); + u8 *buf, size_t len); int sja1105_xfer_u32(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value); int sja1105_xfer_u64(const struct sja1105_private *priv, diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index a7532fb3c162..e25724d99594 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -10,8 +10,12 @@ #define SJA1105_SIZE_RESET_CMD 4 #define SJA1105_SIZE_SPI_MSG_HEADER 4 #define SJA1105_SIZE_SPI_MSG_MAXLEN (64 * 4) -#define SJA1105_SIZE_SPI_TRANSFER_MAX \ - (SJA1105_SIZE_SPI_MSG_HEADER + SJA1105_SIZE_SPI_MSG_MAXLEN) + +struct sja1105_chunk { + u8 *buf; + size_t len; + u64 reg_addr; +}; static void sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) @@ -25,61 +29,98 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) sja1105_pack(buf, &msg->address, 24, 4, size); } +#define sja1105_hdr_xfer(xfers, chunk) \ + ((xfers) + 2 * (chunk)) +#define sja1105_chunk_xfer(xfers, chunk) \ + ((xfers) + 2 * (chunk) + 1) +#define sja1105_hdr_buf(hdr_bufs, chunk) \ + ((hdr_bufs) + (chunk) * SJA1105_SIZE_SPI_MSG_HEADER) + /* If @rw is: * - SPI_WRITE: creates and sends an SPI write message at absolute - * address reg_addr, taking size_bytes from *packed_buf + * address reg_addr, taking @len bytes from *buf * - SPI_READ: creates and sends an SPI read message from absolute - * address reg_addr, writing size_bytes into *packed_buf - * - * This function should only be called if it is priorly known that - * @size_bytes is smaller than SIZE_SPI_MSG_MAXLEN. Larger packed buffers - * are chunked in smaller pieces by sja1105_xfer_long_buf below. + * address reg_addr, writing @len bytes into *buf */ int sja1105_xfer_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, - void *packed_buf, size_t size_bytes) + u8 *buf, size_t len) { - const int msg_len = size_bytes + SJA1105_SIZE_SPI_MSG_HEADER; - u8 tx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; - u8 rx_buf[SJA1105_SIZE_SPI_TRANSFER_MAX] = {0}; - struct spi_device *spi = priv->spidev; - struct sja1105_spi_message msg = {0}; - struct spi_transfer xfer = { - .tx_buf = tx_buf, - .rx_buf = rx_buf, - .len = msg_len, + struct sja1105_chunk chunk = { + .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN), + .reg_addr = reg_addr, + .buf = buf, }; - struct spi_message m; - int rc; - - if (msg_len > SJA1105_SIZE_SPI_TRANSFER_MAX) - return -ERANGE; + struct spi_device *spi = priv->spidev; + struct spi_transfer *xfers; + int num_chunks; + int rc, i = 0; + u8 *hdr_bufs; - msg.access = rw; - msg.address = reg_addr; - if (rw == SPI_READ) - msg.read_count = size_bytes / 4; + num_chunks = DIV_ROUND_UP(len, SJA1105_SIZE_SPI_MSG_MAXLEN); - sja1105_spi_message_pack(tx_buf, &msg); + /* One transfer for each message header, one for each message + * payload (chunk). + */ + xfers = kcalloc(2 * num_chunks, sizeof(struct spi_transfer), + GFP_KERNEL); + if (!xfers) + return -ENOMEM; - if (rw == SPI_WRITE) - memcpy(tx_buf + SJA1105_SIZE_SPI_MSG_HEADER, - packed_buf, size_bytes); + /* Packed buffers for the num_chunks SPI message headers, + * stored as a contiguous array + */ + hdr_bufs = kcalloc(num_chunks, SJA1105_SIZE_SPI_MSG_HEADER, + GFP_KERNEL); + if (!hdr_bufs) { + kfree(xfers); + return -ENOMEM; + } - spi_message_init(&m); - spi_message_add_tail(&xfer, &m); + for (i = 0; i < num_chunks; i++) { + struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i); + struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i); + u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i); + struct sja1105_spi_message msg; + + /* Populate the transfer's header buffer */ + msg.address = chunk.reg_addr; + msg.access = rw; + if (rw == SPI_READ) + msg.read_count = chunk.len / 4; + else + /* Ignored */ + msg.read_count = 0; + sja1105_spi_message_pack(hdr_buf, &msg); + hdr_xfer->tx_buf = hdr_buf; + hdr_xfer->len = SJA1105_SIZE_SPI_MSG_HEADER; + + /* Populate the transfer's data buffer */ + if (rw == SPI_READ) + chunk_xfer->rx_buf = chunk.buf; + else + chunk_xfer->tx_buf = chunk.buf; + chunk_xfer->len = chunk.len; + + /* Calculate next chunk */ + chunk.buf += chunk.len; + chunk.reg_addr += chunk.len / 4; + chunk.len = min_t(size_t, (ptrdiff_t)(buf + len - chunk.buf), + SJA1105_SIZE_SPI_MSG_MAXLEN); + + /* De-assert the chip select after each chunk. */ + if (chunk.len) + chunk_xfer->cs_change = 1; + } - rc = spi_sync(spi, &m); - if (rc < 0) { + rc = spi_sync_transfer(spi, xfers, 2 * num_chunks); + if (rc < 0) dev_err(&spi->dev, "SPI transfer failed: %d\n", rc); - return rc; - } - if (rw == SPI_READ) - memcpy(packed_buf, rx_buf + SJA1105_SIZE_SPI_MSG_HEADER, - size_bytes); + kfree(hdr_bufs); + kfree(xfers); - return 0; + return rc; } /* If @rw is: @@ -134,43 +175,6 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, return rc; } -/* Should be used if a @packed_buf larger than SJA1105_SIZE_SPI_MSG_MAXLEN - * must be sent/received. Splitting the buffer into chunks and assembling - * those into SPI messages is done automatically by this function. - */ -static int sja1105_xfer_long_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 base_addr, - void *packed_buf, u64 buf_len) -{ - struct chunk { - void *buf_ptr; - int len; - u64 spi_address; - } chunk; - int distance_to_end; - int rc; - - /* Initialize chunk */ - chunk.buf_ptr = packed_buf; - chunk.spi_address = base_addr; - chunk.len = min_t(int, buf_len, SJA1105_SIZE_SPI_MSG_MAXLEN); - - while (chunk.len) { - rc = sja1105_xfer_buf(priv, rw, chunk.spi_address, - chunk.buf_ptr, chunk.len); - if (rc < 0) - return rc; - - chunk.buf_ptr += chunk.len; - chunk.spi_address += chunk.len / 4; - distance_to_end = (uintptr_t)(packed_buf + buf_len - - chunk.buf_ptr); - chunk.len = min(distance_to_end, SJA1105_SIZE_SPI_MSG_MAXLEN); - } - - return 0; -} - /* Back-ported structure from UM11040 Table 112. * Reset control register (addr. 100440h) * In the SJA1105 E/T, only warm_rst and cold_rst are @@ -433,8 +437,8 @@ int sja1105_static_config_upload(struct sja1105_private *priv) /* Wait for the switch to come out of reset */ usleep_range(1000, 5000); /* Upload the static config to the device */ - rc = sja1105_xfer_long_buf(priv, SPI_WRITE, regs->config, - config_buf, buf_len); + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->config, + config_buf, buf_len); if (rc < 0) { dev_err(dev, "Failed to upload config, retrying...\n"); continue; -- cgit v1.2.3-59-g8ed1b From 14af7fd1d4279c8db7fbbb3ca0df3b13179eb502 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 12 Oct 2019 18:27:57 +0200 Subject: ethtool: Add support for 400Gbps (50Gbps per lane) link modes Add support for 400Gbps speed, link modes of 50Gbps per lane Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/phy/phy-core.c | 10 +++++++++- include/uapi/linux/ethtool.h | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 9412669b579c..4d96f7a8e8f2 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -8,7 +8,7 @@ const char *phy_speed_to_str(int speed) { - BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 69, + BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 74, "Enum ethtool_link_mode_bit_indices and phylib are out of sync. " "If a speed or mode has been added please update phy_speed_to_str " "and the PHY settings array.\n"); @@ -42,6 +42,8 @@ const char *phy_speed_to_str(int speed) return "100Gbps"; case SPEED_200000: return "200Gbps"; + case SPEED_400000: + return "400Gbps"; case SPEED_UNKNOWN: return "Unknown"; default: @@ -70,6 +72,12 @@ EXPORT_SYMBOL_GPL(phy_duplex_to_str); .bit = ETHTOOL_LINK_MODE_ ## b ## _BIT} static const struct phy_setting settings[] = { + /* 400G */ + PHY_SETTING( 400000, FULL, 400000baseCR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseKR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseLR8_ER8_FR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseDR8_Full ), + PHY_SETTING( 400000, FULL, 400000baseSR8_Full ), /* 200G */ PHY_SETTING( 200000, FULL, 200000baseCR4_Full ), PHY_SETTING( 200000, FULL, 200000baseKR4_Full ), diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index 8938b76c4ee3..d4591792f0b4 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1507,6 +1507,11 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66, ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68, + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS @@ -1618,6 +1623,7 @@ enum ethtool_link_mode_bit_indices { #define SPEED_56000 56000 #define SPEED_100000 100000 #define SPEED_200000 200000 +#define SPEED_400000 400000 #define SPEED_UNKNOWN -1 -- cgit v1.2.3-59-g8ed1b From 5bd29b9b357569d2be6de29eaa79a7dfc215b0e8 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 12 Oct 2019 18:27:58 +0200 Subject: mlxsw: spectrum: Add support for 400Gbps (50Gbps per lane) link modes Extend speed support with 400Gbps Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 1 + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 52 +++++++++++++++++++++----- 2 files changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 7b538e698a3d..f5e39758c6ac 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -4111,6 +4111,7 @@ MLXSW_ITEM32(reg, ptys, an_status, 0x04, 28, 4); #define MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4 BIT(9) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_100GAUI_2_100GBASE_CR2_KR2 BIT(10) #define MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4 BIT(12) +#define MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8 BIT(15) /* reg_ptys_ext_eth_proto_cap * Extended Ethernet port supported speeds and protocols. diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3c5154e559b2..ae3c4da11520 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2912,9 +2912,22 @@ mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4[] = { #define MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN \ ARRAY_SIZE(mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4) +static const enum ethtool_link_mode_bit_indices +mlxsw_sp2_mask_ethtool_400gaui_8[] = { + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, +}; + +#define MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN \ + ARRAY_SIZE(mlxsw_sp2_mask_ethtool_400gaui_8) + #define MLXSW_SP_PORT_MASK_WIDTH_1X BIT(0) #define MLXSW_SP_PORT_MASK_WIDTH_2X BIT(1) #define MLXSW_SP_PORT_MASK_WIDTH_4X BIT(2) +#define MLXSW_SP_PORT_MASK_WIDTH_8X BIT(3) static u8 mlxsw_sp_port_mask_width_get(u8 width) { @@ -2925,6 +2938,8 @@ static u8 mlxsw_sp_port_mask_width_get(u8 width) return MLXSW_SP_PORT_MASK_WIDTH_2X; case 4: return MLXSW_SP_PORT_MASK_WIDTH_4X; + case 8: + return MLXSW_SP_PORT_MASK_WIDTH_8X; default: WARN_ON_ONCE(1); return 0; @@ -2946,7 +2961,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_SGMII_100M_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100, }, { @@ -2955,7 +2971,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_1000BASE_X_SGMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_1000, }, { @@ -2964,7 +2981,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_2_5GBASE_X_2_5GMII_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_2500, }, { @@ -2973,7 +2991,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_5GBASE_R_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_5000, }, { @@ -2982,14 +3001,16 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XFI_XAUI_1_10G_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_10000, }, { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_XLAUI_4_XLPPI_4_40G, .mask_ethtool = mlxsw_sp2_mask_ethtool_xlaui_4_xlppi_4_40g, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_XLAUI_4_XLPPI_4_40G_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_40000, }, { @@ -2998,7 +3019,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_25GAUI_1_25GBASE_CR_KR_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_1X | MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_25000, }, { @@ -3006,7 +3028,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask_ethtool = mlxsw_sp2_mask_ethtool_50gaui_2_laui_2_50gbase_cr2_kr2, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_50GAUI_2_LAUI_2_50GBASE_CR2_KR2_LEN, .mask_width = MLXSW_SP_PORT_MASK_WIDTH_2X | - MLXSW_SP_PORT_MASK_WIDTH_4X, + MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_50000, }, { @@ -3020,7 +3043,8 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_CAUI_4_100GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_caui_4_100gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_CAUI_4_100GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_100000, }, { @@ -3034,9 +3058,17 @@ static const struct mlxsw_sp2_port_link_mode mlxsw_sp2_port_link_mode[] = { .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_200GAUI_4_200GBASE_CR4_KR4, .mask_ethtool = mlxsw_sp2_mask_ethtool_200gaui_4_200gbase_cr4_kr4, .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_200GAUI_4_200GBASE_CR4_KR4_LEN, - .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_4X | + MLXSW_SP_PORT_MASK_WIDTH_8X, .speed = SPEED_200000, }, + { + .mask = MLXSW_REG_PTYS_EXT_ETH_SPEED_400GAUI_8, + .mask_ethtool = mlxsw_sp2_mask_ethtool_400gaui_8, + .m_ethtool_len = MLXSW_SP2_MASK_ETHTOOL_400GAUI_8_LEN, + .mask_width = MLXSW_SP_PORT_MASK_WIDTH_8X, + .speed = SPEED_400000, + }, }; #define MLXSW_SP2_PORT_LINK_MODE_LEN ARRAY_SIZE(mlxsw_sp2_port_link_mode) -- cgit v1.2.3-59-g8ed1b From d033716331bb05277814b7f7725db19188f2277c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 14 Oct 2019 14:20:00 -0700 Subject: net: bcmgenet: Generate a random MAC if none is valid Instead of having a hard failure and stopping the driver's probe routine, generate a random Ethernet MAC address to keep going. Signed-off-by: Florian Fainelli Acked-by: Doug Berger Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 12cb77ef1081..dd4e4f1dd384 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3461,16 +3461,10 @@ static int bcmgenet_probe(struct platform_device *pdev) goto err; } - if (dn) { + if (dn) macaddr = of_get_mac_address(dn); - if (IS_ERR(macaddr)) { - dev_err(&pdev->dev, "can't find MAC address\n"); - err = -EINVAL; - goto err; - } - } else { + else macaddr = pd->mac_address; - } priv->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->base)) { @@ -3482,7 +3476,12 @@ static int bcmgenet_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); dev_set_drvdata(&pdev->dev, dev); - ether_addr_copy(dev->dev_addr, macaddr); + if (IS_ERR_OR_NULL(macaddr) || !is_valid_ether_addr(macaddr)) { + dev_warn(&pdev->dev, "using random Ethernet MAC\n"); + eth_hw_addr_random(dev); + } else { + ether_addr_copy(dev->dev_addr, macaddr); + } dev->watchdog_timeo = 2 * HZ; dev->ethtool_ops = &bcmgenet_ethtool_ops; dev->netdev_ops = &bcmgenet_netdev_ops; -- cgit v1.2.3-59-g8ed1b From 554032cdfbf4491f38241a3f6b27459408d90df3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 15 Oct 2019 11:28:46 +0100 Subject: net: phylink: use more linkmode_* Use more linkmode_* helpers rather than open-coding the bitmap operations. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 7 ++----- include/linux/linkmode.h | 6 ++++++ 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index a5a57ca94c1a..8e53ed90da3c 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -117,9 +117,7 @@ static int phylink_is_empty_linkmode(const unsigned long *linkmode) phylink_set(tmp, Pause); phylink_set(tmp, Asym_Pause); - bitmap_andnot(tmp, linkmode, tmp, __ETHTOOL_LINK_MODE_MASK_NBITS); - - return linkmode_empty(tmp); + return linkmode_subset(linkmode, tmp); } static const char *phylink_an_mode_str(unsigned int mode) @@ -1728,8 +1726,7 @@ static int phylink_sfp_module_insert(void *upstream, if (phy_interface_mode_is_8023z(iface) && pl->phydev) return -EINVAL; - changed = !bitmap_equal(pl->supported, support, - __ETHTOOL_LINK_MODE_MASK_NBITS); + changed = !linkmode_equal(pl->supported, support); if (changed) { linkmode_copy(pl->supported, support); linkmode_copy(pl->link_config.advertising, config.advertising); diff --git a/include/linux/linkmode.h b/include/linux/linkmode.h index a99c58866860..fe740031339d 100644 --- a/include/linux/linkmode.h +++ b/include/linux/linkmode.h @@ -82,4 +82,10 @@ static inline int linkmode_equal(const unsigned long *src1, return bitmap_equal(src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS); } +static inline int linkmode_subset(const unsigned long *src1, + const unsigned long *src2) +{ + return bitmap_subset(src1, src2, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + #endif /* __LINKMODE_H */ -- cgit v1.2.3-59-g8ed1b From d9f45ab9e671166004b75427f10389e1f70cfc30 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 15 Oct 2019 10:36:24 -0700 Subject: net: bcmgenet: Add a shutdown callback Make sure that we completely quiesce the network device, including its DMA to avoid having it continue to receive packets while there is no software alive to service those. Signed-off-by: Florian Fainelli Acked-by: Doug Berger Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index dd4e4f1dd384..f10ffd35bc47 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3596,6 +3596,11 @@ static int bcmgenet_remove(struct platform_device *pdev) return 0; } +static void bcmgenet_shutdown(struct platform_device *pdev) +{ + bcmgenet_remove(pdev); +} + #ifdef CONFIG_PM_SLEEP static int bcmgenet_resume(struct device *d) { @@ -3714,6 +3719,7 @@ static SIMPLE_DEV_PM_OPS(bcmgenet_pm_ops, bcmgenet_suspend, bcmgenet_resume); static struct platform_driver bcmgenet_driver = { .probe = bcmgenet_probe, .remove = bcmgenet_remove, + .shutdown = bcmgenet_shutdown, .driver = { .name = "bcmgenet", .of_match_table = bcmgenet_match, -- cgit v1.2.3-59-g8ed1b From 89dca86d29b46f2a5f38ea6476cfd441bd205d25 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 14 Oct 2019 14:26:48 -0700 Subject: rtw88: mark rtw_fw_hdr __packed The use of u8 and __le16 in this struct assumes that it's going to be packed to byte alignment. C doesn't guarantee that, so we should mark this __packed. Fixes: cc20a7139836 ("rtw88: use struct rtw_fw_hdr to access firmware header") Cc: Ping-Ke Shih Signed-off-by: Brian Norris Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h index 4f7999394235..73d1b9ca8efc 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.h +++ b/drivers/net/wireless/realtek/rtw88/fw.h @@ -127,7 +127,7 @@ struct rtw_fw_hdr { __le32 emem_size; __le32 emem_addr; __le32 imem_addr; -}; +} __packed; /* C2H */ #define GET_CCX_REPORT_SEQNUM(c2h_payload) (c2h_payload[8] & 0xfc) -- cgit v1.2.3-59-g8ed1b From 9370f2d05a2a150b0aa719a3070b26d478180df3 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Wed, 16 Oct 2019 11:02:42 +0800 Subject: r8152: support request_firmware for RTL8153 This patch supports loading additional firmware file through request_firmware(). A firmware file may include a header followed by several blocks which have different types of firmware. Currently, the supported types are RTL_FW_END, RTL_FW_PLA, and RTL_FW_USB. The firmware is used to fix some compatible or hardware issues. For example, the device couldn't be found after rebooting several times. The supported chips are RTL_VER_04 (rtl8153a-2.fw) RTL_VER_05 (rtl8153a-3.fw) RTL_VER_06 (rtl8153a-4.fw) RTL_VER_09 (rtl8153b-2.fw) Signed-off-by: Hayes Wang Reviewed-by: Prashant Malani Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 768 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 756 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 54a83f734ede..55d0bcb00aef 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -24,9 +24,11 @@ #include #include #include +#include +#include /* Information for net-next */ -#define NETNEXT_VERSION "10" +#define NETNEXT_VERSION "11" /* Information for net */ #define NET_VERSION "10" @@ -54,8 +56,11 @@ #define PLA_BDC_CR 0xd1a0 #define PLA_TEREDO_TIMER 0xd2cc #define PLA_REALWOW_TIMER 0xd2e8 +#define PLA_UPHY_TIMER 0xd388 #define PLA_SUSPEND_FLAG 0xd38a #define PLA_INDICATE_FALG 0xd38c +#define PLA_MACDBG_PRE 0xd38c /* RTL_VER_04 only */ +#define PLA_MACDBG_POST 0xd38e /* RTL_VER_04 only */ #define PLA_EXTRA_STATUS 0xd398 #define PLA_EFUSE_DATA 0xdd00 #define PLA_EFUSE_CMD 0xdd02 @@ -110,7 +115,12 @@ #define USB_CONNECT_TIMER 0xcbf8 #define USB_MSC_TIMER 0xcbfc #define USB_BURST_SIZE 0xcfc0 +#define USB_FW_FIX_EN0 0xcfca +#define USB_FW_FIX_EN1 0xcfcc #define USB_LPM_CONFIG 0xcfd8 +#define USB_CSTMR 0xcfef /* RTL8153A */ +#define USB_FW_CTRL 0xd334 /* RTL8153B */ +#define USB_FC_TIMER 0xd340 #define USB_USB_CTRL 0xd406 #define USB_PHY_CTRL 0xd408 #define USB_TX_AGG 0xd40a @@ -126,6 +136,7 @@ #define USB_LPM_CTRL 0xd41a #define USB_BMU_RESET 0xd4b0 #define USB_U1U2_TIMER 0xd4da +#define USB_FW_TASK 0xd4e8 /* RTL8153B */ #define USB_UPS_CTRL 0xd800 #define USB_POWER_CUT 0xd80a #define USB_MISC_0 0xd81a @@ -133,18 +144,19 @@ #define USB_AFE_CTRL2 0xd824 #define USB_UPS_CFG 0xd842 #define USB_UPS_FLAGS 0xd848 +#define USB_WDT1_CTRL 0xe404 #define USB_WDT11_CTRL 0xe43c -#define USB_BP_BA 0xfc26 -#define USB_BP_0 0xfc28 -#define USB_BP_1 0xfc2a -#define USB_BP_2 0xfc2c -#define USB_BP_3 0xfc2e -#define USB_BP_4 0xfc30 -#define USB_BP_5 0xfc32 -#define USB_BP_6 0xfc34 -#define USB_BP_7 0xfc36 -#define USB_BP_EN 0xfc38 -#define USB_BP_8 0xfc38 +#define USB_BP_BA PLA_BP_BA +#define USB_BP_0 PLA_BP_0 +#define USB_BP_1 PLA_BP_1 +#define USB_BP_2 PLA_BP_2 +#define USB_BP_3 PLA_BP_3 +#define USB_BP_4 PLA_BP_4 +#define USB_BP_5 PLA_BP_5 +#define USB_BP_6 PLA_BP_6 +#define USB_BP_7 PLA_BP_7 +#define USB_BP_EN PLA_BP_EN /* RTL8153A */ +#define USB_BP_8 0xfc38 /* RTL8153B */ #define USB_BP_9 0xfc3a #define USB_BP_10 0xfc3c #define USB_BP_11 0xfc3e @@ -346,7 +358,12 @@ /* PLA_INDICATE_FALG */ #define UPCOMING_RUNTIME_D3 BIT(0) +/* PLA_MACDBG_PRE and PLA_MACDBG_POST */ +#define DEBUG_OE BIT(0) +#define DEBUG_LTSSM 0x0082 + /* PLA_EXTRA_STATUS */ +#define U3P3_CHECK_EN BIT(7) /* RTL_VER_05 only */ #define LINK_CHANGE_FLAG BIT(8) /* USB_USB2PHY */ @@ -368,6 +385,12 @@ #define STAT_SPEED_HIGH 0x0000 #define STAT_SPEED_FULL 0x0002 +/* USB_FW_FIX_EN0 */ +#define FW_FIX_SUSPEND BIT(14) + +/* USB_FW_FIX_EN1 */ +#define FW_IP_RESET_EN BIT(9) + /* USB_LPM_CONFIG */ #define LPM_U1U2_EN BIT(0) @@ -392,12 +415,24 @@ #define OWN_UPDATE BIT(0) #define OWN_CLEAR BIT(1) +/* USB_FW_TASK */ +#define FC_PATCH_TASK BIT(1) + /* USB_UPS_CTRL */ #define POWER_CUT 0x0100 /* USB_PM_CTRL_STATUS */ #define RESUME_INDICATE 0x0001 +/* USB_CSTMR */ +#define FORCE_SUPER BIT(0) + +/* USB_FW_CTRL */ +#define FLOW_CTRL_PATCH_OPT BIT(1) + +/* USB_FC_TIMER */ +#define CTRL_TIMER_EN BIT(15) + /* USB_USB_CTRL */ #define RX_AGG_DISABLE 0x0010 #define RX_ZERO_EN 0x0080 @@ -419,6 +454,9 @@ #define COALESCE_HIGH 250000U #define COALESCE_SLOW 524280U +/* USB_WDT1_CTRL */ +#define WTD1_EN BIT(0) + /* USB_WDT11_CTRL */ #define TIMER11_EN 0x0001 @@ -570,6 +608,8 @@ enum spd_duplex { #define EFUSE 0xcfdb #define PASS_THRU_MASK 0x1 +#define BP4_SUPER_ONLY 0x1578 /* RTL_VER_04 only */ + enum rtl_register_content { _1000bps = 0x10, _100bps = 0x08, @@ -766,6 +806,19 @@ struct r8152 { u32 ctap_short_off:1; } ups_info; +#define RTL_VER_SIZE 32 + + struct rtl_fw { + const char *fw_name; + const struct firmware *fw; + + char version[RTL_VER_SIZE]; + int (*pre_fw)(struct r8152 *tp); + int (*post_fw)(struct r8152 *tp); + + bool retry; + } rtl_fw; + atomic_t rx_count; bool eee_en; @@ -788,6 +841,76 @@ struct r8152 { u8 autoneg; }; +/** + * struct fw_block - block type and total length + * @type: type of the current block, such as RTL_FW_END, RTL_FW_PLA, + * RTL_FW_USB and so on. + * @length: total length of the current block. + */ +struct fw_block { + __le32 type; + __le32 length; +} __packed; + +/** + * struct fw_header - header of the firmware file + * @checksum: checksum of sha256 which is calculated from the whole file + * except the checksum field of the file. That is, calculate sha256 + * from the version field to the end of the file. + * @version: version of this firmware. + * @blocks: the first firmware block of the file + */ +struct fw_header { + u8 checksum[32]; + char version[RTL_VER_SIZE]; + struct fw_block blocks[0]; +} __packed; + +/** + * struct fw_type_1 - a firmware block used by RTL_FW_PLA and RTL_FW_USB. + * The layout of the firmware block is: + * + + . + * @fw_offset: offset of the firmware binary data. The start address of + * the data would be the address of struct fw_type_1 + @fw_offset. + * @fw_reg: the register to load the firmware. Depends on chip. + * @bp_ba_addr: the register to write break point base address. Depends on + * chip. + * @bp_ba_value: break point base address. Depends on chip. + * @bp_en_addr: the register to write break point enabled mask. Depends + * on chip. + * @bp_en_value: break point enabled mask. Depends on the firmware. + * @bp_start: the start register of break points. Depends on chip. + * @bp_num: the break point number which needs to be set for this firmware. + * Depends on the firmware. + * @bp: break points. Depends on firmware. + * @fw_ver_reg: the register to store the fw version. + * @fw_ver_data: the firmware version of the current type. + * @info: additional information for debugging, and is followed by the + * binary data of firmware. + */ +struct fw_type_1 { + struct fw_block blk_hdr; + __le16 fw_offset; + __le16 fw_reg; + __le16 bp_ba_addr; + __le16 bp_ba_value; + __le16 bp_en_addr; + __le16 bp_en_value; + __le16 bp_start; + __le16 bp_num; + __le16 bp[16]; /* any value determined by firmware */ + __le32 reserved; + __le16 fw_ver_reg; + u8 fw_ver_data; + char info[0]; +} __packed; + +enum rtl_fw_type { + RTL_FW_END = 0, + RTL_FW_PLA, + RTL_FW_USB, +}; + enum rtl_version { RTL_VER_UNKNOWN = 0, RTL_VER_01, @@ -3226,6 +3349,435 @@ static void rtl_reset_bmu(struct r8152 *tp) ocp_write_byte(tp, MCU_TYPE_USB, USB_BMU_RESET, ocp_data); } +/* Clear the bp to stop the firmware before loading a new one */ +static void rtl_clear_bp(struct r8152 *tp, u16 type) +{ + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + break; + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + ocp_write_byte(tp, type, PLA_BP_EN, 0); + break; + case RTL_VER_08: + case RTL_VER_09: + default: + if (type == MCU_TYPE_USB) { + ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0); + + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_10, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_11, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_12, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_13, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_14, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_15, 0); + } else { + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); + } + break; + } + + ocp_write_word(tp, type, PLA_BP_0, 0); + ocp_write_word(tp, type, PLA_BP_1, 0); + ocp_write_word(tp, type, PLA_BP_2, 0); + ocp_write_word(tp, type, PLA_BP_3, 0); + ocp_write_word(tp, type, PLA_BP_4, 0); + ocp_write_word(tp, type, PLA_BP_5, 0); + ocp_write_word(tp, type, PLA_BP_6, 0); + ocp_write_word(tp, type, PLA_BP_7, 0); + + /* wait 3 ms to make sure the firmware is stopped */ + usleep_range(3000, 6000); + ocp_write_word(tp, type, PLA_BP_BA, 0); +} + +static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) +{ + u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start; + bool rc = false; + u32 length, type; + int i, max_bp; + + type = __le32_to_cpu(type1->blk_hdr.type); + if (type == RTL_FW_PLA) { + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = 0; + bp_start = PLA_BP_0; + max_bp = 8; + break; + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + case RTL_VER_08: + case RTL_VER_09: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = PLA_BP_EN; + bp_start = PLA_BP_0; + max_bp = 8; + break; + default: + goto out; + } + } else if (type == RTL_FW_USB) { + switch (tp->version) { + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + fw_reg = 0xf800; + bp_ba_addr = USB_BP_BA; + bp_en_addr = USB_BP_EN; + bp_start = USB_BP_0; + max_bp = 8; + break; + case RTL_VER_08: + case RTL_VER_09: + fw_reg = 0xe600; + bp_ba_addr = USB_BP_BA; + bp_en_addr = USB_BP2_EN; + bp_start = USB_BP_0; + max_bp = 16; + break; + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + default: + goto out; + } + } else { + goto out; + } + + length = __le32_to_cpu(type1->blk_hdr.length); + if (length < __le16_to_cpu(type1->fw_offset)) { + dev_err(&tp->intf->dev, "invalid fw_offset\n"); + goto out; + } + + length -= __le16_to_cpu(type1->fw_offset); + if (length < 4 || (length & 3)) { + dev_err(&tp->intf->dev, "invalid block length\n"); + goto out; + } + + if (__le16_to_cpu(type1->fw_reg) != fw_reg) { + dev_err(&tp->intf->dev, "invalid register to load firmware\n"); + goto out; + } + + if (__le16_to_cpu(type1->bp_ba_addr) != bp_ba_addr) { + dev_err(&tp->intf->dev, "invalid base address register\n"); + goto out; + } + + if (__le16_to_cpu(type1->bp_en_addr) != bp_en_addr) { + dev_err(&tp->intf->dev, "invalid enabled mask register\n"); + goto out; + } + + if (__le16_to_cpu(type1->bp_start) != bp_start) { + dev_err(&tp->intf->dev, + "invalid start register of break point\n"); + goto out; + } + + if (__le16_to_cpu(type1->bp_num) > max_bp) { + dev_err(&tp->intf->dev, "invalid break point number\n"); + goto out; + } + + for (i = __le16_to_cpu(type1->bp_num); i < max_bp; i++) { + if (type1->bp[i]) { + dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); + goto out; + } + } + + rc = true; +out: + return rc; +} + +/* Verify the checksum for the firmware file. It is calculated from the version + * field to the end of the file. Compare the result with the checksum field to + * make sure the file is correct. + */ +static long rtl8152_fw_verify_checksum(struct r8152 *tp, + struct fw_header *fw_hdr, size_t size) +{ + unsigned char checksum[sizeof(fw_hdr->checksum)]; + struct crypto_shash *alg; + struct shash_desc *sdesc; + size_t len; + long rc; + + alg = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(alg)) { + rc = PTR_ERR(alg); + goto out; + } + + if (crypto_shash_digestsize(alg) != sizeof(fw_hdr->checksum)) { + rc = -EFAULT; + dev_err(&tp->intf->dev, "digestsize incorrect (%u)\n", + crypto_shash_digestsize(alg)); + goto free_shash; + } + + len = sizeof(*sdesc) + crypto_shash_descsize(alg); + sdesc = kmalloc(len, GFP_KERNEL); + if (!sdesc) { + rc = -ENOMEM; + goto free_shash; + } + sdesc->tfm = alg; + + len = size - sizeof(fw_hdr->checksum); + rc = crypto_shash_digest(sdesc, fw_hdr->version, len, checksum); + kfree(sdesc); + if (rc) + goto free_shash; + + if (memcmp(fw_hdr->checksum, checksum, sizeof(fw_hdr->checksum))) { + dev_err(&tp->intf->dev, "checksum fail\n"); + rc = -EFAULT; + } + +free_shash: + crypto_free_shash(alg); +out: + return rc; +} + +static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) +{ + const struct firmware *fw = rtl_fw->fw; + struct fw_header *fw_hdr = (struct fw_header *)fw->data; + struct fw_type_1 *pla = NULL, *usb = NULL; + long ret = -EFAULT; + int i; + + if (fw->size < sizeof(*fw_hdr)) { + dev_err(&tp->intf->dev, "file too small\n"); + goto fail; + } + + ret = rtl8152_fw_verify_checksum(tp, fw_hdr, fw->size); + if (ret) + goto fail; + + ret = -EFAULT; + + for (i = sizeof(*fw_hdr); i < fw->size;) { + struct fw_block *block = (struct fw_block *)&fw->data[i]; + u32 type; + + if ((i + sizeof(*block)) > fw->size) + goto fail; + + type = __le32_to_cpu(block->type); + switch (type) { + case RTL_FW_END: + if (__le32_to_cpu(block->length) != sizeof(*block)) + goto fail; + goto success; + case RTL_FW_PLA: + if (pla) { + dev_err(&tp->intf->dev, + "multiple PLA firmware encountered"); + goto fail; + } + + pla = (struct fw_type_1 *)block; + if (!rtl8152_is_fw_type1_ok(tp, pla)) { + dev_err(&tp->intf->dev, + "load PLA firmware failed\n"); + goto fail; + } + break; + case RTL_FW_USB: + if (usb) { + dev_err(&tp->intf->dev, + "multiple USB firmware encountered"); + goto fail; + } + + usb = (struct fw_type_1 *)block; + if (!rtl8152_is_fw_type1_ok(tp, usb)) { + dev_err(&tp->intf->dev, + "load USB firmware failed\n"); + goto fail; + } + break; + default: + dev_warn(&tp->intf->dev, "Unknown type %u is found\n", + type); + break; + } + + /* next block */ + i += ALIGN(__le32_to_cpu(block->length), 8); + } + +success: + return 0; +fail: + return ret; +} + +static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) +{ + u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; + u32 length; + u8 *data; + int i; + + switch (__le32_to_cpu(type1->blk_hdr.type)) { + case RTL_FW_PLA: + type = MCU_TYPE_PLA; + break; + case RTL_FW_USB: + type = MCU_TYPE_USB; + break; + default: + return; + } + + rtl_clear_bp(tp, type); + + /* Enable backup/restore of MACDBG. This is required after clearing PLA + * break points and before applying the PLA firmware. + */ + if (tp->version == RTL_VER_04 && type == MCU_TYPE_PLA && + !(ocp_read_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST) & DEBUG_OE)) { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_PRE, DEBUG_LTSSM); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); + } + + length = __le32_to_cpu(type1->blk_hdr.length); + length -= __le16_to_cpu(type1->fw_offset); + + data = (u8 *)type1; + data += __le16_to_cpu(type1->fw_offset); + + generic_ocp_write(tp, __le16_to_cpu(type1->fw_reg), 0xff, length, data, + type); + + ocp_write_word(tp, type, __le16_to_cpu(type1->bp_ba_addr), + __le16_to_cpu(type1->bp_ba_value)); + + bp_index = __le16_to_cpu(type1->bp_start); + bp_num = __le16_to_cpu(type1->bp_num); + for (i = 0; i < bp_num; i++) { + ocp_write_word(tp, type, bp_index, __le16_to_cpu(type1->bp[i])); + bp_index += 2; + } + + bp_en_addr = __le16_to_cpu(type1->bp_en_addr); + if (bp_en_addr) + ocp_write_word(tp, type, bp_en_addr, + __le16_to_cpu(type1->bp_en_value)); + + fw_ver_reg = __le16_to_cpu(type1->fw_ver_reg); + if (fw_ver_reg) + ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, + type1->fw_ver_data); + + dev_dbg(&tp->intf->dev, "successfully applied %s\n", type1->info); +} + +static void rtl8152_apply_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + const struct firmware *fw = rtl_fw->fw; + struct fw_header *fw_hdr = (struct fw_header *)fw->data; + int i; + + if (IS_ERR_OR_NULL(rtl_fw->fw)) + return; + + if (rtl_fw->pre_fw) + rtl_fw->pre_fw(tp); + + for (i = offsetof(struct fw_header, blocks); i < fw->size;) { + struct fw_block *block = (struct fw_block *)&fw->data[i]; + + switch (__le32_to_cpu(block->type)) { + case RTL_FW_END: + goto post_fw; + case RTL_FW_PLA: + case RTL_FW_USB: + rtl8152_fw_type_1_apply(tp, (struct fw_type_1 *)block); + break; + default: + break; + } + + i += ALIGN(__le32_to_cpu(block->length), 8); + } + +post_fw: + if (rtl_fw->post_fw) + rtl_fw->post_fw(tp); + + strscpy(rtl_fw->version, fw_hdr->version, RTL_VER_SIZE); + dev_info(&tp->intf->dev, "load %s successfully\n", rtl_fw->version); +} + +static void rtl8152_release_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + + if (!IS_ERR_OR_NULL(rtl_fw->fw)) { + release_firmware(rtl_fw->fw); + rtl_fw->fw = NULL; + } +} + +static int rtl8152_request_firmware(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + long rc; + + if (rtl_fw->fw || !rtl_fw->fw_name) { + dev_info(&tp->intf->dev, "skip request firmware\n"); + rc = 0; + goto result; + } + + rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, &tp->intf->dev); + if (rc < 0) + goto result; + + rc = rtl8152_check_firmware(tp, rtl_fw); + if (rc < 0) + release_firmware(rtl_fw->fw); + +result: + if (rc) { + rtl_fw->fw = ERR_PTR(rc); + + dev_warn(&tp->intf->dev, + "unable to load firmware patch %s (%ld)\n", + rtl_fw->fw_name, rc); + } + + return rc; +} + static void r8152_aldps_en(struct r8152 *tp, bool enable) { if (enable) { @@ -3370,6 +3922,7 @@ static void rtl8152_disable(struct r8152 *tp) static void r8152b_hw_phy_cfg(struct r8152 *tp) { + rtl8152_apply_firmware(tp); rtl_eee_enable(tp, tp->eee_en); r8152_aldps_en(tp, true); r8152b_enable_fc(tp); @@ -3524,6 +4077,126 @@ static int r8153_patch_request(struct r8152 *tp, bool request) } } +static int r8153_pre_firmware_1(struct r8152 *tp) +{ + int i; + + /* Wait till the WTD timer is ready. It would take at most 104 ms. */ + for (i = 0; i < 104; i++) { + u32 ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_WDT1_CTRL); + + if (!(ocp_data & WTD1_EN)) + break; + usleep_range(1000, 2000); + } + + return 0; +} + +static int r8153_post_firmware_1(struct r8152 *tp) +{ + /* set USB_BP_4 to support USB_SPEED_SUPER only */ + if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_4, BP4_SUPER_ONLY); + + /* reset UPHY timer to 36 ms */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); + + return 0; +} + +static int r8153_pre_firmware_2(struct r8152 *tp) +{ + u32 ocp_data; + + r8153_pre_firmware_1(tp); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); + ocp_data &= ~FW_FIX_SUSPEND; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); + + return 0; +} + +static int r8153_post_firmware_2(struct r8152 *tp) +{ + u32 ocp_data; + + /* enable bp0 if support USB_SPEED_SUPER only */ + if (ocp_read_byte(tp, MCU_TYPE_USB, USB_CSTMR) & FORCE_SUPER) { + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); + ocp_data |= BIT(0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); + } + + /* reset UPHY timer to 36 ms */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_UPHY_TIMER, 36000 / 16); + + /* enable U3P3 check, set the counter to 4 */ + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EXTRA_STATUS, U3P3_CHECK_EN | 4); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0); + ocp_data |= FW_FIX_SUSPEND; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN0, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); + ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; + ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); + + return 0; +} + +static int r8153_post_firmware_3(struct r8152 *tp) +{ + u32 ocp_data; + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); + ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; + ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); + ocp_data |= FW_IP_RESET_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); + + return 0; +} + +static int r8153b_pre_firmware_1(struct r8152 *tp) +{ + /* enable fc timer and set timer to 1 second. */ + ocp_write_word(tp, MCU_TYPE_USB, USB_FC_TIMER, + CTRL_TIMER_EN | (1000 / 8)); + + return 0; +} + +static int r8153b_post_firmware_1(struct r8152 *tp) +{ + u32 ocp_data; + + /* enable bp0 for RTL8153-BND */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); + if (ocp_data & BND_MASK) { + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_BP_EN); + ocp_data |= BIT(0); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_EN, ocp_data); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_CTRL); + ocp_data |= FLOW_CTRL_PATCH_OPT; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_CTRL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_TASK); + ocp_data |= FC_PATCH_TASK; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_TASK, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1); + ocp_data |= FW_IP_RESET_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_FW_FIX_EN1, ocp_data); + + return 0; +} + static void r8153_aldps_en(struct r8152 *tp, bool enable) { u16 data; @@ -3558,6 +4231,8 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) /* disable EEE before updating the PHY parameters */ rtl_eee_enable(tp, false); + rtl8152_apply_firmware(tp); + if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); data &= ~CTAP_SHORT_EN; @@ -3630,6 +4305,8 @@ static void r8153b_hw_phy_cfg(struct r8152 *tp) /* disable EEE before updating the PHY parameters */ rtl_eee_enable(tp, false); + rtl8152_apply_firmware(tp); + r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags)); data = sram_read(tp, SRAM_GREEN_CFG); @@ -4156,11 +4833,22 @@ static void rtl_hw_phy_work_func_t(struct work_struct *work) mutex_lock(&tp->control); + if (rtl8152_request_firmware(tp) == -ENODEV && tp->rtl_fw.retry) { + tp->rtl_fw.retry = false; + tp->rtl_fw.fw = NULL; + + /* Delay execution in case request_firmware() is not ready yet. + */ + queue_delayed_work(system_long_wq, &tp->hw_phy_work, HZ * 10); + goto ignore_once; + } + tp->rtl_ops.hw_phy_cfg(tp); rtl8152_set_speed(tp, tp->autoneg, tp->speed, tp->duplex, tp->advertising); +ignore_once: mutex_unlock(&tp->control); usb_autopm_put_interface(tp->intf); @@ -4198,6 +4886,11 @@ static int rtl8152_open(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; + if (work_busy(&tp->hw_phy_work.work) & WORK_BUSY_PENDING) { + cancel_delayed_work_sync(&tp->hw_phy_work); + rtl_hw_phy_work_func_t(&tp->hw_phy_work.work); + } + res = alloc_all_mem(tp); if (res) goto out; @@ -4844,6 +5537,9 @@ static void rtl8152_get_drvinfo(struct net_device *netdev, strlcpy(info->driver, MODULENAME, sizeof(info->driver)); strlcpy(info->version, DRIVER_VERSION, sizeof(info->version)); usb_make_path(tp->udev, info->bus_info, sizeof(info->bus_info)); + if (!IS_ERR_OR_NULL(tp->rtl_fw.fw)) + strlcpy(info->fw_version, tp->rtl_fw.version, + sizeof(info->fw_version)); } static @@ -5468,6 +6164,47 @@ static int rtl_ops_init(struct r8152 *tp) return ret; } +#define FIRMWARE_8153A_2 "rtl_nic/rtl8153a-2.fw" +#define FIRMWARE_8153A_3 "rtl_nic/rtl8153a-3.fw" +#define FIRMWARE_8153A_4 "rtl_nic/rtl8153a-4.fw" +#define FIRMWARE_8153B_2 "rtl_nic/rtl8153b-2.fw" + +MODULE_FIRMWARE(FIRMWARE_8153A_2); +MODULE_FIRMWARE(FIRMWARE_8153A_3); +MODULE_FIRMWARE(FIRMWARE_8153A_4); +MODULE_FIRMWARE(FIRMWARE_8153B_2); + +static int rtl_fw_init(struct r8152 *tp) +{ + struct rtl_fw *rtl_fw = &tp->rtl_fw; + + switch (tp->version) { + case RTL_VER_04: + rtl_fw->fw_name = FIRMWARE_8153A_2; + rtl_fw->pre_fw = r8153_pre_firmware_1; + rtl_fw->post_fw = r8153_post_firmware_1; + break; + case RTL_VER_05: + rtl_fw->fw_name = FIRMWARE_8153A_3; + rtl_fw->pre_fw = r8153_pre_firmware_2; + rtl_fw->post_fw = r8153_post_firmware_2; + break; + case RTL_VER_06: + rtl_fw->fw_name = FIRMWARE_8153A_4; + rtl_fw->post_fw = r8153_post_firmware_3; + break; + case RTL_VER_09: + rtl_fw->fw_name = FIRMWARE_8153B_2; + rtl_fw->pre_fw = r8153b_pre_firmware_1; + rtl_fw->post_fw = r8153b_post_firmware_1; + break; + default: + break; + } + + return 0; +} + static u8 rtl_get_version(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); @@ -5575,6 +6312,8 @@ static int rtl8152_probe(struct usb_interface *intf, if (ret) goto out; + rtl_fw_init(tp); + mutex_init(&tp->control); INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); INIT_DELAYED_WORK(&tp->hw_phy_work, rtl_hw_phy_work_func_t); @@ -5646,6 +6385,10 @@ static int rtl8152_probe(struct usb_interface *intf, intf->needs_remote_wakeup = 1; tp->rtl_ops.init(tp); +#if IS_BUILTIN(CONFIG_USB_RTL8152) + /* Retry in case request_firmware() is not ready yet. */ + tp->rtl_fw.retry = true; +#endif queue_delayed_work(system_long_wq, &tp->hw_phy_work, 0); set_ethernet_addr(tp); @@ -5691,6 +6434,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) tasklet_kill(&tp->tx_tl); cancel_delayed_work_sync(&tp->hw_phy_work); tp->rtl_ops.unload(tp); + rtl8152_release_firmware(tp); free_netdev(tp->netdev); } } -- cgit v1.2.3-59-g8ed1b From 2203cbf2c8b58a1e3bef98c47531d431d11639a0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 15 Oct 2019 11:38:39 +0100 Subject: net: sfp: move fwnode parsing into sfp-bus layer Rather than parsing the sfp firmware node in phylink, parse it in the sfp-bus code, so we can re-use this code for PHYs without having to duplicate the parsing. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 21 +++++---------- drivers/net/phy/sfp-bus.c | 65 ++++++++++++++++++++++++++++++----------------- include/linux/sfp.h | 10 ++++---- 3 files changed, 53 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 8e53ed90da3c..4c5e8b4f8d80 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -548,26 +548,17 @@ static const struct sfp_upstream_ops sfp_phylink_ops; static int phylink_register_sfp(struct phylink *pl, struct fwnode_handle *fwnode) { - struct fwnode_reference_args ref; + struct sfp_bus *bus; int ret; - if (!fwnode) - return 0; - - ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL, - 0, 0, &ref); - if (ret < 0) { - if (ret == -ENOENT) - return 0; - - phylink_err(pl, "unable to parse \"sfp\" node: %d\n", - ret); + bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops); + if (IS_ERR(bus)) { + ret = PTR_ERR(bus); + phylink_err(pl, "unable to attach SFP bus: %d\n", ret); return ret; } - pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops); - if (!pl->sfp_bus) - return -ENOMEM; + pl->sfp_bus = bus; return 0; } diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index b23fc41896ef..d037aab6a71d 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -445,45 +446,63 @@ static void sfp_upstream_clear(struct sfp_bus *bus) } /** - * sfp_register_upstream() - Register the neighbouring device - * @fwnode: firmware node for the SFP bus + * sfp_register_upstream_node() - parse and register the neighbouring device + * @fwnode: firmware node for the parent device (MAC or PHY) * @upstream: the upstream private data * @ops: the upstream's &struct sfp_upstream_ops * - * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers - * should use phylink, which will call this function for them. Returns - * a pointer to the allocated &struct sfp_bus. + * Parse the parent device's firmware node for a SFP bus, and register the + * SFP bus using sfp_register_upstream(). * - * On error, returns %NULL. + * Returns: on success, a pointer to the sfp_bus structure, + * %NULL if no SFP is specified, + * on failure, an error pointer value: + * corresponding to the errors detailed for + * fwnode_property_get_reference_args(). + * %-ENOMEM if we failed to allocate the bus. + * an error from the upstream's connect_phy() method. */ -struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode, - void *upstream, - const struct sfp_upstream_ops *ops) +struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, + void *upstream, + const struct sfp_upstream_ops *ops) { - struct sfp_bus *bus = sfp_bus_get(fwnode); - int ret = 0; + struct fwnode_reference_args ref; + struct sfp_bus *bus; + int ret; - if (bus) { - rtnl_lock(); - bus->upstream_ops = ops; - bus->upstream = upstream; + ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL, + 0, 0, &ref); + if (ret == -ENOENT) + return NULL; + else if (ret < 0) + return ERR_PTR(ret); - if (bus->sfp) { - ret = sfp_register_bus(bus); - if (ret) - sfp_upstream_clear(bus); - } - rtnl_unlock(); + bus = sfp_bus_get(ref.fwnode); + fwnode_handle_put(ref.fwnode); + if (!bus) + return ERR_PTR(-ENOMEM); + + rtnl_lock(); + bus->upstream_ops = ops; + bus->upstream = upstream; + + if (bus->sfp) { + ret = sfp_register_bus(bus); + if (ret) + sfp_upstream_clear(bus); + } else { + ret = 0; } + rtnl_unlock(); if (ret) { sfp_bus_put(bus); - bus = NULL; + bus = ERR_PTR(ret); } return bus; } -EXPORT_SYMBOL_GPL(sfp_register_upstream); +EXPORT_SYMBOL_GPL(sfp_register_upstream_node); /** * sfp_unregister_upstream() - Unregister sfp bus diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 1c35428e98bc..355a08a76fd4 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -508,9 +508,9 @@ int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, u8 *data); void sfp_upstream_start(struct sfp_bus *bus); void sfp_upstream_stop(struct sfp_bus *bus); -struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode, - void *upstream, - const struct sfp_upstream_ops *ops); +struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, + void *upstream, + const struct sfp_upstream_ops *ops); void sfp_unregister_upstream(struct sfp_bus *bus); #else static inline int sfp_parse_port(struct sfp_bus *bus, @@ -553,11 +553,11 @@ static inline void sfp_upstream_stop(struct sfp_bus *bus) { } -static inline struct sfp_bus *sfp_register_upstream( +static inline struct sfp_bus *sfp_register_upstream_node( struct fwnode_handle *fwnode, void *upstream, const struct sfp_upstream_ops *ops) { - return (struct sfp_bus *)-1; + return NULL; } static inline void sfp_unregister_upstream(struct sfp_bus *bus) -- cgit v1.2.3-59-g8ed1b From 0c5378f9d5003334775ea0e5e9934976aa4a1b66 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 17 Oct 2019 14:28:32 +0200 Subject: net: socionext: netsec: fix xdp stats accounting Increment netdev rx counters even for XDP_DROP verdict. Report even tx bytes for xdp buffers (TYPE_NETSEC_XDP_TX or TYPE_NETSEC_XDP_NDO). Moreover account pending buffer length in netsec_xdp_queue_one as it is done for skb counterpart Tested-by: Ilias Apalodimas Signed-off-by: Lorenzo Bianconi Reviewed-by: Ilias Apalodimas Signed-off-by: David S. Miller --- drivers/net/ethernet/socionext/netsec.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index f9e6744d8fd6..c40294470bfa 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -252,7 +252,6 @@ #define NETSEC_XDP_CONSUMED BIT(0) #define NETSEC_XDP_TX BIT(1) #define NETSEC_XDP_REDIR BIT(2) -#define NETSEC_XDP_RX_OK (NETSEC_XDP_PASS | NETSEC_XDP_TX | NETSEC_XDP_REDIR) enum ring_id { NETSEC_RING_TX = 0, @@ -661,6 +660,7 @@ static bool netsec_clean_tx_dring(struct netsec_priv *priv) bytes += desc->skb->len; dev_kfree_skb(desc->skb); } else { + bytes += desc->xdpf->len; xdp_return_frame(desc->xdpf); } next: @@ -858,6 +858,7 @@ static u32 netsec_xdp_queue_one(struct netsec_priv *priv, tx_desc.addr = xdpf->data; tx_desc.len = xdpf->len; + netdev_sent_queue(priv->ndev, xdpf->len); netsec_set_tx_de(priv, tx_ring, &tx_ctrl, &tx_desc, xdpf); return NETSEC_XDP_TX; @@ -1030,7 +1031,7 @@ static int netsec_process_rx(struct netsec_priv *priv, int budget) next: if ((skb && napi_gro_receive(&priv->napi, skb) != GRO_DROP) || - xdp_result & NETSEC_XDP_RX_OK) { + xdp_result) { ndev->stats.rx_packets++; ndev->stats.rx_bytes += xdp.data_end - xdp.data; } -- cgit v1.2.3-59-g8ed1b From d9496f3ecfe4823c1e12aecbcc29220147fa012c Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 16 Oct 2019 14:40:32 +0300 Subject: net: netsec: Correct dma sync for XDP_TX frames bpf_xdp_adjust_head() can change the frame boundaries. Account for the potential shift properly by calculating the new offset before syncing the buffer to the device for XDP_TX Fixes: ba2b232108d3 ("net: netsec: add XDP support") Signed-off-by: Ilias Apalodimas Reviewed-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/socionext/netsec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index c40294470bfa..869a498e3b5e 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -847,8 +847,8 @@ static u32 netsec_xdp_queue_one(struct netsec_priv *priv, enum dma_data_direction dma_dir = page_pool_get_dma_dir(rx_ring->page_pool); - dma_handle = page_pool_get_dma_addr(page) + - NETSEC_RXBUF_HEADROOM; + dma_handle = page_pool_get_dma_addr(page) + xdpf->headroom + + sizeof(*xdpf); dma_sync_single_for_device(priv->dev, dma_handle, xdpf->len, dma_dir); tx_desc.buf_type = TYPE_NETSEC_XDP_TX; -- cgit v1.2.3-59-g8ed1b From 2fb079a28ae856145e8977d08b77403a3a5d6a70 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 16 Oct 2019 21:41:02 +0300 Subject: net: dsa: sja1105: Switch to hardware operations for PTP Adjusting the hardware clock (PTPCLKVAL, PTPCLKADD, PTPCLKRATE) is a requirement for the auxiliary PTP functionality of the switch (TTEthernet, PPS input, PPS output). Therefore we need to switch to using these registers to keep a synchronized time in hardware, instead of the timecounter/cyclecounter implementation, which is reliant on the free-running PTPTSCLK. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 3 +- drivers/net/dsa/sja1105/sja1105_ptp.c | 218 +++++++++++++++++----------------- drivers/net/dsa/sja1105/sja1105_ptp.h | 25 ++-- drivers/net/dsa/sja1105/sja1105_spi.c | 6 +- 4 files changed, 128 insertions(+), 124 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 0ef97a916707..397a49da35e4 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -33,9 +33,8 @@ struct sja1105_regs { u64 config; u64 rmii_pll1; u64 ptp_control; - u64 ptpclk; + u64 ptpclkval; u64 ptpclkrate; - u64 ptptsclk; u64 ptpegr_ts[SJA1105_NUM_PORTS]; u64 pad_mii_tx[SJA1105_NUM_PORTS]; u64 pad_mii_id[SJA1105_NUM_PORTS]; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index b43096063cf4..783100397f8a 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -13,24 +13,6 @@ #define SJA1105_MAX_ADJ_PPB 32000000 #define SJA1105_SIZE_PTP_CMD 4 -/* Timestamps are in units of 8 ns clock ticks (equivalent to a fixed - * 125 MHz clock) so the scale factor (MULT / SHIFT) needs to be 8. - * Furthermore, wisely pick SHIFT as 28 bits, which translates - * MULT into 2^31 (0x80000000). This is the same value around which - * the hardware PTPCLKRATE is centered, so the same ppb conversion - * arithmetic can be reused. - */ -#define SJA1105_CC_SHIFT 28 -#define SJA1105_CC_MULT (8 << SJA1105_CC_SHIFT) - -/* Having 33 bits of cycle counter left until a 64-bit overflow during delta - * conversion, we multiply this by the 8 ns counter resolution and arrive at - * a comfortable 68.71 second refresh interval until the delta would cause - * an integer overflow, in absence of any other readout. - * Approximate to 1 minute. - */ -#define SJA1105_REFRESH_INTERVAL (HZ * 60) - /* This range is actually +/- SJA1105_MAX_ADJ_PPB * divided by 1000 (ppb -> ppm) and with a 16-bit * "fractional" part (actually fixed point). @@ -41,7 +23,7 @@ * * This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC) * and defines the scaling factor between scaled_ppm and the actual - * frequency adjustments (both cycle counter and hardware). + * frequency adjustments of the PHC. * * ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16) * simplifies to @@ -49,13 +31,15 @@ */ #define SJA1105_CC_MULT_NUM (1 << 9) #define SJA1105_CC_MULT_DEM 15625 +#define SJA1105_CC_MULT 0x80000000 + +enum sja1105_ptp_clk_mode { + PTP_ADD_MODE = 1, + PTP_SET_MODE = 0, +}; #define ptp_caps_to_data(d) \ container_of((d), struct sja1105_ptp_data, caps) -#define cc_to_ptp_data(d) \ - container_of((d), struct sja1105_ptp_data, tstamp_cc) -#define dw_to_ptp_data(d) \ - container_of((d), struct sja1105_ptp_data, refresh_work) #define ptp_data_to_sja1105(d) \ container_of((d), struct sja1105_private, ptp_data) @@ -220,6 +204,8 @@ int sja1105et_ptp_cmd(const struct dsa_switch *ds, sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 2, 2, size); + sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -237,6 +223,8 @@ int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, sja1105_pack(buf, &valid, 31, 31, size); sja1105_pack(buf, &cmd->resptp, 3, 3, size); + sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); + sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, SJA1105_SIZE_PTP_CMD); @@ -346,6 +334,22 @@ static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) return 0; } +/* Caller must hold ptp_data->lock */ +static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks) +{ + const struct sja1105_regs *regs = priv->info->regs; + + return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks); +} + +/* Caller must hold ptp_data->lock */ +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) +{ + const struct sja1105_regs *regs = priv->info->regs; + + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks); +} + #define rxtstamp_to_tagger(d) \ container_of((d), struct sja1105_tagger_data, rxtstamp_work) #define tagger_to_sja1105(d) \ @@ -363,17 +367,22 @@ static void sja1105_rxtstamp_work(struct work_struct *work) while ((skb = skb_dequeue(&tagger_data->skb_rxtstamp_queue)) != NULL) { struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb); - u64 now, ts; + u64 ticks, ts; + int rc; - now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + rc = sja1105_ptpclkval_read(priv, &ticks); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + kfree_skb(skb); + continue; + } *shwt = (struct skb_shared_hwtstamps) {0}; ts = SJA1105_SKB_CB(skb)->meta_tstamp; - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(ds, ticks, ts); - shwt->hwtstamp = ns_to_ktime(ts); + shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); netif_rx_ni(skb); } @@ -427,9 +436,6 @@ int sja1105_ptp_reset(struct dsa_switch *ds) dev_dbg(ds->dev, "Resetting PTP clock\n"); rc = priv->info->ptp_cmd(ds, &cmd); - timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, - ktime_to_ns(ktime_get_real())); - mutex_unlock(&ptp_data->lock); return rc; @@ -439,112 +445,106 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - u64 ns; + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + u64 ticks = 0; + int rc; mutex_lock(&ptp_data->lock); - ns = timecounter_read(&ptp_data->tstamp_tc); + + rc = sja1105_ptpclkval_read(priv, &ticks); + *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + mutex_unlock(&ptp_data->lock); - *ts = ns_to_timespec64(ns); + return rc; +} - return 0; +/* Caller must hold ptp_data->lock */ +static int sja1105_ptp_mode_set(struct sja1105_private *priv, + enum sja1105_ptp_clk_mode mode) +{ + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + + if (ptp_data->cmd.ptpclkadd == mode) + return 0; + + ptp_data->cmd.ptpclkadd = mode; + + return priv->info->ptp_cmd(priv->ds, &ptp_data->cmd); } +/* Write to PTPCLKVAL while PTPCLKADD is 0 */ static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - u64 ns = timespec64_to_ns(ts); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); + int rc; mutex_lock(&ptp_data->lock); - timecounter_init(&ptp_data->tstamp_tc, &ptp_data->tstamp_cc, ns); + + rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); + goto out; + } + + rc = sja1105_ptpclkval_write(priv, ticks); +out: mutex_unlock(&ptp_data->lock); - return 0; + return rc; } static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + const struct sja1105_regs *regs = priv->info->regs; + u32 clkrate32; s64 clkrate; + int rc; clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM; clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM); - mutex_lock(&ptp_data->lock); + /* Take a +/- value and re-center it around 2^31. */ + clkrate = SJA1105_CC_MULT + clkrate; + WARN_ON(abs(clkrate) >= GENMASK_ULL(31, 0)); + clkrate32 = clkrate; - /* Force a readout to update the timer *before* changing its frequency. - * - * This way, its corrected time curve can at all times be modeled - * as a linear "A * x + B" function, where: - * - * - B are past frequency adjustments and offset shifts, all - * accumulated into the cycle_last variable. - * - * - A is the new frequency adjustments we're just about to set. - * - * Reading now makes B accumulate the correct amount of time, - * corrected at the old rate, before changing it. - * - * Hardware timestamps then become simple points on the curve and - * are approximated using the above function. This is still better - * than letting the switch take the timestamps using the hardware - * rate-corrected clock (PTPCLKVAL) - the comparison in this case would - * be that we're shifting the ruler at the same time as we're taking - * measurements with it. - * - * The disadvantage is that it's possible to receive timestamps when - * a frequency adjustment took place in the near past. - * In this case they will be approximated using the new ppb value - * instead of a compound function made of two segments (one at the old - * and the other at the new rate) - introducing some inaccuracy. - */ - timecounter_read(&ptp_data->tstamp_tc); + mutex_lock(&ptp_data->lock); - ptp_data->tstamp_cc.mult = SJA1105_CC_MULT + clkrate; + rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32); mutex_unlock(&ptp_data->lock); - return 0; + return rc; } +/* Write to PTPCLKVAL while PTPCLKADD is 1 */ static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - - mutex_lock(&ptp_data->lock); - timecounter_adjtime(&ptp_data->tstamp_tc, delta); - mutex_unlock(&ptp_data->lock); - - return 0; -} - -static u64 sja1105_ptptsclk_read(const struct cyclecounter *cc) -{ - struct sja1105_ptp_data *ptp_data = cc_to_ptp_data(cc); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - const struct sja1105_regs *regs = priv->info->regs; - u64 ptptsclk = 0; + s64 ticks = ns_to_sja1105_ticks(delta); int rc; - rc = sja1105_xfer_u64(priv, SPI_READ, regs->ptptsclk, &ptptsclk); - if (rc < 0) - dev_err_ratelimited(priv->ds->dev, - "failed to read ptp cycle counter: %d\n", - rc); - return ptptsclk; -} + mutex_lock(&ptp_data->lock); -static void sja1105_ptp_overflow_check(struct work_struct *work) -{ - struct delayed_work *dw = to_delayed_work(work); - struct sja1105_ptp_data *ptp_data = dw_to_ptp_data(dw); - struct timespec64 ts; + rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); + goto out; + } - sja1105_ptp_gettime(&ptp_data->caps, &ts); + rc = sja1105_ptpclkval_write(priv, ticks); - schedule_delayed_work(&ptp_data->refresh_work, - SJA1105_REFRESH_INTERVAL); +out: + mutex_unlock(&ptp_data->lock); + + return rc; } int sja1105_ptp_clock_register(struct dsa_switch *ds) @@ -553,13 +553,6 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) struct sja1105_tagger_data *tagger_data = &priv->tagger_data; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; - /* Set up the cycle counter */ - ptp_data->tstamp_cc = (struct cyclecounter) { - .read = sja1105_ptptsclk_read, - .mask = CYCLECOUNTER_MASK(64), - .shift = SJA1105_CC_SHIFT, - .mult = SJA1105_CC_MULT, - }; ptp_data->caps = (struct ptp_clock_info) { .owner = THIS_MODULE, .name = "SJA1105 PHC", @@ -578,8 +571,8 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) if (IS_ERR_OR_NULL(ptp_data->clock)) return PTR_ERR(ptp_data->clock); - INIT_DELAYED_WORK(&ptp_data->refresh_work, sja1105_ptp_overflow_check); - schedule_delayed_work(&ptp_data->refresh_work, SJA1105_REFRESH_INTERVAL); + ptp_data->cmd.corrclk4ts = true; + ptp_data->cmd.ptpclkadd = PTP_SET_MODE; return sja1105_ptp_reset(ds); } @@ -594,7 +587,6 @@ void sja1105_ptp_clock_unregister(struct dsa_switch *ds) cancel_work_sync(&priv->tagger_data.rxtstamp_work); skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue); - cancel_delayed_work_sync(&ptp_data->refresh_work); ptp_clock_unregister(ptp_data->clock); ptp_data->clock = NULL; } @@ -605,14 +597,19 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, struct sja1105_private *priv = ds->priv; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; struct skb_shared_hwtstamps shwt = {0}; - u64 now, ts; + u64 ticks, ts; int rc; skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; mutex_lock(&ptp_data->lock); - now = ptp_data->tstamp_cc.read(&ptp_data->tstamp_cc); + rc = sja1105_ptpclkval_read(priv, &ticks); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + kfree_skb(skb); + goto out; + } rc = sja1105_ptpegr_ts_poll(ds, slot, &ts); if (rc < 0) { @@ -621,10 +618,9 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, goto out; } - ts = sja1105_tstamp_reconstruct(ds, now, ts); - ts = timecounter_cyc2time(&ptp_data->tstamp_tc, ts); + ts = sja1105_tstamp_reconstruct(ds, ticks, ts); - shwt.hwtstamp = ns_to_ktime(ts); + shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts)); skb_complete_tx_timestamp(skb, &shwt); out: diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 507107ffd6a3..ea80e479dc1c 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -6,21 +6,32 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_PTP) +/* Timestamps are in units of 8 ns clock ticks (equivalent to + * a fixed 125 MHz clock). + */ +#define SJA1105_TICK_NS 8 + +static inline s64 ns_to_sja1105_ticks(s64 ns) +{ + return ns / SJA1105_TICK_NS; +} + +static inline s64 sja1105_ticks_to_ns(s64 ticks) +{ + return ticks * SJA1105_TICK_NS; +} + struct sja1105_ptp_cmd { u64 resptp; /* reset */ + u64 corrclk4ts; /* use the corrected clock for timestamps */ + u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ }; struct sja1105_ptp_data { struct ptp_clock_info caps; struct ptp_clock *clock; struct sja1105_ptp_cmd cmd; - /* The cycle counter translates the PTP timestamps (based on - * a free-running counter) into a software time domain. - */ - struct cyclecounter tstamp_cc; - struct timecounter tstamp_tc; - struct delayed_work refresh_work; - /* Serializes all operations on the cycle counter */ + /* Serializes all operations on the PTP hardware clock */ struct mutex lock; }; diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index e25724d99594..ed02410a9366 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -516,9 +516,8 @@ static struct sja1105_regs sja1105et_regs = { .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, .ptp_control = 0x17, - .ptpclk = 0x18, /* Spans 0x18 to 0x19 */ + .ptpclkval = 0x18, /* Spans 0x18 to 0x19 */ .ptpclkrate = 0x1A, - .ptptsclk = 0x1B, /* Spans 0x1B to 0x1C */ }; static struct sja1105_regs sja1105pqrs_regs = { @@ -547,9 +546,8 @@ static struct sja1105_regs sja1105pqrs_regs = { .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, .ptp_control = 0x18, - .ptpclk = 0x19, + .ptpclkval = 0x19, .ptpclkrate = 0x1B, - .ptptsclk = 0x1C, }; struct sja1105_info sja1105e_info = { -- cgit v1.2.3-59-g8ed1b From f86854a2e76256ee82025f981a5385480eec17b7 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 16 Oct 2019 21:53:31 +0200 Subject: net: phy: avoid NPE if read_page/write_page callbacks are not available Currently there's a bug in the module subsystem [0] preventing load of the PHY driver module on certain systems (as one symptom). This results in a NPE on such systems for the following reason: Instead of the correct PHY driver the genphy driver is loaded that doesn't implement the read_page/write_page callbacks. Every call to phy_read_paged() et al will result in a NPE therefore. In parallel to fixing the root cause we should make sure that this one and maybe similar issues in other subsystems don't result in a NPE in phylib. So let's check for the callbacks before using them and warn once if they are not available. [0] https://marc.info/?t=157072642100001&r=1&w=2 Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 4d96f7a8e8f2..5458ed1b87a8 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -697,11 +697,17 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd); static int __phy_read_page(struct phy_device *phydev) { + if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n")) + return -EOPNOTSUPP; + return phydev->drv->read_page(phydev); } static int __phy_write_page(struct phy_device *phydev, int page) { + if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n")) + return -EOPNOTSUPP; + return phydev->drv->write_page(phydev, page); } -- cgit v1.2.3-59-g8ed1b From 868678c574ecbd09d14331cf3b5418b5b28f7288 Mon Sep 17 00:00:00 2001 From: Danielle Ratson Date: Thu, 17 Oct 2019 09:55:14 +0300 Subject: mlxsw: spectrum: Register switched port analyzers (SPAN) as resource The switch supports an enhanced switched port analyzer that enables selecting network traffic for analysis by a network analyzer. SPAN agents are configured and consumed whenever a tc filter is added with a mirror action to a new destination. The destination can either be a physical port (e.g., swp1), a VLAN device or a gretap. Expose the maximum number of SPAN agents and their current usage to the user. Signed-off-by: Danielle Ratson Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 51 +++++++++++++++++++++- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 3 ++ .../net/ethernet/mellanox/mlxsw/spectrum_span.c | 21 +++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ae3c4da11520..1275d21e8fbd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -5202,14 +5202,61 @@ static int mlxsw_sp2_resources_kvd_register(struct mlxsw_core *mlxsw_core) &kvd_size_params); } +static int mlxsw_sp_resources_span_register(struct mlxsw_core *mlxsw_core) +{ + struct devlink *devlink = priv_to_devlink(mlxsw_core); + struct devlink_resource_size_params span_size_params; + u32 max_span; + + if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_SPAN)) + return -EIO; + + max_span = MLXSW_CORE_RES_GET(mlxsw_core, MAX_SPAN); + devlink_resource_size_params_init(&span_size_params, max_span, max_span, + 1, DEVLINK_RESOURCE_UNIT_ENTRY); + + return devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_SPAN, + max_span, MLXSW_SP_RESOURCE_SPAN, + DEVLINK_RESOURCE_ID_PARENT_TOP, + &span_size_params); +} + static int mlxsw_sp1_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp1_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp1_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp2_resources_register(struct mlxsw_core *mlxsw_core) { - return mlxsw_sp2_resources_kvd_register(mlxsw_core); + int err; + + err = mlxsw_sp2_resources_kvd_register(mlxsw_core); + if (err) + return err; + + err = mlxsw_sp_resources_span_register(mlxsw_core); + if (err) + goto err_resources_span_register; + + return 0; + +err_resources_span_register: + devlink_resources_unregister(priv_to_devlink(mlxsw_core), NULL); + return err; } static int mlxsw_sp_kvd_sizes_get(struct mlxsw_core *mlxsw_core, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8f99d70d6b8b..a5fdd84b4ca7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -48,6 +48,8 @@ #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS "chunks" #define MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS "large_chunks" +#define MLXSW_SP_RESOURCE_NAME_SPAN "span_agents" + enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD = 1, MLXSW_SP_RESOURCE_KVD_LINEAR, @@ -56,6 +58,7 @@ enum mlxsw_sp_resource_id { MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE, MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS, MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS, + MLXSW_SP_RESOURCE_SPAN, }; struct mlxsw_sp_port; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c index 560a60e522f9..200d324e6d99 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c @@ -14,8 +14,23 @@ #include "spectrum_span.h" #include "spectrum_switchdev.h" +static u64 mlxsw_sp_span_occ_get(void *priv) +{ + const struct mlxsw_sp *mlxsw_sp = priv; + u64 occ = 0; + int i; + + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { + if (mlxsw_sp->span.entries[i].ref_count) + occ++; + } + + return occ; +} + int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) @@ -36,13 +51,19 @@ int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) curr->id = i; } + devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN, + mlxsw_sp_span_occ_get, mlxsw_sp); + return 0; } void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) { + struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); int i; + devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN); + for (i = 0; i < mlxsw_sp->span.entries_count; i++) { struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; -- cgit v1.2.3-59-g8ed1b From 3503bf024b3ec6d36ba1fe7a19ad083f058bb95d Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 18 Oct 2019 00:22:31 +0200 Subject: net: lpc_eth: parse phy nodes from device tree When connected to a micrel phy, phy_find_first doesn't work properly because the first phy found is on address 0, the broadcast address but, the first thing the phy driver is doing is disabling this broadcast address. The phy is then available only on address 1 but the mdio driver doesn't know about it. Instead, register the mdio bus using of_mdiobus_register and try to find the phy description in device tree before falling back to phy_find_first. This ultimately also allows to describe the interrupt the phy is connected to. Signed-off-by: Alexandre Belloni Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/nxp/lpc_eth.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c index 141571e2ec11..501782e233b3 100644 --- a/drivers/net/ethernet/nxp/lpc_eth.c +++ b/drivers/net/ethernet/nxp/lpc_eth.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -391,6 +392,7 @@ struct rx_status_t { struct netdata_local { struct platform_device *pdev; struct net_device *ndev; + struct device_node *phy_node; spinlock_t lock; void __iomem *net_base; u32 msg_enable; @@ -749,22 +751,26 @@ static void lpc_handle_link_change(struct net_device *ndev) static int lpc_mii_probe(struct net_device *ndev) { struct netdata_local *pldat = netdev_priv(ndev); - struct phy_device *phydev = phy_find_first(pldat->mii_bus); - - if (!phydev) { - netdev_err(ndev, "no PHY found\n"); - return -ENODEV; - } + struct phy_device *phydev; /* Attach to the PHY */ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII) netdev_info(ndev, "using MII interface\n"); else netdev_info(ndev, "using RMII interface\n"); + + if (pldat->phy_node) + phydev = of_phy_find_device(pldat->phy_node); + else + phydev = phy_find_first(pldat->mii_bus); + if (!phydev) { + netdev_err(ndev, "no PHY found\n"); + return -ENODEV; + } + phydev = phy_connect(ndev, phydev_name(phydev), &lpc_handle_link_change, lpc_phy_interface_mode(&pldat->pdev->dev)); - if (IS_ERR(phydev)) { netdev_err(ndev, "Could not attach to PHY\n"); return PTR_ERR(phydev); @@ -783,6 +789,7 @@ static int lpc_mii_probe(struct net_device *ndev) static int lpc_mii_init(struct netdata_local *pldat) { + struct device_node *node; int err = -ENXIO; pldat->mii_bus = mdiobus_alloc(); @@ -812,7 +819,10 @@ static int lpc_mii_init(struct netdata_local *pldat) platform_set_drvdata(pldat->pdev, pldat->mii_bus); - if (mdiobus_register(pldat->mii_bus)) + node = of_get_child_by_name(pldat->pdev->dev.of_node, "mdio"); + err = of_mdiobus_register(pldat->mii_bus, node); + of_node_put(node); + if (err) goto err_out_unregister_bus; if (lpc_mii_probe(pldat->ndev) != 0) @@ -1345,6 +1355,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev) netdev_dbg(ndev, "DMA buffer V address :0x%p\n", pldat->dma_buff_base_v); + pldat->phy_node = of_parse_phandle(np, "phy-handle", 0); + /* Get MAC address from current HW setting (POR state is all zeros) */ __lpc_get_mac(pldat, ndev->dev_addr); -- cgit v1.2.3-59-g8ed1b From 5f06b903cb0b85194e66675267b565d40a22026c Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:49 +0800 Subject: net: hns3: remove struct hns3_nic_ring_data in hns3_enet module Only the queue_index field in struct hns3_nic_ring_data is used, other field is unused and unnecessary for hns3 driver, so this patch removes it and move the queue_index field to hns3_enet_ring. This patch also removes an unused struct hns_queue declaration. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 24 ++-- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 139 +++++++-------------- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 16 +-- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 33 +++-- 4 files changed, 74 insertions(+), 138 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 28961a68e333..fe5bc6fa8bcd 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -16,15 +16,14 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, const char *cmd_buf) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; struct hns3_enet_ring *ring; u32 base_add_l, base_add_h; u32 queue_num, queue_max; u32 value, i = 0; int cnt; - if (!priv->ring_data) { - dev_err(&h->pdev->dev, "ring_data is NULL\n"); + if (!priv->ring) { + dev_err(&h->pdev->dev, "priv->ring is NULL\n"); return -EFAULT; } @@ -44,7 +43,6 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, return -EINVAL; } - ring_data = priv->ring_data; for (i = queue_num; i < queue_max; i++) { /* Each cycle needs to determine whether the instance is reset, * to prevent reference to invalid memory. And need to ensure @@ -54,7 +52,7 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, test_bit(HNS3_NIC_STATE_RESETTING, &priv->state)) return -EPERM; - ring = ring_data[(u32)(i + h->kinfo.num_tqps)].ring; + ring = &priv->ring[(u32)(i + h->kinfo.num_tqps)]; base_add_h = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + @@ -86,7 +84,7 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, HNS3_RING_RX_RING_PKTNUM_RECORD_REG); dev_info(&h->pdev->dev, "RX(%d) RING PKTNUM: %u\n", i, value); - ring = ring_data[i].ring; + ring = &priv->ring[i]; base_add_h = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + @@ -130,7 +128,6 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, static int hns3_dbg_queue_map(struct hnae3_handle *h) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; int i; if (!h->ae_algo->ops->get_global_queue_id) @@ -143,15 +140,12 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h) u16 global_qid; global_qid = h->ae_algo->ops->get_global_queue_id(h, i); - ring_data = &priv->ring_data[i]; - if (!ring_data || !ring_data->ring || - !ring_data->ring->tqp_vector) + if (!priv->ring || !priv->ring[i].tqp_vector) continue; dev_info(&h->pdev->dev, " %4d %4d %4d\n", - i, global_qid, - ring_data->ring->tqp_vector->vector_irq); + i, global_qid, priv->ring[i].tqp_vector->vector_irq); } return 0; @@ -160,7 +154,6 @@ static int hns3_dbg_queue_map(struct hnae3_handle *h) static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) { struct hns3_nic_priv *priv = h->priv; - struct hns3_nic_ring_data *ring_data; struct hns3_desc *rx_desc, *tx_desc; struct device *dev = &h->pdev->dev; struct hns3_enet_ring *ring; @@ -183,8 +176,7 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) return -EINVAL; } - ring_data = priv->ring_data; - ring = ring_data[q_num].ring; + ring = &priv->ring[q_num]; value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG); tx_index = (cnt == 1) ? value : tx_index; @@ -214,7 +206,7 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) dev_info(dev, "(TX)vld_ra_ri: %u\n", tx_desc->tx.bdtp_fe_sc_vld_ra_ri); dev_info(dev, "(TX)mss: %u\n", tx_desc->tx.mss); - ring = ring_data[q_num + h->kinfo.num_tqps].ring; + ring = &priv->ring[q_num + h->kinfo.num_tqps]; value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG); rx_index = (cnt == 1) ? value : tx_index; rx_desc = &ring->desc[rx_index]; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 6e0b2612d92d..635bddae4a07 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -483,7 +483,7 @@ static void hns3_reset_tx_queue(struct hnae3_handle *h) for (i = 0; i < h->kinfo.num_tqps; i++) { dev_queue = netdev_get_tx_queue(ndev, - priv->ring_data[i].queue_index); + priv->ring[i].queue_index); netdev_tx_reset_queue(dev_queue); } } @@ -1390,9 +1390,7 @@ static int hns3_fill_skb_to_desc(struct hns3_enet_ring *ring, netdev_tx_t hns3_nic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); - struct hns3_nic_ring_data *ring_data = - &tx_ring_data(priv, skb->queue_mapping); - struct hns3_enet_ring *ring = ring_data->ring; + struct hns3_enet_ring *ring = &priv->ring[skb->queue_mapping]; struct netdev_queue *dev_queue; int pre_ntu, next_to_use_head; struct sk_buff *frag_skb; @@ -1444,7 +1442,7 @@ out: cpu_to_le16(BIT(HNS3_TXD_FE_B)); /* Complete translate all packets */ - dev_queue = netdev_get_tx_queue(netdev, ring_data->queue_index); + dev_queue = netdev_get_tx_queue(netdev, ring->queue_index); netdev_tx_sent_queue(dev_queue, skb->len); wmb(); /* Commit all data before submit */ @@ -1461,7 +1459,7 @@ out_err_tx_ok: return NETDEV_TX_OK; out_net_tx_busy: - netif_stop_subqueue(netdev, ring_data->queue_index); + netif_stop_subqueue(netdev, ring->queue_index); smp_mb(); /* Commit all data before submit */ return NETDEV_TX_BUSY; @@ -1584,7 +1582,7 @@ static void hns3_nic_get_stats64(struct net_device *netdev, for (idx = 0; idx < queue_num; idx++) { /* fetch the tx stats */ - ring = priv->ring_data[idx].ring; + ring = &priv->ring[idx]; do { start = u64_stats_fetch_begin_irq(&ring->syncp); tx_bytes += ring->stats.tx_bytes; @@ -1602,7 +1600,7 @@ static void hns3_nic_get_stats64(struct net_device *netdev, } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); /* fetch the rx stats */ - ring = priv->ring_data[idx + queue_num].ring; + ring = &priv->ring[idx + queue_num]; do { start = u64_stats_fetch_begin_irq(&ring->syncp); rx_bytes += ring->stats.rx_bytes; @@ -1807,7 +1805,7 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev) priv->tx_timeout_count++; - tx_ring = priv->ring_data[timeout_queue].ring; + tx_ring = &priv->ring[timeout_queue]; napi = &tx_ring->tqp_vector->napi; netdev_info(ndev, @@ -3484,13 +3482,13 @@ static int hns3_nic_init_vector_data(struct hns3_nic_priv *priv) tqp_vector = &priv->tqp_vector[vector_i]; hns3_add_ring_to_group(&tqp_vector->tx_group, - priv->ring_data[i].ring); + &priv->ring[i]); hns3_add_ring_to_group(&tqp_vector->rx_group, - priv->ring_data[i + tqp_num].ring); + &priv->ring[i + tqp_num]); - priv->ring_data[i].ring->tqp_vector = tqp_vector; - priv->ring_data[i + tqp_num].ring->tqp_vector = tqp_vector; + priv->ring[i].tqp_vector = tqp_vector; + priv->ring[i + tqp_num].tqp_vector = tqp_vector; tqp_vector->num_tqps++; } @@ -3634,28 +3632,22 @@ static int hns3_nic_dealloc_vector_data(struct hns3_nic_priv *priv) return 0; } -static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, - unsigned int ring_type) +static void hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, + unsigned int ring_type) { - struct hns3_nic_ring_data *ring_data = priv->ring_data; int queue_num = priv->ae_handle->kinfo.num_tqps; - struct pci_dev *pdev = priv->ae_handle->pdev; struct hns3_enet_ring *ring; int desc_num; - ring = devm_kzalloc(&pdev->dev, sizeof(*ring), GFP_KERNEL); - if (!ring) - return -ENOMEM; - if (ring_type == HNAE3_RING_TYPE_TX) { + ring = &priv->ring[q->tqp_index]; desc_num = priv->ae_handle->kinfo.num_tx_desc; - ring_data[q->tqp_index].ring = ring; - ring_data[q->tqp_index].queue_index = q->tqp_index; + ring->queue_index = q->tqp_index; ring->io_base = (u8 __iomem *)q->io_base + HNS3_TX_REG_OFFSET; } else { + ring = &priv->ring[q->tqp_index + queue_num]; desc_num = priv->ae_handle->kinfo.num_rx_desc; - ring_data[q->tqp_index + queue_num].ring = ring; - ring_data[q->tqp_index + queue_num].queue_index = q->tqp_index; + ring->queue_index = q->tqp_index; ring->io_base = q->io_base; } @@ -3670,76 +3662,41 @@ static int hns3_ring_get_cfg(struct hnae3_queue *q, struct hns3_nic_priv *priv, ring->desc_num = desc_num; ring->next_to_use = 0; ring->next_to_clean = 0; - - return 0; } -static int hns3_queue_to_ring(struct hnae3_queue *tqp, - struct hns3_nic_priv *priv) +static void hns3_queue_to_ring(struct hnae3_queue *tqp, + struct hns3_nic_priv *priv) { - int ret; - - ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX); - if (ret) - return ret; - - ret = hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX); - if (ret) { - devm_kfree(priv->dev, priv->ring_data[tqp->tqp_index].ring); - return ret; - } - - return 0; + hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_TX); + hns3_ring_get_cfg(tqp, priv, HNAE3_RING_TYPE_RX); } static int hns3_get_ring_config(struct hns3_nic_priv *priv) { struct hnae3_handle *h = priv->ae_handle; struct pci_dev *pdev = h->pdev; - int i, ret; + int i; - priv->ring_data = devm_kzalloc(&pdev->dev, - array3_size(h->kinfo.num_tqps, - sizeof(*priv->ring_data), - 2), - GFP_KERNEL); - if (!priv->ring_data) + priv->ring = devm_kzalloc(&pdev->dev, + array3_size(h->kinfo.num_tqps, + sizeof(*priv->ring), 2), + GFP_KERNEL); + if (!priv->ring) return -ENOMEM; - for (i = 0; i < h->kinfo.num_tqps; i++) { - ret = hns3_queue_to_ring(h->kinfo.tqp[i], priv); - if (ret) - goto err; - } + for (i = 0; i < h->kinfo.num_tqps; i++) + hns3_queue_to_ring(h->kinfo.tqp[i], priv); return 0; -err: - while (i--) { - devm_kfree(priv->dev, priv->ring_data[i].ring); - devm_kfree(priv->dev, - priv->ring_data[i + h->kinfo.num_tqps].ring); - } - - devm_kfree(&pdev->dev, priv->ring_data); - priv->ring_data = NULL; - return ret; } static void hns3_put_ring_config(struct hns3_nic_priv *priv) { - struct hnae3_handle *h = priv->ae_handle; - int i; - - if (!priv->ring_data) + if (!priv->ring) return; - for (i = 0; i < h->kinfo.num_tqps; i++) { - devm_kfree(priv->dev, priv->ring_data[i].ring); - devm_kfree(priv->dev, - priv->ring_data[i + h->kinfo.num_tqps].ring); - } - devm_kfree(priv->dev, priv->ring_data); - priv->ring_data = NULL; + devm_kfree(priv->dev, priv->ring); + priv->ring = NULL; } static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring) @@ -3856,7 +3813,7 @@ static void hns3_init_tx_ring_tc(struct hns3_nic_priv *priv) for (j = 0; j < tc_info->tqp_count; j++) { struct hnae3_queue *q; - q = priv->ring_data[tc_info->tqp_offset + j].ring->tqp; + q = priv->ring[tc_info->tqp_offset + j].tqp; hns3_write_dev(q, HNS3_RING_TX_RING_TC_REG, tc_info->tc); } @@ -3871,21 +3828,21 @@ int hns3_init_all_ring(struct hns3_nic_priv *priv) int ret; for (i = 0; i < ring_num; i++) { - ret = hns3_alloc_ring_memory(priv->ring_data[i].ring); + ret = hns3_alloc_ring_memory(&priv->ring[i]); if (ret) { dev_err(priv->dev, "Alloc ring memory fail! ret=%d\n", ret); goto out_when_alloc_ring_memory; } - u64_stats_init(&priv->ring_data[i].ring->syncp); + u64_stats_init(&priv->ring[i].syncp); } return 0; out_when_alloc_ring_memory: for (j = i - 1; j >= 0; j--) - hns3_fini_ring(priv->ring_data[j].ring); + hns3_fini_ring(&priv->ring[j]); return -ENOMEM; } @@ -3896,8 +3853,8 @@ int hns3_uninit_all_ring(struct hns3_nic_priv *priv) int i; for (i = 0; i < h->kinfo.num_tqps; i++) { - hns3_fini_ring(priv->ring_data[i].ring); - hns3_fini_ring(priv->ring_data[i + h->kinfo.num_tqps].ring); + hns3_fini_ring(&priv->ring[i]); + hns3_fini_ring(&priv->ring[i + h->kinfo.num_tqps]); } return 0; } @@ -4058,7 +4015,7 @@ static int hns3_client_init(struct hnae3_handle *handle) ret = hns3_init_all_ring(priv); if (ret) { ret = -ENOMEM; - goto out_init_ring_data; + goto out_init_ring; } ret = hns3_init_phy(netdev); @@ -4097,12 +4054,12 @@ out_reg_netdev_fail: hns3_uninit_phy(netdev); out_init_phy: hns3_uninit_all_ring(priv); -out_init_ring_data: +out_init_ring: hns3_nic_uninit_vector_data(priv); out_init_vector_data: hns3_nic_dealloc_vector_data(priv); out_alloc_vector_data: - priv->ring_data = NULL; + priv->ring = NULL; out_get_ring_cfg: priv->ae_handle = NULL; free_netdev(netdev); @@ -4309,10 +4266,10 @@ static void hns3_clear_all_ring(struct hnae3_handle *h, bool force) for (i = 0; i < h->kinfo.num_tqps; i++) { struct hns3_enet_ring *ring; - ring = priv->ring_data[i].ring; + ring = &priv->ring[i]; hns3_clear_tx_ring(ring); - ring = priv->ring_data[i + h->kinfo.num_tqps].ring; + ring = &priv->ring[i + h->kinfo.num_tqps]; /* Continue to clear other rings even if clearing some * rings failed. */ @@ -4336,16 +4293,16 @@ int hns3_nic_reset_all_ring(struct hnae3_handle *h) if (ret) return ret; - hns3_init_ring_hw(priv->ring_data[i].ring); + hns3_init_ring_hw(&priv->ring[i]); /* We need to clear tx ring here because self test will * use the ring and will not run down before up */ - hns3_clear_tx_ring(priv->ring_data[i].ring); - priv->ring_data[i].ring->next_to_clean = 0; - priv->ring_data[i].ring->next_to_use = 0; + hns3_clear_tx_ring(&priv->ring[i]); + priv->ring[i].next_to_clean = 0; + priv->ring[i].next_to_use = 0; - rx_ring = priv->ring_data[i + h->kinfo.num_tqps].ring; + rx_ring = &priv->ring[i + h->kinfo.num_tqps]; hns3_init_ring_hw(rx_ring); ret = hns3_clear_rx_ring(rx_ring); if (ret) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index c5b7c22263b1..33222847e149 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -409,6 +409,7 @@ struct hns3_enet_ring { struct hns3_enet_ring *next; struct hns3_enet_tqp_vector *tqp_vector; struct hnae3_queue *tqp; + int queue_index; struct device *dev; /* will be used for DMA mapping of descriptors */ /* statistic */ @@ -436,17 +437,6 @@ struct hns3_enet_ring { struct sk_buff *tail_skb; }; -struct hns_queue; - -struct hns3_nic_ring_data { - struct hns3_enet_ring *ring; - struct napi_struct napi; - int queue_index; - int (*poll_one)(struct hns3_nic_ring_data *, int, void *); - void (*ex_process)(struct hns3_nic_ring_data *, struct sk_buff *); - void (*fini_process)(struct hns3_nic_ring_data *); -}; - enum hns3_flow_level_range { HNS3_FLOW_LOW = 0, HNS3_FLOW_MID = 1, @@ -522,7 +512,7 @@ struct hns3_nic_priv { * the cb for nic to manage the ring buffer, the first half of the * array is for tx_ring and vice versa for the second half */ - struct hns3_nic_ring_data *ring_data; + struct hns3_enet_ring *ring; struct hns3_enet_tqp_vector *tqp_vector; u16 vector_num; @@ -620,8 +610,6 @@ static inline bool hns3_nic_resetting(struct net_device *netdev) #define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \ DMA_TO_DEVICE : DMA_FROM_DEVICE) -#define tx_ring_data(priv, idx) ((priv)->ring_data[idx]) - #define hns3_buf_size(_ring) ((_ring)->buf_size) static inline unsigned int hns3_page_order(struct hns3_enet_ring *ring) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 680c3508876d..50b07b9aafa5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -203,7 +203,7 @@ static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget) kinfo = &h->kinfo; for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) { - struct hns3_enet_ring *ring = priv->ring_data[i].ring; + struct hns3_enet_ring *ring = &priv->ring[i]; struct hns3_enet_ring_group *rx_group; u64 pre_rx_pkt; @@ -226,7 +226,7 @@ static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid, u32 i; for (i = start_ringid; i <= end_ringid; i++) { - struct hns3_enet_ring *ring = priv->ring_data[i].ring; + struct hns3_enet_ring *ring = &priv->ring[i]; hns3_clean_tx_ring(ring); } @@ -491,7 +491,7 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) /* get stats for Tx */ for (i = 0; i < kinfo->num_tqps; i++) { - ring = nic_priv->ring_data[i].ring; + ring = &nic_priv->ring[i]; for (j = 0; j < HNS3_TXQ_STATS_COUNT; j++) { stat = (u8 *)ring + hns3_txq_stats[j].stats_offset; *data++ = *(u64 *)stat; @@ -500,7 +500,7 @@ static u64 *hns3_get_stats_tqps(struct hnae3_handle *handle, u64 *data) /* get stats for Rx */ for (i = 0; i < kinfo->num_tqps; i++) { - ring = nic_priv->ring_data[i + kinfo->num_tqps].ring; + ring = &nic_priv->ring[i + kinfo->num_tqps]; for (j = 0; j < HNS3_RXQ_STATS_COUNT; j++) { stat = (u8 *)ring + hns3_rxq_stats[j].stats_offset; *data++ = *(u64 *)stat; @@ -603,8 +603,8 @@ static void hns3_get_ringparam(struct net_device *netdev, param->tx_max_pending = HNS3_RING_MAX_PENDING; param->rx_max_pending = HNS3_RING_MAX_PENDING; - param->tx_pending = priv->ring_data[0].ring->desc_num; - param->rx_pending = priv->ring_data[queue_num].ring->desc_num; + param->tx_pending = priv->ring[0].desc_num; + param->rx_pending = priv->ring[queue_num].desc_num; } static void hns3_get_pauseparam(struct net_device *netdev, @@ -906,9 +906,8 @@ static void hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv, h->kinfo.num_rx_desc = rx_desc_num; for (i = 0; i < h->kinfo.num_tqps; i++) { - priv->ring_data[i].ring->desc_num = tx_desc_num; - priv->ring_data[i + h->kinfo.num_tqps].ring->desc_num = - rx_desc_num; + priv->ring[i].desc_num = tx_desc_num; + priv->ring[i + h->kinfo.num_tqps].desc_num = rx_desc_num; } } @@ -924,7 +923,7 @@ static struct hns3_enet_ring *hns3_backup_ringparam(struct hns3_nic_priv *priv) return NULL; for (i = 0; i < handle->kinfo.num_tqps * 2; i++) { - memcpy(&tmp_rings[i], priv->ring_data[i].ring, + memcpy(&tmp_rings[i], &priv->ring[i], sizeof(struct hns3_enet_ring)); tmp_rings[i].skb = NULL; } @@ -972,8 +971,8 @@ static int hns3_set_ringparam(struct net_device *ndev, /* Hardware requires that its descriptors must be multiple of eight */ new_tx_desc_num = ALIGN(param->tx_pending, HNS3_RING_BD_MULTIPLE); new_rx_desc_num = ALIGN(param->rx_pending, HNS3_RING_BD_MULTIPLE); - old_tx_desc_num = priv->ring_data[0].ring->desc_num; - old_rx_desc_num = priv->ring_data[queue_num].ring->desc_num; + old_tx_desc_num = priv->ring[0].desc_num; + old_rx_desc_num = priv->ring[queue_num].desc_num; if (old_tx_desc_num == new_tx_desc_num && old_rx_desc_num == new_rx_desc_num) return 0; @@ -1002,7 +1001,7 @@ static int hns3_set_ringparam(struct net_device *ndev, hns3_change_all_ring_bd_num(priv, old_tx_desc_num, old_rx_desc_num); for (i = 0; i < h->kinfo.num_tqps * 2; i++) - memcpy(priv->ring_data[i].ring, &tmp_rings[i], + memcpy(&priv->ring[i], &tmp_rings[i], sizeof(struct hns3_enet_ring)); } else { for (i = 0; i < h->kinfo.num_tqps * 2; i++) @@ -1103,8 +1102,8 @@ static int hns3_get_coalesce_per_queue(struct net_device *netdev, u32 queue, return -EINVAL; } - tx_vector = priv->ring_data[queue].ring->tqp_vector; - rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector; + tx_vector = priv->ring[queue].tqp_vector; + rx_vector = priv->ring[queue_num + queue].tqp_vector; cmd->use_adaptive_tx_coalesce = tx_vector->tx_group.coal.gl_adapt_enable; @@ -1229,8 +1228,8 @@ static void hns3_set_coalesce_per_queue(struct net_device *netdev, struct hnae3_handle *h = priv->ae_handle; int queue_num = h->kinfo.num_tqps; - tx_vector = priv->ring_data[queue].ring->tqp_vector; - rx_vector = priv->ring_data[queue_num + queue].ring->tqp_vector; + tx_vector = priv->ring[queue].tqp_vector; + rx_vector = priv->ring[queue_num + queue].tqp_vector; tx_vector->tx_group.coal.gl_adapt_enable = cmd->use_adaptive_tx_coalesce; -- cgit v1.2.3-59-g8ed1b From 0e02a53d64b470b96739189c015f6d9225c11587 Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Sat, 19 Oct 2019 16:03:50 +0800 Subject: net: hns3: optimized MAC address in management table. mac_addr_hi32 and mac_addr_lo16 are used to store the MAC address for management table. But using array of mac_addr[ETH_ALEN] would be more general and not need to care about the big-endian mode of the CPU. Signed-off-by: Guojia Liao Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 3578832067ff..919911fe02ae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -5,6 +5,7 @@ #define __HCLGE_CMD_H #include #include +#include #define HCLGE_CMDQ_TX_TIMEOUT 30000 @@ -712,8 +713,7 @@ struct hclge_mac_mgr_tbl_entry_cmd { u8 flags; u8 resp_code; __le16 vlan_tag; - __le32 mac_addr_hi32; - __le16 mac_addr_lo16; + u8 mac_addr[ETH_ALEN]; __le16 rsv1; __le16 ethter_type; __le16 egress_port; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 2f0386dcb2f6..ad8e1797eb04 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -325,8 +325,7 @@ static const struct hclge_mac_mgr_tbl_entry_cmd hclge_mgr_table[] = { { .flags = HCLGE_MAC_MGR_MASK_VLAN_B, .ethter_type = cpu_to_le16(ETH_P_LLDP), - .mac_addr_hi32 = cpu_to_le32(htonl(0x0180C200)), - .mac_addr_lo16 = cpu_to_le16(htons(0x000E)), + .mac_addr = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}, .i_port_bitmap = 0x1, }, }; -- cgit v1.2.3-59-g8ed1b From 88b7c58c199dd231fd87703f4a6209eec60ab138 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:51 +0800 Subject: net: hns3: minor optimization for barrier in IO path Currently, the TX and RX ring in a queue is bounded to the same IRQ, there may be unnecessary barrier op when only one of the ring need to be processed. This patch adjusts the location of rmb() in hns3_clean_tx_ring() and adds a checking in hns3_clean_rx_ring() to avoid unnecessary barrier op when there is nothing to do for the ring. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 635bddae4a07..089cd58275a2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2485,11 +2485,12 @@ void hns3_clean_tx_ring(struct hns3_enet_ring *ring) int head; head = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_HEAD_REG); - rmb(); /* Make sure head is ready before touch any data */ if (is_ring_empty(ring) || head == ring->next_to_clean) return; /* no data to poll */ + rmb(); /* Make sure head is ready before touch any data */ + if (unlikely(!is_valid_clean_head(ring, head))) { netdev_err(netdev, "wrong head (%d, %d-%d)\n", head, ring->next_to_use, ring->next_to_clean); @@ -3105,11 +3106,14 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, int err, num; num = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG); - rmb(); /* Make sure num taken effect before the other data is touched */ - num -= unused_count; unused_count -= ring->pending_buf; + if (num <= 0) + goto out; + + rmb(); /* Make sure num taken effect before the other data is touched */ + while (recv_pkts < budget && recv_bds < num) { /* Reuse or realloc buffers */ if (unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) { -- cgit v1.2.3-59-g8ed1b From c871195601793118ab081d82f7ddd987aa6c7da1 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:52 +0800 Subject: net: hns3: introduce ring_to_netdev() in enet module There are a few places that need to access the netdev of a ring through ring->tqp->handle->kinfo.netdev, and ring->tqp is a struct which both in enet and hclge modules, it is better to use the struct that is only used in enet module. This patch adds the ring_to_netdev() to access the netdev of ring through ring->tqp_vector->napi.dev. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 14 +++++++------- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 089cd58275a2..422fa4d6745e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2478,7 +2478,7 @@ static int is_valid_clean_head(struct hns3_enet_ring *ring, int h) void hns3_clean_tx_ring(struct hns3_enet_ring *ring) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); struct hns3_nic_priv *priv = netdev_priv(netdev); struct netdev_queue *dev_queue; int bytes, pkts; @@ -2560,7 +2560,7 @@ static void hns3_nic_alloc_rx_buffers(struct hns3_enet_ring *ring, ring->stats.sw_err_cnt++; u64_stats_update_end(&ring->syncp); - hns3_rl_err(ring->tqp_vector->napi.dev, + hns3_rl_err(ring_to_netdev(ring), "alloc rx buffer failed: %d\n", ret); break; @@ -2669,7 +2669,7 @@ static int hns3_gro_complete(struct sk_buff *skb, u32 l234info) static void hns3_rx_checksum(struct hns3_enet_ring *ring, struct sk_buff *skb, u32 l234info, u32 bd_base_info, u32 ol_info) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); int l3_type, l4_type; int ol4_type; @@ -2785,7 +2785,7 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, { #define HNS3_NEED_ADD_FRAG 1 struct hns3_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_clean]; - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); struct sk_buff *skb; ring->skb = napi_alloc_skb(&ring->tqp_vector->napi, HNS3_RX_HEAD_SIZE); @@ -2866,7 +2866,7 @@ static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc, new_skb = napi_alloc_skb(&ring->tqp_vector->napi, HNS3_RX_HEAD_SIZE); if (unlikely(!new_skb)) { - hns3_rl_err(ring->tqp_vector->napi.dev, + hns3_rl_err(ring_to_netdev(ring), "alloc rx fraglist skb fail\n"); return -ENXIO; } @@ -2942,7 +2942,7 @@ static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring, static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) { - struct net_device *netdev = ring->tqp->handle->kinfo.netdev; + struct net_device *netdev = ring_to_netdev(ring); enum hns3_pkt_l2t_type l2_frame_type; u32 bd_base_info, l234info, ol_info; struct hns3_desc *desc; @@ -4224,7 +4224,7 @@ static int hns3_clear_rx_ring(struct hns3_enet_ring *ring) /* if alloc new buffer fail, exit directly * and reclear in up flow. */ - netdev_warn(ring->tqp->handle->kinfo.netdev, + netdev_warn(ring_to_netdev(ring), "reserve buffer map failed, ret = %d\n", ret); return ret; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 33222847e149..8a88002313fe 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -607,6 +607,8 @@ static inline bool hns3_nic_resetting(struct net_device *netdev) #define ring_to_dev(ring) ((ring)->dev) +#define ring_to_netdev(ring) ((ring)->tqp_vector->napi.dev) + #define ring_to_dma_dir(ring) (HNAE3_IS_TX_RING(ring) ? \ DMA_TO_DEVICE : DMA_FROM_DEVICE) -- cgit v1.2.3-59-g8ed1b From 76643555a145b06ec6dcc0d1cc0691575dceffc9 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:53 +0800 Subject: net: hns3: make struct hns3_enet_ring cacheline aligned Since struct hns3_enet_ring is a frequently used in critical data path, so make it cacheline aligned as struct hns3_enet_tqp_vector. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 8a88002313fe..0725dc52341e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -435,7 +435,7 @@ struct hns3_enet_ring { int pending_buf; struct sk_buff *skb; struct sk_buff *tail_skb; -}; +} ____cacheline_internodealigned_in_smp; enum hns3_flow_level_range { HNS3_FLOW_LOW = 0, -- cgit v1.2.3-59-g8ed1b From d35bced88f7043bee42df795cb7a0d5a8e99248c Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:54 +0800 Subject: net: hns3: minor cleanup for hns3_handle_rx_bd() Since commit e55970950556 ("net: hns3: Add handling of GRO Pkts not fully RX'ed in NAPI poll"), ring->skb is used to record the current SKB when processing the RX BD in hns3_handle_rx_bd(), so the parameter out_skb is unnecessary. This patch also adjusts the err checking to reduce duplication in hns3_handle_rx_bd(), and "err == -ENXIO" is rare case, so put it in the unlikely annotation. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 38 +++++++++---------------- 1 file changed, 13 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 422fa4d6745e..1c5e0d2a9181 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2831,10 +2831,10 @@ static int hns3_alloc_skb(struct hns3_enet_ring *ring, unsigned int length, } static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc, - struct sk_buff **out_skb, bool pending) + bool pending) { - struct sk_buff *skb = *out_skb; - struct sk_buff *head_skb = *out_skb; + struct sk_buff *skb = ring->skb; + struct sk_buff *head_skb = skb; struct sk_buff *new_skb; struct hns3_desc_cb *desc_cb; struct hns3_desc *pre_desc; @@ -3017,8 +3017,7 @@ static int hns3_handle_bdinfo(struct hns3_enet_ring *ring, struct sk_buff *skb) return 0; } -static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, - struct sk_buff **out_skb) +static int hns3_handle_rx_bd(struct hns3_enet_ring *ring) { struct sk_buff *skb = ring->skb; struct hns3_desc_cb *desc_cb; @@ -3056,12 +3055,12 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, if (!skb) { ret = hns3_alloc_skb(ring, length, ring->va); - *out_skb = skb = ring->skb; + skb = ring->skb; if (ret < 0) /* alloc buffer fail */ return ret; if (ret > 0) { /* need add frag */ - ret = hns3_add_frag(ring, desc, &skb, false); + ret = hns3_add_frag(ring, desc, false); if (ret) return ret; @@ -3072,7 +3071,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, ALIGN(ring->pull_len, sizeof(long))); } } else { - ret = hns3_add_frag(ring, desc, &skb, true); + ret = hns3_add_frag(ring, desc, true); if (ret) return ret; @@ -3090,8 +3089,6 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, } skb_record_rx_queue(skb, ring->tqp->tqp_index); - *out_skb = skb; - return 0; } @@ -3100,7 +3097,6 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, { #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 int unused_count = hns3_desc_unused(ring); - struct sk_buff *skb = ring->skb; int recv_pkts = 0; int recv_bds = 0; int err, num; @@ -3123,27 +3119,19 @@ int hns3_clean_rx_ring(struct hns3_enet_ring *ring, int budget, } /* Poll one pkt */ - err = hns3_handle_rx_bd(ring, &skb); - if (unlikely(!skb)) /* This fault cannot be repaired */ + err = hns3_handle_rx_bd(ring); + /* Do not get FE for the packet or failed to alloc skb */ + if (unlikely(!ring->skb || err == -ENXIO)) { goto out; - - if (err == -ENXIO) { /* Do not get FE for the packet */ - goto out; - } else if (unlikely(err)) { /* Do jump the err */ - recv_bds += ring->pending_buf; - unused_count += ring->pending_buf; - ring->skb = NULL; - ring->pending_buf = 0; - continue; + } else if (likely(!err)) { + rx_fn(ring, ring->skb); + recv_pkts++; } - rx_fn(ring, skb); recv_bds += ring->pending_buf; unused_count += ring->pending_buf; ring->skb = NULL; ring->pending_buf = 0; - - recv_pkts++; } out: -- cgit v1.2.3-59-g8ed1b From 7fda3a930d15a993389018e31532f3a1e34974ab Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Sat, 19 Oct 2019 16:03:55 +0800 Subject: net: hns3: do not allocate linear data for fraglist skb Currently, napi_alloc_skb() is used to allocate skb for fraglist when the head skb is not enough to hold the remaining data, and the remaining data is added to the frags part of the fraglist skb, leaving the linear part unused. So this patch passes length of 0 to allocate fraglist skb with zero size of linear data. Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 1c5e0d2a9181..0fdd684a8524 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2863,8 +2863,7 @@ static int hns3_add_frag(struct hns3_enet_ring *ring, struct hns3_desc *desc, return -ENXIO; if (unlikely(ring->frag_num >= MAX_SKB_FRAGS)) { - new_skb = napi_alloc_skb(&ring->tqp_vector->napi, - HNS3_RX_HEAD_SIZE); + new_skb = napi_alloc_skb(&ring->tqp_vector->napi, 0); if (unlikely(!new_skb)) { hns3_rl_err(ring_to_netdev(ring), "alloc rx fraglist skb fail\n"); -- cgit v1.2.3-59-g8ed1b From 4fdd0bca6152aa201898454e63cbb255a18ae6e9 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Sat, 19 Oct 2019 16:03:56 +0800 Subject: net: hns3: log and clear hardware error after reset complete When device is resetting, the CMDQ service may be stopped until reset completed. If a new RAS error occurs at this moment, it will no be able to clear the RAS source. This patch fixes it by clear the RAS source after reset complete. Signed-off-by: Jian Shen Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ad8e1797eb04..bf6bca26c337 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -9800,6 +9800,9 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } + /* Log and clear the hw errors those already occurred */ + hclge_handle_all_hns_hw_errors(ae_dev); + /* Re-enable the hw error interrupts because * the interrupts get disabled on global reset. */ -- cgit v1.2.3-59-g8ed1b From 0ac960a8e135c902cb526903ff2ec457dfabf1b4 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 11 Sep 2019 11:17:58 +0300 Subject: igc: Add SCTP CRC checksumming functionality Add stream control transmission protocol CRC checksum. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 63b62d74f961..69e70b297e85 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4211,6 +4211,7 @@ static int igc_probe(struct pci_dev *pdev, /* Add supported features to the features list*/ netdev->features |= NETIF_F_HW_CSUM; + netdev->features |= NETIF_F_SCTP_CRC; /* setup the private structure */ err = igc_sw_init(adapter); -- cgit v1.2.3-59-g8ed1b From f15bb6dde738cc8fa00c24fb89b5456ea3342879 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Mon, 16 Sep 2019 09:52:40 +0300 Subject: e1000e: Add support for S0ix Implement flow for S0ix support. Modern SoCs support S0ix low power states during idle periods, which are sub-states of ACPI S0 that increase power saving while supporting an instant-on experience for providing lower latency that ACPI S0. The S0ix states shut off parts of the SoC when they are not in use, while still maintaning optimal performance. This patch add support for S0ix started from an Ice Lake platform. Suggested-by: "Rafael J. Wysocki" Signed-off-by: Vitaly Lifshits Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 182 +++++++++++++++++++++++++++++ drivers/net/ethernet/intel/e1000e/regs.h | 4 + 2 files changed, 186 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index d7d56e42a6aa..42f57ab8fb8e 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6294,6 +6294,174 @@ fl_out: pm_runtime_put_sync(netdev->dev.parent); } +/* S0ix implementation */ +static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 mac_data; + u16 phy_data; + + /* Disable the periodic inband message, + * don't request PCIe clock in K1 page770_17[10:9] = 10b + */ + e1e_rphy(hw, HV_PM_CTRL, &phy_data); + phy_data &= ~HV_PM_CTRL_K1_CLK_REQ; + phy_data |= BIT(10); + e1e_wphy(hw, HV_PM_CTRL, phy_data); + + /* Make sure we don't exit K1 every time a new packet arrives + * 772_29[5] = 1 CS_Mode_Stay_In_K1 + */ + e1e_rphy(hw, I217_CGFREG, &phy_data); + phy_data |= BIT(5); + e1e_wphy(hw, I217_CGFREG, phy_data); + + /* Change the MAC/PHY interface to SMBus + * Force the SMBus in PHY page769_23[0] = 1 + * Force the SMBus in MAC CTRL_EXT[11] = 1 + */ + e1e_rphy(hw, CV_SMB_CTRL, &phy_data); + phy_data |= CV_SMB_CTRL_FORCE_SMBUS; + e1e_wphy(hw, CV_SMB_CTRL, phy_data); + mac_data = er32(CTRL_EXT); + mac_data |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_data); + + /* DFT control: PHY bit: page769_20[0] = 1 + * Gate PPW via EXTCNF_CTRL - set 0x0F00[7] = 1 + */ + e1e_rphy(hw, I82579_DFT_CTRL, &phy_data); + phy_data |= BIT(0); + e1e_wphy(hw, I82579_DFT_CTRL, phy_data); + + mac_data = er32(EXTCNF_CTRL); + mac_data |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; + ew32(EXTCNF_CTRL, mac_data); + + /* Check MAC Tx/Rx packet buffer pointers. + * Reset MAC Tx/Rx packet buffer pointers to suppress any + * pending traffic indication that would prevent power gating. + */ + mac_data = er32(TDFH); + if (mac_data) + ew32(TDFH, 0); + mac_data = er32(TDFT); + if (mac_data) + ew32(TDFT, 0); + mac_data = er32(TDFHS); + if (mac_data) + ew32(TDFHS, 0); + mac_data = er32(TDFTS); + if (mac_data) + ew32(TDFTS, 0); + mac_data = er32(TDFPC); + if (mac_data) + ew32(TDFPC, 0); + mac_data = er32(RDFH); + if (mac_data) + ew32(RDFH, 0); + mac_data = er32(RDFT); + if (mac_data) + ew32(RDFT, 0); + mac_data = er32(RDFHS); + if (mac_data) + ew32(RDFHS, 0); + mac_data = er32(RDFTS); + if (mac_data) + ew32(RDFTS, 0); + mac_data = er32(RDFPC); + if (mac_data) + ew32(RDFPC, 0); + + /* Enable the Dynamic Power Gating in the MAC */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(22); + ew32(FEXTNVM7, mac_data); + + /* Disable the time synchronization clock */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(31); + mac_data &= ~BIT(0); + ew32(FEXTNVM7, mac_data); + + /* Dynamic Power Gating Enable */ + mac_data = er32(CTRL_EXT); + mac_data |= BIT(3); + ew32(CTRL_EXT, mac_data); + + /* Enable the Dynamic Clock Gating in the DMA and MAC */ + mac_data = er32(CTRL_EXT); + mac_data |= E1000_CTRL_EXT_DMA_DYN_CLK_EN; + ew32(CTRL_EXT, mac_data); + + /* No MAC DPG gating SLP_S0 in modern standby + * Switch the logic of the lanphypc to use PMC counter + */ + mac_data = er32(FEXTNVM5); + mac_data |= BIT(7); + ew32(FEXTNVM5, mac_data); +} + +static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 mac_data; + u16 phy_data; + + /* Disable the Dynamic Power Gating in the MAC */ + mac_data = er32(FEXTNVM7); + mac_data &= 0xFFBFFFFF; + ew32(FEXTNVM7, mac_data); + + /* Enable the time synchronization clock */ + mac_data = er32(FEXTNVM7); + mac_data |= BIT(0); + ew32(FEXTNVM7, mac_data); + + /* Disable Dynamic Power Gating */ + mac_data = er32(CTRL_EXT); + mac_data &= 0xFFFFFFF7; + ew32(CTRL_EXT, mac_data); + + /* Disable the Dynamic Clock Gating in the DMA and MAC */ + mac_data = er32(CTRL_EXT); + mac_data &= 0xFFF7FFFF; + ew32(CTRL_EXT, mac_data); + + /* Revert the lanphypc logic to use the internal Gbe counter + * and not the PMC counter + */ + mac_data = er32(FEXTNVM5); + mac_data &= 0xFFFFFF7F; + ew32(FEXTNVM5, mac_data); + + /* Enable the periodic inband message, + * Request PCIe clock in K1 page770_17[10:9] =01b + */ + e1e_rphy(hw, HV_PM_CTRL, &phy_data); + phy_data &= 0xFBFF; + phy_data |= HV_PM_CTRL_K1_CLK_REQ; + e1e_wphy(hw, HV_PM_CTRL, phy_data); + + /* Return back configuration + * 772_29[5] = 0 CS_Mode_Stay_In_K1 + */ + e1e_rphy(hw, I217_CGFREG, &phy_data); + phy_data &= 0xFFDF; + e1e_wphy(hw, I217_CGFREG, phy_data); + + /* Change the MAC/PHY interface to Kumeran + * Unforce the SMBus in PHY page769_23[0] = 0 + * Unforce the SMBus in MAC CTRL_EXT[11] = 0 + */ + e1e_rphy(hw, CV_SMB_CTRL, &phy_data); + phy_data &= ~CV_SMB_CTRL_FORCE_SMBUS; + e1e_wphy(hw, CV_SMB_CTRL, phy_data); + mac_data = er32(CTRL_EXT); + mac_data &= ~E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_data); +} + static int e1000e_pm_freeze(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); @@ -6649,7 +6817,10 @@ static int e1000e_pm_thaw(struct device *dev) static int e1000e_pm_suspend(struct device *dev) { + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); + struct e1000_hw *hw = &adapter->hw; int rc; e1000e_flush_lpic(pdev); @@ -6660,14 +6831,25 @@ static int e1000e_pm_suspend(struct device *dev) if (rc) e1000e_pm_thaw(dev); + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp) + e1000e_s0ix_entry_flow(adapter); + return rc; } static int e1000e_pm_resume(struct device *dev) { + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); struct pci_dev *pdev = to_pci_dev(dev); + struct e1000_hw *hw = &adapter->hw; int rc; + /* Introduce S0ix implementation */ + if (hw->mac.type >= e1000_pch_cnp) + e1000e_s0ix_exit_flow(adapter); + rc = __e1000_resume(pdev); if (rc) return rc; diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index 47f5ca793970..df59fd1d660c 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -18,6 +18,7 @@ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM5 0x00014 /* Future Extended NVM 5 - RW */ #define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FEXTNVM7 0x000E4 /* Future Extended NVM 7 - RW */ #define E1000_FEXTNVM9 0x5BB4 /* Future Extended NVM 9 - RW */ @@ -234,4 +235,7 @@ #define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ #define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ +/* PHY registers */ +#define I82579_DFT_CTRL PHY_REG(769, 20) + #endif -- cgit v1.2.3-59-g8ed1b From 7f839684c5c42f1d36ee0eb21ba751c7b51fa928 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 25 Sep 2019 11:58:53 +0300 Subject: igc: Add set_rx_mode support Add multicast addresses list to the MTA table. Implement basic Rx mode support. Add option for IPv6 address settings. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_defines.h | 3 + drivers/net/ethernet/intel/igc/igc_hw.h | 1 + drivers/net/ethernet/intel/igc/igc_mac.c | 104 +++++++++++++++ drivers/net/ethernet/intel/igc/igc_mac.h | 2 + drivers/net/ethernet/intel/igc/igc_main.c | 181 +++++++++++++++++++++++++++ 5 files changed, 291 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index f3f2325fe567..03f1aca3f57f 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -402,4 +402,7 @@ #define IGC_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet Type of TCP */ #define IGC_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ +/* Maximum size of the MTA register table in all supported adapters */ +#define MAX_MTA_REG 128 + #endif /* _IGC_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h index abb2d72911ff..20f710645746 100644 --- a/drivers/net/ethernet/intel/igc/igc_hw.h +++ b/drivers/net/ethernet/intel/igc/igc_hw.h @@ -91,6 +91,7 @@ struct igc_mac_info { u16 mta_reg_count; u16 uta_reg_count; + u32 mta_shadow[MAX_MTA_REG]; u16 rar_entry_count; u8 forced_speed_duplex; diff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c index 5eeb4c8caf4a..12aa6b5fcb5d 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.c +++ b/drivers/net/ethernet/intel/igc/igc_mac.c @@ -784,3 +784,107 @@ bool igc_enable_mng_pass_thru(struct igc_hw *hw) out: return ret_val; } + +/** + * igc_hash_mc_addr - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * igc_mta_set() + **/ +static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. + */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + * + * For example, given the following Destination MAC Address and an + * MTA register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16)mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * igc_update_mc_addr_list - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * + * Updates entire Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + **/ +void igc_update_mc_addr_list(struct igc_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count) +{ + u32 hash_value, hash_bit, hash_reg; + int i; + + /* clear mta_shadow */ + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + + /* update mta_shadow from mc_addr_list */ + for (i = 0; (u32)i < mc_addr_count; i++) { + hash_value = igc_hash_mc_addr(hw, mc_addr_list); + + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + hw->mac.mta_shadow[hash_reg] |= BIT(hash_bit); + mc_addr_list += ETH_ALEN; + } + + /* replace the entire MTA table */ + for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) + array_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]); + wrfl(); +} diff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h index 782bc995badc..832cccec87cd 100644 --- a/drivers/net/ethernet/intel/igc/igc_mac.h +++ b/drivers/net/ethernet/intel/igc/igc_mac.h @@ -29,6 +29,8 @@ s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed, u16 *duplex); bool igc_enable_mng_pass_thru(struct igc_hw *hw); +void igc_update_mc_addr_list(struct igc_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count); enum igc_mng_mode { igc_mng_mode_none = 0, diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 69e70b297e85..7d2f479b57cf 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -795,6 +795,44 @@ static int igc_set_mac(struct net_device *netdev, void *p) return 0; } +/** + * igc_write_mc_addr_list - write multicast addresses to MTA + * @netdev: network interface device structure + * + * Writes multicast address list to the MTA hash table. + * Returns: -ENOMEM on failure + * 0 on no addresses written + * X on writing X addresses to MTA + **/ +static int igc_write_mc_addr_list(struct net_device *netdev) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + struct netdev_hw_addr *ha; + u8 *mta_list; + int i; + + if (netdev_mc_empty(netdev)) { + /* nothing to program, so clear mc list */ + igc_update_mc_addr_list(hw, NULL, 0); + return 0; + } + + mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); + if (!mta_list) + return -ENOMEM; + + /* The shared function expects a packed array of only addresses. */ + i = 0; + netdev_for_each_mc_addr(ha, netdev) + memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN); + + igc_update_mc_addr_list(hw, mta_list, i); + kfree(mta_list); + + return netdev_mc_count(netdev); +} + static void igc_tx_ctxtdesc(struct igc_ring *tx_ring, struct igc_tx_buffer *first, u32 vlan_macip_lens, u32 type_tucmd, @@ -2518,6 +2556,110 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, IGC_MAC_STATE_QUEUE_STEERING | flags); } +/* Add a MAC filter for 'addr' directing matching traffic to 'queue', + * 'flags' is used to indicate what kind of match is made, match is by + * default for the destination address, if matching by source address + * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_add_mac_filter(struct igc_adapter *adapter, + const u8 *addr, const u8 queue) +{ + struct igc_hw *hw = &adapter->hw; + int rar_entries = hw->mac.rar_entry_count; + int i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + /* Search for the first empty entry in the MAC table. + * Do not touch entries at the end of the table reserved for the VF MAC + * addresses. + */ + for (i = 0; i < rar_entries; i++) { + if (!igc_mac_entry_can_be_used(&adapter->mac_table[i], + addr, 0)) + continue; + + ether_addr_copy(adapter->mac_table[i].addr, addr); + adapter->mac_table[i].queue = queue; + adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE; + + igc_rar_set_index(adapter, i); + return i; + } + + return -ENOSPC; +} + +/* Remove a MAC filter for 'addr' directing matching traffic to + * 'queue', 'flags' is used to indicate what kind of match need to be + * removed, match is by default for the destination address, if + * matching by source address is to be removed the flag + * IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_del_mac_filter(struct igc_adapter *adapter, + const u8 *addr, const u8 queue) +{ + struct igc_hw *hw = &adapter->hw; + int rar_entries = hw->mac.rar_entry_count; + int i; + + if (is_zero_ether_addr(addr)) + return -EINVAL; + + /* Search for matching entry in the MAC table based on given address + * and queue. Do not touch entries at the end of the table reserved + * for the VF MAC addresses. + */ + for (i = 0; i < rar_entries; i++) { + if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE)) + continue; + if (adapter->mac_table[i].state != 0) + continue; + if (adapter->mac_table[i].queue != queue) + continue; + if (!ether_addr_equal(adapter->mac_table[i].addr, addr)) + continue; + + /* When a filter for the default address is "deleted", + * we return it to its initial configuration + */ + if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) { + adapter->mac_table[i].state = + IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; + adapter->mac_table[i].queue = 0; + } else { + adapter->mac_table[i].state = 0; + adapter->mac_table[i].queue = 0; + memset(adapter->mac_table[i].addr, 0, ETH_ALEN); + } + + igc_rar_set_index(adapter, i); + return 0; + } + + return -ENOENT; +} + +static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + int ret; + + ret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues); + + return min_t(int, ret, 0); +} + +static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) +{ + struct igc_adapter *adapter = netdev_priv(netdev); + + igc_del_mac_filter(adapter, addr, adapter->num_rx_queues); + + return 0; +} + /** * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure @@ -2529,6 +2671,44 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter, */ static void igc_set_rx_mode(struct net_device *netdev) { + struct igc_adapter *adapter = netdev_priv(netdev); + struct igc_hw *hw = &adapter->hw; + u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE; + int count; + + /* Check for Promiscuous and All Multicast modes */ + if (netdev->flags & IFF_PROMISC) { + rctl |= IGC_RCTL_UPE | IGC_RCTL_MPE; + } else { + if (netdev->flags & IFF_ALLMULTI) { + rctl |= IGC_RCTL_MPE; + } else { + /* Write addresses to the MTA, if the attempt fails + * then we should just turn on promiscuous mode so + * that we can at least receive multicast traffic + */ + count = igc_write_mc_addr_list(netdev); + if (count < 0) + rctl |= IGC_RCTL_MPE; + } + } + + /* Write addresses to available RAR registers, if there is not + * sufficient space to store all the addresses then enable + * unicast promiscuous mode + */ + if (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync)) + rctl |= IGC_RCTL_UPE; + + /* update state of unicast and multicast */ + rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE); + wr32(IGC_RCTL, rctl); + +#if (PAGE_SIZE < 8192) + if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB) + rlpml = IGC_MAX_FRAME_BUILD_SKB; +#endif + wr32(IGC_RLPML, rlpml); } /** @@ -3982,6 +4162,7 @@ static const struct net_device_ops igc_netdev_ops = { .ndo_open = igc_open, .ndo_stop = igc_close, .ndo_start_xmit = igc_xmit_frame, + .ndo_set_rx_mode = igc_set_rx_mode, .ndo_set_mac_address = igc_set_mac, .ndo_change_mtu = igc_change_mtu, .ndo_get_stats = igc_get_stats, -- cgit v1.2.3-59-g8ed1b From 3bdd7086f77757314256e8d0a273b8935106d649 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 3 Oct 2019 13:43:05 +0300 Subject: igc: Add Rx checksum support Extend the socket buffer field process and add Rx checksum functionality Minor: fix indentation with tab instead of spaces. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc_defines.h | 5 +++- drivers/net/ethernet/intel/igc/igc_main.c | 43 ++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index 03f1aca3f57f..f3788f0b95b4 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -282,7 +282,10 @@ #define IGC_RCTL_BAM 0x00008000 /* broadcast enable */ /* Receive Descriptor bit definitions */ -#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IGC_RXD_STAT_EOP 0x02 /* End of Packet */ +#define IGC_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define IGC_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ +#define IGC_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ #define IGC_RXDEXT_STATERR_CE 0x01000000 #define IGC_RXDEXT_STATERR_SE 0x02000000 diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 7d2f479b57cf..a16c657a1506 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -1201,6 +1201,46 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb, return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb)); } +static void igc_rx_checksum(struct igc_ring *ring, + union igc_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + skb_checksum_none_assert(skb); + + /* Ignore Checksum bit is set */ + if (igc_test_staterr(rx_desc, IGC_RXD_STAT_IXSM)) + return; + + /* Rx checksum disabled via ethtool */ + if (!(ring->netdev->features & NETIF_F_RXCSUM)) + return; + + /* TCP/UDP checksum error bit is set */ + if (igc_test_staterr(rx_desc, + IGC_RXDEXT_STATERR_TCPE | + IGC_RXDEXT_STATERR_IPE)) { + /* work around errata with sctp packets where the TCPE aka + * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) + * packets (aka let the stack check the crc32c) + */ + if (!(skb->len == 60 && + test_bit(IGC_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) { + u64_stats_update_begin(&ring->rx_syncp); + ring->rx_stats.csum_err++; + u64_stats_update_end(&ring->rx_syncp); + } + /* let the stack verify checksum errors */ + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (igc_test_staterr(rx_desc, IGC_RXD_STAT_TCPCS | + IGC_RXD_STAT_UDPCS)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + dev_dbg(ring->dev, "cksum success: bits %08X\n", + le32_to_cpu(rx_desc->wb.upper.status_error)); +} + static inline void igc_rx_hash(struct igc_ring *ring, union igc_adv_rx_desc *rx_desc, struct sk_buff *skb) @@ -1227,6 +1267,8 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring, { igc_rx_hash(rx_ring, rx_desc, skb); + igc_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); @@ -4391,6 +4433,7 @@ static int igc_probe(struct pci_dev *pdev, goto err_sw_init; /* Add supported features to the features list*/ + netdev->features |= NETIF_F_RXCSUM; netdev->features |= NETIF_F_HW_CSUM; netdev->features |= NETIF_F_SCTP_CRC; -- cgit v1.2.3-59-g8ed1b From 70332577e4d9ee343a7d57a7721c858172e5925c Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 3 Oct 2019 14:47:01 +0300 Subject: igc: Clean up unused shadow_vfta pointer VLAN filter table array not implemented yet and shadow_vfta pointer not used. Clean up the code and remove the unused shadow_vfta pointer. Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igc/igc.h | 1 - drivers/net/ethernet/intel/igc/igc_main.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 7e16345d836e..0868677d43ed 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -411,7 +411,6 @@ struct igc_adapter { u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_skipped; u32 rx_hwtstamp_cleared; - u32 *shadow_vfta; u32 rss_queues; u32 rss_indir_tbl_init; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index a16c657a1506..6e0af464326e 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -4573,7 +4573,6 @@ static void igc_remove(struct pci_dev *pdev) pci_release_mem_regions(pdev); kfree(adapter->mac_table); - kfree(adapter->shadow_vfta); free_netdev(netdev); pci_disable_pcie_error_reporting(pdev); -- cgit v1.2.3-59-g8ed1b From ff519e2acd463bff6c5bb4e8d7ed350c9bae885b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:21 +0200 Subject: net: mvneta: introduce mvneta_update_stats routine Introduce mvneta_update_stats routine to collect {rx/tx} statistics (packets and bytes). This is a preliminary patch to add XDP support to mvneta driver Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 43 ++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e49820675c8c..3a8110d0a5b6 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1900,6 +1900,23 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, } } +static void +mvneta_update_stats(struct mvneta_port *pp, u32 pkts, + u32 len, bool tx) +{ + struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); + + u64_stats_update_begin(&stats->syncp); + if (tx) { + stats->tx_packets += pkts; + stats->tx_bytes += len; + } else { + stats->rx_packets += pkts; + stats->rx_bytes += len; + } + u64_stats_update_end(&stats->syncp); +} + static inline int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) { @@ -2075,14 +2092,8 @@ static int mvneta_rx_swbm(struct napi_struct *napi, rxq->left_size = 0; } - if (rcvd_pkts) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets += rcvd_pkts; - stats->rx_bytes += rcvd_bytes; - u64_stats_update_end(&stats->syncp); - } + if (rcvd_pkts) + mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); /* return some buffers to hardware queue, one at a time is too slow */ refill = mvneta_rx_refill_queue(pp, rxq); @@ -2206,14 +2217,8 @@ err_drop_frame: napi_gro_receive(napi, skb); } - if (rcvd_pkts) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); - - u64_stats_update_begin(&stats->syncp); - stats->rx_packets += rcvd_pkts; - stats->rx_bytes += rcvd_bytes; - u64_stats_update_end(&stats->syncp); - } + if (rcvd_pkts) + mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); /* Update rxq management counters */ mvneta_rxq_desc_num_update(pp, rxq, rx_done, rx_done); @@ -2459,7 +2464,6 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) out: if (frags > 0) { - struct mvneta_pcpu_stats *stats = this_cpu_ptr(pp->stats); struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id); netdev_tx_sent_queue(nq, len); @@ -2474,10 +2478,7 @@ out: else txq->pending += frags; - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += len; - u64_stats_update_end(&stats->syncp); + mvneta_update_stats(pp, 1, len, true); } else { dev->stats.tx_dropped++; dev_kfree_skb_any(skb); -- cgit v1.2.3-59-g8ed1b From 568a3fa24a95476d40afe3f8616bafb543bc4182 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:22 +0200 Subject: net: mvneta: introduce page pool API for sw buffer manager Use the page_pool api for allocations and DMA handling instead of __dev_alloc_page()/dma_map_page() and free_page()/dma_unmap_page(). Pages are unmapped using page_pool_release_page before packets go into the network stack. The page_pool API offers buffer recycling capabilities for XDP but allocates one page per packet, unless the driver splits and manages the allocated page. This is a preliminary patch to add XDP support to mvneta driver Signed-off-by: Ilias Apalodimas Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/Kconfig | 1 + drivers/net/ethernet/marvell/mvneta.c | 83 +++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index fb942167ee54..3d5caea096fb 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -61,6 +61,7 @@ config MVNETA depends on ARCH_MVEBU || COMPILE_TEST select MVMDIO select PHYLINK + select PAGE_POOL ---help--- This driver supports the network interface units in the Marvell ARMADA XP, ARMADA 370, ARMADA 38x and diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 3a8110d0a5b6..cd1a59c7e9d2 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -37,6 +37,7 @@ #include #include #include +#include /* Registers */ #define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2)) @@ -603,6 +604,10 @@ struct mvneta_rx_queue { u32 pkts_coal; u32 time_coal; + /* page_pool */ + struct page_pool *page_pool; + struct xdp_rxq_info xdp_rxq; + /* Virtual address of the RX buffer */ void **buf_virt_addr; @@ -1812,23 +1817,21 @@ static int mvneta_rx_refill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, gfp_t gfp_mask) { + enum dma_data_direction dma_dir; dma_addr_t phys_addr; struct page *page; - page = __dev_alloc_page(gfp_mask); + page = page_pool_alloc_pages(rxq->page_pool, + gfp_mask | __GFP_NOWARN); if (!page) return -ENOMEM; - /* map page for use */ - phys_addr = dma_map_page(pp->dev->dev.parent, page, 0, PAGE_SIZE, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(pp->dev->dev.parent, phys_addr))) { - __free_page(page); - return -ENOMEM; - } - - phys_addr += pp->rx_offset_correction; + phys_addr = page_pool_get_dma_addr(page) + pp->rx_offset_correction; + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_device(pp->dev->dev.parent, phys_addr, + PAGE_SIZE, dma_dir); mvneta_rx_desc_fill(rx_desc, phys_addr, page, rxq); + return 0; } @@ -1894,10 +1897,12 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp, if (!data || !(rx_desc->buf_phys_addr)) continue; - dma_unmap_page(pp->dev->dev.parent, rx_desc->buf_phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); - __free_page(data); + page_pool_put_page(rxq->page_pool, data, false); } + if (xdp_rxq_info_is_reg(&rxq->xdp_rxq)) + xdp_rxq_info_unreg(&rxq->xdp_rxq); + page_pool_destroy(rxq->page_pool); + rxq->page_pool = NULL; } static void @@ -2029,8 +2034,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi, skb_add_rx_frag(rxq->skb, frag_num, page, frag_offset, frag_size, PAGE_SIZE); - dma_unmap_page(dev->dev.parent, phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); + page_pool_release_page(rxq->page_pool, page); rxq->left_size -= frag_size; } } else { @@ -2060,9 +2064,7 @@ static int mvneta_rx_swbm(struct napi_struct *napi, frag_offset, frag_size, PAGE_SIZE); - dma_unmap_page(dev->dev.parent, phys_addr, - PAGE_SIZE, DMA_FROM_DEVICE); - + page_pool_release_page(rxq->page_pool, page); rxq->left_size -= frag_size; } } /* Middle or Last descriptor */ @@ -2831,11 +2833,54 @@ static int mvneta_poll(struct napi_struct *napi, int budget) return rx_done; } +static int mvneta_create_page_pool(struct mvneta_port *pp, + struct mvneta_rx_queue *rxq, int size) +{ + struct page_pool_params pp_params = { + .order = 0, + .flags = PP_FLAG_DMA_MAP, + .pool_size = size, + .nid = cpu_to_node(0), + .dev = pp->dev->dev.parent, + .dma_dir = DMA_FROM_DEVICE, + }; + int err; + + rxq->page_pool = page_pool_create(&pp_params); + if (IS_ERR(rxq->page_pool)) { + err = PTR_ERR(rxq->page_pool); + rxq->page_pool = NULL; + return err; + } + + err = xdp_rxq_info_reg(&rxq->xdp_rxq, pp->dev, rxq->id); + if (err < 0) + goto err_free_pp; + + err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq, MEM_TYPE_PAGE_POOL, + rxq->page_pool); + if (err) + goto err_unregister_rxq; + + return 0; + +err_unregister_rxq: + xdp_rxq_info_unreg(&rxq->xdp_rxq); +err_free_pp: + page_pool_destroy(rxq->page_pool); + rxq->page_pool = NULL; + return err; +} + /* Handle rxq fill: allocates rxq skbs; called when initializing a port */ static int mvneta_rxq_fill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int num) { - int i; + int i, err; + + err = mvneta_create_page_pool(pp, rxq, num); + if (err < 0) + return err; for (i = 0; i < num; i++) { memset(rxq->descs + i, 0, sizeof(struct mvneta_rx_desc)); -- cgit v1.2.3-59-g8ed1b From 8dc9a0888f4c8e27b25e48ff1b4bc2b3a845cc2d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:23 +0200 Subject: net: mvneta: rely on build_skb in mvneta_rx_swbm poll routine Refactor mvneta_rx_swbm code introducing mvneta_swbm_rx_frame and mvneta_swbm_add_rx_fragment routines. Rely on build_skb in oreder to allocate skb since the previous patch introduced buffer recycling using the page_pool API. This patch fixes even an issue in the original driver where dma buffers are accessed before dma sync. mvneta driver can run on not cache coherent devices so it is necessary to sync DMA buffers before sending them to the device in order to avoid memory corruptions. Running perf analysis we can see a performance cost associated with this DMA-sync (anyway it is already there in the original driver code). In follow up patches we will add more logic to reduce DMA-sync as much as possible. Signed-off-by: Ilias Apalodimas Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 179 ++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 84 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index cd1a59c7e9d2..624e30b3fb4d 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -323,6 +323,11 @@ ETH_HLEN + ETH_FCS_LEN, \ cache_line_size()) +#define MVNETA_SKB_PAD (SKB_DATA_ALIGN(sizeof(struct skb_shared_info) + \ + NET_SKB_PAD)) +#define MVNETA_SKB_SIZE(len) (SKB_DATA_ALIGN(len) + MVNETA_SKB_PAD) +#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)) @@ -646,7 +651,6 @@ static int txq_number = 8; static int rxq_def; static int rx_copybreak __read_mostly = 256; -static int rx_header_size __read_mostly = 128; /* HW BM need that each port be identify by a unique ID */ static int global_port_id; @@ -1829,7 +1833,7 @@ static int mvneta_rx_refill(struct mvneta_port *pp, phys_addr = page_pool_get_dma_addr(page) + pp->rx_offset_correction; dma_dir = page_pool_get_dma_dir(rxq->page_pool); dma_sync_single_for_device(pp->dev->dev.parent, phys_addr, - PAGE_SIZE, dma_dir); + MVNETA_MAX_RX_BUF_SIZE, dma_dir); mvneta_rx_desc_fill(rx_desc, phys_addr, page, rxq); return 0; @@ -1947,30 +1951,102 @@ int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) return i; } +static int +mvneta_swbm_rx_frame(struct mvneta_port *pp, + struct mvneta_rx_desc *rx_desc, + struct mvneta_rx_queue *rxq, + struct page *page) +{ + unsigned char *data = page_address(page); + int data_len = -MVNETA_MH_SIZE, len; + struct net_device *dev = pp->dev; + enum dma_data_direction dma_dir; + + if (MVNETA_SKB_SIZE(rx_desc->data_size) > PAGE_SIZE) { + len = MVNETA_MAX_RX_BUF_SIZE; + data_len += len; + } else { + len = rx_desc->data_size; + data_len += len - ETH_FCS_LEN; + } + + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_cpu(dev->dev.parent, + rx_desc->buf_phys_addr, + len, dma_dir); + + rxq->skb = build_skb(data, PAGE_SIZE); + if (unlikely(!rxq->skb)) { + netdev_err(dev, + "Can't allocate skb on queue %d\n", + rxq->id); + dev->stats.rx_dropped++; + rxq->skb_alloc_err++; + return -ENOMEM; + } + page_pool_release_page(rxq->page_pool, page); + + skb_reserve(rxq->skb, MVNETA_MH_SIZE + NET_SKB_PAD); + skb_put(rxq->skb, data_len); + mvneta_rx_csum(pp, rx_desc->status, rxq->skb); + + rxq->left_size = rx_desc->data_size - len; + rx_desc->buf_phys_addr = 0; + + return 0; +} + +static void +mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, + struct mvneta_rx_desc *rx_desc, + struct mvneta_rx_queue *rxq, + struct page *page) +{ + struct net_device *dev = pp->dev; + enum dma_data_direction dma_dir; + int data_len, len; + + if (rxq->left_size > MVNETA_MAX_RX_BUF_SIZE) { + len = MVNETA_MAX_RX_BUF_SIZE; + data_len = len; + } else { + len = rxq->left_size; + data_len = len - ETH_FCS_LEN; + } + dma_dir = page_pool_get_dma_dir(rxq->page_pool); + dma_sync_single_for_cpu(dev->dev.parent, + rx_desc->buf_phys_addr, + len, dma_dir); + if (data_len > 0) { + /* refill descriptor with new buffer later */ + skb_add_rx_frag(rxq->skb, + skb_shinfo(rxq->skb)->nr_frags, + page, NET_SKB_PAD, data_len, + PAGE_SIZE); + } + page_pool_release_page(rxq->page_pool, page); + rx_desc->buf_phys_addr = 0; + rxq->left_size -= len; +} + /* Main rx processing when using software buffer management */ static int mvneta_rx_swbm(struct napi_struct *napi, struct mvneta_port *pp, int budget, struct mvneta_rx_queue *rxq) { + int rcvd_pkts = 0, rcvd_bytes = 0, rx_proc = 0; struct net_device *dev = pp->dev; - int rx_todo, rx_proc; - int refill = 0; - u32 rcvd_pkts = 0; - u32 rcvd_bytes = 0; + int rx_todo, refill; /* Get number of received packets */ rx_todo = mvneta_rxq_busy_desc_num_get(pp, rxq); - rx_proc = 0; /* Fairness NAPI loop */ - while ((rcvd_pkts < budget) && (rx_proc < rx_todo)) { + while (rx_proc < budget && rx_proc < rx_todo) { struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq); + u32 rx_status, index; unsigned char *data; struct page *page; - dma_addr_t phys_addr; - u32 rx_status, index; - int rx_bytes, skb_size, copy_size; - int frag_num, frag_size, frag_offset; index = rx_desc - rxq->descs; page = (struct page *)rxq->buf_virt_addr[index]; @@ -1978,12 +2054,13 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* Prefetch header */ prefetch(data); - phys_addr = rx_desc->buf_phys_addr; rx_status = rx_desc->status; rx_proc++; rxq->refill_num++; if (rx_status & MVNETA_RXD_FIRST_DESC) { + int err; + /* Check errors only for FIRST descriptor */ if (rx_status & MVNETA_RXD_ERR_SUMMARY) { mvneta_rx_error(pp, rx_desc); @@ -1991,82 +2068,17 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* leave the descriptor untouched */ continue; } - rx_bytes = rx_desc->data_size - - (ETH_FCS_LEN + MVNETA_MH_SIZE); - /* Allocate small skb for each new packet */ - skb_size = max(rx_copybreak, rx_header_size); - rxq->skb = netdev_alloc_skb_ip_align(dev, skb_size); - if (unlikely(!rxq->skb)) { - netdev_err(dev, - "Can't allocate skb on queue %d\n", - rxq->id); - dev->stats.rx_dropped++; - rxq->skb_alloc_err++; + err = mvneta_swbm_rx_frame(pp, rx_desc, rxq, page); + if (err) continue; - } - copy_size = min(skb_size, rx_bytes); - - /* Copy data from buffer to SKB, skip Marvell header */ - memcpy(rxq->skb->data, data + MVNETA_MH_SIZE, - copy_size); - skb_put(rxq->skb, copy_size); - rxq->left_size = rx_bytes - copy_size; - - mvneta_rx_csum(pp, rx_status, rxq->skb); - if (rxq->left_size == 0) { - int size = copy_size + MVNETA_MH_SIZE; - - dma_sync_single_range_for_cpu(dev->dev.parent, - phys_addr, 0, - size, - DMA_FROM_DEVICE); - - /* leave the descriptor and buffer untouched */ - } else { - /* refill descriptor with new buffer later */ - rx_desc->buf_phys_addr = 0; - - frag_num = 0; - frag_offset = copy_size + MVNETA_MH_SIZE; - frag_size = min(rxq->left_size, - (int)(PAGE_SIZE - frag_offset)); - skb_add_rx_frag(rxq->skb, frag_num, page, - frag_offset, frag_size, - PAGE_SIZE); - page_pool_release_page(rxq->page_pool, page); - rxq->left_size -= frag_size; - } } else { - /* Middle or Last descriptor */ if (unlikely(!rxq->skb)) { pr_debug("no skb for rx_status 0x%x\n", rx_status); continue; } - if (!rxq->left_size) { - /* last descriptor has only FCS */ - /* and can be discarded */ - dma_sync_single_range_for_cpu(dev->dev.parent, - phys_addr, 0, - ETH_FCS_LEN, - DMA_FROM_DEVICE); - /* leave the descriptor and buffer untouched */ - } else { - /* refill descriptor with new buffer later */ - rx_desc->buf_phys_addr = 0; - - frag_num = skb_shinfo(rxq->skb)->nr_frags; - frag_offset = 0; - frag_size = min(rxq->left_size, - (int)(PAGE_SIZE - frag_offset)); - skb_add_rx_frag(rxq->skb, frag_num, page, - frag_offset, frag_size, - PAGE_SIZE); - - page_pool_release_page(rxq->page_pool, page); - rxq->left_size -= frag_size; - } + mvneta_swbm_add_rx_fragment(pp, rx_desc, rxq, page); } /* Middle or Last descriptor */ if (!(rx_status & MVNETA_RXD_LAST_DESC)) @@ -2091,7 +2103,6 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* clean uncomplete skb pointer in queue */ rxq->skb = NULL; - rxq->left_size = 0; } if (rcvd_pkts) @@ -2954,7 +2965,7 @@ static void mvneta_rxq_hw_init(struct mvneta_port *pp, /* Set Offset */ mvneta_rxq_offset_set(pp, rxq, 0); mvneta_rxq_buf_size_set(pp, rxq, PAGE_SIZE < SZ_64K ? - PAGE_SIZE : + MVNETA_MAX_RX_BUF_SIZE : MVNETA_RX_BUF_SIZE(pp->pkt_size)); mvneta_rxq_bm_disable(pp, rxq); mvneta_rxq_fill(pp, rxq, rxq->size); @@ -4664,7 +4675,7 @@ static int mvneta_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); pp->id = global_port_id++; - pp->rx_offset_correction = 0; /* not relevant for SW BM */ + pp->rx_offset_correction = NET_SKB_PAD; /* Obtain access to BM resources if enabled and already initialized */ bm_node = of_parse_phandle(dn, "buffer-manager", 0); -- cgit v1.2.3-59-g8ed1b From 0db51da7a8e99f0803ec3a8e25c1a66234a219cb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:24 +0200 Subject: net: mvneta: add basic XDP support Add basic XDP support to mvneta driver for devices that rely on software buffer management. Currently supported verdicts are: - XDP_DROP - XDP_PASS - XDP_REDIRECT - XDP_ABORTED - iptables drop: $iptables -t raw -I PREROUTING -p udp --dport 9 -j DROP $nstat -n && sleep 1 && nstat IpInReceives 151169 0.0 IpExtInOctets 6953544 0.0 IpExtInNoECTPkts 151165 0.0 - XDP_DROP via xdp1 $./samples/bpf/xdp1 3 proto 0: 421419 pkt/s proto 0: 421444 pkt/s proto 0: 421393 pkt/s proto 0: 421440 pkt/s proto 0: 421184 pkt/s Tested-by: Matteo Croce Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 148 +++++++++++++++++++++++++++++++--- 1 file changed, 139 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 624e30b3fb4d..7ca3cd16d781 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -38,6 +38,7 @@ #include #include #include +#include /* Registers */ #define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2)) @@ -323,8 +324,10 @@ ETH_HLEN + ETH_FCS_LEN, \ cache_line_size()) +#define MVNETA_SKB_HEADROOM (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + \ + NET_IP_ALIGN) #define MVNETA_SKB_PAD (SKB_DATA_ALIGN(sizeof(struct skb_shared_info) + \ - NET_SKB_PAD)) + MVNETA_SKB_HEADROOM)) #define MVNETA_SKB_SIZE(len) (SKB_DATA_ALIGN(len) + MVNETA_SKB_PAD) #define MVNETA_MAX_RX_BUF_SIZE (PAGE_SIZE - MVNETA_SKB_PAD) @@ -352,6 +355,11 @@ struct mvneta_statistic { #define T_REG_64 64 #define T_SW 1 +#define MVNETA_XDP_PASS BIT(0) +#define MVNETA_XDP_DROPPED BIT(1) +#define MVNETA_XDP_TX BIT(2) +#define MVNETA_XDP_REDIR BIT(3) + static const struct mvneta_statistic mvneta_statistics[] = { { 0x3000, T_REG_64, "good_octets_received", }, { 0x3010, T_REG_32, "good_frames_received", }, @@ -431,6 +439,8 @@ struct mvneta_port { u32 cause_rx_tx; struct napi_struct napi; + struct bpf_prog *xdp_prog; + /* Core clock */ struct clk *clk; /* AXI clock */ @@ -1951,11 +1961,51 @@ int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) return i; } +static int +mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, + struct bpf_prog *prog, struct xdp_buff *xdp) +{ + u32 ret, act = bpf_prog_run_xdp(prog, xdp); + + switch (act) { + case XDP_PASS: + ret = MVNETA_XDP_PASS; + break; + case XDP_REDIRECT: { + int err; + + err = xdp_do_redirect(pp->dev, xdp, prog); + if (err) { + ret = MVNETA_XDP_DROPPED; + xdp_return_buff(xdp); + } else { + ret = MVNETA_XDP_REDIR; + } + break; + } + default: + bpf_warn_invalid_xdp_action(act); + /* fall through */ + case XDP_ABORTED: + trace_xdp_exception(pp->dev, prog, act); + /* fall through */ + case XDP_DROP: + page_pool_recycle_direct(rxq->page_pool, + virt_to_head_page(xdp->data)); + ret = MVNETA_XDP_DROPPED; + break; + } + + return ret; +} + static int mvneta_swbm_rx_frame(struct mvneta_port *pp, struct mvneta_rx_desc *rx_desc, struct mvneta_rx_queue *rxq, - struct page *page) + struct xdp_buff *xdp, + struct bpf_prog *xdp_prog, + struct page *page, u32 *xdp_ret) { unsigned char *data = page_address(page); int data_len = -MVNETA_MH_SIZE, len; @@ -1975,7 +2025,26 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, rx_desc->buf_phys_addr, len, dma_dir); - rxq->skb = build_skb(data, PAGE_SIZE); + xdp->data_hard_start = data; + xdp->data = data + MVNETA_SKB_HEADROOM + MVNETA_MH_SIZE; + xdp->data_end = xdp->data + data_len; + xdp_set_data_meta_invalid(xdp); + + if (xdp_prog) { + u32 ret; + + ret = mvneta_run_xdp(pp, rxq, xdp_prog, xdp); + if (ret != MVNETA_XDP_PASS) { + mvneta_update_stats(pp, 1, + xdp->data_end - xdp->data, + false); + rx_desc->buf_phys_addr = 0; + *xdp_ret |= ret; + return ret; + } + } + + rxq->skb = build_skb(xdp->data_hard_start, PAGE_SIZE); if (unlikely(!rxq->skb)) { netdev_err(dev, "Can't allocate skb on queue %d\n", @@ -1986,8 +2055,9 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, } page_pool_release_page(rxq->page_pool, page); - skb_reserve(rxq->skb, MVNETA_MH_SIZE + NET_SKB_PAD); - skb_put(rxq->skb, data_len); + skb_reserve(rxq->skb, + xdp->data - xdp->data_hard_start); + skb_put(rxq->skb, xdp->data_end - xdp->data); mvneta_rx_csum(pp, rx_desc->status, rxq->skb); rxq->left_size = rx_desc->data_size - len; @@ -2021,7 +2091,7 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, /* refill descriptor with new buffer later */ skb_add_rx_frag(rxq->skb, skb_shinfo(rxq->skb)->nr_frags, - page, NET_SKB_PAD, data_len, + page, MVNETA_SKB_HEADROOM, data_len, PAGE_SIZE); } page_pool_release_page(rxq->page_pool, page); @@ -2036,11 +2106,18 @@ static int mvneta_rx_swbm(struct napi_struct *napi, { int rcvd_pkts = 0, rcvd_bytes = 0, rx_proc = 0; struct net_device *dev = pp->dev; + struct bpf_prog *xdp_prog; + struct xdp_buff xdp_buf; int rx_todo, refill; + u32 xdp_ret = 0; /* Get number of received packets */ rx_todo = mvneta_rxq_busy_desc_num_get(pp, rxq); + rcu_read_lock(); + xdp_prog = READ_ONCE(pp->xdp_prog); + xdp_buf.rxq = &rxq->xdp_rxq; + /* Fairness NAPI loop */ while (rx_proc < budget && rx_proc < rx_todo) { struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq); @@ -2069,7 +2146,8 @@ static int mvneta_rx_swbm(struct napi_struct *napi, continue; } - err = mvneta_swbm_rx_frame(pp, rx_desc, rxq, page); + err = mvneta_swbm_rx_frame(pp, rx_desc, rxq, &xdp_buf, + xdp_prog, page, &xdp_ret); if (err) continue; } else { @@ -2104,6 +2182,10 @@ static int mvneta_rx_swbm(struct napi_struct *napi, /* clean uncomplete skb pointer in queue */ rxq->skb = NULL; } + rcu_read_unlock(); + + if (xdp_ret & MVNETA_XDP_REDIR) + xdp_do_flush_map(); if (rcvd_pkts) mvneta_update_stats(pp, rcvd_pkts, rcvd_bytes, false); @@ -2847,13 +2929,14 @@ static int mvneta_poll(struct napi_struct *napi, int budget) static int mvneta_create_page_pool(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, int size) { + struct bpf_prog *xdp_prog = READ_ONCE(pp->xdp_prog); struct page_pool_params pp_params = { .order = 0, .flags = PP_FLAG_DMA_MAP, .pool_size = size, .nid = cpu_to_node(0), .dev = pp->dev->dev.parent, - .dma_dir = DMA_FROM_DEVICE, + .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE, }; int err; @@ -3320,6 +3403,11 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu) mtu = ALIGN(MVNETA_RX_PKT_SIZE(mtu), 8); } + if (pp->xdp_prog && mtu > MVNETA_MAX_RX_BUF_SIZE) { + netdev_info(dev, "Illegal MTU value %d for XDP mode\n", mtu); + return -EINVAL; + } + dev->mtu = mtu; if (!netif_running(dev)) { @@ -3989,6 +4077,47 @@ static int mvneta_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return phylink_mii_ioctl(pp->phylink, ifr, cmd); } +static int mvneta_xdp_setup(struct net_device *dev, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + bool need_update, running = netif_running(dev); + struct mvneta_port *pp = netdev_priv(dev); + struct bpf_prog *old_prog; + + if (prog && dev->mtu > MVNETA_MAX_RX_BUF_SIZE) { + NL_SET_ERR_MSG_MOD(extack, "Jumbo frames not supported on XDP"); + return -EOPNOTSUPP; + } + + need_update = !!pp->xdp_prog != !!prog; + if (running && need_update) + mvneta_stop(dev); + + old_prog = xchg(&pp->xdp_prog, prog); + if (old_prog) + bpf_prog_put(old_prog); + + if (running && need_update) + return mvneta_open(dev); + + return 0; +} + +static int mvneta_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + struct mvneta_port *pp = netdev_priv(dev); + + switch (xdp->command) { + case XDP_SETUP_PROG: + return mvneta_xdp_setup(dev, xdp->prog, xdp->extack); + case XDP_QUERY_PROG: + xdp->prog_id = pp->xdp_prog ? pp->xdp_prog->aux->id : 0; + return 0; + default: + return -EINVAL; + } +} + /* Ethtool methods */ /* Set link ksettings (phy address, speed) for ethtools */ @@ -4385,6 +4514,7 @@ static const struct net_device_ops mvneta_netdev_ops = { .ndo_fix_features = mvneta_fix_features, .ndo_get_stats64 = mvneta_get_stats64, .ndo_do_ioctl = mvneta_ioctl, + .ndo_bpf = mvneta_xdp, }; static const struct ethtool_ops mvneta_eth_tool_ops = { @@ -4675,7 +4805,7 @@ static int mvneta_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); pp->id = global_port_id++; - pp->rx_offset_correction = NET_SKB_PAD; + pp->rx_offset_correction = MVNETA_SKB_HEADROOM; /* Obtain access to BM resources if enabled and already initialized */ bm_node = of_parse_phandle(dn, "buffer-manager", 0); -- cgit v1.2.3-59-g8ed1b From fa383f6b77a2ed788266fa8fbfb659aa284d2f58 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:25 +0200 Subject: net: mvneta: move header prefetch in mvneta_swbm_rx_frame Move data buffer prefetch in mvneta_swbm_rx_frame after dma_sync_single_range_for_cpu Signed-off-by: Ilias Apalodimas Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 7ca3cd16d781..64f59baa2a3c 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2025,6 +2025,9 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, rx_desc->buf_phys_addr, len, dma_dir); + /* Prefetch header */ + prefetch(data); + xdp->data_hard_start = data; xdp->data = data + MVNETA_SKB_HEADROOM + MVNETA_MH_SIZE; xdp->data_end = xdp->data + data_len; @@ -2122,14 +2125,10 @@ static int mvneta_rx_swbm(struct napi_struct *napi, while (rx_proc < budget && rx_proc < rx_todo) { struct mvneta_rx_desc *rx_desc = mvneta_rxq_next_desc_get(rxq); u32 rx_status, index; - unsigned char *data; struct page *page; index = rx_desc - rxq->descs; page = (struct page *)rxq->buf_virt_addr[index]; - data = page_address(page); - /* Prefetch header */ - prefetch(data); rx_status = rx_desc->status; rx_proc++; -- cgit v1.2.3-59-g8ed1b From 9e58c8b410650b5a6eb5b8fad8474bd8425a4023 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:26 +0200 Subject: net: mvneta: make tx buffer array agnostic Allow tx buffer array to contain both skb and xdp buffers in order to enable xdp frame recycling adding XDP_TX verdict support Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 66 +++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 64f59baa2a3c..e83d5e069b4f 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -561,6 +561,20 @@ struct mvneta_rx_desc { }; #endif +enum mvneta_tx_buf_type { + MVNETA_TYPE_SKB, + MVNETA_TYPE_XDP_TX, + MVNETA_TYPE_XDP_NDO, +}; + +struct mvneta_tx_buf { + enum mvneta_tx_buf_type type; + union { + struct xdp_frame *xdpf; + struct sk_buff *skb; + }; +}; + struct mvneta_tx_queue { /* Number of this TX queue, in the range 0-7 */ u8 id; @@ -576,8 +590,8 @@ struct mvneta_tx_queue { int tx_stop_threshold; int tx_wake_threshold; - /* Array of transmitted skb */ - struct sk_buff **tx_skb; + /* Array of transmitted buffers */ + struct mvneta_tx_buf *buf; /* Index of last TX DMA descriptor that was inserted */ int txq_put_index; @@ -1780,14 +1794,9 @@ static void mvneta_txq_bufs_free(struct mvneta_port *pp, int i; for (i = 0; i < num; i++) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_get_index]; struct mvneta_tx_desc *tx_desc = txq->descs + txq->txq_get_index; - struct sk_buff *skb = txq->tx_skb[txq->txq_get_index]; - - if (skb) { - bytes_compl += skb->len; - pkts_compl++; - } mvneta_txq_inc_get(txq); @@ -1795,9 +1804,12 @@ 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 (!skb) + if (!buf->skb) continue; - dev_kfree_skb_any(skb); + + bytes_compl += buf->skb->len; + pkts_compl++; + dev_kfree_skb_any(buf->skb); } netdev_tx_completed_queue(nq, pkts_compl, bytes_compl); @@ -2324,16 +2336,19 @@ static inline void mvneta_tso_put_hdr(struct sk_buff *skb, struct mvneta_port *pp, struct mvneta_tx_queue *txq) { - struct mvneta_tx_desc *tx_desc; int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; + struct mvneta_tx_desc *tx_desc; - txq->tx_skb[txq->txq_put_index] = NULL; tx_desc = mvneta_txq_next_desc_get(txq); tx_desc->data_size = hdr_len; tx_desc->command = mvneta_skb_tx_csum(pp, skb); 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->skb = NULL; + mvneta_txq_inc_put(txq); } @@ -2342,6 +2357,7 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, struct sk_buff *skb, char *data, int size, bool last_tcp, bool is_last) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; struct mvneta_tx_desc *tx_desc; tx_desc = mvneta_txq_next_desc_get(txq); @@ -2355,7 +2371,8 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, } tx_desc->command = 0; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->type = MVNETA_TYPE_SKB; + buf->skb = NULL; if (last_tcp) { /* last descriptor in the TCP packet */ @@ -2363,7 +2380,7 @@ mvneta_tso_put_data(struct net_device *dev, struct mvneta_tx_queue *txq, /* last descriptor in SKB */ if (is_last) - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; } mvneta_txq_inc_put(txq); return 0; @@ -2448,6 +2465,7 @@ static int mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, int i, nr_frags = skb_shinfo(skb)->nr_frags; for (i = 0; i < nr_frags; i++) { + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; void *addr = skb_frag_address(frag); @@ -2467,12 +2485,13 @@ static int mvneta_tx_frag_process(struct mvneta_port *pp, struct sk_buff *skb, if (i == nr_frags - 1) { /* Last descriptor */ tx_desc->command = MVNETA_TXD_L_DESC | MVNETA_TXD_Z_PAD; - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; } else { /* Descriptor in the middle: Not First, Not Last */ tx_desc->command = 0; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->skb = NULL; } + buf->type = MVNETA_TYPE_SKB; mvneta_txq_inc_put(txq); } @@ -2500,6 +2519,7 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) struct mvneta_port *pp = netdev_priv(dev); u16 txq_id = skb_get_queue_mapping(skb); struct mvneta_tx_queue *txq = &pp->txqs[txq_id]; + struct mvneta_tx_buf *buf = &txq->buf[txq->txq_put_index]; struct mvneta_tx_desc *tx_desc; int len = skb->len; int frags = 0; @@ -2532,16 +2552,17 @@ static netdev_tx_t mvneta_tx(struct sk_buff *skb, struct net_device *dev) goto out; } + buf->type = MVNETA_TYPE_SKB; if (frags == 1) { /* First and Last descriptor */ tx_cmd |= MVNETA_TXD_FLZ_DESC; tx_desc->command = tx_cmd; - txq->tx_skb[txq->txq_put_index] = skb; + buf->skb = skb; mvneta_txq_inc_put(txq); } else { /* First but not Last */ tx_cmd |= MVNETA_TXD_F_DESC; - txq->tx_skb[txq->txq_put_index] = NULL; + buf->skb = NULL; mvneta_txq_inc_put(txq); tx_desc->command = tx_cmd; /* Continue with other skb fragments */ @@ -3128,9 +3149,8 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp, txq->last_desc = txq->size - 1; - txq->tx_skb = kmalloc_array(txq->size, sizeof(*txq->tx_skb), - GFP_KERNEL); - if (!txq->tx_skb) { + txq->buf = kmalloc_array(txq->size, sizeof(*txq->buf), GFP_KERNEL); + if (!txq->buf) { dma_free_coherent(pp->dev->dev.parent, txq->size * MVNETA_DESC_ALIGNED_SIZE, txq->descs, txq->descs_phys); @@ -3142,7 +3162,7 @@ static int mvneta_txq_sw_init(struct mvneta_port *pp, txq->size * TSO_HEADER_SIZE, &txq->tso_hdrs_phys, GFP_KERNEL); if (!txq->tso_hdrs) { - kfree(txq->tx_skb); + kfree(txq->buf); dma_free_coherent(pp->dev->dev.parent, txq->size * MVNETA_DESC_ALIGNED_SIZE, txq->descs, txq->descs_phys); @@ -3195,7 +3215,7 @@ static void mvneta_txq_sw_deinit(struct mvneta_port *pp, { struct netdev_queue *nq = netdev_get_tx_queue(pp->dev, txq->id); - kfree(txq->tx_skb); + kfree(txq->buf); if (txq->tso_hdrs) dma_free_coherent(pp->dev->dev.parent, -- cgit v1.2.3-59-g8ed1b From b0a43db9087a21d96e1a0b716b8d9963064b2d58 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sat, 19 Oct 2019 10:13:27 +0200 Subject: net: mvneta: add XDP_TX support Implement XDP_TX verdict and ndo_xdp_xmit net_device_ops function pointer Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 128 ++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index e83d5e069b4f..8f9df6efda61 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1800,16 +1800,19 @@ 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)) + if (!IS_TSO_HEADER(txq, tx_desc->buf_phys_addr) && + buf->type != MVNETA_TYPE_XDP_TX) dma_unmap_single(pp->dev->dev.parent, tx_desc->buf_phys_addr, tx_desc->data_size, DMA_TO_DEVICE); - if (!buf->skb) - continue; - - bytes_compl += buf->skb->len; - pkts_compl++; - dev_kfree_skb_any(buf->skb); + if (buf->type == MVNETA_TYPE_SKB && buf->skb) { + bytes_compl += buf->skb->len; + pkts_compl++; + dev_kfree_skb_any(buf->skb); + } else if (buf->type == MVNETA_TYPE_XDP_TX || + buf->type == MVNETA_TYPE_XDP_NDO) { + xdp_return_frame(buf->xdpf); + } } netdev_tx_completed_queue(nq, pkts_compl, bytes_compl); @@ -1973,6 +1976,111 @@ int mvneta_rx_refill_queue(struct mvneta_port *pp, struct mvneta_rx_queue *rxq) return i; } +static int +mvneta_xdp_submit_frame(struct mvneta_port *pp, struct mvneta_tx_queue *txq, + struct xdp_frame *xdpf, bool dma_map) +{ + struct mvneta_tx_desc *tx_desc; + struct mvneta_tx_buf *buf; + dma_addr_t dma_addr; + + if (txq->count >= txq->tx_stop_threshold) + return MVNETA_XDP_DROPPED; + + tx_desc = mvneta_txq_next_desc_get(txq); + + buf = &txq->buf[txq->txq_put_index]; + if (dma_map) { + /* ndo_xdp_xmit */ + dma_addr = dma_map_single(pp->dev->dev.parent, xdpf->data, + xdpf->len, DMA_TO_DEVICE); + if (dma_mapping_error(pp->dev->dev.parent, dma_addr)) { + mvneta_txq_desc_put(txq); + return MVNETA_XDP_DROPPED; + } + buf->type = MVNETA_TYPE_XDP_NDO; + } else { + struct page *page = virt_to_page(xdpf->data); + + dma_addr = page_pool_get_dma_addr(page) + + sizeof(*xdpf) + xdpf->headroom; + dma_sync_single_for_device(pp->dev->dev.parent, dma_addr, + xdpf->len, DMA_BIDIRECTIONAL); + buf->type = MVNETA_TYPE_XDP_TX; + } + buf->xdpf = xdpf; + + tx_desc->command = MVNETA_TXD_FLZ_DESC; + tx_desc->buf_phys_addr = dma_addr; + tx_desc->data_size = xdpf->len; + + mvneta_update_stats(pp, 1, xdpf->len, true); + mvneta_txq_inc_put(txq); + txq->pending++; + txq->count++; + + return MVNETA_XDP_TX; +} + +static int +mvneta_xdp_xmit_back(struct mvneta_port *pp, struct xdp_buff *xdp) +{ + struct mvneta_tx_queue *txq; + struct netdev_queue *nq; + struct xdp_frame *xdpf; + int cpu; + u32 ret; + + xdpf = convert_to_xdp_frame(xdp); + if (unlikely(!xdpf)) + return MVNETA_XDP_DROPPED; + + cpu = smp_processor_id(); + txq = &pp->txqs[cpu % txq_number]; + nq = netdev_get_tx_queue(pp->dev, txq->id); + + __netif_tx_lock(nq, cpu); + ret = mvneta_xdp_submit_frame(pp, txq, xdpf, false); + if (ret == MVNETA_XDP_TX) + mvneta_txq_pend_desc_add(pp, txq, 0); + __netif_tx_unlock(nq); + + return ret; +} + +static int +mvneta_xdp_xmit(struct net_device *dev, int num_frame, + struct xdp_frame **frames, u32 flags) +{ + struct mvneta_port *pp = netdev_priv(dev); + int cpu = smp_processor_id(); + struct mvneta_tx_queue *txq; + struct netdev_queue *nq; + int i, drops = 0; + u32 ret; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + txq = &pp->txqs[cpu % txq_number]; + nq = netdev_get_tx_queue(pp->dev, txq->id); + + __netif_tx_lock(nq, cpu); + for (i = 0; i < num_frame; i++) { + ret = mvneta_xdp_submit_frame(pp, txq, frames[i], true); + if (ret != MVNETA_XDP_TX) { + xdp_return_frame_rx_napi(frames[i]); + drops++; + } + } + + if (unlikely(flags & XDP_XMIT_FLUSH)) + mvneta_txq_pend_desc_add(pp, txq, 0); + __netif_tx_unlock(nq); + + return num_frame - drops; +} + static int mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, struct bpf_prog *prog, struct xdp_buff *xdp) @@ -1995,6 +2103,11 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, } break; } + case XDP_TX: + ret = mvneta_xdp_xmit_back(pp, xdp); + if (ret != MVNETA_XDP_TX) + xdp_return_buff(xdp); + break; default: bpf_warn_invalid_xdp_action(act); /* fall through */ @@ -4534,6 +4647,7 @@ static const struct net_device_ops mvneta_netdev_ops = { .ndo_get_stats64 = mvneta_get_stats64, .ndo_do_ioctl = mvneta_ioctl, .ndo_bpf = mvneta_xdp, + .ndo_xdp_xmit = mvneta_xdp_xmit, }; static const struct ethtool_ops mvneta_eth_tool_ops = { -- cgit v1.2.3-59-g8ed1b From a3bdfce7bf9cfc621888974670ac1a96d379201a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 19 Oct 2019 15:57:33 +0200 Subject: net: phy: marvell: support downshift as PHY tunable So far downshift is implemented for one small use case only and can't be controlled from userspace. So let's implement this feature properly as a PHY tunable so that it can be controlled via ethtool. More Marvell PHY's may support downshift, but I restricted it for now to the ones where I have the datasheet. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index a7796134e3be..9716b39484c1 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -54,11 +54,15 @@ #define MII_M1011_PHY_SCR 0x10 #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) #define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12 -#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK 0x7800 +#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12) +#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 #define MII_M1011_PHY_SCR_MDI (0x0 << 5) #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) #define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5) +#define MII_M1011_PHY_SSR 0x11 +#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5) + #define MII_M1111_PHY_LED_CONTROL 0x18 #define MII_M1111_PHY_LED_DIRECT 0x4100 #define MII_M1111_PHY_LED_COMBINE 0x411c @@ -833,6 +837,79 @@ static int m88e1111_config_init(struct phy_device *phydev) return genphy_soft_reset(phydev); } +static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = phy_read(phydev, MII_M1011_PHY_SCR); + if (val < 0) + return val; + + enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); + cnt = FIELD_GET(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, val) + 1; + + *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int val; + + if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX) + return -E2BIG; + + if (!cnt) + return phy_clear_bits(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_DOWNSHIFT_EN); + + val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; + val |= FIELD_PREP(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, cnt - 1); + + return phy_modify(phydev, MII_M1011_PHY_SCR, + MII_M1011_PHY_SCR_DOWNSHIFT_EN | + MII_M1011_PHY_SRC_DOWNSHIFT_MASK, + val); +} + +static int m88e1111_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int m88e1111_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + +static void m88e1111_link_change_notify(struct phy_device *phydev) +{ + int status; + + if (phydev->state != PHY_RUNNING) + return; + + /* we may be on fiber page currently */ + status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE, + MII_M1011_PHY_SSR); + + if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT) + phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n"); +} + static int m88e1318_config_init(struct phy_device *phydev) { if (phy_interrupt_is_valid(phydev)) { @@ -1117,6 +1194,8 @@ static int m88e1540_get_tunable(struct phy_device *phydev, switch (tuna->id) { case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_get_fld(phydev, data); + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_get_downshift(phydev, data); default: return -EOPNOTSUPP; } @@ -1128,6 +1207,8 @@ static int m88e1540_set_tunable(struct phy_device *phydev, switch (tuna->id) { case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_set_fld(phydev, data); + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_set_downshift(phydev, *(const u8 *)data); default: return -EOPNOTSUPP; } @@ -2220,6 +2301,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1111_get_tunable, + .set_tunable = m88e1111_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1318S, @@ -2359,6 +2443,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1545, @@ -2421,6 +2506,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, + .link_change_notify = m88e1111_link_change_notify, }, }; -- cgit v1.2.3-59-g8ed1b From e2d861cc0ff3c9d512177655756a93d4489f9456 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 19 Oct 2019 15:58:19 +0200 Subject: net: phy: marvell: remove superseded function marvell_set_downshift Instead of superseded function marvell_set_downshift() we can use new function m88e1111_set_downshift() in m88e1116r_config_init(). For this m88e1116r_config_init() has to be moved in the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 88 +++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 9716b39484c1..0a814fde136a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -53,7 +53,6 @@ #define MII_M1011_PHY_SCR 0x10 #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) -#define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12 #define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12) #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 #define MII_M1011_PHY_SCR_MDI (0x0 << 5) @@ -277,23 +276,6 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity) return val != reg; } -static int marvell_set_downshift(struct phy_device *phydev, bool enable, - u8 retries) -{ - int reg; - - reg = phy_read(phydev, MII_M1011_PHY_SCR); - if (reg < 0) - return reg; - - reg &= MII_M1011_PHY_SRC_DOWNSHIFT_MASK; - reg |= ((retries - 1) << MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT); - if (enable) - reg |= MII_M1011_PHY_SCR_DOWNSHIFT_EN; - - return phy_write(phydev, MII_M1011_PHY_SCR, reg); -} - static int marvell_config_aneg(struct phy_device *phydev) { int changed = 0; @@ -662,41 +644,6 @@ static int marvell_config_init(struct phy_device *phydev) return marvell_of_reg_init(phydev); } -static int m88e1116r_config_init(struct phy_device *phydev) -{ - int err; - - err = genphy_soft_reset(phydev); - if (err < 0) - return err; - - msleep(500); - - err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); - if (err < 0) - return err; - - err = marvell_set_polarity(phydev, phydev->mdix_ctrl); - if (err < 0) - return err; - - err = marvell_set_downshift(phydev, true, 8); - if (err < 0) - return err; - - if (phy_interface_is_rgmii(phydev)) { - err = m88e1121_config_aneg_rgmii_delays(phydev); - if (err < 0) - return err; - } - - err = genphy_soft_reset(phydev); - if (err < 0) - return err; - - return marvell_config_init(phydev); -} - static int m88e3016_config_init(struct phy_device *phydev) { int ret; @@ -910,6 +857,41 @@ static void m88e1111_link_change_notify(struct phy_device *phydev) phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n"); } +static int m88e1116r_config_init(struct phy_device *phydev) +{ + int err; + + err = genphy_soft_reset(phydev); + if (err < 0) + return err; + + msleep(500); + + err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE); + if (err < 0) + return err; + + err = marvell_set_polarity(phydev, phydev->mdix_ctrl); + if (err < 0) + return err; + + err = m88e1111_set_downshift(phydev, 8); + if (err < 0) + return err; + + if (phy_interface_is_rgmii(phydev)) { + err = m88e1121_config_aneg_rgmii_delays(phydev); + if (err < 0) + return err; + } + + err = genphy_soft_reset(phydev); + if (err < 0) + return err; + + return marvell_config_init(phydev); +} + static int m88e1318_config_init(struct phy_device *phydev) { if (phy_interrupt_is_valid(phydev)) { -- cgit v1.2.3-59-g8ed1b From 0eeb91ade90ce06d2fa1e2fcb55e3316b64c203c Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 16 Oct 2019 09:54:08 +0800 Subject: rtl8xxxu: fix RTL8723BU connection failure issue after warm reboot The RTL8723BU has problems connecting to AP after each warm reboot. Sometimes it returns no scan result, and in most cases, it fails the authentication for unknown reason. However, it works totally fine after cold reboot. Compare the value of register SYS_CR and SYS_CLK_MAC_CLK_ENABLE for cold reboot and warm reboot, the registers imply that the MAC is already powered and thus some procedures are skipped during driver initialization. Double checked the vendor driver, it reads the SYS_CR and SYS_CLK_MAC_CLK_ENABLE also but doesn't skip any during initialization based on them. This commit only tells the RTL8723BU to do full initialization without checking MAC status. Signed-off-by: Chris Chiu Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 +++ 3 files changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 22e95b11bfbb..6598c8d786ea 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -1425,6 +1425,7 @@ struct rtl8xxxu_fileops { u8 has_s0s1:1; u8 has_tx_report:1; u8 gen2_thermal_meter:1; + u8 needs_full_init: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_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index d15dde388435..a71e1816e632 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1668,6 +1668,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .has_s0s1 = 1, .has_tx_report = 1, .gen2_thermal_meter = 1, + .needs_full_init = 1, .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 1e3b71626f1b..f982f91b8bb6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -3900,6 +3900,9 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) else macpower = true; + if (fops->needs_full_init) + macpower = false; + ret = fops->power_on(priv); if (ret < 0) { dev_warn(dev, "%s: Failed power on\n", __func__); -- cgit v1.2.3-59-g8ed1b From bfd6e6e6c5d2ee43a3d9902b36e01fc7527ebb27 Mon Sep 17 00:00:00 2001 From: Hui Peng Date: Sat, 19 Oct 2019 14:42:23 +0300 Subject: ath10k: Fix a NULL-ptr-deref bug in ath10k_usb_alloc_urb_from_pipe The `ar_usb` field of `ath10k_usb_pipe_usb_pipe` objects are initialized to point to the containing `ath10k_usb` object according to endpoint descriptors read from the device side, as shown below in `ath10k_usb_setup_pipe_resources`: for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; // get the address from endpoint descriptor pipe_num = ath10k_usb_get_logical_pipe_num(ar_usb, endpoint->bEndpointAddress, &urbcount); ...... // select the pipe object pipe = &ar_usb->pipes[pipe_num]; // initialize the ar_usb field pipe->ar_usb = ar_usb; } The driver assumes that the addresses reported in endpoint descriptors from device side to be complete. If a device is malicious and does not report complete addresses, it may trigger NULL-ptr-deref `ath10k_usb_alloc_urb_from_pipe` and `ath10k_usb_free_urb_to_pipe`. This patch fixes the bug by preventing potential NULL-ptr-deref. Signed-off-by: Hui Peng Reported-by: Hui Peng Reported-by: Mathias Payer Reviewed-by: Greg Kroah-Hartman [groeck: Add driver tag to subject, fix build warning] Signed-off-by: Guenter Roeck Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/usb.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 730ed22e08a0..1e0343081be9 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -38,6 +38,10 @@ ath10k_usb_alloc_urb_from_pipe(struct ath10k_usb_pipe *pipe) struct ath10k_urb_context *urb_context = NULL; unsigned long flags; + /* bail if this pipe is not initialized */ + if (!pipe->ar_usb) + return NULL; + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); if (!list_empty(&pipe->urb_list_head)) { urb_context = list_first_entry(&pipe->urb_list_head, @@ -55,6 +59,10 @@ static void ath10k_usb_free_urb_to_pipe(struct ath10k_usb_pipe *pipe, { unsigned long flags; + /* bail if this pipe is not initialized */ + if (!pipe->ar_usb) + return; + spin_lock_irqsave(&pipe->ar_usb->cs_lock, flags); pipe->urb_cnt++; -- cgit v1.2.3-59-g8ed1b From a66edaafae08c37f9ea31fdfbc64d2a9be8d588f Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Mon, 21 Oct 2019 11:41:10 +0800 Subject: r8152: rename fw_type_1 with fw_mac The struct fw_type_1 is used by MAC only, so rename it to a meaningful one. Besides, adjust two messages. Replace "load xxx fail" with "check xxx fail" Signed-off-by: Hayes Wang Signed-off-by: Jakub Kicinski --- drivers/net/usb/r8152.c | 82 ++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 55d0bcb00aef..55a7674a0c06 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -867,11 +867,11 @@ struct fw_header { } __packed; /** - * struct fw_type_1 - a firmware block used by RTL_FW_PLA and RTL_FW_USB. + * struct fw_mac - a firmware block used by RTL_FW_PLA and RTL_FW_USB. * The layout of the firmware block is: - * + + . + * + + . * @fw_offset: offset of the firmware binary data. The start address of - * the data would be the address of struct fw_type_1 + @fw_offset. + * the data would be the address of struct fw_mac + @fw_offset. * @fw_reg: the register to load the firmware. Depends on chip. * @bp_ba_addr: the register to write break point base address. Depends on * chip. @@ -888,7 +888,7 @@ struct fw_header { * @info: additional information for debugging, and is followed by the * binary data of firmware. */ -struct fw_type_1 { +struct fw_mac { struct fw_block blk_hdr; __le16 fw_offset; __le16 fw_reg; @@ -3397,14 +3397,14 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) ocp_write_word(tp, type, PLA_BP_BA, 0); } -static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) +static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start; bool rc = false; u32 length, type; int i, max_bp; - type = __le32_to_cpu(type1->blk_hdr.type); + type = __le32_to_cpu(mac->blk_hdr.type); if (type == RTL_FW_PLA) { switch (tp->version) { case RTL_VER_01: @@ -3461,46 +3461,46 @@ static bool rtl8152_is_fw_type1_ok(struct r8152 *tp, struct fw_type_1 *type1) goto out; } - length = __le32_to_cpu(type1->blk_hdr.length); - if (length < __le16_to_cpu(type1->fw_offset)) { + length = __le32_to_cpu(mac->blk_hdr.length); + if (length < __le16_to_cpu(mac->fw_offset)) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } - length -= __le16_to_cpu(type1->fw_offset); + length -= __le16_to_cpu(mac->fw_offset); if (length < 4 || (length & 3)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; } - if (__le16_to_cpu(type1->fw_reg) != fw_reg) { + if (__le16_to_cpu(mac->fw_reg) != fw_reg) { dev_err(&tp->intf->dev, "invalid register to load firmware\n"); goto out; } - if (__le16_to_cpu(type1->bp_ba_addr) != bp_ba_addr) { + if (__le16_to_cpu(mac->bp_ba_addr) != bp_ba_addr) { dev_err(&tp->intf->dev, "invalid base address register\n"); goto out; } - if (__le16_to_cpu(type1->bp_en_addr) != bp_en_addr) { + if (__le16_to_cpu(mac->bp_en_addr) != bp_en_addr) { dev_err(&tp->intf->dev, "invalid enabled mask register\n"); goto out; } - if (__le16_to_cpu(type1->bp_start) != bp_start) { + if (__le16_to_cpu(mac->bp_start) != bp_start) { dev_err(&tp->intf->dev, "invalid start register of break point\n"); goto out; } - if (__le16_to_cpu(type1->bp_num) > max_bp) { + if (__le16_to_cpu(mac->bp_num) > max_bp) { dev_err(&tp->intf->dev, "invalid break point number\n"); goto out; } - for (i = __le16_to_cpu(type1->bp_num); i < max_bp; i++) { - if (type1->bp[i]) { + for (i = __le16_to_cpu(mac->bp_num); i < max_bp; i++) { + if (mac->bp[i]) { dev_err(&tp->intf->dev, "unused bp%u is not zero\n", i); goto out; } @@ -3566,7 +3566,7 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) { const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; - struct fw_type_1 *pla = NULL, *usb = NULL; + struct fw_mac *pla = NULL, *usb = NULL; long ret = -EFAULT; int i; @@ -3601,10 +3601,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } - pla = (struct fw_type_1 *)block; - if (!rtl8152_is_fw_type1_ok(tp, pla)) { + pla = (struct fw_mac *)block; + if (!rtl8152_is_fw_mac_ok(tp, pla)) { dev_err(&tp->intf->dev, - "load PLA firmware failed\n"); + "check PLA firmware failed\n"); goto fail; } break; @@ -3615,10 +3615,10 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) goto fail; } - usb = (struct fw_type_1 *)block; - if (!rtl8152_is_fw_type1_ok(tp, usb)) { + usb = (struct fw_mac *)block; + if (!rtl8152_is_fw_mac_ok(tp, usb)) { dev_err(&tp->intf->dev, - "load USB firmware failed\n"); + "check USB firmware failed\n"); goto fail; } break; @@ -3638,14 +3638,14 @@ fail: return ret; } -static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) +static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) { u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; u32 length; u8 *data; int i; - switch (__le32_to_cpu(type1->blk_hdr.type)) { + switch (__le32_to_cpu(mac->blk_hdr.type)) { case RTL_FW_PLA: type = MCU_TYPE_PLA; break; @@ -3667,36 +3667,36 @@ static void rtl8152_fw_type_1_apply(struct r8152 *tp, struct fw_type_1 *type1) ocp_write_word(tp, MCU_TYPE_PLA, PLA_MACDBG_POST, DEBUG_LTSSM); } - length = __le32_to_cpu(type1->blk_hdr.length); - length -= __le16_to_cpu(type1->fw_offset); + length = __le32_to_cpu(mac->blk_hdr.length); + length -= __le16_to_cpu(mac->fw_offset); - data = (u8 *)type1; - data += __le16_to_cpu(type1->fw_offset); + data = (u8 *)mac; + data += __le16_to_cpu(mac->fw_offset); - generic_ocp_write(tp, __le16_to_cpu(type1->fw_reg), 0xff, length, data, + generic_ocp_write(tp, __le16_to_cpu(mac->fw_reg), 0xff, length, data, type); - ocp_write_word(tp, type, __le16_to_cpu(type1->bp_ba_addr), - __le16_to_cpu(type1->bp_ba_value)); + ocp_write_word(tp, type, __le16_to_cpu(mac->bp_ba_addr), + __le16_to_cpu(mac->bp_ba_value)); - bp_index = __le16_to_cpu(type1->bp_start); - bp_num = __le16_to_cpu(type1->bp_num); + bp_index = __le16_to_cpu(mac->bp_start); + bp_num = __le16_to_cpu(mac->bp_num); for (i = 0; i < bp_num; i++) { - ocp_write_word(tp, type, bp_index, __le16_to_cpu(type1->bp[i])); + ocp_write_word(tp, type, bp_index, __le16_to_cpu(mac->bp[i])); bp_index += 2; } - bp_en_addr = __le16_to_cpu(type1->bp_en_addr); + bp_en_addr = __le16_to_cpu(mac->bp_en_addr); if (bp_en_addr) ocp_write_word(tp, type, bp_en_addr, - __le16_to_cpu(type1->bp_en_value)); + __le16_to_cpu(mac->bp_en_value)); - fw_ver_reg = __le16_to_cpu(type1->fw_ver_reg); + fw_ver_reg = __le16_to_cpu(mac->fw_ver_reg); if (fw_ver_reg) ocp_write_byte(tp, MCU_TYPE_USB, fw_ver_reg, - type1->fw_ver_data); + mac->fw_ver_data); - dev_dbg(&tp->intf->dev, "successfully applied %s\n", type1->info); + dev_dbg(&tp->intf->dev, "successfully applied %s\n", mac->info); } static void rtl8152_apply_firmware(struct r8152 *tp) @@ -3720,7 +3720,7 @@ static void rtl8152_apply_firmware(struct r8152 *tp) goto post_fw; case RTL_FW_PLA: case RTL_FW_USB: - rtl8152_fw_type_1_apply(tp, (struct fw_type_1 *)block); + rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); break; default: break; -- cgit v1.2.3-59-g8ed1b From 5a16a3d9f9b9714508d6c9ab69897576a3709566 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Mon, 21 Oct 2019 11:41:11 +0800 Subject: r8152: add checking fw_offset field of struct fw_mac Make sure @fw_offset field of struct fw_mac is more than the size of struct fw_mac. Signed-off-by: Hayes Wang Signed-off-by: Jakub Kicinski --- drivers/net/usb/r8152.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 55a7674a0c06..090ddd5fb973 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3399,7 +3399,7 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { - u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start; + u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; bool rc = false; u32 length, type; int i, max_bp; @@ -3461,13 +3461,19 @@ static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) goto out; } + fw_offset = __le16_to_cpu(mac->fw_offset); + if (fw_offset < sizeof(*mac)) { + dev_err(&tp->intf->dev, "fw_offset too small\n"); + goto out; + } + length = __le32_to_cpu(mac->blk_hdr.length); - if (length < __le16_to_cpu(mac->fw_offset)) { + if (length < fw_offset) { dev_err(&tp->intf->dev, "invalid fw_offset\n"); goto out; } - length -= __le16_to_cpu(mac->fw_offset); + length -= fw_offset; if (length < 4 || (length & 3)) { dev_err(&tp->intf->dev, "invalid block length\n"); goto out; -- cgit v1.2.3-59-g8ed1b From 470e39194a46c8e447fcf2801c9f3e683af8a475 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Mon, 21 Oct 2019 11:41:12 +0800 Subject: r8152: move r8153_patch_request forward Move r8153_patch_request() forward for later patch. Signed-off-by: Hayes Wang Signed-off-by: Jakub Kicinski --- drivers/net/usb/r8152.c | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 090ddd5fb973..ab57c672c4ca 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3397,6 +3397,33 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) ocp_write_word(tp, type, PLA_BP_BA, 0); } +static int r8153_patch_request(struct r8152 *tp, bool request) +{ + u16 data; + int i; + + data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); + if (request) + data |= PATCH_REQUEST; + else + data &= ~PATCH_REQUEST; + ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); + + for (i = 0; request && i < 5000; i++) { + usleep_range(1000, 2000); + if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) + break; + } + + if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { + netif_err(tp, drv, tp->netdev, "patch request fail\n"); + r8153_patch_request(tp, false); + return -ETIME; + } else { + return 0; + } +} + static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; @@ -4056,33 +4083,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } -static int r8153_patch_request(struct r8152 *tp, bool request) -{ - u16 data; - int i; - - data = ocp_reg_read(tp, OCP_PHY_PATCH_CMD); - if (request) - data |= PATCH_REQUEST; - else - data &= ~PATCH_REQUEST; - ocp_reg_write(tp, OCP_PHY_PATCH_CMD, data); - - for (i = 0; request && i < 5000; i++) { - usleep_range(1000, 2000); - if (ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY) - break; - } - - if (request && !(ocp_reg_read(tp, OCP_PHY_PATCH_STAT) & PATCH_READY)) { - netif_err(tp, drv, tp->netdev, "patch request fail\n"); - r8153_patch_request(tp, false); - return -ETIME; - } else { - return 0; - } -} - static int r8153_pre_firmware_1(struct r8152 *tp) { int i; -- cgit v1.2.3-59-g8ed1b From af14288f945b4f2967acef8cec168f9c1a56eeb0 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Mon, 21 Oct 2019 11:41:13 +0800 Subject: r8152: support firmware of PHY NC for RTL8153A Support the firmware of PHY NC which is used to fix the issue found for PHY. Currently, only RTL_VER_04, RTL_VER_05, and RTL_VER_06 need it. The order of loading PHY firmware would be RTL_FW_PHY_START RTL_FW_PHY_NC RTL_FW_PHY_STOP The RTL_FW_PHY_START/RTL_FW_PHY_STOP are used to lock/unlock the PHY, and set/clear the patch key from the firmware file. Signed-off-by: Hayes Wang Signed-off-by: Jakub Kicinski --- drivers/net/usb/r8152.c | 284 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 282 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ab57c672c4ca..d3c30ccc8577 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -187,6 +187,7 @@ #define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ #define OCP_PHY_PATCH_STAT 0xb800 #define OCP_PHY_PATCH_CMD 0xb820 +#define OCP_PHY_LOCK 0xb82e #define OCP_ADC_IOFFSET 0xbcfc #define OCP_ADC_CFG 0xbc06 #define OCP_SYSCLK_CFG 0xc416 @@ -197,6 +198,7 @@ #define SRAM_10M_AMP1 0x8080 #define SRAM_10M_AMP2 0x8082 #define SRAM_IMPEDANCE 0x8084 +#define SRAM_PHY_LOCK 0xb82e /* PLA_RCR */ #define RCR_AAP 0x00000001 @@ -577,6 +579,9 @@ enum spd_duplex { /* OCP_PHY_PATCH_CMD */ #define PATCH_REQUEST BIT(4) +/* OCP_PHY_LOCK */ +#define PATCH_LOCK BIT(0) + /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 @@ -601,6 +606,9 @@ enum spd_duplex { /* SRAM_IMPEDANCE */ #define RX_DRIVING_MASK 0x6000 +/* SRAM_PHY_LOCK */ +#define PHY_PATCH_LOCK 0x0001 + /* MAC PASSTHRU */ #define AD_MASK 0xfee0 #define BND_MASK 0x0004 @@ -905,10 +913,65 @@ struct fw_mac { char info[0]; } __packed; +/** + * struct fw_phy_patch_key - a firmware block used by RTL_FW_PHY_START. + * This is used to set patch key when loading the firmware of PHY. + * @key_reg: the register to write the patch key. + * @key_data: patch key. + */ +struct fw_phy_patch_key { + struct fw_block blk_hdr; + __le16 key_reg; + __le16 key_data; + __le32 reserved; +} __packed; + +/** + * struct fw_phy_nc - a firmware block used by RTL_FW_PHY_NC. + * The layout of the firmware block is: + * + + . + * @fw_offset: offset of the firmware binary data. The start address of + * the data would be the address of struct fw_phy_nc + @fw_offset. + * @fw_reg: the register to load the firmware. Depends on chip. + * @ba_reg: the register to write the base address. Depends on chip. + * @ba_data: base address. Depends on chip. + * @patch_en_addr: the register of enabling patch mode. Depends on chip. + * @patch_en_value: patch mode enabled mask. Depends on the firmware. + * @mode_reg: the regitster of switching the mode. + * @mod_pre: the mode needing to be set before loading the firmware. + * @mod_post: the mode to be set when finishing to load the firmware. + * @bp_start: the start register of break points. Depends on chip. + * @bp_num: the break point number which needs to be set for this firmware. + * Depends on the firmware. + * @bp: break points. Depends on firmware. + * @info: additional information for debugging, and is followed by the + * binary data of firmware. + */ +struct fw_phy_nc { + struct fw_block blk_hdr; + __le16 fw_offset; + __le16 fw_reg; + __le16 ba_reg; + __le16 ba_data; + __le16 patch_en_addr; + __le16 patch_en_value; + __le16 mode_reg; + __le16 mode_pre; + __le16 mode_post; + __le16 reserved; + __le16 bp_start; + __le16 bp_num; + __le16 bp[4]; + char info[0]; +} __packed; + enum rtl_fw_type { RTL_FW_END = 0, RTL_FW_PLA, RTL_FW_USB, + RTL_FW_PHY_START, + RTL_FW_PHY_STOP, + RTL_FW_PHY_NC, }; enum rtl_version { @@ -3424,6 +3487,114 @@ static int r8153_patch_request(struct r8152 *tp, bool request) } } +static int r8153_pre_ram_code(struct r8152 *tp, u16 key_addr, u16 patch_key) +{ + if (r8153_patch_request(tp, true)) { + dev_err(&tp->intf->dev, "patch request fail\n"); + return -ETIME; + } + + sram_write(tp, key_addr, patch_key); + sram_write(tp, SRAM_PHY_LOCK, PHY_PATCH_LOCK); + + return 0; +} + +static int r8153_post_ram_code(struct r8152 *tp, u16 key_addr) +{ + u16 data; + + sram_write(tp, 0x0000, 0x0000); + + data = ocp_reg_read(tp, OCP_PHY_LOCK); + data &= ~PATCH_LOCK; + ocp_reg_write(tp, OCP_PHY_LOCK, data); + + sram_write(tp, key_addr, 0x0000); + + r8153_patch_request(tp, false); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, tp->ocp_base); + + return 0; +} + +static bool rtl8152_is_fw_phy_nc_ok(struct r8152 *tp, struct fw_phy_nc *phy) +{ + u32 length; + u16 fw_offset, fw_reg, ba_reg, patch_en_addr, mode_reg, bp_start; + bool rc = false; + + switch (tp->version) { + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + fw_reg = 0xa014; + ba_reg = 0xa012; + patch_en_addr = 0xa01a; + mode_reg = 0xb820; + bp_start = 0xa000; + break; + default: + goto out; + } + + fw_offset = __le16_to_cpu(phy->fw_offset); + if (fw_offset < sizeof(*phy)) { + dev_err(&tp->intf->dev, "fw_offset too small\n"); + goto out; + } + + length = __le32_to_cpu(phy->blk_hdr.length); + if (length < fw_offset) { + dev_err(&tp->intf->dev, "invalid fw_offset\n"); + goto out; + } + + length -= __le16_to_cpu(phy->fw_offset); + if (!length || (length & 1)) { + dev_err(&tp->intf->dev, "invalid block length\n"); + goto out; + } + + if (__le16_to_cpu(phy->fw_reg) != fw_reg) { + dev_err(&tp->intf->dev, "invalid register to load firmware\n"); + goto out; + } + + if (__le16_to_cpu(phy->ba_reg) != ba_reg) { + dev_err(&tp->intf->dev, "invalid base address register\n"); + goto out; + } + + if (__le16_to_cpu(phy->patch_en_addr) != patch_en_addr) { + dev_err(&tp->intf->dev, + "invalid patch mode enabled register\n"); + goto out; + } + + if (__le16_to_cpu(phy->mode_reg) != mode_reg) { + dev_err(&tp->intf->dev, + "invalid register to switch the mode\n"); + goto out; + } + + if (__le16_to_cpu(phy->bp_start) != bp_start) { + dev_err(&tp->intf->dev, + "invalid start register of break point\n"); + goto out; + } + + if (__le16_to_cpu(phy->bp_num) > 4) { + dev_err(&tp->intf->dev, "invalid break point number\n"); + goto out; + } + + rc = true; +out: + return rc; +} + static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) { u16 fw_reg, bp_ba_addr, bp_en_addr, bp_start, fw_offset; @@ -3600,6 +3771,9 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; struct fw_mac *pla = NULL, *usb = NULL; + struct fw_phy_patch_key *start = NULL; + struct fw_phy_nc *phy_nc = NULL; + struct fw_block *stop = NULL; long ret = -EFAULT; int i; @@ -3626,7 +3800,7 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) case RTL_FW_END: if (__le32_to_cpu(block->length) != sizeof(*block)) goto fail; - goto success; + goto fw_end; case RTL_FW_PLA: if (pla) { dev_err(&tp->intf->dev, @@ -3654,6 +3828,57 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) "check USB firmware failed\n"); goto fail; } + break; + case RTL_FW_PHY_START: + if (start || phy_nc || stop) { + dev_err(&tp->intf->dev, + "check PHY_START fail\n"); + goto fail; + } + + if (__le32_to_cpu(block->length) != sizeof(*start)) { + dev_err(&tp->intf->dev, + "Invalid length for PHY_START\n"); + goto fail; + } + + start = (struct fw_phy_patch_key *)block; + break; + case RTL_FW_PHY_STOP: + if (stop || !start) { + dev_err(&tp->intf->dev, + "Check PHY_STOP fail\n"); + goto fail; + } + + if (__le32_to_cpu(block->length) != sizeof(*block)) { + dev_err(&tp->intf->dev, + "Invalid length for PHY_STOP\n"); + goto fail; + } + + stop = block; + break; + case RTL_FW_PHY_NC: + if (!start || stop) { + dev_err(&tp->intf->dev, + "check PHY_NC fail\n"); + goto fail; + } + + if (phy_nc) { + dev_err(&tp->intf->dev, + "multiple PHY NC encountered\n"); + goto fail; + } + + phy_nc = (struct fw_phy_nc *)block; + if (!rtl8152_is_fw_phy_nc_ok(tp, phy_nc)) { + dev_err(&tp->intf->dev, + "check PHY NC firmware failed\n"); + goto fail; + } + break; default: dev_warn(&tp->intf->dev, "Unknown type %u is found\n", @@ -3665,12 +3890,52 @@ static long rtl8152_check_firmware(struct r8152 *tp, struct rtl_fw *rtl_fw) i += ALIGN(__le32_to_cpu(block->length), 8); } -success: +fw_end: + if ((phy_nc || start) && !stop) { + dev_err(&tp->intf->dev, "without PHY_STOP\n"); + goto fail; + } + return 0; fail: return ret; } +static void rtl8152_fw_phy_nc_apply(struct r8152 *tp, struct fw_phy_nc *phy) +{ + u16 mode_reg, bp_index; + u32 length, i, num; + __le16 *data; + + mode_reg = __le16_to_cpu(phy->mode_reg); + sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_pre)); + sram_write(tp, __le16_to_cpu(phy->ba_reg), + __le16_to_cpu(phy->ba_data)); + + length = __le32_to_cpu(phy->blk_hdr.length); + length -= __le16_to_cpu(phy->fw_offset); + num = length / 2; + data = (__le16 *)((u8 *)phy + __le16_to_cpu(phy->fw_offset)); + + ocp_reg_write(tp, OCP_SRAM_ADDR, __le16_to_cpu(phy->fw_reg)); + for (i = 0; i < num; i++) + ocp_reg_write(tp, OCP_SRAM_DATA, __le16_to_cpu(data[i])); + + sram_write(tp, __le16_to_cpu(phy->patch_en_addr), + __le16_to_cpu(phy->patch_en_value)); + + bp_index = __le16_to_cpu(phy->bp_start); + num = __le16_to_cpu(phy->bp_num); + for (i = 0; i < num; i++) { + sram_write(tp, bp_index, __le16_to_cpu(phy->bp[i])); + bp_index += 2; + } + + sram_write(tp, mode_reg, __le16_to_cpu(phy->mode_post)); + + dev_dbg(&tp->intf->dev, "successfully applied %s\n", phy->info); +} + static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) { u16 bp_en_addr, bp_index, type, bp_num, fw_ver_reg; @@ -3737,6 +4002,8 @@ static void rtl8152_apply_firmware(struct r8152 *tp) struct rtl_fw *rtl_fw = &tp->rtl_fw; const struct firmware *fw = rtl_fw->fw; struct fw_header *fw_hdr = (struct fw_header *)fw->data; + struct fw_phy_patch_key *key; + u16 key_addr = 0; int i; if (IS_ERR_OR_NULL(rtl_fw->fw)) @@ -3755,6 +4022,19 @@ static void rtl8152_apply_firmware(struct r8152 *tp) case RTL_FW_USB: rtl8152_fw_mac_apply(tp, (struct fw_mac *)block); break; + case RTL_FW_PHY_START: + key = (struct fw_phy_patch_key *)block; + key_addr = __le16_to_cpu(key->key_reg); + r8153_pre_ram_code(tp, key_addr, + __le16_to_cpu(key->key_data)); + break; + case RTL_FW_PHY_STOP: + WARN_ON(!key_addr); + r8153_post_ram_code(tp, key_addr); + break; + case RTL_FW_PHY_NC: + rtl8152_fw_phy_nc_apply(tp, (struct fw_phy_nc *)block); + break; default: break; } -- cgit v1.2.3-59-g8ed1b From 2ac061ce97f413bfbbdd768f7d2e0fda2e8170df Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 21 Oct 2019 07:30:52 +0200 Subject: xen/netback: cleanup init and deinit code Do some cleanup of the netback init and deinit code: - add an omnipotent queue deinit function usable from xenvif_disconnect_data() and the error path of xenvif_connect_data() - only install the irq handlers after initializing all relevant items (especially the kthreads related to the queue) - there is no need to use get_task_struct() after creating a kthread and using put_task_struct() again after having stopped it. - use kthread_run() instead of kthread_create() to spare the call of wake_up_process(). Signed-off-by: Juergen Gross Reviewed-by: Paul Durrant Signed-off-by: Jakub Kicinski --- drivers/net/xen-netback/interface.c | 114 +++++++++++++++++------------------- 1 file changed, 54 insertions(+), 60 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 103ed00775eb..68dd7bb07ca6 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -626,6 +626,38 @@ err: return err; } +static void xenvif_disconnect_queue(struct xenvif_queue *queue) +{ + if (queue->tx_irq) { + unbind_from_irqhandler(queue->tx_irq, queue); + if (queue->tx_irq == queue->rx_irq) + queue->rx_irq = 0; + queue->tx_irq = 0; + } + + if (queue->rx_irq) { + unbind_from_irqhandler(queue->rx_irq, queue); + queue->rx_irq = 0; + } + + if (queue->task) { + kthread_stop(queue->task); + queue->task = NULL; + } + + if (queue->dealloc_task) { + kthread_stop(queue->dealloc_task); + queue->dealloc_task = NULL; + } + + if (queue->napi.poll) { + netif_napi_del(&queue->napi); + queue->napi.poll = NULL; + } + + xenvif_unmap_frontend_data_rings(queue); +} + int xenvif_connect_data(struct xenvif_queue *queue, unsigned long tx_ring_ref, unsigned long rx_ring_ref, @@ -651,13 +683,27 @@ int xenvif_connect_data(struct xenvif_queue *queue, netif_napi_add(queue->vif->dev, &queue->napi, xenvif_poll, XENVIF_NAPI_WEIGHT); + queue->stalled = true; + + task = kthread_run(xenvif_kthread_guest_rx, queue, + "%s-guest-rx", queue->name); + if (IS_ERR(task)) + goto kthread_err; + queue->task = task; + + task = kthread_run(xenvif_dealloc_kthread, queue, + "%s-dealloc", queue->name); + if (IS_ERR(task)) + goto kthread_err; + queue->dealloc_task = task; + if (tx_evtchn == rx_evtchn) { /* feature-split-event-channels == 0 */ err = bind_interdomain_evtchn_to_irqhandler( queue->vif->domid, tx_evtchn, xenvif_interrupt, 0, queue->name, queue); if (err < 0) - goto err_unmap; + goto err; queue->tx_irq = queue->rx_irq = err; disable_irq(queue->tx_irq); } else { @@ -668,7 +714,7 @@ int xenvif_connect_data(struct xenvif_queue *queue, queue->vif->domid, tx_evtchn, xenvif_tx_interrupt, 0, queue->tx_irq_name, queue); if (err < 0) - goto err_unmap; + goto err; queue->tx_irq = err; disable_irq(queue->tx_irq); @@ -678,47 +724,18 @@ int xenvif_connect_data(struct xenvif_queue *queue, queue->vif->domid, rx_evtchn, xenvif_rx_interrupt, 0, queue->rx_irq_name, queue); if (err < 0) - goto err_tx_unbind; + goto err; queue->rx_irq = err; disable_irq(queue->rx_irq); } - queue->stalled = true; - - task = kthread_create(xenvif_kthread_guest_rx, - (void *)queue, "%s-guest-rx", queue->name); - if (IS_ERR(task)) { - pr_warn("Could not allocate kthread for %s\n", queue->name); - err = PTR_ERR(task); - goto err_rx_unbind; - } - queue->task = task; - get_task_struct(task); - - task = kthread_create(xenvif_dealloc_kthread, - (void *)queue, "%s-dealloc", queue->name); - if (IS_ERR(task)) { - pr_warn("Could not allocate kthread for %s\n", queue->name); - err = PTR_ERR(task); - goto err_rx_unbind; - } - queue->dealloc_task = task; - - wake_up_process(queue->task); - wake_up_process(queue->dealloc_task); - return 0; -err_rx_unbind: - unbind_from_irqhandler(queue->rx_irq, queue); - queue->rx_irq = 0; -err_tx_unbind: - unbind_from_irqhandler(queue->tx_irq, queue); - queue->tx_irq = 0; -err_unmap: - xenvif_unmap_frontend_data_rings(queue); - netif_napi_del(&queue->napi); +kthread_err: + pr_warn("Could not allocate kthread for %s\n", queue->name); + err = PTR_ERR(task); err: + xenvif_disconnect_queue(queue); return err; } @@ -746,30 +763,7 @@ void xenvif_disconnect_data(struct xenvif *vif) for (queue_index = 0; queue_index < num_queues; ++queue_index) { queue = &vif->queues[queue_index]; - netif_napi_del(&queue->napi); - - if (queue->task) { - kthread_stop(queue->task); - put_task_struct(queue->task); - queue->task = NULL; - } - - if (queue->dealloc_task) { - kthread_stop(queue->dealloc_task); - queue->dealloc_task = NULL; - } - - if (queue->tx_irq) { - if (queue->tx_irq == queue->rx_irq) - unbind_from_irqhandler(queue->tx_irq, queue); - else { - unbind_from_irqhandler(queue->tx_irq, queue); - unbind_from_irqhandler(queue->rx_irq, queue); - } - queue->tx_irq = 0; - } - - xenvif_unmap_frontend_data_rings(queue); + xenvif_disconnect_queue(queue); } xenvif_mcast_addr_list_free(vif); -- cgit v1.2.3-59-g8ed1b From f366cd2a2e510b155e18b21a2d149332aa08eb61 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 21 Oct 2019 13:30:30 +0300 Subject: mlxsw: reg: Add macro for getting QSFP module EEPROM page number Provide a macro for getting QSFP module EEPROM page number from the optional upper page number row offset, specified in request. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index f5e39758c6ac..adb63a266fc7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8412,6 +8412,7 @@ MLXSW_ITEM32(reg, mcia, device_address, 0x04, 0, 16); MLXSW_ITEM32(reg, mcia, size, 0x08, 0, 16); #define MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH 256 +#define MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH 128 #define MLXSW_REG_MCIA_EEPROM_SIZE 48 #define MLXSW_REG_MCIA_I2C_ADDR_LOW 0x50 #define MLXSW_REG_MCIA_I2C_ADDR_HIGH 0x51 @@ -8447,6 +8448,14 @@ enum mlxsw_reg_mcia_eeprom_module_info { */ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); +/* This is used to access the optional upper pages (1-3) in the QSFP+ + * memory map. Page 1 is available on offset 256 through 383, page 2 - + * on offset 384 through 511, page 3 - on offset 512 through 639. + */ +#define MLXSW_REG_MCIA_PAGE_GET(off) (((off) - \ + MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) / \ + MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) + static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, u8 page_number, u16 device_addr, u8 size, u8 i2c_device_addr) -- cgit v1.2.3-59-g8ed1b From a45bfb5a50701cec6799cf24386c2be56770328d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 21 Oct 2019 13:30:31 +0300 Subject: mlxsw: core: Extend QSFP EEPROM size for ethtool Extend the size of QSFP EEPROM for the cable types SSF8436 and SFF8636 from 256 to 640 bytes in order to expose all the EEPROM pages by ethtool. For SFF-8636 and SFF-8436 specifications, the driver exposes 256 bytes of data for ethtool's get_module_eeprom() callback. This is because the driver uses the below defines to specify SFF module length in ethtool's get_module_info() callback: 'ETH_MODULE_SFF_8636_LEN' and 'ETH_MODULE_SFF_8436_LEN' (both are 256). As a result of exposing 256 bytes only, ethtool shows wrong "zero" info for pages 1, 2, 3. The patch changes the length returned by callback for get_module_info() to the values from the next defines: 'ETH_MODULE_SFF_8636_MAX_LEN' and 'ETH_MODULE_SFF_8436_MAX_LEN' (both are 640) to allow exposing of upper page 1, 2 and 3. Signed-off-by: Vadim Pasternak Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/core_env.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c index d2c7ce67c300..08215fed193d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c @@ -50,6 +50,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, char eeprom_tmp[MLXSW_REG_MCIA_EEPROM_SIZE]; char mcia_pl[MLXSW_REG_MCIA_LEN]; u16 i2c_addr; + u8 page = 0; int status; int err; @@ -62,11 +63,21 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_LOW; if (offset >= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) { - i2c_addr = MLXSW_REG_MCIA_I2C_ADDR_HIGH; - offset -= MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH; + page = MLXSW_REG_MCIA_PAGE_GET(offset); + offset -= MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH * page; + /* When reading upper pages 1, 2 and 3 the offset starts at + * 128. Please refer to "QSFP+ Memory Map" figure in SFF-8436 + * specification for graphical depiction. + * MCIA register accepts buffer size <= 48. Page of size 128 + * should be read by chunks of size 48, 48, 32. Align the size + * of the last chunk to avoid reading after the end of the + * page. + */ + if (offset + size > MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) + size = MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH - offset; } - mlxsw_reg_mcia_pack(mcia_pl, module, 0, 0, offset, size, i2c_addr); + mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); if (err) @@ -168,7 +179,7 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, switch (module_id) { case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP: modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP_PLUS: /* fall-through */ case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_QSFP28: @@ -176,10 +187,10 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, module_rev_id >= MLXSW_REG_MCIA_EEPROM_MODULE_INFO_REV_ID_8636) { modinfo->type = ETH_MODULE_SFF_8636; - modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; } else { modinfo->type = ETH_MODULE_SFF_8436; - modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; } break; case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: -- cgit v1.2.3-59-g8ed1b From 2df49d36549808a7357ad9f78b7a8e39516e7809 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 21 Oct 2019 21:22:07 +0200 Subject: r8169: remove fiddling with the PCIe max read request size The attempt to improve performance by changing the PCIe max read request size was added in the vendor driver more than 10 years back and copied to r8169 driver. In the vendor driver this has been removed long ago. Obviously it had no effect, also in my tests I didn't see any difference. Typically the max payload size is less than 512 bytes anyway, and the PCI core takes care that the maximum supported value is set. So let's remove fiddling with PCIe max read request size from r8169 too. Signed-off-by: Heiner Kallweit Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 40 ++++--------------------------- 1 file changed, 4 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 350b0d949611..41680bd08037 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -741,12 +741,6 @@ static void rtl_unlock_config_regs(struct rtl8169_private *tp) RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } -static void rtl_tx_performance_tweak(struct rtl8169_private *tp, u16 force) -{ - pcie_capability_clear_and_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_READRQ, force); -} - static bool rtl_is_8125(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_60; @@ -4032,14 +4026,12 @@ static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) @@ -4057,7 +4049,6 @@ static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) RTL_W8(tp, MaxTxPacketSize, 0x3f); RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_512B); } static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) @@ -4065,19 +4056,18 @@ static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) RTL_W8(tp, MaxTxPacketSize, 0x0c); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp) { - rtl_tx_performance_tweak(tp, - PCI_EXP_DEVCTL_READRQ_512B | PCI_EXP_DEVCTL_NOSNOOP_EN); + pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); } static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp) { - rtl_tx_performance_tweak(tp, - PCI_EXP_DEVCTL_READRQ_4096B | PCI_EXP_DEVCTL_NOSNOOP_EN); + pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_NOSNOOP_EN); } static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) @@ -4550,18 +4540,12 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); rtl_disable_clock_request(tp); - - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); } static void rtl_hw_start_8168dp(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); - if (tp->dev->mtu <= ETH_DATA_LEN) - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_disable_clock_request(tp); } @@ -4576,8 +4560,6 @@ static void rtl_hw_start_8168d_4(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_ephy_init(tp, e_info_8168d_4); rtl_enable_clock_request(tp); @@ -4652,8 +4634,6 @@ static void rtl_hw_start_8168f(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); rtl_set_fifo_size(tp, 0x10, 0x10, 0x02, 0x06); @@ -4716,8 +4696,6 @@ static void rtl_hw_start_8168g(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_write(tp, 0x2f8, ERIAR_MASK_0011, 0x1d8f); @@ -4954,8 +4932,6 @@ static void rtl_hw_start_8168h_1(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_set_bits(tp, 0xdc, ERIAR_MASK_1111, BIT(4)); @@ -5013,8 +4989,6 @@ static void rtl_hw_start_8168ep(struct rtl8169_private *tp) rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_reset_packet_filter(tp); rtl_eri_set_bits(tp, 0xd4, ERIAR_MASK_1111, 0x1f80); @@ -5117,8 +5091,6 @@ static void rtl_hw_start_8102e_1(struct rtl8169_private *tp) RTL_W8(tp, DBG_REG, FIX_NAK_1); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - RTL_W8(tp, Config1, LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); @@ -5134,8 +5106,6 @@ static void rtl_hw_start_8102e_2(struct rtl8169_private *tp) { rtl_set_def_aspm_entry_latency(tp); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - RTL_W8(tp, Config1, MEMMAP | IOMAP | VPD | PMEnable); RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); } @@ -5196,8 +5166,6 @@ static void rtl_hw_start_8402(struct rtl8169_private *tp) rtl_ephy_init(tp, e_info_8402); - rtl_tx_performance_tweak(tp, PCI_EXP_DEVCTL_READRQ_4096B); - rtl_set_fifo_size(tp, 0x00, 0x00, 0x02, 0x06); rtl_reset_packet_filter(tp); rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); -- cgit v1.2.3-59-g8ed1b From e0bbe7cbb3c5ff72d680993edf89db2391e80d5d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 21 Oct 2019 21:22:42 +0200 Subject: r8169: simplify setting PCI_EXP_DEVCTL_NOSNOOP_EN r8168b_0_hw_jumbo_enable() and r8168b_0_hw_jumbo_disable() both do the same and just set PCI_EXP_DEVCTL_NOSNOOP_EN. We can simplify the code by moving this setting for RTL8168B to rtl_hw_start_8168(). Signed-off-by: Heiner Kallweit Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 34 +++++++++---------------------- 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 41680bd08037..990b941f5e94 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4058,29 +4058,13 @@ static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); } -static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp) -{ - pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_NOSNOOP_EN); -} - -static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp) -{ - pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_NOSNOOP_EN); -} - static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) { - r8168b_0_hw_jumbo_enable(tp); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); } static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) { - r8168b_0_hw_jumbo_disable(tp); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); } @@ -4088,9 +4072,6 @@ static void rtl_hw_jumbo_enable(struct rtl8169_private *tp) { rtl_unlock_config_regs(tp); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - r8168b_0_hw_jumbo_enable(tp); - break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: r8168b_1_hw_jumbo_enable(tp); @@ -4114,9 +4095,6 @@ static void rtl_hw_jumbo_disable(struct rtl8169_private *tp) { rtl_unlock_config_regs(tp); switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - r8168b_0_hw_jumbo_disable(tp); - break; case RTL_GIGA_MAC_VER_12: case RTL_GIGA_MAC_VER_17: r8168b_1_hw_jumbo_disable(tp); @@ -5381,10 +5359,18 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) static void rtl_hw_start_8168(struct rtl8169_private *tp) { - if (tp->mac_version == RTL_GIGA_MAC_VER_13 || - tp->mac_version == RTL_GIGA_MAC_VER_16) + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_11: + case RTL_GIGA_MAC_VER_12: + case RTL_GIGA_MAC_VER_13: + case RTL_GIGA_MAC_VER_16: + case RTL_GIGA_MAC_VER_17: pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_NOSNOOP_EN); + break; + default: + break; + } if (rtl_is_8168evl_up(tp)) RTL_W8(tp, MaxTxPacketSize, EarlySize); -- cgit v1.2.3-59-g8ed1b From 0a413e6b577c8ccf70b3c40bb5f5e3087f7e2f4c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 21 Oct 2019 21:23:21 +0200 Subject: r8169: remove rtl_hw_start_8168dp We can remove rtl_hw_start_8168dp() because it's the same as rtl_hw_start_8168dp() now. Signed-off-by: Heiner Kallweit Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 990b941f5e94..481a6df5966a 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4520,13 +4520,6 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp) rtl_disable_clock_request(tp); } -static void rtl_hw_start_8168dp(struct rtl8169_private *tp) -{ - rtl_set_def_aspm_entry_latency(tp); - - rtl_disable_clock_request(tp); -} - static void rtl_hw_start_8168d_4(struct rtl8169_private *tp) { static const struct ephy_info e_info_8168d_4[] = { @@ -5317,7 +5310,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_28] = rtl_hw_start_8168d_4, [RTL_GIGA_MAC_VER_29] = rtl_hw_start_8105e_1, [RTL_GIGA_MAC_VER_30] = rtl_hw_start_8105e_2, - [RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168dp, + [RTL_GIGA_MAC_VER_31] = rtl_hw_start_8168d, [RTL_GIGA_MAC_VER_32] = rtl_hw_start_8168e_1, [RTL_GIGA_MAC_VER_33] = rtl_hw_start_8168e_1, [RTL_GIGA_MAC_VER_34] = rtl_hw_start_8168e_2, -- cgit v1.2.3-59-g8ed1b From 94b5ff749e56084aab93c32d4561dd9bea329aa6 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 21 Oct 2019 21:24:15 +0200 Subject: r8169: remove rtl_hw_start_8168bef We can remove rtl_hw_start_8168bef() and use rtl_hw_start_8168b() instead because setting register Config4 is done in rtl_jumbo_config(), being called from rtl_hw_start(). Signed-off-by: Heiner Kallweit Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/realtek/r8169_main.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 481a6df5966a..57942383b73d 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4415,18 +4415,11 @@ static void rtl8168g_set_pause_thresholds(struct rtl8169_private *tp, rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, high); } -static void rtl_hw_start_8168bb(struct rtl8169_private *tp) +static void rtl_hw_start_8168b(struct rtl8169_private *tp) { RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Beacon_en); } -static void rtl_hw_start_8168bef(struct rtl8169_private *tp) -{ - rtl_hw_start_8168bb(tp); - - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); -} - static void __rtl_hw_start_8168cp(struct rtl8169_private *tp) { RTL_W8(tp, Config1, RTL_R8(tp, Config1) | Speed_down); @@ -5290,13 +5283,13 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168bb, - [RTL_GIGA_MAC_VER_12] = rtl_hw_start_8168bef, + [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, + [RTL_GIGA_MAC_VER_12] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_13] = NULL, [RTL_GIGA_MAC_VER_14] = NULL, [RTL_GIGA_MAC_VER_15] = NULL, [RTL_GIGA_MAC_VER_16] = NULL, - [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168bef, + [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, [RTL_GIGA_MAC_VER_19] = rtl_hw_start_8168c_1, [RTL_GIGA_MAC_VER_20] = rtl_hw_start_8168c_2, -- cgit v1.2.3-59-g8ed1b From 68bb8ea8ad0d497c28ed47423246b1ab20f26976 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:15 -0400 Subject: net: dsa: use dsa_to_port helper everywhere Do not let the drivers access the ds->ports static array directly while there is a dsa_to_port helper for this purpose. At the same time, un-const this helper since the SJA1105 driver assigns the priv member of the returned dsa_port structure. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 6 +++--- drivers/net/dsa/bcm_sf2.c | 8 ++++---- drivers/net/dsa/bcm_sf2_cfp.c | 6 +++--- drivers/net/dsa/mt7530.c | 12 ++++++------ drivers/net/dsa/mv88e6xxx/chip.c | 10 +++++----- drivers/net/dsa/qca8k.c | 2 +- drivers/net/dsa/sja1105/sja1105_main.c | 18 +++++++++--------- include/net/dsa.h | 2 +- net/dsa/dsa.c | 8 +++++--- net/dsa/dsa2.c | 4 ++-- net/dsa/switch.c | 4 ++-- net/dsa/tag_8021q.c | 6 +++--- 12 files changed, 44 insertions(+), 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index cc3536315eff..aef9b56781ef 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -524,7 +524,7 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) if (!dsa_is_user_port(ds, port)) return 0; - cpu_port = ds->ports[port].cpu_dp->index; + cpu_port = dsa_to_port(ds, port)->cpu_dp->index; if (dev->ops->irq_enable) ret = dev->ops->irq_enable(dev, port); @@ -1629,7 +1629,7 @@ EXPORT_SYMBOL(b53_fdb_dump); int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; u16 pvlan, reg; unsigned int i; @@ -1675,7 +1675,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; struct b53_vlan *vl = &dev->vlans[0]; - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; unsigned int i; u16 pvlan, reg, pvid; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 26509fa37a50..c068a3b7207b 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -662,7 +662,7 @@ static void bcm_sf2_sw_fixed_state(struct dsa_switch *ds, int port, * state machine and make it go in PHY_FORCING state instead. */ if (!status->link) - netif_carrier_off(ds->ports[port].slave); + netif_carrier_off(dsa_to_port(ds, port)->slave); status->duplex = DUPLEX_FULL; } else { status->link = true; @@ -728,7 +728,7 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds) static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_wolinfo pwol = { }; @@ -752,9 +752,9 @@ static void bcm_sf2_sw_get_wol(struct dsa_switch *ds, int port, static int bcm_sf2_sw_set_wol(struct dsa_switch *ds, int port, struct ethtool_wolinfo *wol) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; struct ethtool_wolinfo pwol = { }; if (p->ethtool_ops->get_wol) diff --git a/drivers/net/dsa/bcm_sf2_cfp.c b/drivers/net/dsa/bcm_sf2_cfp.c index d264776a95a3..f3f0c3f07391 100644 --- a/drivers/net/dsa/bcm_sf2_cfp.c +++ b/drivers/net/dsa/bcm_sf2_cfp.c @@ -821,7 +821,7 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port, struct ethtool_rx_flow_spec *fs) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - s8 cpu_port = ds->ports[port].cpu_dp->index; + s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index; __u64 ring_cookie = fs->ring_cookie; unsigned int queue_num, port_num; int ret; @@ -1049,7 +1049,7 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv, int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc, u32 *rule_locs) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; @@ -1092,7 +1092,7 @@ int bcm_sf2_get_rxnfc(struct dsa_switch *ds, int port, int bcm_sf2_set_rxnfc(struct dsa_switch *ds, int port, struct ethtool_rxnfc *nfc) { - struct net_device *p = ds->ports[port].cpu_dp->master; + struct net_device *p = dsa_to_port(ds, port)->cpu_dp->master; struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); int ret = 0; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 1d8d36de4d20..a91293e47a57 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -862,7 +862,7 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port) for (i = 0; i < MT7530_NUM_PORTS; i++) { if (dsa_is_user_port(ds, i) && - dsa_port_is_vlan_filtering(&ds->ports[i])) { + dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) { all_user_ports_removed = false; break; } @@ -922,7 +922,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port, * other port is still a VLAN-aware port. */ if (dsa_is_user_port(ds, i) && i != port && - !dsa_port_is_vlan_filtering(&ds->ports[i])) { + !dsa_port_is_vlan_filtering(dsa_to_port(ds, i))) { if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) @@ -1165,7 +1165,7 @@ mt7530_port_vlan_add(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) return; mutex_lock(&priv->reg_mutex); @@ -1196,7 +1196,7 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port, /* The port is kept as VLAN-unaware if bridge with vlan_filtering not * being set. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) return 0; mutex_lock(&priv->reg_mutex); @@ -1252,7 +1252,7 @@ mt7530_setup(struct dsa_switch *ds) * controller also is the container for two GMACs nodes representing * as two netdev instances. */ - dn = ds->ports[MT7530_CPU_PORT].master->dev.of_node->parent; + dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; if (priv->id == ID_MT7530) { priv->ethernet = syscon_node_to_regmap(dn); @@ -1340,7 +1340,7 @@ mt7530_setup(struct dsa_switch *ds) if (!dsa_is_unused_port(ds, 5)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5; - interface = of_get_phy_mode(ds->ports[5].dn); + interface = of_get_phy_mode(dsa_to_port(ds, 5)->dn); } else { /* Scan the ethernet nodes. look for GMAC1, lookup used phy */ for_each_child_of_node(dn, mac_np) { diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 6787d560e9e3..d67deec77452 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1075,7 +1075,7 @@ static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) return mv88e6xxx_port_mask(chip); - br = ds->ports[port].bridge_dev; + br = dsa_to_port(ds, port)->bridge_dev; pvlan = 0; /* Frames from user ports can egress any local DSA links and CPU ports, @@ -1402,7 +1402,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) continue; - if (!ds->ports[i].slave) + if (!dsa_to_port(ds, i)->slave) continue; if (vlan.member[i] == @@ -1410,7 +1410,7 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, continue; if (dsa_to_port(ds, i)->bridge_dev == - ds->ports[port].bridge_dev) + dsa_to_port(ds, port)->bridge_dev) break; /* same bridge, check next VLAN */ if (!dsa_to_port(ds, i)->bridge_dev) @@ -2042,7 +2042,7 @@ static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, /* Remap the Port VLAN of each local bridge group member */ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { - if (chip->ds->ports[port].bridge_dev == br) { + if (dsa_to_port(chip->ds, port)->bridge_dev == br) { err = mv88e6xxx_port_vlan_map(chip, port); if (err) return err; @@ -2059,7 +2059,7 @@ static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, break; for (port = 0; port < ds->num_ports; ++port) { - if (ds->ports[port].bridge_dev == br) { + if (dsa_to_port(ds, port)->bridge_dev == br) { err = mv88e6xxx_pvt_map(chip, dev, port); if (err) return err; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index b00274caae4f..71e44c8763b8 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -661,7 +661,7 @@ qca8k_setup(struct dsa_switch *ds) return ret; /* Initialize CPU port pad mode (xMII type, delays...) */ - phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); + phy_mode = of_get_phy_mode(dsa_to_port(ds, QCA8K_CPU_PORT)->dn); if (phy_mode < 0) { pr_err("Can't find phy-mode for master device\n"); return phy_mode; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 2ffe642cf54b..4b0cb779f187 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1058,7 +1058,7 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { l2_lookup.mask_vlanid = VLAN_VID_MASK; l2_lookup.mask_iotag = BIT(0); } else { @@ -1121,7 +1121,7 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port, l2_lookup.vlanid = vid; l2_lookup.iotag = SJA1105_S_TAG; l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0); - if (dsa_port_is_vlan_filtering(&ds->ports[port])) { + if (dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) { l2_lookup.mask_vlanid = VLAN_VID_MASK; l2_lookup.mask_iotag = BIT(0); } else { @@ -1167,7 +1167,7 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, * for what gets printed in 'bridge fdb show'. In the case of zero, * no VID gets printed at all. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) vid = 0; return priv->info->fdb_add_cmd(ds, port, addr, vid); @@ -1178,7 +1178,7 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port, { struct sja1105_private *priv = ds->priv; - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) vid = 0; return priv->info->fdb_del_cmd(ds, port, addr, vid); @@ -1217,7 +1217,7 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, u64_to_ether_addr(l2_lookup.macaddr, macaddr); /* We need to hide the dsa_8021q VLANs from the user. */ - if (!dsa_port_is_vlan_filtering(&ds->ports[port])) + if (!dsa_port_is_vlan_filtering(dsa_to_port(ds, port))) l2_lookup.vlanid = 0; cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data); } @@ -1704,7 +1704,7 @@ static int sja1105_port_enable(struct dsa_switch *ds, int port, if (!dsa_is_user_port(ds, port)) return 0; - slave = ds->ports[port].slave; + slave = dsa_to_port(ds, port)->slave; slave->features &= ~NETIF_F_HW_VLAN_CTAG_FILTER; @@ -1736,7 +1736,7 @@ static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot, } /* Transfer skb to the host port. */ - dsa_enqueue_skb(skb, ds->ports[port].slave); + dsa_enqueue_skb(skb, dsa_to_port(ds, port)->slave); /* Wait until the switch has processed the frame */ do { @@ -2061,8 +2061,8 @@ static int sja1105_probe(struct spi_device *spi) for (i = 0; i < SJA1105_NUM_PORTS; i++) { struct sja1105_port *sp = &priv->ports[i]; - ds->ports[i].priv = sp; - sp->dp = &ds->ports[i]; + dsa_to_port(ds, i)->priv = sp; + sp->dp = dsa_to_port(ds, i); sp->data = tagger_data; } mutex_init(&priv->ptp_data.lock); diff --git a/include/net/dsa.h b/include/net/dsa.h index 8c3ea0530f65..2e4fe2f8962b 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -278,7 +278,7 @@ struct dsa_switch { struct dsa_port ports[]; }; -static inline const struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p) +static inline struct dsa_port *dsa_to_port(struct dsa_switch *ds, int p) { return &ds->ports[p]; } diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 43120a3fb06f..a5545762f5e7 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -246,7 +246,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, #ifdef CONFIG_PM_SLEEP static bool dsa_is_port_initialized(struct dsa_switch *ds, int p) { - return dsa_is_user_port(ds, p) && ds->ports[p].slave; + const struct dsa_port *dp = dsa_to_port(ds, p); + + return dp->type == DSA_PORT_TYPE_USER && dp->slave; } int dsa_switch_suspend(struct dsa_switch *ds) @@ -258,7 +260,7 @@ int dsa_switch_suspend(struct dsa_switch *ds) if (!dsa_is_port_initialized(ds, i)) continue; - ret = dsa_slave_suspend(ds->ports[i].slave); + ret = dsa_slave_suspend(dsa_to_port(ds, i)->slave); if (ret) return ret; } @@ -285,7 +287,7 @@ int dsa_switch_resume(struct dsa_switch *ds) if (!dsa_is_port_initialized(ds, i)) continue; - ret = dsa_slave_resume(ds->ports[i].slave); + ret = dsa_slave_resume(dsa_to_port(ds, i)->slave); if (ret) return ret; } diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 716d265ba8ca..1716535167ee 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -708,7 +708,7 @@ static int dsa_switch_parse_ports_of(struct dsa_switch *ds, goto out_put_node; } - dp = &ds->ports[reg]; + dp = dsa_to_port(ds, reg); err = dsa_port_parse_of(dp, port); if (err) @@ -787,7 +787,7 @@ static int dsa_switch_parse_ports(struct dsa_switch *ds, for (i = 0; i < DSA_MAX_PORTS; i++) { name = cd->port_names[i]; dev = cd->netdev[i]; - dp = &ds->ports[i]; + dp = dsa_to_port(ds, i); if (!name) continue; diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 6a9607518823..df4abe897ed6 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -20,7 +20,7 @@ static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds, int i; for (i = 0; i < ds->num_ports; ++i) { - struct dsa_port *dp = &ds->ports[i]; + struct dsa_port *dp = dsa_to_port(ds, i); if (dp->ageing_time && dp->ageing_time < ageing_time) ageing_time = dp->ageing_time; @@ -98,7 +98,7 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, if (unset_vlan_filtering) { struct switchdev_trans trans = {0}; - err = dsa_port_vlan_filtering(&ds->ports[info->port], + err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port), false, &trans); if (err && err != EOPNOTSUPP) return err; diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index 9c1cc2482b68..bf91fc55fc44 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -103,7 +103,7 @@ static int dsa_8021q_restore_pvid(struct dsa_switch *ds, int port) if (!dsa_is_user_port(ds, port)) return 0; - slave = ds->ports[port].slave; + slave = dsa_to_port(ds, port)->slave; err = br_vlan_get_pvid(slave, &pvid); if (err < 0) @@ -118,7 +118,7 @@ static int dsa_8021q_restore_pvid(struct dsa_switch *ds, int port) return err; } - return dsa_port_vid_add(&ds->ports[port], pvid, vinfo.flags); + return dsa_port_vid_add(dsa_to_port(ds, port), pvid, vinfo.flags); } /* If @enabled is true, installs @vid with @flags into the switch port's HW @@ -130,7 +130,7 @@ static int dsa_8021q_restore_pvid(struct dsa_switch *ds, int port) static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid, u16 flags, bool enabled) { - struct dsa_port *dp = &ds->ports[port]; + struct dsa_port *dp = dsa_to_port(ds, port); struct bridge_vlan_info vinfo; int err; -- cgit v1.2.3-59-g8ed1b From d14939be8bfc4b7493007c365cce5d707d4fbfa1 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:25 -0400 Subject: net: dsa: mv88e6xxx: silently skip PVT ops Since mv88e6xxx_pvt_map is a static helper, no need to return -EOPNOTSUPP if the chip has no PVT, simply silently skip the operation. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index d67deec77452..510ccdc2d03c 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1253,7 +1253,7 @@ static int mv88e6xxx_pvt_map(struct mv88e6xxx_chip *chip, int dev, int port) u16 pvlan = 0; if (!mv88e6xxx_has_pvt(chip)) - return -EOPNOTSUPP; + return 0; /* Skip the local source device, which uses in-chip port VLAN */ if (dev != chip->ds->index) @@ -2049,9 +2049,6 @@ static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, } } - if (!mv88e6xxx_has_pvt(chip)) - return 0; - /* Remap the Port VLAN of each cross-chip bridge group member */ for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { ds = chip->ds->dst->ds[dev]; @@ -2101,9 +2098,6 @@ static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds, int dev, struct mv88e6xxx_chip *chip = ds->priv; int err; - if (!mv88e6xxx_has_pvt(chip)) - return 0; - mv88e6xxx_reg_lock(chip); err = mv88e6xxx_pvt_map(chip, dev, port); mv88e6xxx_reg_unlock(chip); @@ -2116,9 +2110,6 @@ static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds, int dev, { struct mv88e6xxx_chip *chip = ds->priv; - if (!mv88e6xxx_has_pvt(chip)) - return; - mv88e6xxx_reg_lock(chip); if (mv88e6xxx_pvt_map(chip, dev, port)) dev_err(ds->dev, "failed to remap cross-chip Port VLAN\n"); -- cgit v1.2.3-59-g8ed1b From 9dc8b13e230a802f2510de5e37bfceaa59c9e281 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:26 -0400 Subject: net: dsa: mv88e6xxx: use ports list to map port VLAN Instead of digging into the other dsa_switch structures of the fabric and relying too much on the dsa_to_port helper, use the new list of switch fabric ports to define the mask of the local ports allowed to receive frames from another port of the fabric. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 510ccdc2d03c..af8943142053 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1057,35 +1057,43 @@ static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, return 0; } +/* Mask of the local ports allowed to receive frames from a given fabric port */ static u16 mv88e6xxx_port_vlan(struct mv88e6xxx_chip *chip, int dev, int port) { - struct dsa_switch *ds = NULL; + struct dsa_switch *ds = chip->ds; + struct dsa_switch_tree *dst = ds->dst; struct net_device *br; + struct dsa_port *dp; + bool found = false; u16 pvlan; - int i; - if (dev < DSA_MAX_SWITCHES) - ds = chip->ds->dst->ds[dev]; + list_for_each_entry(dp, &dst->ports, list) { + if (dp->ds->index == dev && dp->index == port) { + found = true; + break; + } + } /* Prevent frames from unknown switch or port */ - if (!ds || port >= ds->num_ports) + if (!found) return 0; /* Frames from DSA links and CPU ports can egress any local port */ - if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) + if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) return mv88e6xxx_port_mask(chip); - br = dsa_to_port(ds, port)->bridge_dev; + br = dp->bridge_dev; pvlan = 0; /* Frames from user ports can egress any local DSA links and CPU ports, * as well as any local member of their bridge group. */ - for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) - if (dsa_is_cpu_port(chip->ds, i) || - dsa_is_dsa_port(chip->ds, i) || - (br && dsa_to_port(chip->ds, i)->bridge_dev == br)) - pvlan |= BIT(i); + list_for_each_entry(dp, &dst->ports, list) + if (dp->ds == ds && + (dp->type == DSA_PORT_TYPE_CPU || + dp->type == DSA_PORT_TYPE_DSA || + (br && dp->bridge_dev == br))) + pvlan |= BIT(dp->index); return pvlan; } -- cgit v1.2.3-59-g8ed1b From ef2025ec0acc92fa15ad3df386cb18fefe880643 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:27 -0400 Subject: net: dsa: mv88e6xxx: use ports list to map bridge Instead of digging into the other dsa_switch structures of the fabric and relying too much on the dsa_to_port helper, use the new list of switch fabric ports to remap the Port VLAN Map of local bridge group members or remap the Port VLAN Table entry of external bridge group members. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/mv88e6xxx/chip.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index af8943142053..c53d4dc88e90 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2043,29 +2043,26 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip, struct net_device *br) { - struct dsa_switch *ds; - int port; - int dev; + struct dsa_switch *ds = chip->ds; + struct dsa_switch_tree *dst = ds->dst; + struct dsa_port *dp; int err; - /* Remap the Port VLAN of each local bridge group member */ - for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { - if (dsa_to_port(chip->ds, port)->bridge_dev == br) { - err = mv88e6xxx_port_vlan_map(chip, port); - if (err) - return err; - } - } - - /* Remap the Port VLAN of each cross-chip bridge group member */ - for (dev = 0; dev < DSA_MAX_SWITCHES; ++dev) { - ds = chip->ds->dst->ds[dev]; - if (!ds) - break; - - for (port = 0; port < ds->num_ports; ++port) { - if (dsa_to_port(ds, port)->bridge_dev == br) { - err = mv88e6xxx_pvt_map(chip, dev, port); + list_for_each_entry(dp, &dst->ports, list) { + if (dp->bridge_dev == br) { + if (dp->ds == ds) { + /* This is a local bridge group member, + * remap its Port VLAN Map. + */ + err = mv88e6xxx_port_vlan_map(chip, dp->index); + if (err) + return err; + } else { + /* This is an external bridge group member, + * remap its cross-chip Port VLAN Table entry. + */ + err = mv88e6xxx_pvt_map(chip, dp->ds->index, + dp->index); if (err) return err; } -- cgit v1.2.3-59-g8ed1b From d5a619bf60ecf910175606921b4610a2842c635e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:28 -0400 Subject: net: dsa: sja1105: register switch before assigning port private data Like the dsa_switch_tree structures, the dsa_port structures will be allocated on switch registration. The SJA1105 driver is the only one accessing the dsa_port structure after the switch allocation and before the switch registration. For that reason, move switch registration prior to assigning the priv member of the dsa_port structures. Signed-off-by: Vivien Didelot Signed-off-by: Jakub Kicinski --- drivers/net/dsa/sja1105/sja1105_main.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 4b0cb779f187..0ebbda5ca665 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2057,6 +2057,15 @@ static int sja1105_probe(struct spi_device *spi) tagger_data = &priv->tagger_data; + mutex_init(&priv->ptp_data.lock); + mutex_init(&priv->mgmt_lock); + + sja1105_tas_setup(ds); + + rc = dsa_register_switch(priv->ds); + if (rc) + return rc; + /* Connections between dsa_port and sja1105_port */ for (i = 0; i < SJA1105_NUM_PORTS; i++) { struct sja1105_port *sp = &priv->ports[i]; @@ -2065,12 +2074,8 @@ static int sja1105_probe(struct spi_device *spi) sp->dp = dsa_to_port(ds, i); sp->data = tagger_data; } - mutex_init(&priv->ptp_data.lock); - mutex_init(&priv->mgmt_lock); - sja1105_tas_setup(ds); - - return dsa_register_switch(priv->ds); + return 0; } static int sja1105_remove(struct spi_device *spi) -- cgit v1.2.3-59-g8ed1b From 7e99e34701728d54ccd0466eccf377a42b9db215 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Oct 2019 16:51:30 -0400 Subject: net: dsa: remove dsa_switch_alloc helper Now that ports are dynamically listed in the fabric, there is no need to provide a special helper to allocate the dsa_switch structure. This will give more flexibility to drivers to embed this structure as they wish in their private structure. Signed-off-by: Vivien Didelot Reviewed-by: Florian Fainelli Signed-off-by: Jakub Kicinski --- drivers/net/dsa/b53/b53_common.c | 5 ++++- drivers/net/dsa/dsa_loop.c | 5 ++++- drivers/net/dsa/lan9303-core.c | 4 +++- drivers/net/dsa/lantiq_gswip.c | 4 +++- drivers/net/dsa/microchip/ksz_common.c | 5 ++++- drivers/net/dsa/mt7530.c | 5 ++++- drivers/net/dsa/mv88e6060.c | 4 +++- drivers/net/dsa/mv88e6xxx/chip.c | 4 +++- drivers/net/dsa/qca8k.c | 5 ++++- drivers/net/dsa/realtek-smi-core.c | 5 ++++- drivers/net/dsa/sja1105/sja1105_main.c | 4 +++- drivers/net/dsa/vitesse-vsc73xx-core.c | 5 ++++- include/net/dsa.h | 1 - net/dsa/dsa2.c | 21 ++++++--------------- 14 files changed, 49 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index aef9b56781ef..baadf622ac55 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2341,10 +2341,13 @@ struct b53_device *b53_switch_alloc(struct device *base, struct dsa_switch *ds; struct b53_device *dev; - ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL); if (!ds) return NULL; + ds->dev = base; + ds->num_ports = DSA_MAX_PORTS; + dev = devm_kzalloc(base, sizeof(*dev), GFP_KERNEL); if (!dev) return NULL; diff --git a/drivers/net/dsa/dsa_loop.c b/drivers/net/dsa/dsa_loop.c index 925ed135a4d9..c8d7ef27fd72 100644 --- a/drivers/net/dsa/dsa_loop.c +++ b/drivers/net/dsa/dsa_loop.c @@ -286,10 +286,13 @@ static int dsa_loop_drv_probe(struct mdio_device *mdiodev) dev_info(&mdiodev->dev, "%s: 0x%0x\n", pdata->name, pdata->enabled_ports); - ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); + ds = devm_kzalloc(&mdiodev->dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = &mdiodev->dev; + ds->num_ports = DSA_MAX_PORTS; + ps = devm_kzalloc(&mdiodev->dev, sizeof(*ps), GFP_KERNEL); if (!ps) return -ENOMEM; diff --git a/drivers/net/dsa/lan9303-core.c b/drivers/net/dsa/lan9303-core.c index bbec86b9418e..e3c333a8f45d 100644 --- a/drivers/net/dsa/lan9303-core.c +++ b/drivers/net/dsa/lan9303-core.c @@ -1283,10 +1283,12 @@ static int lan9303_register_switch(struct lan9303 *chip) { int base; - chip->ds = dsa_switch_alloc(chip->dev, LAN9303_NUM_PORTS); + chip->ds = devm_kzalloc(chip->dev, sizeof(*chip->ds), GFP_KERNEL); if (!chip->ds) return -ENOMEM; + chip->ds->dev = chip->dev; + chip->ds->num_ports = LAN9303_NUM_PORTS; chip->ds->priv = chip; chip->ds->ops = &lan9303_switch_ops; base = chip->phy_addr_base; diff --git a/drivers/net/dsa/lantiq_gswip.c b/drivers/net/dsa/lantiq_gswip.c index a69c9b9878b7..955324968b74 100644 --- a/drivers/net/dsa/lantiq_gswip.c +++ b/drivers/net/dsa/lantiq_gswip.c @@ -1854,10 +1854,12 @@ static int gswip_probe(struct platform_device *pdev) if (!priv->hw_info) return -EINVAL; - priv->ds = dsa_switch_alloc(dev, priv->hw_info->max_ports); + priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM; + priv->ds->dev = dev; + priv->ds->num_ports = priv->hw_info->max_ports; priv->ds->priv = priv; priv->ds->ops = &gswip_switch_ops; priv->dev = dev; diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index fe47180c908b..5d08e4430824 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -398,10 +398,13 @@ struct ksz_device *ksz_switch_alloc(struct device *base, void *priv) struct dsa_switch *ds; struct ksz_device *swdev; - ds = dsa_switch_alloc(base, DSA_MAX_PORTS); + ds = devm_kzalloc(base, sizeof(*ds), GFP_KERNEL); if (!ds) return NULL; + ds->dev = base; + ds->num_ports = DSA_MAX_PORTS; + swdev = devm_kzalloc(base, sizeof(*swdev), GFP_KERNEL); if (!swdev) return NULL; diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index a91293e47a57..add9e4279176 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1632,10 +1632,13 @@ mt7530_probe(struct mdio_device *mdiodev) if (!priv) return -ENOMEM; - priv->ds = dsa_switch_alloc(&mdiodev->dev, DSA_MAX_PORTS); + priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM; + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = DSA_MAX_PORTS; + /* Use medatek,mcm property to distinguish hardware type that would * casues a little bit differences on power-on sequence. */ diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c index 2a2489b5196d..a5a37f47b320 100644 --- a/drivers/net/dsa/mv88e6060.c +++ b/drivers/net/dsa/mv88e6060.c @@ -270,10 +270,12 @@ static int mv88e6060_probe(struct mdio_device *mdiodev) dev_info(dev, "switch %s detected\n", name); - ds = dsa_switch_alloc(dev, MV88E6060_PORTS); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = MV88E6060_PORTS; ds->priv = priv; ds->dev = dev; ds->ops = &mv88e6060_switch_ops; diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index c53d4dc88e90..5fdf6d6ebe27 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4978,10 +4978,12 @@ static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) struct device *dev = chip->dev; struct dsa_switch *ds; - ds = dsa_switch_alloc(dev, mv88e6xxx_num_ports(chip)); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = mv88e6xxx_num_ports(chip); ds->priv = chip; ds->dev = dev; ds->ops = &mv88e6xxx_switch_ops; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 71e44c8763b8..7e742cd491e8 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -1077,10 +1077,13 @@ qca8k_sw_probe(struct mdio_device *mdiodev) if (id != QCA8K_ID_QCA8337) return -ENODEV; - priv->ds = dsa_switch_alloc(&mdiodev->dev, QCA8K_NUM_PORTS); + priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), + QCA8K_NUM_PORTS); if (!priv->ds) return -ENOMEM; + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = DSA_MAX_PORTS; priv->ds->priv = priv; priv->ops = qca8k_switch_ops; priv->ds->ops = &priv->ops; diff --git a/drivers/net/dsa/realtek-smi-core.c b/drivers/net/dsa/realtek-smi-core.c index dc0509c02d29..fae188c60191 100644 --- a/drivers/net/dsa/realtek-smi-core.c +++ b/drivers/net/dsa/realtek-smi-core.c @@ -444,9 +444,12 @@ static int realtek_smi_probe(struct platform_device *pdev) return ret; } - smi->ds = dsa_switch_alloc(dev, smi->num_ports); + smi->ds = devm_kzalloc(dev, sizeof(*smi->ds), GFP_KERNEL); if (!smi->ds) return -ENOMEM; + + smi->ds->dev = dev; + smi->ds->num_ports = smi->num_ports; smi->ds->priv = smi; smi->ds->ops = var->ds_ops; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 0ebbda5ca665..2ae84a9dea59 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -2047,10 +2047,12 @@ static int sja1105_probe(struct spi_device *spi) dev_info(dev, "Probed switch chip: %s\n", priv->info->name); - ds = dsa_switch_alloc(dev, SJA1105_NUM_PORTS); + ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); if (!ds) return -ENOMEM; + ds->dev = dev; + ds->num_ports = SJA1105_NUM_PORTS; ds->ops = &sja1105_switch_ops; ds->priv = priv; priv->ds = ds; diff --git a/drivers/net/dsa/vitesse-vsc73xx-core.c b/drivers/net/dsa/vitesse-vsc73xx-core.c index 614377ef7956..42c1574d45f2 100644 --- a/drivers/net/dsa/vitesse-vsc73xx-core.c +++ b/drivers/net/dsa/vitesse-vsc73xx-core.c @@ -1178,9 +1178,12 @@ int vsc73xx_probe(struct vsc73xx *vsc) * We allocate 8 ports and avoid access to the nonexistant * ports. */ - vsc->ds = dsa_switch_alloc(dev, 8); + vsc->ds = devm_kzalloc(dev, sizeof(*vsc->ds), GFP_KERNEL); if (!vsc->ds) return -ENOMEM; + + vsc->ds->dev = dev; + vsc->ds->num_ports = 8; vsc->ds->priv = vsc; vsc->ds->ops = &vsc73xx_ds_ops; diff --git a/include/net/dsa.h b/include/net/dsa.h index 9bc1d3f71f89..e3c14dc3bab9 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -577,7 +577,6 @@ static inline bool dsa_can_decode(const struct sk_buff *skb, return false; } -struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n); void dsa_unregister_switch(struct dsa_switch *ds); int dsa_register_switch(struct dsa_switch *ds); #ifdef CONFIG_PM_SLEEP diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index 83cba4623698..1e3ac9b56c89 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -846,6 +846,12 @@ static int dsa_switch_probe(struct dsa_switch *ds) struct device_node *np = ds->dev->of_node; int err; + if (!ds->dev) + return -ENODEV; + + if (!ds->num_ports) + return -EINVAL; + if (np) err = dsa_switch_parse_of(ds, np); else if (pdata) @@ -859,21 +865,6 @@ static int dsa_switch_probe(struct dsa_switch *ds) return dsa_switch_add(ds); } -struct dsa_switch *dsa_switch_alloc(struct device *dev, size_t n) -{ - struct dsa_switch *ds; - - ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL); - if (!ds) - return NULL; - - ds->dev = dev; - ds->num_ports = n; - - return ds; -} -EXPORT_SYMBOL_GPL(dsa_switch_alloc); - int dsa_register_switch(struct dsa_switch *ds) { int err; -- cgit v1.2.3-59-g8ed1b From e7312efbd5dec50d791dd98bd92ec9ae4f05a832 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Tue, 22 Oct 2019 11:31:06 -0700 Subject: net: phy: modify assignment to OR for dev_flags in phy_attach_direct Modify the assignment to OR when dealing with phydev->dev_flags in phy_attach_direct function, and this is to make sure dev_flags set in driver's probe callback won't be lost. Suggested-by: Andrew Lunn CC: Heiner Kallweit CC: Vladimir Oltean Signed-off-by: Tao Ren Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index adb66a2fae18..f1f60bd4865a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1270,7 +1270,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, phydev_err(phydev, "error creating 'phy_standalone' sysfs entry\n"); } - phydev->dev_flags = flags; + phydev->dev_flags |= flags; phydev->interface = interface; -- cgit v1.2.3-59-g8ed1b From fa6e98cee558622565c97924e922b97340aeabd8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 22 Oct 2019 11:31:07 -0700 Subject: net: phy: add support for clause 37 auto-negotiation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for clause 37 1000Base-X auto-negotiation. Signed-off-by: Heiner Kallweit Signed-off-by: Tao Ren Tested-by: René van Dorst Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 139 +++++++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 4 ++ 2 files changed, 143 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index f1f60bd4865a..fa71998fea51 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1607,6 +1607,40 @@ static int genphy_config_advert(struct phy_device *phydev) return changed; } +/** + * genphy_c37_config_advert - sanitize and advertise auto-negotiation parameters + * @phydev: target phy_device struct + * + * Description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. This function is intended + * for Clause 37 1000Base-X mode. + */ +static int genphy_c37_config_advert(struct phy_device *phydev) +{ + u16 adv = 0; + + /* Only allow advertising what this PHY supports */ + linkmode_and(phydev->advertising, phydev->advertising, + phydev->supported); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XFULL; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XPAUSE; + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + phydev->advertising)) + adv |= ADVERTISE_1000XPSE_ASYM; + + return phy_modify_changed(phydev, MII_ADVERTISE, + ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | + ADVERTISE_1000XHALF | ADVERTISE_1000XPSE_ASYM, + adv); +} + /** * genphy_config_eee_advert - disable unwanted eee mode advertisement * @phydev: target phy_device struct @@ -1715,6 +1749,54 @@ int __genphy_config_aneg(struct phy_device *phydev, bool changed) } EXPORT_SYMBOL(__genphy_config_aneg); +/** + * genphy_c37_config_aneg - restart auto-negotiation or write BMCR + * @phydev: target phy_device struct + * + * Description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR. This function is intended + * for use with Clause 37 1000Base-X mode. + */ +int genphy_c37_config_aneg(struct phy_device *phydev) +{ + int err, changed; + + if (phydev->autoneg != AUTONEG_ENABLE) + return genphy_setup_forced(phydev); + + err = phy_modify(phydev, MII_BMCR, BMCR_SPEED1000 | BMCR_SPEED100, + BMCR_SPEED1000); + if (err) + return err; + + changed = genphy_c37_config_advert(phydev); + if (changed < 0) /* error */ + return changed; + + if (!changed) { + /* Advertisement hasn't changed, but maybe aneg was never on to + * begin with? Or maybe phy was isolated? + */ + int ctl = phy_read(phydev, MII_BMCR); + + if (ctl < 0) + return ctl; + + if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) + changed = 1; /* do restart aneg */ + } + + /* Only restart aneg if we are advertising something different + * than we were before. + */ + if (changed > 0) + return genphy_restart_aneg(phydev); + + return 0; +} +EXPORT_SYMBOL(genphy_c37_config_aneg); + /** * genphy_aneg_done - return auto-negotiation status * @phydev: target phy_device struct @@ -1886,6 +1968,63 @@ int genphy_read_status(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_read_status); +/** + * genphy_c37_read_status - check the link status and update current link state + * @phydev: target phy_device struct + * + * Description: Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. This function is for Clause 37 1000Base-X mode. + */ +int genphy_c37_read_status(struct phy_device *phydev) +{ + int lpa, err, old_link = phydev->link; + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { + lpa = phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + phydev->lp_advertising, lpa & LPA_LPACK); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->lp_advertising, lpa & LPA_1000XFULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, + phydev->lp_advertising, lpa & LPA_1000XPAUSE); + linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, + phydev->lp_advertising, + lpa & LPA_1000XPAUSE_ASYM); + + phy_resolve_aneg_linkmode(phydev); + } else if (phydev->autoneg == AUTONEG_DISABLE) { + int bmcr = phy_read(phydev, MII_BMCR); + + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + } + + return 0; +} +EXPORT_SYMBOL(genphy_c37_read_status); + /** * genphy_soft_reset - software reset the PHY via BMCR_RESET bit * @phydev: target phy_device struct diff --git a/include/linux/phy.h b/include/linux/phy.h index 9a0e981df502..78436d58ce7c 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1106,6 +1106,10 @@ int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, u16 regnum, u16 val); +/* Clause 37 */ +int genphy_c37_config_aneg(struct phy_device *phydev); +int genphy_c37_read_status(struct phy_device *phydev); + /* Clause 45 PHY */ int genphy_c45_restart_aneg(struct phy_device *phydev); int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart); -- cgit v1.2.3-59-g8ed1b From b9bcb95315febd09419ab870ddc7cb98a393f9d0 Mon Sep 17 00:00:00 2001 From: Tao Ren Date: Tue, 22 Oct 2019 11:31:08 -0700 Subject: net: phy: broadcom: add 1000Base-X support for BCM54616S The BCM54616S PHY cannot work properly in RGMII->1000Base-X mode, mainly because genphy functions are designed for copper links, and 1000Base-X (clause 37) auto negotiation needs to be handled differently. This patch enables 1000Base-X support for BCM54616S by customizing 3 driver callbacks, and it's verified to be working on Facebook CMM BMC platform (RGMII->1000Base-KX): - probe: probe callback detects PHY's operation mode based on INTERF_SEL[1:0] pins and 1000X/100FX selection bit in SerDES 100-FX Control register. - config_aneg: calls genphy_c37_config_aneg when the PHY is running in 1000Base-X mode; otherwise, genphy_config_aneg will be called. - read_status: calls genphy_c37_read_status when the PHY is running in 1000Base-X mode; otherwise, genphy_read_status will be called. Note: BCM54616S PHY can also be configured in RGMII->100Base-FX mode, and 100Base-FX support is not available as of now. Signed-off-by: Tao Ren Acked-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/broadcom.c | 57 ++++++++++++++++++++++++++++++++++++++++++---- include/linux/brcmphy.h | 10 ++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 4313c74b4fd8..7d68b28bb893 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -359,9 +359,9 @@ static int bcm5482_config_init(struct phy_device *phydev) /* * Select 1000BASE-X register set (primary SerDes) */ - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_MODE); - bcm_phy_write_shadow(phydev, BCM5482_SHD_MODE, - reg | BCM5482_SHD_MODE_1000BX); + reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); + bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, + reg | BCM54XX_SHD_MODE_1000BX); /* * LED1=ACTIVITYLED, LED3=LINKSPD[2] @@ -427,12 +427,47 @@ static int bcm5481_config_aneg(struct phy_device *phydev) return ret; } +static int bcm54616s_probe(struct phy_device *phydev) +{ + int val, intf_sel; + + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); + if (val < 0) + return val; + + /* The PHY is strapped in RGMII-fiber mode when INTERF_SEL[1:0] + * is 01b, and the link between PHY and its link partner can be + * either 1000Base-X or 100Base-FX. + * RGMII-1000Base-X is properly supported, but RGMII-100Base-FX + * support is still missing as of now. + */ + intf_sel = (val & BCM54XX_SHD_INTF_SEL_MASK) >> 1; + if (intf_sel == 1) { + val = bcm_phy_read_shadow(phydev, BCM54616S_SHD_100FX_CTRL); + if (val < 0) + return val; + + /* Bit 0 of the SerDes 100-FX Control register, when set + * to 1, sets the MII/RGMII -> 100BASE-FX configuration. + * When this bit is set to 0, it sets the GMII/RGMII -> + * 1000BASE-X configuration. + */ + if (!(val & BCM54616S_100FX_MODE)) + phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX; + } + + return 0; +} + static int bcm54616s_config_aneg(struct phy_device *phydev) { int ret; /* Aneg firsly. */ - ret = genphy_config_aneg(phydev); + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + ret = genphy_c37_config_aneg(phydev); + else + ret = genphy_config_aneg(phydev); /* Then we can set up the delay. */ bcm54xx_config_clock_delay(phydev); @@ -440,6 +475,18 @@ static int bcm54616s_config_aneg(struct phy_device *phydev) return ret; } +static int bcm54616s_read_status(struct phy_device *phydev) +{ + int err; + + if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + err = genphy_c37_read_status(phydev); + else + err = genphy_read_status(phydev); + + return err; +} + static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set) { int val; @@ -631,6 +678,8 @@ static struct phy_driver broadcom_drivers[] = { .config_aneg = bcm54616s_config_aneg, .ack_interrupt = bcm_phy_ack_intr, .config_intr = bcm_phy_config_intr, + .read_status = bcm54616s_read_status, + .probe = bcm54616s_probe, }, { .phy_id = PHY_ID_BCM5464, .phy_id_mask = 0xfffffff0, diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h index 6db2d9a6e503..b475e7f20d28 100644 --- a/include/linux/brcmphy.h +++ b/include/linux/brcmphy.h @@ -200,9 +200,15 @@ #define BCM5482_SHD_SSD 0x14 /* 10100: Secondary SerDes control */ #define BCM5482_SHD_SSD_LEDM 0x0008 /* SSD LED Mode enable */ #define BCM5482_SHD_SSD_EN 0x0001 /* SSD enable */ -#define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ -#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ +/* 10011: SerDes 100-FX Control Register */ +#define BCM54616S_SHD_100FX_CTRL 0x13 +#define BCM54616S_100FX_MODE BIT(0) /* 100-FX SerDes Enable */ + +/* 11111: Mode Control Register */ +#define BCM54XX_SHD_MODE 0x1f +#define BCM54XX_SHD_INTF_SEL_MASK GENMASK(2, 1) /* INTERF_SEL[1:0] */ +#define BCM54XX_SHD_MODE_1000BX BIT(0) /* Enable 1000-X registers */ /* * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) -- cgit v1.2.3-59-g8ed1b From 06cd9da58fb25526bd1a4b0f36e25e1a8824ea1f Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 22 Oct 2019 21:30:57 +0200 Subject: r8169: never set PCI_EXP_DEVCTL_NOSNOOP_EN Setting PCI_EXP_DEVCTL_NOSNOOP_EN for certain chip versions had been added to the vendor driver more than 10 years ago, and copied from there to r8169. It has been removed from the vendor driver meanwhile and I think we can safely remove this too. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 57942383b73d..c317af9c60e9 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5345,19 +5345,6 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) static void rtl_hw_start_8168(struct rtl8169_private *tp) { - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - case RTL_GIGA_MAC_VER_12: - case RTL_GIGA_MAC_VER_13: - case RTL_GIGA_MAC_VER_16: - case RTL_GIGA_MAC_VER_17: - pcie_capability_set_word(tp->pci_dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_NOSNOOP_EN); - break; - default: - break; - } - if (rtl_is_8168evl_up(tp)) RTL_W8(tp, MaxTxPacketSize, EarlySize); else -- cgit v1.2.3-59-g8ed1b From 914c4fc1b792dd963f9606b2e8b33e3d6606eb84 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 23 Oct 2019 09:04:59 +0300 Subject: mlxsw: spectrum: Use guaranteed buffer size as pool size limit There are two resources associated with shared buffer size: cap_total_buffer_size, and cap_guaranteed_shared_buffer. So far, mlxsw has been using the former as a limit to determine how large a pool size is allowed to be. However, the total size also includes headrooms and reserved space, which really cannot be used for shared buffer pools. Therefore convert mlxsw to use the latter resource as a limit. Adjust hard-coded pool sizes to be the guaranteed size minus 256000 bytes for CPU port pool. On Spectrum-1 that actually leads to an increase. A follow-up patch will have this size calculated automatically. Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/resources.h | 4 ++-- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 15 ++++++++------- drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 33a9fc9ef6a4..85f919fe851b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -26,7 +26,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_LAG_MEMBERS, MLXSW_RES_ID_LOCAL_PORTS_IN_1X, MLXSW_RES_ID_LOCAL_PORTS_IN_2X, - MLXSW_RES_ID_MAX_BUFFER_SIZE, + MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, MLXSW_RES_ID_CELL_SIZE, MLXSW_RES_ID_MAX_HEADROOM_SIZE, MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS, @@ -82,7 +82,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, [MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610, [MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611, - [MLXSW_RES_ID_MAX_BUFFER_SIZE] = 0x2802, /* Bytes */ + [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ [MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */ [MLXSW_RES_ID_ACL_MAX_TCAM_REGIONS] = 0x2901, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index b9eeae37a4dc..637151682cf2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -421,8 +421,8 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) .freeze_size = _freeze_size, \ } -#define MLXSW_SP1_SB_PR_INGRESS_SIZE 12440000 -#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13232000 +#define MLXSW_SP1_SB_PR_INGRESS_SIZE 13768608 +#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13768608 #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp1_sb_pool_dess */ @@ -445,8 +445,8 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 35297568 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 35297568 +#define MLXSW_SP2_SB_PR_INGRESS_SIZE 34084800 +#define MLXSW_SP2_SB_PR_EGRESS_SIZE 34084800 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ @@ -904,7 +904,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE)) return -EIO; - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE)) + if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, GUARANTEED_SHARED_BUFFER)) return -EIO; if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_HEADROOM_SIZE)) @@ -915,7 +915,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) return -ENOMEM; mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE); mlxsw_sp->sb->sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, - MAX_BUFFER_SIZE); + GUARANTEED_SHARED_BUFFER); max_headroom_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_HEADROOM_SIZE); /* Round down, because this limit must not be overstepped. */ @@ -1013,7 +1013,8 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, mode = (enum mlxsw_reg_sbpr_mode) threshold_type; pr = &mlxsw_sp->sb_vals->prs[pool_index]; - if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (size > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { NL_SET_ERR_MSG_MOD(extack, "Exceeded shared buffer size"); return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c index bdf53cf350f6..68cc6737d45c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c @@ -305,7 +305,8 @@ mlxsw_sp_qdisc_red_check_params(struct mlxsw_sp_port *mlxsw_sp_port, p->max); return -EINVAL; } - if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE)) { + if (p->max > MLXSW_CORE_RES_GET(mlxsw_sp->core, + GUARANTEED_SHARED_BUFFER)) { dev_err(mlxsw_sp->bus_info->dev, "spectrum: RED: max value %u is too big\n", p->max); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From bc9f6e94bcb5652860c1b3bc82ca27697c496b4d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Wed, 23 Oct 2019 09:05:00 +0300 Subject: mlxsw: spectrum_buffers: Calculate the size of the main pool Instead of hard-coding the size of the largest pool, calculate it from the reported guaranteed shared buffer size and sizes of other pools (currently only the CPU port pool). Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 46 ++++++++++++++++------ 1 file changed, 34 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 637151682cf2..5fd9a72c8471 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -35,6 +35,7 @@ struct mlxsw_sp_sb_cm { }; #define MLXSW_SP_SB_INFI -1U +#define MLXSW_SP_SB_REST -2U struct mlxsw_sp_sb_pm { u32 min_buff; @@ -421,19 +422,16 @@ static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp) .freeze_size = _freeze_size, \ } -#define MLXSW_SP1_SB_PR_INGRESS_SIZE 13768608 -#define MLXSW_SP1_SB_PR_EGRESS_SIZE 13768608 #define MLXSW_SP1_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp1_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP1_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, 0), @@ -445,19 +443,16 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp1_sb_prs[] = { MLXSW_SP1_SB_PR_CPU_SIZE, true, false), }; -#define MLXSW_SP2_SB_PR_INGRESS_SIZE 34084800 -#define MLXSW_SP2_SB_PR_EGRESS_SIZE 34084800 #define MLXSW_SP2_SB_PR_CPU_SIZE (256 * 1000) /* Order according to mlxsw_sp2_sb_pool_dess */ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { - MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_INGRESS_SIZE), + MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), - MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, - MLXSW_SP2_SB_PR_EGRESS_SIZE, true, false), + MLXSW_SP_SB_PR_EXT(MLXSW_REG_SBPR_MODE_DYNAMIC, MLXSW_SP_SB_REST, + true, false), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), MLXSW_SP_SB_PR(MLXSW_REG_SBPR_MODE_STATIC, 0), @@ -471,11 +466,33 @@ static const struct mlxsw_sp_sb_pr mlxsw_sp2_sb_prs[] = { static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_sb_pr *prs, + const struct mlxsw_sp_sb_pool_des *pool_dess, size_t prs_len) { + /* Round down, unlike mlxsw_sp_bytes_cells(). */ + u32 sb_cells = mlxsw_sp->sb->sb_size / mlxsw_sp->sb->cell_size; + u32 rest_cells[2] = {sb_cells, sb_cells}; int i; int err; + /* Calculate how much space to give to the "REST" pools in either + * direction. + */ + for (i = 0; i < prs_len; i++) { + enum mlxsw_reg_sbxx_dir dir = pool_dess[i].dir; + u32 size = prs[i].size; + u32 size_cells; + + if (size == MLXSW_SP_SB_INFI || size == MLXSW_SP_SB_REST) + continue; + + size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); + if (WARN_ON_ONCE(size_cells > rest_cells[dir])) + continue; + + rest_cells[dir] -= size_cells; + } + for (i = 0; i < prs_len; i++) { u32 size = prs[i].size; u32 size_cells; @@ -483,6 +500,10 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, if (size == MLXSW_SP_SB_INFI) { err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, 0, true); + } else if (size == MLXSW_SP_SB_REST) { + size_cells = rest_cells[pool_dess[i].dir]; + err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, + size_cells, false); } else { size_cells = mlxsw_sp_bytes_cells(mlxsw_sp, size); err = mlxsw_sp_sb_pr_write(mlxsw_sp, i, prs[i].mode, @@ -926,6 +947,7 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_sb_ports_init; err = mlxsw_sp_sb_prs_init(mlxsw_sp, mlxsw_sp->sb_vals->prs, + mlxsw_sp->sb_vals->pool_dess, mlxsw_sp->sb_vals->pool_count); if (err) goto err_sb_prs_init; -- cgit v1.2.3-59-g8ed1b From 337d866a8014987dd45cf138ddcb9eca1ae44d56 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Oct 2019 15:36:26 +0800 Subject: net: lan78xx: remove set but not used variable 'event' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/usb/lan78xx.c:3995:6: warning: variable event set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 62948098191f..f8c0818e56c9 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3992,9 +3992,6 @@ static int lan78xx_suspend(struct usb_interface *intf, pm_message_t message) struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); u32 buf; int ret; - int event; - - event = message.event; if (!dev->suspend_count++) { spin_lock_irq(&dev->txq.lock); -- cgit v1.2.3-59-g8ed1b From 8575b534b0006dcfc539cbe079bcfbda52576fac Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 22 Oct 2019 18:04:16 +0800 Subject: rtw88: use macro to check the current band Add macros to see which band we are, based on the current channel. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.c | 2 +- drivers/net/wireless/realtek/rtw88/main.h | 13 +++++++++ drivers/net/wireless/realtek/rtw88/phy.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 40 ++++++++++++--------------- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 16 +++++------ 5 files changed, 41 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index 8d72825ed3a7..c471117b1472 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -47,7 +47,7 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, value8 = rtw_read8(rtwdev, REG_CCK_CHECK); value8 = value8 & ~BIT_CHECK_CCK_EN; - if (channel > 35) + if (IS_CH_5G_BAND(channel)) value8 |= BIT_CHECK_CCK_EN; rtw_write8(rtwdev, REG_CCK_CHECK, value8); } diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 4759d6a0ca6e..492a2bfc0d5a 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -58,6 +58,19 @@ struct rtw_hci { u8 bulkout_num; }; +#define IS_CH_5G_BAND_1(channel) ((channel) >= 36 && (channel <= 48)) +#define IS_CH_5G_BAND_2(channel) ((channel) >= 52 && (channel <= 64)) +#define IS_CH_5G_BAND_3(channel) ((channel) >= 100 && (channel <= 144)) +#define IS_CH_5G_BAND_4(channel) ((channel) >= 149 && (channel <= 177)) + +#define IS_CH_5G_BAND_MID(channel) \ + (IS_CH_5G_BAND_2(channel) || IS_CH_5G_BAND_3(channel)) + +#define IS_CH_2G_BAND(channel) ((channel) <= 14) +#define IS_CH_5G_BAND(channel) \ + (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel) || \ + IS_CH_5G_BAND_3(channel) || IS_CH_5G_BAND_4(channel)) + enum rtw_supported_band { RTW_BAND_2G = 1 << 0, RTW_BAND_5G = 1 << 1, diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 8ebe1f4b76ad..ae5ecefb424e 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -1748,7 +1748,7 @@ void rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, group = rtw_get_channel_group(ch); /* base power index for 2.4G/5G */ - if (ch <= 14) { + if (IS_CH_2G_BAND(ch)) { band = PHY_BAND_2G; *base = rtw_phy_get_2g_tx_power_index(rtwdev, &pwr_idx->pwr_idx_2g, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 1e20c4465bc9..baf5091fa253 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -211,9 +211,8 @@ static int rtw8822b_mac_init(struct rtw_dev *rtwdev) static void rtw8822b_set_channel_rfe_efem(struct rtw_dev *rtwdev, u8 channel) { struct rtw_hal *hal = &rtwdev->hal; - bool is_channel_2g = (channel <= 14) ? true : false; - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { rtw_write32s_mask(rtwdev, REG_RFESEL0, 0xffffff, 0x705770); rtw_write32s_mask(rtwdev, REG_RFESEL8, MASKBYTE1, 0x57); rtw_write32s_mask(rtwdev, REG_RFECTL, BIT(4), 0); @@ -241,9 +240,8 @@ static void rtw8822b_set_channel_rfe_efem(struct rtw_dev *rtwdev, u8 channel) static void rtw8822b_set_channel_rfe_ifem(struct rtw_dev *rtwdev, u8 channel) { struct rtw_hal *hal = &rtwdev->hal; - bool is_channel_2g = (channel <= 14) ? true : false; - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { /* signal source */ rtw_write32s_mask(rtwdev, REG_RFESEL0, 0xffffff, 0x745774); rtw_write32s_mask(rtwdev, REG_RFESEL8, MASKBYTE1, 0x57); @@ -255,7 +253,7 @@ static void rtw8822b_set_channel_rfe_ifem(struct rtw_dev *rtwdev, u8 channel) rtw_write32s_mask(rtwdev, REG_RFEINV, BIT(11) | BIT(10) | 0x3f, 0x0); - if (is_channel_2g) { + if (IS_CH_2G_BAND(channel)) { if (hal->antenna_rx == BB_PATH_AB || hal->antenna_tx == BB_PATH_AB) { /* 2TX or 2RX */ @@ -350,7 +348,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, u32 reg82c, reg830, reg838; bool is_efem_cca = false, is_ifem_cca = false, is_rfe_type = false; - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { cca_ccut = rfe_info->cca_ccut_2g; if (hal->antenna_rx == BB_PATH_A || @@ -381,7 +379,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, is_efem_cca = true; break; case RTW_RFE_IFEM2G_EFEM5G: - if (channel <= 14) + if (IS_CH_2G_BAND(channel)) is_ifem_cca = true; else is_efem_cca = true; @@ -405,9 +403,7 @@ static void rtw8822b_set_channel_cca(struct rtw_dev *rtwdev, u8 channel, u8 bw, if (is_efem_cca && !(hal->cut_version == RTW_CHIP_VER_CUT_B)) rtw_write32_mask(rtwdev, REG_L1WT, MASKDWORD, 0x9194b2b9); - if (bw == RTW_CHANNEL_WIDTH_20 && - ((channel >= 52 && channel <= 64) || - (channel >= 100 && channel <= 144))) + if (bw == RTW_CHANNEL_WIDTH_20 && IS_CH_5G_BAND_MID(channel)) rtw_write32_mask(rtwdev, REG_CCA2ND, 0xf0, 0x4); } @@ -442,7 +438,7 @@ static void rtw8822b_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) rf_reg18 &= ~(RF18_BAND_MASK | RF18_CHANNEL_MASK | RF18_RFSI_MASK | RF18_BW_MASK); - rf_reg18 |= (channel <= 14 ? RF18_BAND_2G : RF18_BAND_5G); + rf_reg18 |= (IS_CH_2G_BAND(channel) ? RF18_BAND_2G : RF18_BAND_5G); rf_reg18 |= (channel & RF18_CHANNEL_MASK); if (channel > 144) rf_reg18 |= RF18_RFSI_GT_CH144; @@ -464,13 +460,13 @@ static void rtw8822b_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) break; } - if (channel <= 14) + if (IS_CH_2G_BAND(channel)) rf_reg_be = 0x0; - else if (channel >= 36 && channel <= 64) + else if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) rf_reg_be = low_band[(channel - 36) >> 1]; - else if (channel >= 100 && channel <= 144) + else if (IS_CH_5G_BAND_3(channel)) rf_reg_be = middle_band[(channel - 100) >> 1]; - else if (channel >= 149 && channel <= 177) + else if (IS_CH_5G_BAND_4(channel)) rf_reg_be = high_band[(channel - 149) >> 1]; else goto err; @@ -539,7 +535,7 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 rfe_option = efuse->rfe_option; u32 val32; - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x1); rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x0); rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x0); @@ -556,22 +552,22 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, } rtw_write32_mask(rtwdev, REG_RFEINV, 0x300, 0x2); - } else if (channel > 35) { + } else if (IS_CH_5G_BAND(channel)) { rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1); rtw_write32_mask(rtwdev, REG_CCK_CHECK, BIT(7), 0x1); rtw_write32_mask(rtwdev, REG_RXPSEL, BIT(28), 0x0); rtw_write32_mask(rtwdev, REG_RXCCAMSK, 0x0000FC00, 34); - if (channel >= 36 && channel <= 64) + if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x1); - else if (channel >= 100 && channel <= 144) + else if (IS_CH_5G_BAND_3(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x2); - else if (channel >= 149) + else if (IS_CH_5G_BAND_4(channel)) rtw_write32_mask(rtwdev, REG_ACGG2TBL, 0x1f, 0x3); - if (channel >= 36 && channel <= 48) + if (IS_CH_5G_BAND_1(channel)) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x494); - else if (channel >= 52 && channel <= 64) + else if (IS_CH_5G_BAND_2(channel)) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x453); else if (channel >= 100 && channel <= 116) rtw_write32_mask(rtwdev, REG_CLKTRK, 0x1ffe0000, 0x452); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 690934386b85..167af317c7c5 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1287,11 +1287,11 @@ static void rtw8822c_set_channel_rf(struct rtw_dev *rtwdev, u8 channel, u8 bw) rf_reg18 &= ~(RF18_BAND_MASK | RF18_CHANNEL_MASK | RF18_RFSI_MASK | RF18_BW_MASK); - rf_reg18 |= (channel <= 14 ? RF18_BAND_2G : RF18_BAND_5G); + rf_reg18 |= (IS_CH_2G_BAND(channel) ? RF18_BAND_2G : RF18_BAND_5G); rf_reg18 |= (channel & RF18_CHANNEL_MASK); - if (channel > 144) + if (IS_CH_5G_BAND_4(channel)) rf_reg18 |= RF18_RFSI_GT_CH140; - else if (channel >= 80) + else if (IS_CH_5G_BAND_3(channel)) rf_reg18 |= RF18_RFSI_GE_CH80; switch (bw) { @@ -1341,7 +1341,7 @@ static void rtw8822c_toggle_igi(struct rtw_dev *rtwdev) static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, u8 primary_ch_idx) { - if (channel <= 14) { + if (IS_CH_2G_BAND(channel)) { rtw_write32_clr(rtwdev, REG_BGCTRL, BITS_RX_IQ_WEIGHT); rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x8); rtw_write32_set(rtwdev, REG_TXF4, BIT(20)); @@ -1406,7 +1406,7 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3); else rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x1); - } else if (channel > 35) { + } else if (IS_CH_5G_BAND(channel)) { rtw_write32_set(rtwdev, REG_CCKTXONLY, BIT_BB_CCK_CHECK_EN); rtw_write32_set(rtwdev, REG_CCK_CHECK, BIT_CHECK_CCK_EN); rtw_write32_set(rtwdev, REG_BGCTRL, BITS_RX_IQ_WEIGHT); @@ -1414,17 +1414,17 @@ static void rtw8822c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_RXCCKSEL, 0xf0000000, 0x0); rtw_write32_mask(rtwdev, REG_CCAMSK, 0x3F000000, 0x22); rtw_write32_mask(rtwdev, REG_TXDFIR0, 0x70, 0x3); - if (channel >= 36 && channel <= 64) { + if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x1); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, 0x1); - } else if (channel >= 100 && channel <= 144) { + } else if (IS_CH_5G_BAND_3(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x2); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, 0x2); - } else if (channel >= 149) { + } else if (IS_CH_5G_BAND_4(channel)) { rtw_write32_mask(rtwdev, REG_RXAGCCTL0, BITS_RXAGC_OFDM, 0x3); rtw_write32_mask(rtwdev, REG_RXAGCCTL, BITS_RXAGC_OFDM, -- cgit v1.2.3-59-g8ed1b From c97ee3e0bea29827f4b44276fc792bd32977edb0 Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Tue, 22 Oct 2019 18:04:17 +0800 Subject: rtw88: add power tracking support The temperature of the chip can affect the output power of the RF components. Hence driver requires to compensate the power by adjusting the power index recorded in the power swing table. And if the difference of current thermal value to the default thermal value exceeds a threshold, the RF IQK should be triggered to re-calibrate the characteristics of the RF components, to keep the output IQ vectors of the RF components orthogonal enough. Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/fw.c | 1 + drivers/net/wireless/realtek/rtw88/main.h | 49 +++- drivers/net/wireless/realtek/rtw88/phy.c | 126 ++++++++++ drivers/net/wireless/realtek/rtw88/phy.h | 12 + drivers/net/wireless/realtek/rtw88/rtw8822b.c | 330 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 228 ++++++++++++++++++ 6 files changed, 745 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 65594393dd1e..b8c581161f61 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -117,6 +117,7 @@ static void rtw_fw_ra_report_handle(struct rtw_dev *rtwdev, u8 *payload, if (WARN(length < 7, "invalid ra report c2h length\n")) return; + rtwdev->dm_info.tx_rate = GET_RA_REPORT_RATE(payload); ra_data.rtwdev = rtwdev; ra_data.payload = payload; rtw_iterate_stas_atomic(rtwdev, rtw_fw_ra_report_iter, &ra_data); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 492a2bfc0d5a..757b0ce2bbee 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -691,6 +691,7 @@ struct rtw_chip_ops { void (*phy_calibration)(struct rtw_dev *rtwdev); void (*dpk_track)(struct rtw_dev *rtwdev); void (*cck_pd_set)(struct rtw_dev *rtwdev, u8 level); + void (*pwr_track)(struct rtw_dev *rtwdev); /* for coex */ void (*coex_set_init)(struct rtw_dev *rtwdev); @@ -867,6 +868,34 @@ struct rtw_rfe_def { .txpwr_lmt_tbl = &rtw ## chip ## _txpwr_lmt_type ## pwrlmt ## _tbl, \ } +#define RTW_PWR_TRK_5G_1 0 +#define RTW_PWR_TRK_5G_2 1 +#define RTW_PWR_TRK_5G_3 2 +#define RTW_PWR_TRK_5G_NUM 3 + +#define RTW_PWR_TRK_TBL_SZ 30 + +/* This table stores the values of TX power that will be adjusted by power + * tracking. + * + * For 5G bands, there are 3 different settings. + * For 2G there are cck rate and ofdm rate with different settings. + */ +struct rtw_pwr_track_tbl { + const u8 *pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM]; + const u8 *pwrtrk_2gb_n; + const u8 *pwrtrk_2gb_p; + const u8 *pwrtrk_2ga_n; + const u8 *pwrtrk_2ga_p; + const u8 *pwrtrk_2g_cckb_n; + const u8 *pwrtrk_2g_cckb_p; + const u8 *pwrtrk_2g_ccka_n; + const u8 *pwrtrk_2g_ccka_p; +}; + /* hardware configuration for each IC */ struct rtw_chip_info { struct rtw_chip_ops *ops; @@ -918,6 +947,8 @@ struct rtw_chip_info { bool en_dis_dpd; u16 dpd_ratemask; + u8 iqk_threshold; + const struct rtw_pwr_track_tbl *pwr_track_tbl; /* coex paras */ u32 coex_para_ver; @@ -1171,6 +1202,11 @@ struct rtw_phy_cck_pd_reg { #define DACK_MSBK_BACKUP_NUM 0xf #define DACK_DCK_BACKUP_NUM 0x2 +struct rtw_swing_table { + const u8 *p[RTW_RF_PATH_MAX]; + const u8 *n[RTW_RF_PATH_MAX]; +}; + struct rtw_dm_info { u32 cck_fa_cnt; u32 ofdm_fa_cnt; @@ -1197,6 +1233,15 @@ struct rtw_dm_info { u8 cck_gi_u_bnd; u8 cck_gi_l_bnd; + u8 tx_rate; + u8 thermal_avg[RTW_RF_PATH_MAX]; + u8 thermal_meter_k; + s8 delta_power_index[RTW_RF_PATH_MAX]; + u8 default_ofdm_index; + bool pwr_trk_triggered; + bool pwr_trk_init_trigger; + struct ewma_thermal avg_thermal[RTW_RF_PATH_MAX]; + /* backup dack results for each path and I/Q */ u32 dack_adck[RTW_RF_PATH_MAX]; u16 dack_msbk[RTW_RF_PATH_MAX][2][DACK_MSBK_BACKUP_NUM]; @@ -1220,7 +1265,9 @@ struct rtw_efuse { u8 country_code[2]; u8 rf_board_option; u8 rfe_option; - u8 thermal_meter; + u8 power_track_type; + u8 thermal_meter[RTW_RF_PATH_MAX]; + u8 thermal_meter_k; u8 crystal_cap; u8 ant_div_cfg; u8 ant_div_type; diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index ae5ecefb424e..0fa8d91a882b 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -539,6 +539,11 @@ static void rtw_phy_cck_pd(struct rtw_dev *rtwdev) chip->ops->cck_pd_set(rtwdev, level); } +static void rtw_phy_pwr_track(struct rtw_dev *rtwdev) +{ + rtwdev->chip->ops->pwr_track(rtwdev); +} + void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) { /* for further calculation */ @@ -547,6 +552,7 @@ void rtw_phy_dynamic_mechanism(struct rtw_dev *rtwdev) rtw_phy_cck_pd(rtwdev); rtw_phy_ra_info_update(rtwdev); rtw_phy_dpk_track(rtwdev); + rtw_phy_pwr_track(rtwdev); } #define FRAC_BITS 3 @@ -1968,3 +1974,123 @@ void rtw_phy_init_tx_power(struct rtw_dev *rtwdev) rtw_phy_init_tx_power_limit(rtwdev, regd, bw, rs); } + +void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table) +{ + const struct rtw_pwr_track_tbl *tbl = rtwdev->chip->pwr_track_tbl; + u8 channel = rtwdev->hal.current_channel; + + if (IS_CH_2G_BAND(channel)) { + if (rtwdev->dm_info.tx_rate <= DESC_RATE11M) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2g_ccka_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2g_ccka_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2g_cckb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2g_cckb_n; + } else { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n; + } + } else if (IS_CH_5G_BAND_1(channel) || IS_CH_5G_BAND_2(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_1]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_1]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_1]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_1]; + } else if (IS_CH_5G_BAND_3(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_2]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_2]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_2]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_2]; + } else if (IS_CH_5G_BAND_4(channel)) { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_5ga_p[RTW_PWR_TRK_5G_3]; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_5ga_n[RTW_PWR_TRK_5G_3]; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_5gb_p[RTW_PWR_TRK_5G_3]; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_5gb_n[RTW_PWR_TRK_5G_3]; + } else { + swing_table->p[RF_PATH_A] = tbl->pwrtrk_2ga_p; + swing_table->n[RF_PATH_A] = tbl->pwrtrk_2ga_n; + swing_table->p[RF_PATH_B] = tbl->pwrtrk_2gb_p; + swing_table->n[RF_PATH_B] = tbl->pwrtrk_2gb_n; + } +} + +void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + ewma_thermal_add(&dm_info->avg_thermal[path], thermal); + dm_info->thermal_avg[path] = + ewma_thermal_read(&dm_info->avg_thermal[path]); +} + +bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 avg = ewma_thermal_read(&dm_info->avg_thermal[path]); + + if (avg == thermal) + return false; + + return true; +} + +u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 therm_avg, therm_efuse, therm_delta; + + therm_avg = dm_info->thermal_avg[path]; + therm_efuse = rtwdev->efuse.thermal_meter[path]; + therm_delta = abs(therm_avg - therm_efuse); + + return min_t(u8, therm_delta, RTW_PWR_TRK_TBL_SZ - 1); +} + +s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 tbl_path, u8 therm_path, u8 delta) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + const u8 *delta_swing_table_idx_pos; + const u8 *delta_swing_table_idx_neg; + + if (delta >= RTW_PWR_TRK_TBL_SZ) { + rtw_warn(rtwdev, "power track table overflow\n"); + return 0; + } + + if (!swing_table || !swing_table->n || !swing_table->p) { + rtw_warn(rtwdev, "swing table not configured\n"); + return 0; + } + + delta_swing_table_idx_pos = swing_table->p[tbl_path]; + delta_swing_table_idx_neg = swing_table->n[tbl_path]; + + if (!delta_swing_table_idx_pos || !delta_swing_table_idx_neg) { + rtw_warn(rtwdev, "invalid swing table index\n"); + return 0; + } + + if (dm_info->thermal_avg[therm_path] > + rtwdev->efuse.thermal_meter[therm_path]) + return delta_swing_table_idx_pos[delta]; + else + return -delta_swing_table_idx_neg[delta]; +} + +bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 delta_iqk; + + delta_iqk = abs(dm_info->thermal_avg[0] - dm_info->thermal_meter_k); + if (delta_iqk >= rtwdev->chip->iqk_threshold) { + dm_info->thermal_meter_k = dm_info->thermal_avg[0]; + return true; + } + return false; +} diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index e79b084628e7..0dc7720aaad7 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -41,9 +41,21 @@ void rtw_phy_cfg_rf(struct rtw_dev *rtwdev, const struct rtw_table *tbl, u32 addr, u32 data); void rtw_phy_init_tx_power(struct rtw_dev *rtwdev); void rtw_phy_load_tables(struct rtw_dev *rtwdev); +u8 rtw_phy_get_tx_power_index(struct rtw_dev *rtwdev, u8 rf_path, u8 rate, + enum rtw_bandwidth bw, u8 channel, u8 regd); void rtw_phy_set_tx_power_level(struct rtw_dev *rtwdev, u8 channel); void rtw_phy_tx_power_by_rate_config(struct rtw_hal *hal); void rtw_phy_tx_power_limit_config(struct rtw_hal *hal); +void rtw_phy_pwrtrack_avg(struct rtw_dev *rtwdev, u8 thermal, u8 path); +bool rtw_phy_pwrtrack_thermal_changed(struct rtw_dev *rtwdev, u8 thermal, + u8 path); +u8 rtw_phy_pwrtrack_get_delta(struct rtw_dev *rtwdev, u8 path); +s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 tbl_path, u8 therm_path, u8 delta); +bool rtw_phy_pwrtrack_need_iqk(struct rtw_dev *rtwdev); +void rtw_phy_config_swing_table(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table); struct rtw_txpwr_lmt_cfg_pair { u8 regd; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index baf5091fa253..34fbfe6b4a11 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -43,6 +43,8 @@ static int rtw8822b_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) efuse->country_code[1] = map->country_code[1]; efuse->bt_setting = map->rf_bt_setting; efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[RF_PATH_A] = map->thermal_meter; + efuse->thermal_meter_k = map->thermal_meter; for (i = 0; i < 4; i++) efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; @@ -75,6 +77,49 @@ static void rtw8822b_phy_rfe_init(struct rtw_dev *rtwdev) rtw_write32_mask(rtwdev, 0x974, (BIT(11) | BIT(10)), 0x3); } +#define RTW_TXSCALE_SIZE 37 +static const u32 rtw8822b_txscale_tbl[RTW_TXSCALE_SIZE] = { + 0x081, 0x088, 0x090, 0x099, 0x0a2, 0x0ac, 0x0b6, 0x0c0, 0x0cc, 0x0d8, + 0x0e5, 0x0f2, 0x101, 0x110, 0x120, 0x131, 0x143, 0x156, 0x16a, 0x180, + 0x197, 0x1af, 0x1c8, 0x1e3, 0x200, 0x21e, 0x23e, 0x261, 0x285, 0x2ab, + 0x2d3, 0x2fe, 0x32b, 0x35c, 0x38e, 0x3c4, 0x3fe +}; + +static const u8 rtw8822b_get_swing_index(struct rtw_dev *rtwdev) +{ + u8 i = 0; + u32 swing, table_value; + + swing = rtw_read32_mask(rtwdev, 0xc1c, 0xffe00000); + for (i = 0; i < RTW_TXSCALE_SIZE; i++) { + table_value = rtw8822b_txscale_tbl[i]; + if (swing == table_value) + break; + } + + return i; +} + +static void rtw8822b_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 swing_idx = rtw8822b_get_swing_index(rtwdev); + u8 path; + + if (swing_idx >= RTW_TXSCALE_SIZE) + dm_info->default_ofdm_index = 24; + else + dm_info->default_ofdm_index = swing_idx; + + for (path = RF_PATH_A; path < rtwdev->hal.rf_path_num; path++) { + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->delta_power_index[path] = 0; + } + dm_info->pwr_trk_triggered = false; + dm_info->pwr_trk_init_trigger = true; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) { struct rtw_hal *hal = &rtwdev->hal; @@ -106,6 +151,7 @@ static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) rtw_phy_init(rtwdev); rtw8822b_phy_rfe_init(rtwdev); + rtw8822b_pwrtrack_init(rtwdev); } #define WLAN_SLOT_TIME 0x09 @@ -1252,6 +1298,164 @@ static void rtw8822b_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) } } +static void rtw8822b_txagc_swing_offset(struct rtw_dev *rtwdev, u8 path, + u8 tx_pwr_idx_offset, + s8 *txagc_idx, u8 *swing_idx) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + s8 delta_pwr_idx = dm_info->delta_power_index[path]; + u8 swing_upper_bound = dm_info->default_ofdm_index + 10; + u8 swing_lower_bound = 0; + u8 max_tx_pwr_idx_offset = 0xf; + s8 agc_index = 0; + u8 swing_index = dm_info->default_ofdm_index; + + tx_pwr_idx_offset = min_t(u8, tx_pwr_idx_offset, max_tx_pwr_idx_offset); + + if (delta_pwr_idx >= 0) { + if (delta_pwr_idx <= tx_pwr_idx_offset) { + agc_index = delta_pwr_idx; + swing_index = dm_info->default_ofdm_index; + } else if (delta_pwr_idx > tx_pwr_idx_offset) { + agc_index = tx_pwr_idx_offset; + swing_index = dm_info->default_ofdm_index + + delta_pwr_idx - tx_pwr_idx_offset; + swing_index = min_t(u8, swing_index, swing_upper_bound); + } + } else { + if (dm_info->default_ofdm_index > abs(delta_pwr_idx)) + swing_index = + dm_info->default_ofdm_index + delta_pwr_idx; + else + swing_index = swing_lower_bound; + swing_index = max_t(u8, swing_index, swing_lower_bound); + + agc_index = 0; + } + + if (swing_index >= RTW_TXSCALE_SIZE) { + rtw_warn(rtwdev, "swing index overflow\n"); + swing_index = RTW_TXSCALE_SIZE - 1; + } + *txagc_idx = agc_index; + *swing_idx = swing_index; +} + +static void rtw8822b_pwrtrack_set_pwr(struct rtw_dev *rtwdev, u8 path, + u8 pwr_idx_offset) +{ + s8 txagc_idx; + u8 swing_idx; + u32 reg1, reg2; + + if (path == RF_PATH_A) { + reg1 = 0xc94; + reg2 = 0xc1c; + } else if (path == RF_PATH_B) { + reg1 = 0xe94; + reg2 = 0xe1c; + } else { + return; + } + + rtw8822b_txagc_swing_offset(rtwdev, path, pwr_idx_offset, + &txagc_idx, &swing_idx); + rtw_write32_mask(rtwdev, reg1, GENMASK(29, 25), txagc_idx); + rtw_write32_mask(rtwdev, reg2, GENMASK(31, 21), + rtw8822b_txscale_tbl[swing_idx]); +} + +static void rtw8822b_pwrtrack_set(struct rtw_dev *rtwdev, u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 pwr_idx_offset, tx_pwr_idx; + u8 channel = rtwdev->hal.current_channel; + u8 band_width = rtwdev->hal.current_band_width; + u8 regd = rtwdev->regd.txpwr_regd; + u8 tx_rate = dm_info->tx_rate; + u8 max_pwr_idx = rtwdev->chip->max_power_index; + + tx_pwr_idx = rtw_phy_get_tx_power_index(rtwdev, path, tx_rate, + band_width, channel, regd); + + tx_pwr_idx = min_t(u8, tx_pwr_idx, max_pwr_idx); + + pwr_idx_offset = max_pwr_idx - tx_pwr_idx; + + rtw8822b_pwrtrack_set_pwr(rtwdev, path, pwr_idx_offset); +} + +static void rtw8822b_phy_pwrtrack_path(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 power_idx_cur, power_idx_last; + u8 delta; + + /* 8822B only has one thermal meter at PATH A */ + delta = rtw_phy_pwrtrack_get_delta(rtwdev, RF_PATH_A); + + power_idx_last = dm_info->delta_power_index[path]; + power_idx_cur = rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, + path, RF_PATH_A, delta); + + /* if delta of power indexes are the same, just skip */ + if (power_idx_cur == power_idx_last) + return; + + dm_info->delta_power_index[path] = power_idx_cur; + rtw8822b_pwrtrack_set(rtwdev, path); +} + +static void rtw8822b_phy_pwrtrack(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_swing_table swing_table; + u8 thermal_value, path; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + if (rtwdev->efuse.thermal_meter[RF_PATH_A] == 0xff) + return; + + thermal_value = rtw_read_rf(rtwdev, RF_PATH_A, RF_T_METER, 0xfc00); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, RF_PATH_A); + + if (dm_info->pwr_trk_init_trigger) + dm_info->pwr_trk_init_trigger = false; + else if (!rtw_phy_pwrtrack_thermal_changed(rtwdev, thermal_value, + RF_PATH_A)) + goto iqk; + + for (path = 0; path < rtwdev->hal.rf_path_num; path++) + rtw8822b_phy_pwrtrack_path(rtwdev, &swing_table, path); + +iqk: + if (rtw_phy_pwrtrack_need_iqk(rtwdev)) + rtw8822b_do_iqk(rtwdev); +} + +void rtw8822b_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (efuse->power_track_type != 0) + return; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, + GENMASK(17, 16), 0x03); + dm_info->pwr_trk_triggered = true; + return; + } + + rtw8822b_phy_pwrtrack(rtwdev); + dm_info->pwr_trk_triggered = false; +} + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, @@ -1798,6 +2002,7 @@ static struct rtw_chip_ops rtw8822b_ops = { .cfg_ldo25 = rtw8822b_cfg_ldo25, .false_alarm_statistics = rtw8822b_false_alarm_statistics, .phy_calibration = rtw8822b_phy_calibration, + .pwr_track = rtw8822b_pwr_track, .coex_set_init = rtw8822b_coex_cfg_init, .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, @@ -1952,6 +2157,129 @@ static const struct coex_rf_para rf_para_rx_8822b[] = { static_assert(ARRAY_SIZE(rf_para_tx_8822b) == ARRAY_SIZE(rf_para_rx_8822b)); +static const u8 +rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, +}; + +static const u8 +rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23 }, +}; + +static const u8 +rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, + 15, 16, 17, 17, 18, 19, 20, 20, 21, 22 }, +}; + +static const u8 +rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, + { 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, + 8, 9, 9, 10, 11, 12, 13, 14, 14, 15, + 16, 17, 18, 19, 19, 20, 21, 22, 22, 23}, +}; + +static const u8 rtw8822b_pwrtrk_2gb_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2gb_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 11, 12, 12, 12, 13, 13 +}; + +static const u8 rtw8822b_pwrtrk_2ga_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2ga_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_b_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_b_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, + 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, + 9, 10, 10, 11, 11, 12, 12, 12, 13, 13 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_a_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, + 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, + 8, 9, 9, 9, 10, 10, 11, 11, 11, 12 +}; + +static const u8 rtw8822b_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, + 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, + 10, 11, 11, 12, 12, 13, 13, 14, 14, 15 +}; + +static const struct rtw_pwr_track_tbl rtw8822b_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5gb_p[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5ga_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_1] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_2] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_3] = rtw8822b_pwrtrk_5ga_p[RTW_PWR_TRK_5G_3], + .pwrtrk_2gb_n = rtw8822b_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8822b_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8822b_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8822b_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8822b_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8822b_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8822b_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8822b_pwrtrk_2g_cck_a_p, +}; + struct rtw_chip_info rtw8822b_hw_spec = { .ops = &rtw8822b_ops, .id = RTW_CHIP_TYPE_8822B, @@ -1990,6 +2318,8 @@ struct rtw_chip_info rtw8822b_hw_spec = { .rf_tbl = {&rtw8822b_rf_a_tbl, &rtw8822b_rf_b_tbl}, .rfe_defs = rtw8822b_rfe_defs, .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), + .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, + .iqk_threshold = 8, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 167af317c7c5..21c2d9e651fe 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -40,6 +40,11 @@ static int rtw8822c_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) efuse->country_code[1] = map->country_code[1]; efuse->bt_setting = map->rf_bt_setting; efuse->regd = map->rf_board_option & 0x7; + efuse->thermal_meter[RF_PATH_A] = map->path_a_thermal; + efuse->thermal_meter[RF_PATH_B] = map->path_b_thermal; + efuse->thermal_meter_k = + (map->path_a_thermal + map->path_b_thermal) >> 1; + efuse->power_track_type = (map->tx_pwr_calibrate_rate >> 4) & 0xf; for (i = 0; i < 4; i++) efuse->txpwr_idx_table[i] = map->txpwr_idx_table[i]; @@ -1000,6 +1005,21 @@ static void rtw8822c_rf_init(struct rtw_dev *rtwdev) rtw8822c_rf_x2_check(rtwdev); } +void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 path; + + for (path = RF_PATH_A; path < RTW_RF_PATH_MAX; path++) { + dm_info->delta_power_index[path] = 0; + ewma_thermal_init(&dm_info->avg_thermal[path]); + dm_info->thermal_avg[path] = 0xff; + } + + dm_info->pwr_trk_triggered = false; + dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; +} + static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; @@ -1047,6 +1067,7 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) dm_info->cck_gi_l_bnd = ((cck_gi_l_bnd_msb << 4) | (cck_gi_l_bnd_lsb)); rtw8822c_rf_init(rtwdev); + rtw8822c_pwrtrack_init(rtwdev); } #define WLAN_TXQ_RPT_EN 0x1F @@ -3195,6 +3216,87 @@ static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) dm_info->cck_pd_lv[bw][nrx] = new_lvl; } +#define PWR_TRACK_MASK 0x7f +static void rtw8822c_pwrtrack_set(struct rtw_dev *rtwdev, u8 rf_path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + switch (rf_path) { + case RF_PATH_A: + rtw_write32_mask(rtwdev, 0x18a0, PWR_TRACK_MASK, + dm_info->delta_power_index[rf_path]); + break; + case RF_PATH_B: + rtw_write32_mask(rtwdev, 0x41a0, PWR_TRACK_MASK, + dm_info->delta_power_index[rf_path]); + break; + default: + break; + } +} + +static void rtw8822c_pwr_track_path(struct rtw_dev *rtwdev, + struct rtw_swing_table *swing_table, + u8 path) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + u8 thermal_value, delta; + + if (rtwdev->efuse.thermal_meter[path] == 0xff) + return; + + thermal_value = rtw_read_rf(rtwdev, path, RF_T_METER, 0x7e); + + rtw_phy_pwrtrack_avg(rtwdev, thermal_value, path); + + delta = rtw_phy_pwrtrack_get_delta(rtwdev, path); + + dm_info->delta_power_index[path] = + rtw_phy_pwrtrack_get_pwridx(rtwdev, swing_table, path, path, + delta); + + rtw8822c_pwrtrack_set(rtwdev, path); +} + +static void __rtw8822c_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_swing_table swing_table; + u8 i; + + rtw_phy_config_swing_table(rtwdev, &swing_table); + + for (i = 0; i < rtwdev->hal.rf_path_num; i++) + rtw8822c_pwr_track_path(rtwdev, &swing_table, i); + + if (rtw_phy_pwrtrack_need_iqk(rtwdev)) + rtw8822c_do_iqk(rtwdev); +} + +static void rtw8822c_pwr_track(struct rtw_dev *rtwdev) +{ + struct rtw_efuse *efuse = &rtwdev->efuse; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + if (efuse->power_track_type != 0) + return; + + if (!dm_info->pwr_trk_triggered) { + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, BIT(19), 0x01); + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, BIT(19), 0x00); + rtw_write_rf(rtwdev, RF_PATH_A, RF_T_METER, BIT(19), 0x01); + + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x01); + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x00); + rtw_write_rf(rtwdev, RF_PATH_B, RF_T_METER, BIT(19), 0x01); + + dm_info->pwr_trk_triggered = true; + return; + } + + __rtw8822c_pwr_track(rtwdev); + dm_info->pwr_trk_triggered = false; +} + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822c[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, @@ -3575,6 +3677,7 @@ static struct rtw_chip_ops rtw8822c_ops = { .dpk_track = rtw8822c_dpk_track, .phy_calibration = rtw8822c_phy_calibration, .cck_pd_set = rtw8822c_phy_cck_pd_set, + .pwr_track = rtw8822c_pwr_track, .coex_set_init = rtw8822c_coex_cfg_init, .coex_set_ant_switch = NULL, @@ -3729,6 +3832,129 @@ static const struct coex_rf_para rf_para_rx_8822c[] = { static_assert(ARRAY_SIZE(rf_para_tx_8822c) == ARRAY_SIZE(rf_para_rx_8822c)); +static const u8 +rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, + { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 32 }, +}; + +static const u8 +rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 23, 24, 25, 26, 27 }, +}; + +static const u8 +rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, + { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, + 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 33 }, +}; + +static const u8 +rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_NUM][RTW_PWR_TRK_TBL_SZ] = { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, +}; + +static const u8 rtw8822c_pwrtrk_2gb_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, + 9, 9, 10, 11, 12, 13, 14, 15, 15, 16, + 17, 18, 19, 20, 20, 21, 22, 23, 24, 25 +}; + +static const u8 rtw8822c_pwrtrk_2gb_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 +}; + +static const u8 rtw8822c_pwrtrk_2ga_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, + 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, + 13, 14, 15, 15, 16, 17, 17, 18, 19, 19 +}; + +static const u8 rtw8822c_pwrtrk_2ga_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 25, 26, 27 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_b_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, + 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, + 17, 18, 19, 20, 21, 22, 23, 23, 24, 25 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_b_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_a_n[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, + 8, 9, 9, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 17, 18, 18, 19, 20, 21, 21, 22 +}; + +static const u8 rtw8822c_pwrtrk_2g_cck_a_p[RTW_PWR_TRK_TBL_SZ] = { + 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, + 9, 10, 11, 11, 12, 13, 14, 15, 16, 17, + 18, 18, 19, 20, 21, 22, 23, 24, 24, 25 +}; + +static const struct rtw_pwr_track_tbl rtw8822c_rtw_pwr_track_tbl = { + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5gb_p[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5gb_p[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_n[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5ga_n[RTW_PWR_TRK_5G_3], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_1] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_1], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_2] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_2], + .pwrtrk_5ga_p[RTW_PWR_TRK_5G_3] = rtw8822c_pwrtrk_5ga_p[RTW_PWR_TRK_5G_3], + .pwrtrk_2gb_n = rtw8822c_pwrtrk_2gb_n, + .pwrtrk_2gb_p = rtw8822c_pwrtrk_2gb_p, + .pwrtrk_2ga_n = rtw8822c_pwrtrk_2ga_n, + .pwrtrk_2ga_p = rtw8822c_pwrtrk_2ga_p, + .pwrtrk_2g_cckb_n = rtw8822c_pwrtrk_2g_cck_b_n, + .pwrtrk_2g_cckb_p = rtw8822c_pwrtrk_2g_cck_b_p, + .pwrtrk_2g_ccka_n = rtw8822c_pwrtrk_2g_cck_a_n, + .pwrtrk_2g_ccka_p = rtw8822c_pwrtrk_2g_cck_a_p, +}; + struct rtw_chip_info rtw8822c_hw_spec = { .ops = &rtw8822c_ops, .id = RTW_CHIP_TYPE_8822C, @@ -3770,6 +3996,8 @@ struct rtw_chip_info rtw8822c_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8822c_rfe_defs), .en_dis_dpd = true, .dpd_ratemask = DIS_DPD_RATEALL, + .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, + .iqk_threshold = 8, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, -- cgit v1.2.3-59-g8ed1b From 0bd9557341b7fb44bf591921d7feb4dcf4f4bb52 Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Tue, 22 Oct 2019 18:04:18 +0800 Subject: rtw88: Enable 802.11ac beamformee support Enable MU-MIMO transmit beamformee support for chipset 8822b and 8822c. If the driver is in station mode and associated with an AP, and the capabilities of both meet the requirement of beamforming, driver will run as a beamformee and the corresponding chip settings will be set. In addition, module parameter support_bf is added to enable or disable beamforming. Sometimes driver will need to disable for inter-operate issues, and it would be easier for driver to debug. Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/Makefile | 1 + drivers/net/wireless/realtek/rtw88/bf.c | 400 ++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/bf.h | 92 ++++++ drivers/net/wireless/realtek/rtw88/debug.h | 1 + drivers/net/wireless/realtek/rtw88/mac80211.c | 11 + drivers/net/wireless/realtek/rtw88/main.c | 38 +++ drivers/net/wireless/realtek/rtw88/main.h | 43 +++ drivers/net/wireless/realtek/rtw88/reg.h | 1 + drivers/net/wireless/realtek/rtw88/rtw8822b.c | 46 +++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 59 ++++ 10 files changed, 692 insertions(+) create mode 100644 drivers/net/wireless/realtek/rtw88/bf.c create mode 100644 drivers/net/wireless/realtek/rtw88/bf.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/Makefile b/drivers/net/wireless/realtek/rtw88/Makefile index 77edee2df8b8..15e12155a04c 100644 --- a/drivers/net/wireless/realtek/rtw88/Makefile +++ b/drivers/net/wireless/realtek/rtw88/Makefile @@ -14,6 +14,7 @@ rtw88-y += main.o \ fw.o \ ps.o \ sec.o \ + bf.o \ regd.o rtw88-$(CONFIG_RTW88_8822BE) += rtw8822b.o rtw8822b_table.o diff --git a/drivers/net/wireless/realtek/rtw88/bf.c b/drivers/net/wireless/realtek/rtw88/bf.c new file mode 100644 index 000000000000..fda771d23f71 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/bf.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2018-2019 Realtek Corporation. + */ + +#include "main.h" +#include "reg.h" +#include "bf.h" +#include "debug.h" + +void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + if (bfee->role == RTW_BFEE_NONE) + return; + + if (bfee->role == RTW_BFEE_MU) + bfinfo->bfer_mu_cnt--; + else if (bfee->role == RTW_BFEE_SU) + bfinfo->bfer_su_cnt--; + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, false); + + bfee->role = RTW_BFEE_NONE; +} + +void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_hw *hw = rtwdev->hw; + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + struct rtw_chip_info *chip = rtwdev->chip; + struct ieee80211_sta *sta; + struct ieee80211_sta_vht_cap *vht_cap; + struct ieee80211_sta_vht_cap *ic_vht_cap; + const u8 *bssid = bss_conf->bssid; + u32 sound_dim; + u8 bfee_role = RTW_BFEE_NONE; + u8 i; + + if (!(chip->band & RTW_BAND_5G)) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta(vif, bssid); + if (!sta) { + rtw_warn(rtwdev, "failed to find station entry for bss %pM\n", + bssid); + goto out_unlock; + } + + ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap; + vht_cap = &sta->vht_cap; + + if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) && + (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) { + if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) { + rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n"); + goto out_unlock; + } + + ether_addr_copy(bfee->mac_addr, bssid); + bfee_role = RTW_BFEE_MU; + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); + bfee->aid = bss_conf->aid; + bfinfo->bfer_mu_cnt++; + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); + } else if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) && + (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) { + if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) { + rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n"); + goto out_unlock; + } + + sound_dim = vht_cap->cap & + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK; + sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; + + ether_addr_copy(bfee->mac_addr, bssid); + bfee_role = RTW_BFEE_SU; + bfee->sound_dim = (u8)sound_dim; + bfee->g_id = 0; + bfee->p_aid = (bssid[5] << 1) | (bssid[4] >> 7); + bfinfo->bfer_su_cnt++; + for (i = 0; i < chip->bfer_su_max_num; i++) { + if (!test_bit(i, bfinfo->bfer_su_reg_maping)) { + set_bit(i, bfinfo->bfer_su_reg_maping); + bfee->su_reg_index = i; + break; + } + } + + chip->ops->config_bfee(rtwdev, rtwvif, bfee, true); + } + +out_unlock: + bfee->role = bfee_role; + rcu_read_unlock(); +} + +void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, + struct mu_bfer_init_para *param) +{ + u16 mu_bf_ctl = 0; + u8 *addr = param->bfer_address; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtw_write8(rtwdev, REG_ASSOCIATED_BFMER0_INFO + i, addr[i]); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 6, param->paid); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, param->csi_para); + + mu_bf_ctl = rtw_read16(rtwdev, REG_WMAC_MU_BF_CTL) & 0xC000; + mu_bf_ctl |= param->my_aid | (param->csi_length_sel << 12); + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, mu_bf_ctl); +} + +void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, + enum rtw_trx_desc_rate rate) +{ + u32 psf_ctl = 0; + u8 csi_rsc = 0x1; + + psf_ctl = rtw_read32(rtwdev, REG_BBPSF_CTRL) | + BIT_WMAC_USE_NDPARATE | + (csi_rsc << 13); + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, 0x26); + rtw_write8_clr(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF_REPORT_POLL); + rtw_write8_clr(rtwdev, REG_RXFLTMAP4, BIT_RXFLTMAP4_BF_REPORT_POLL); + + if (vif->net_type == RTW_NET_AP_MODE) + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl | BIT(12)); + else + rtw_write32(rtwdev, REG_BBPSF_CTRL, psf_ctl & ~BIT(12)); +} + +void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param) +{ + u8 mu_tbl_sel; + u8 mu_valid; + + mu_valid = rtw_read8(rtwdev, REG_MU_TX_CTL) & + ~BIT_MASK_R_MU_TABLE_VALID; + + rtw_write8(rtwdev, REG_MU_TX_CTL, + (mu_valid | BIT(0) | BIT(1)) & ~(BIT(7))); + + mu_tbl_sel = rtw_read8(rtwdev, REG_MU_TX_CTL + 1) & 0xF8; + + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel); + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[0]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[0]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, + param->given_user_pos[1]); + + rtw_write8(rtwdev, REG_MU_TX_CTL + 1, mu_tbl_sel | 1); + rtw_write32(rtwdev, REG_MU_STA_GID_VLD, param->given_gid_tab[1]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO, param->given_user_pos[2]); + rtw_write32(rtwdev, REG_MU_STA_USER_POS_INFO + 4, + param->given_user_pos[3]); +} + +void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev) +{ + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); + rtw_write8(rtwdev, REG_MU_TX_CTL, 0); +} + +void rtw_bf_del_sounding(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, 0); +} + +void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + u8 nc_index = 1; + u8 nr_index = bfee->sound_dim; + u8 grouping = 0, codebookinfo = 1, coefficientsize = 3; + u32 addr_bfer_info, addr_csi_rpt, csi_param; + u8 i; + + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an su bfee\n"); + + switch (bfee->su_reg_index) { + case 1: + addr_bfer_info = REG_ASSOCIATED_BFMER1_INFO; + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20 + 2; + break; + case 0: + default: + addr_bfer_info = REG_ASSOCIATED_BFMER0_INFO; + addr_csi_rpt = REG_TX_CSI_RPT_PARAM_BW20; + break; + } + + /* Sounding protocol control */ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_SOUNDING); + + /* MAC address/Partial AID of Beamformer */ + for (i = 0; i < ETH_ALEN; i++) + rtw_write8(rtwdev, addr_bfer_info + i, bfee->mac_addr[i]); + + csi_param = (u16)((coefficientsize << 10) | + (codebookinfo << 8) | + (grouping << 6) | + (nr_index << 3) | + nc_index); + rtw_write16(rtwdev, addr_csi_rpt, csi_param); + + /* ndp rx standby timer */ + rtw_write8(rtwdev, REG_SND_PTCL_CTRL + 3, RTW_NDP_RX_STANDBY_TIME); +} + +/* nc index: 1 2T2R 0 1T1R + * nr index: 1 use Nsts 0 use reg setting + * codebookinfo: 1 802.11ac 3 802.11n + */ +void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bf_info = &rtwdev->bf_info; + struct mu_bfer_init_para param; + u8 nc_index = 1, nr_index = 1; + u8 grouping = 0, codebookinfo = 1, coefficientsize = 0; + u32 csi_param; + + rtw_dbg(rtwdev, RTW_DBG_BF, "config as an mu bfee\n"); + + csi_param = (u16)((coefficientsize << 10) | + (codebookinfo << 8) | + (grouping << 6) | + (nr_index << 3) | + nc_index); + + rtw_dbg(rtwdev, RTW_DBG_BF, "nc=%d nr=%d group=%d codebookinfo=%d coefficientsize=%d\n", + nc_index, nr_index, grouping, codebookinfo, + coefficientsize); + + param.paid = bfee->p_aid; + param.csi_para = csi_param; + param.my_aid = bfee->aid & 0xfff; + param.csi_length_sel = HAL_CSI_SEG_4K; + ether_addr_copy(param.bfer_address, bfee->mac_addr); + + rtw_bf_init_bfer_entry_mu(rtwdev, ¶m); + + bf_info->cur_csi_rpt_rate = DESC_RATE6M; + rtw_bf_cfg_sounding(rtwdev, vif, DESC_RATE6M); + + /* accept action_no_ack */ + rtw_write16_set(rtwdev, REG_RXFLTMAP0, BIT_RXFLTMAP0_ACTIONNOACK); + + /* accept NDPA and BF report poll */ + rtw_write16_set(rtwdev, REG_RXFLTMAP1, BIT_RXFLTMAP1_BF); +} + +void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + rtw_dbg(rtwdev, RTW_DBG_BF, "remove as a su bfee\n"); + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); + + switch (bfee->su_reg_index) { + case 0: + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER0_INFO, 0); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER0_INFO + 4, 0); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20, 0); + break; + case 1: + rtw_write32(rtwdev, REG_ASSOCIATED_BFMER1_INFO, 0); + rtw_write16(rtwdev, REG_ASSOCIATED_BFMER1_INFO + 4, 0); + rtw_write16(rtwdev, REG_TX_CSI_RPT_PARAM_BW20 + 2, 0); + break; + } + + clear_bit(bfee->su_reg_index, bfinfo->bfer_su_reg_maping); + bfee->su_reg_index = 0xFF; +} + +void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_bfee *bfee) +{ + struct rtw_bf_info *bfinfo = &rtwdev->bf_info; + + rtw_write8(rtwdev, REG_SND_PTCL_CTRL, RTW_SND_CTRL_REMOVE); + + rtw_bf_del_bfer_entry_mu(rtwdev); + + if (bfinfo->bfer_su_cnt == 0 && bfinfo->bfer_mu_cnt == 0) + rtw_bf_del_sounding(rtwdev); +} + +void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf) +{ + struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; + struct rtw_bfee *bfee = &rtwvif->bfee; + struct cfg_mumimo_para param; + + if (bfee->role != RTW_BFEE_MU) { + rtw_dbg(rtwdev, RTW_DBG_BF, "this vif is not mu bfee\n"); + return; + } + + param.grouping_bitmap = 0; + param.mu_tx_en = 0; + memset(param.sounding_sts, 0, 6); + memcpy(param.given_gid_tab, conf->mu_group.membership, 8); + memcpy(param.given_user_pos, conf->mu_group.position, 16); + rtw_dbg(rtwdev, RTW_DBG_BF, "STA0: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", + param.given_gid_tab[0], param.given_user_pos[0], + param.given_user_pos[1]); + + rtw_dbg(rtwdev, RTW_DBG_BF, "STA1: gid_valid=0x%x, user_position_l=0x%x, user_position_h=0x%x\n", + param.given_gid_tab[1], param.given_user_pos[2], + param.given_user_pos[3]); + + rtw_bf_cfg_mu_bfee(rtwdev, ¶m); +} + +void rtw_bf_phy_init(struct rtw_dev *rtwdev) +{ + u8 tmp8; + u32 tmp32; + u8 retry_limit = 0xA; + u8 ndpa_rate = 0x10; + u8 ack_policy = 3; + + tmp32 = rtw_read32(rtwdev, REG_MU_TX_CTL); + /* Enable P1 aggr new packet according to P0 transfer time */ + tmp32 |= BIT_MU_P1_WAIT_STATE_EN; + /* MU Retry Limit */ + tmp32 &= ~BIT_MASK_R_MU_RL; + tmp32 |= (retry_limit << BIT_SHIFT_R_MU_RL) & BIT_MASK_R_MU_RL; + /* Disable Tx MU-MIMO until sounding done */ + tmp32 &= ~BIT_EN_MU_MIMO; + /* Clear validity of MU STAs */ + tmp32 &= ~BIT_MASK_R_MU_TABLE_VALID; + rtw_write32(rtwdev, REG_MU_TX_CTL, tmp32); + + /* MU-MIMO Option as default value */ + tmp8 = ack_policy << BIT_SHIFT_WMAC_TXMU_ACKPOLICY; + tmp8 |= BIT_WMAC_TXMU_ACKPOLICY_EN; + rtw_write8(rtwdev, REG_WMAC_MU_BF_OPTION, tmp8); + + /* MU-MIMO Control as default value */ + rtw_write16(rtwdev, REG_WMAC_MU_BF_CTL, 0); + /* Set MU NDPA rate & BW source */ + rtw_write32_set(rtwdev, REG_TXBF_CTRL, BIT_USE_NDPA_PARAMETER); + /* Set NDPA Rate */ + rtw_write8(rtwdev, REG_NDPA_OPT_CTRL, ndpa_rate); + + rtw_write32_mask(rtwdev, REG_BBPSF_CTRL, BIT_MASK_CSI_RATE, + DESC_RATE6M); +} + +void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate) +{ + u32 csi_cfg; + u16 cur_rrsr; + + csi_cfg = rtw_read32(rtwdev, REG_BBPSF_CTRL) & ~BIT_MASK_CSI_RATE; + cur_rrsr = rtw_read16(rtwdev, REG_RRSR); + + if (rssi >= 40) { + if (cur_rate != DESC_RATE54M) { + cur_rrsr |= BIT(DESC_RATE54M); + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << + BIT_SHIFT_CSI_RATE; + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); + } + *new_rate = DESC_RATE54M; + } else { + if (cur_rate != DESC_RATE24M) { + cur_rrsr &= ~BIT(DESC_RATE54M); + csi_cfg |= (DESC_RATE54M & BIT_MASK_CSI_RATE_VAL) << + BIT_SHIFT_CSI_RATE; + rtw_write16(rtwdev, REG_RRSR, cur_rrsr); + rtw_write32(rtwdev, REG_BBPSF_CTRL, csi_cfg); + } + *new_rate = DESC_RATE24M; + } +} diff --git a/drivers/net/wireless/realtek/rtw88/bf.h b/drivers/net/wireless/realtek/rtw88/bf.h new file mode 100644 index 000000000000..96a8216dd11f --- /dev/null +++ b/drivers/net/wireless/realtek/rtw88/bf.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2018-2019 Realtek Corporation. + */ + +#ifndef __RTW_BF_H_ +#define __RTW_BF_H_ + +#define REG_TXBF_CTRL 0x042C +#define REG_RRSR 0x0440 +#define REG_NDPA_OPT_CTRL 0x045F + +#define REG_ASSOCIATED_BFMER0_INFO 0x06E4 +#define REG_ASSOCIATED_BFMER1_INFO 0x06EC +#define REG_TX_CSI_RPT_PARAM_BW20 0x06F4 +#define REG_SND_PTCL_CTRL 0x0718 +#define REG_MU_TX_CTL 0x14C0 +#define REG_MU_STA_GID_VLD 0x14C4 +#define REG_MU_STA_USER_POS_INFO 0x14C8 +#define REG_CSI_RRSR 0x1678 +#define REG_WMAC_MU_BF_OPTION 0x167C +#define REG_WMAC_MU_BF_CTL 0x1680 + +#define BIT_WMAC_USE_NDPARATE BIT(30) +#define BIT_WMAC_TXMU_ACKPOLICY_EN BIT(6) +#define BIT_USE_NDPA_PARAMETER BIT(30) +#define BIT_MU_P1_WAIT_STATE_EN BIT(16) +#define BIT_EN_MU_MIMO BIT(7) + +#define R_MU_RL 0xf +#define BIT_SHIFT_R_MU_RL 12 +#define BIT_SHIFT_WMAC_TXMU_ACKPOLICY 4 +#define BIT_SHIFT_CSI_RATE 24 + +#define BIT_MASK_R_MU_RL (R_MU_RL << BIT_SHIFT_R_MU_RL) +#define BIT_MASK_R_MU_TABLE_VALID 0x3f +#define BIT_MASK_CSI_RATE_VAL 0x3F +#define BIT_MASK_CSI_RATE (BIT_MASK_CSI_RATE_VAL << BIT_SHIFT_CSI_RATE) + +#define BIT_RXFLTMAP0_ACTIONNOACK BIT(14) +#define BIT_RXFLTMAP1_BF (BIT(4) | BIT(5)) +#define BIT_RXFLTMAP1_BF_REPORT_POLL BIT(4) +#define BIT_RXFLTMAP4_BF_REPORT_POLL BIT(4) + +#define RTW_NDP_RX_STANDBY_TIME 0x70 +#define RTW_SND_CTRL_REMOVE 0xD8 +#define RTW_SND_CTRL_SOUNDING 0xDB + +enum csi_seg_len { + HAL_CSI_SEG_4K = 0, + HAL_CSI_SEG_8K = 1, + HAL_CSI_SEG_11K = 2, +}; + +struct cfg_mumimo_para { + u8 sounding_sts[6]; + u16 grouping_bitmap; + u8 mu_tx_en; + u32 given_gid_tab[2]; + u32 given_user_pos[4]; +}; + +struct mu_bfer_init_para { + u16 paid; + u16 csi_para; + u16 my_aid; + enum csi_seg_len csi_length_sel; + u8 bfer_address[ETH_ALEN]; +}; + +void rtw_bf_disassoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); +void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf); +void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev, + struct mu_bfer_init_para *param); +void rtw_bf_cfg_sounding(struct rtw_dev *rtwdev, struct rtw_vif *vif, + enum rtw_trx_desc_rate rate); +void rtw_bf_cfg_mu_bfee(struct rtw_dev *rtwdev, struct cfg_mumimo_para *param); +void rtw_bf_del_bfer_entry_mu(struct rtw_dev *rtwdev); +void rtw_bf_del_sounding(struct rtw_dev *rtwdev); +void rtw_bf_enable_bfee_su(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee); +void rtw_bf_enable_bfee_mu(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee); +void rtw_bf_remove_bfee_su(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); +void rtw_bf_remove_bfee_mu(struct rtw_dev *rtwdev, struct rtw_bfee *bfee); +void rtw_bf_set_gid_table(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf); +void rtw_bf_phy_init(struct rtw_dev *rtwdev); +void rtw_bf_cfg_csi_rate(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate); +#endif diff --git a/drivers/net/wireless/realtek/rtw88/debug.h b/drivers/net/wireless/realtek/rtw88/debug.h index 9449105f4259..cd28f675e9cb 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.h +++ b/drivers/net/wireless/realtek/rtw88/debug.h @@ -17,6 +17,7 @@ enum rtw_debug_mask { RTW_DBG_REGD = 0x00000100, RTW_DBG_DEBUGFS = 0x00000200, RTW_DBG_PS = 0x00000400, + RTW_DBG_BF = 0x00000800, RTW_DBG_ALL = 0xffffffff }; diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 8d7a3429ea06..bc04cc280a96 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -10,6 +10,7 @@ #include "coex.h" #include "ps.h" #include "reg.h" +#include "bf.h" #include "debug.h" static void rtw_ops_tx(struct ieee80211_hw *hw, @@ -157,6 +158,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw, rtwvif->stats.tx_cnt = 0; rtwvif->stats.rx_cnt = 0; rtwvif->in_lps = false; + memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee)); rtwvif->conf = &rtw_vif_port[port]; rtw_txq_init(rtwdev, vif->txq); @@ -348,11 +350,14 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, rtw_fw_download_rsvd_page(rtwdev, vif); rtw_send_rsvd_page_h2c(rtwdev); rtw_coex_media_status_notify(rtwdev, conf->assoc); + if (rtw_bf_support) + rtw_bf_assoc(rtwdev, vif, conf); } else { rtw_leave_lps(rtwdev); net_type = RTW_NET_NO_LINK; rtwvif->aid = 0; rtw_reset_rsvd_page(rtwdev); + rtw_bf_disassoc(rtwdev, vif, conf); } rtwvif->net_type = net_type; @@ -368,6 +373,12 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON) rtw_fw_download_rsvd_page(rtwdev, vif); + if (changed & BSS_CHANGED_MU_GROUPS) { + struct rtw_chip_info *chip = rtwdev->chip; + + chip->ops->set_gid_table(rtwdev, vif, conf); + } + if (changed & BSS_CHANGED_ERP_SLOT) rtw_conf_tx(rtwdev, rtwvif); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 5343d860189b..47e74f0aec06 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -14,16 +14,20 @@ #include "efuse.h" #include "tx.h" #include "debug.h" +#include "bf.h" unsigned int rtw_fw_lps_deep_mode; EXPORT_SYMBOL(rtw_fw_lps_deep_mode); +bool rtw_bf_support = true; unsigned int rtw_debug_mask; EXPORT_SYMBOL(rtw_debug_mask); module_param_named(lps_deep_mode, rtw_fw_lps_deep_mode, uint, 0644); +module_param_named(support_bf, rtw_bf_support, bool, 0644); module_param_named(debug_mask, rtw_debug_mask, uint, 0644); MODULE_PARM_DESC(lps_deep_mode, "Deeper PS mode. If 0, deep PS is disabled"); +MODULE_PARM_DESC(support_bf, "Set Y to enable beamformee support"); MODULE_PARM_DESC(debug_mask, "Debugging mask"); static struct ieee80211_channel rtw_channeltable_2g[] = { @@ -126,9 +130,29 @@ static struct ieee80211_supported_band rtw_band_5ghz = { }; struct rtw_watch_dog_iter_data { + struct rtw_dev *rtwdev; struct rtw_vif *rtwvif; }; +static void rtw_dynamic_csi_rate(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif) +{ + struct rtw_bf_info *bf_info = &rtwdev->bf_info; + struct rtw_chip_info *chip = rtwdev->chip; + u8 fix_rate_enable = 0; + u8 new_csi_rate_idx; + + if (rtwvif->bfee.role != RTW_BFEE_SU && + rtwvif->bfee.role != RTW_BFEE_MU) + return; + + chip->ops->cfg_csi_rate(rtwdev, rtwdev->dm_info.min_rssi, + bf_info->cur_csi_rpt_rate, + fix_rate_enable, &new_csi_rate_idx); + + if (new_csi_rate_idx != bf_info->cur_csi_rpt_rate) + bf_info->cur_csi_rpt_rate = new_csi_rate_idx; +} + static void rtw_vif_watch_dog_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -139,6 +163,8 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, if (vif->bss_conf.assoc) iter_data->rtwvif = rtwvif; + rtw_dynamic_csi_rate(iter_data->rtwdev, rtwvif); + rtwvif->stats.tx_unicast = 0; rtwvif->stats.rx_unicast = 0; rtwvif->stats.tx_cnt = 0; @@ -192,6 +218,7 @@ static void rtw_watch_dog_work(struct work_struct *work) rtw_phy_dynamic_mechanism(rtwdev); + data.rtwdev = rtwdev; /* use atomic version to avoid taking local->iflist_mtx mutex */ rtw_iterate_vifs_atomic(rtwdev, rtw_vif_watch_dog_iter, &data); @@ -870,6 +897,12 @@ static void rtw_init_vht_cap(struct rtw_dev *rtwdev, IEEE80211_VHT_CAP_HTC_VHT | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | 0; + + vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + vht_cap->cap |= (rtwdev->hal.bfee_sts_cap << + IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9 << 0 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | @@ -1005,6 +1038,8 @@ static int rtw_chip_parameter_setup(struct rtw_dev *rtwdev) /* default use ack */ rtwdev->hal.rcr |= BIT_VHT_DACK; + hal->bfee_sts_cap = 3; + return ret; } @@ -1342,6 +1377,9 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) rtw_debugfs_init(rtwdev); + rtwdev->bf_info.bfer_mu_cnt = 0; + rtwdev->bf_info.bfer_su_cnt = 0; + return 0; } EXPORT_SYMBOL(rtw_register_hw); diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 757b0ce2bbee..14b35152fe9f 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -29,6 +29,7 @@ #define RTW_RF_PATH_MAX 4 #define HW_FEATURE_LEN 13 +extern bool rtw_bf_support; extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; extern const struct ieee80211_ops rtw_ops; @@ -647,6 +648,34 @@ struct rtw_sta_info { struct rtw_ra_report ra_report; }; +enum rtw_bfee_role { + RTW_BFEE_NONE, + RTW_BFEE_SU, + RTW_BFEE_MU +}; + +struct rtw_bfee { + enum rtw_bfee_role role; + + u16 p_aid; + u8 g_id; + u8 mac_addr[ETH_ALEN]; + u8 sound_dim; + + /* SU-MIMO */ + u8 su_reg_index; + + /* MU-MIMO */ + u16 aid; +}; + +struct rtw_bf_info { + u8 bfer_mu_cnt; + u8 bfer_su_cnt; + DECLARE_BITMAP(bfer_su_reg_maping, 2); + u8 cur_csi_rpt_rate; +}; + struct rtw_vif { struct ieee80211_vif *vif; enum rtw_net_type net_type; @@ -660,6 +689,8 @@ struct rtw_vif { struct rtw_traffic_stats stats; bool in_lps; + + struct rtw_bfee bfee; }; struct rtw_regulatory { @@ -692,6 +723,13 @@ struct rtw_chip_ops { void (*dpk_track)(struct rtw_dev *rtwdev); void (*cck_pd_set)(struct rtw_dev *rtwdev, u8 level); void (*pwr_track)(struct rtw_dev *rtwdev); + void (*config_bfee)(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable); + void (*set_gid_table)(struct rtw_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf); + void (*cfg_csi_rate)(struct rtw_dev *rtwdev, u8 rssi, u8 cur_rate, + u8 fixrate_en, u8 *new_rate); /* for coex */ void (*coex_set_init)(struct rtw_dev *rtwdev); @@ -950,6 +988,9 @@ struct rtw_chip_info { u8 iqk_threshold; const struct rtw_pwr_track_tbl *pwr_track_tbl; + u8 bfer_su_max_num; + u8 bfer_mu_max_num; + /* coex paras */ u32 coex_para_ver; u8 bt_desired_ver; @@ -1386,6 +1427,7 @@ struct rtw_hal { u8 rf_path_num; u8 antenna_tx; u8 antenna_rx; + u8 bfee_sts_cap; /* protect tx power section */ struct mutex tx_power_mutex; @@ -1423,6 +1465,7 @@ struct rtw_dev { struct rtw_sec_desc sec; struct rtw_traffic_stats stats; struct rtw_regulatory regd; + struct rtw_bf_info bf_info; struct rtw_dm_info dm_info; struct rtw_coex coex; diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 330574a9f55a..7e817bc997eb 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -326,6 +326,7 @@ #define REG_RXFLTMAP0 0x06A0 #define REG_RXFLTMAP1 0x06A2 #define REG_RXFLTMAP2 0x06A4 +#define REG_RXFLTMAP4 0x068A #define REG_BT_COEX_TABLE0 0x06C0 #define REG_BT_COEX_TABLE1 0x06C4 #define REG_BT_COEX_BRK_TABLE 0x06C8 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 34fbfe6b4a11..87a9178ba022 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -13,6 +13,7 @@ #include "mac.h" #include "reg.h" #include "debug.h" +#include "bf.h" static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, u8 rx_path, bool is_tx2_path); @@ -120,6 +121,13 @@ static void rtw8822b_pwrtrack_init(struct rtw_dev *rtwdev) dm_info->thermal_meter_k = rtwdev->efuse.thermal_meter_k; } +static void rtw8822b_phy_bf_init(struct rtw_dev *rtwdev) +{ + rtw_bf_phy_init(rtwdev); + /* Grouping bitmap parameters */ + rtw_write32(rtwdev, 0x1C94, 0xAFFFAFFF); +} + static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) { struct rtw_hal *hal = &rtwdev->hal; @@ -152,6 +160,8 @@ static void rtw8822b_phy_set_param(struct rtw_dev *rtwdev) rtw8822b_phy_rfe_init(rtwdev); rtw8822b_pwrtrack_init(rtwdev); + + rtw8822b_phy_bf_init(rtwdev); } #define WLAN_SLOT_TIME 0x09 @@ -1456,6 +1466,37 @@ void rtw8822b_pwr_track(struct rtw_dev *rtwdev) dm_info->pwr_trk_triggered = false; } +static void rtw8822b_bf_config_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + +static void rtw8822b_bf_config_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_mu(rtwdev, bfee); +} + +static void rtw8822b_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (bfee->role == RTW_BFEE_SU) + rtw8822b_bf_config_bfee_su(rtwdev, vif, bfee, enable); + else if (bfee->role == RTW_BFEE_MU) + rtw8822b_bf_config_bfee_mu(rtwdev, vif, bfee, enable); + else + rtw_warn(rtwdev, "wrong bfee role\n"); +} + static struct rtw_pwr_seq_cmd trans_carddis_to_cardemu_8822b[] = { {0x0086, RTW_PWR_CUT_ALL_MSK, @@ -2003,6 +2044,9 @@ static struct rtw_chip_ops rtw8822b_ops = { .false_alarm_statistics = rtw8822b_false_alarm_statistics, .phy_calibration = rtw8822b_phy_calibration, .pwr_track = rtw8822b_pwr_track, + .config_bfee = rtw8822b_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, .coex_set_init = rtw8822b_coex_cfg_init, .coex_set_ant_switch = rtw8822b_coex_cfg_ant_switch, @@ -2320,6 +2364,8 @@ struct rtw_chip_info rtw8822b_hw_spec = { .rfe_defs_size = ARRAY_SIZE(rtw8822b_rfe_defs), .pwr_track_tbl = &rtw8822b_rtw_pwr_track_tbl, .iqk_threshold = 8, + .bfer_su_max_num = 2, + .bfer_mu_max_num = 1, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 21c2d9e651fe..ae4417d6c272 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -14,6 +14,7 @@ #include "reg.h" #include "debug.h" #include "util.h" +#include "bf.h" static void rtw8822c_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, u8 rx_path, bool is_tx2_path); @@ -1068,6 +1069,8 @@ static void rtw8822c_phy_set_param(struct rtw_dev *rtwdev) rtw8822c_rf_init(rtwdev); rtw8822c_pwrtrack_init(rtwdev); + + rtw_bf_phy_init(rtwdev); } #define WLAN_TXQ_RPT_EN 0x1F @@ -2078,6 +2081,57 @@ static void rtw8822c_coex_cfg_wl_rx_gain(struct rtw_dev *rtwdev, bool low_gain) } } +static void rtw8822c_bf_enable_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee) +{ + u8 csi_rsc = 0; + u32 tmp6dc; + + rtw_bf_enable_bfee_su(rtwdev, vif, bfee); + + tmp6dc = rtw_read32(rtwdev, REG_BBPSF_CTRL) | + BIT_WMAC_USE_NDPARATE | + (csi_rsc << 13); + if (vif->net_type == RTW_NET_AP_MODE) + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc | BIT(12)); + else + rtw_write32(rtwdev, REG_BBPSF_CTRL, tmp6dc & ~BIT(12)); + + rtw_write32(rtwdev, REG_CSI_RRSR, 0x550); +} + +static void rtw8822c_bf_config_bfee_su(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw8822c_bf_enable_bfee_su(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_su(rtwdev, bfee); +} + +static void rtw8822c_bf_config_bfee_mu(struct rtw_dev *rtwdev, + struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (enable) + rtw_bf_enable_bfee_mu(rtwdev, vif, bfee); + else + rtw_bf_remove_bfee_mu(rtwdev, bfee); +} + +static void rtw8822c_bf_config_bfee(struct rtw_dev *rtwdev, struct rtw_vif *vif, + struct rtw_bfee *bfee, bool enable) +{ + if (bfee->role == RTW_BFEE_SU) + rtw8822c_bf_config_bfee_su(rtwdev, vif, bfee, enable); + else if (bfee->role == RTW_BFEE_MU) + rtw8822c_bf_config_bfee_mu(rtwdev, vif, bfee, enable); + else + rtw_warn(rtwdev, "wrong bfee role\n"); +} + struct dpk_cfg_pair { u32 addr; u32 bitmask; @@ -3678,6 +3732,9 @@ static struct rtw_chip_ops rtw8822c_ops = { .phy_calibration = rtw8822c_phy_calibration, .cck_pd_set = rtw8822c_phy_cck_pd_set, .pwr_track = rtw8822c_pwr_track, + .config_bfee = rtw8822c_bf_config_bfee, + .set_gid_table = rtw_bf_set_gid_table, + .cfg_csi_rate = rtw_bf_cfg_csi_rate, .coex_set_init = rtw8822c_coex_cfg_init, .coex_set_ant_switch = NULL, @@ -3998,6 +4055,8 @@ struct rtw_chip_info rtw8822c_hw_spec = { .dpd_ratemask = DIS_DPD_RATEALL, .pwr_track_tbl = &rtw8822c_rtw_pwr_track_tbl, .iqk_threshold = 8, + .bfer_su_max_num = 2, + .bfer_mu_max_num = 1, .coex_para_ver = 0x19062706, .bt_desired_ver = 0x6, -- cgit v1.2.3-59-g8ed1b From f39e9bd49a3d612a2489b774265107f61ffd82fa Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Tue, 22 Oct 2019 18:04:19 +0800 Subject: rtw88: add set_bitrate_mask support Support setting bit rate from upper layer. After configuring the original rate control result in the driver, the result is then masked by the bit rate mask received from the ops set_bitrate_mask. Lastly, the masked result will be sent to firmware. Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac80211.c | 53 ++++++++++++++++++ drivers/net/wireless/realtek/rtw88/main.c | 78 +++++++++++++++++++++------ drivers/net/wireless/realtek/rtw88/main.h | 3 ++ 3 files changed, 118 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index bc04cc280a96..2247bd61e716 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -475,6 +475,8 @@ static int rtw_ops_sta_remove(struct ieee80211_hw *hw, for (i = 0; i < ARRAY_SIZE(sta->txq); i++) rtw_txq_cleanup(rtwdev, sta->txq[i]); + kfree(si->mask); + rtwdev->sta_cnt--; rtw_info(rtwdev, "sta %pM with macid %d left\n", @@ -684,6 +686,56 @@ static void rtw_ops_flush(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } +struct rtw_iter_bitrate_mask_data { + struct rtw_dev *rtwdev; + struct ieee80211_vif *vif; + const struct cfg80211_bitrate_mask *mask; +}; + +static void rtw_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw_iter_bitrate_mask_data *br_data = data; + struct rtw_sta_info *si = (struct rtw_sta_info *)sta->drv_priv; + + if (si->vif != br_data->vif) + return; + + /* free previous mask setting */ + kfree(si->mask); + si->mask = kmemdup(br_data->mask, sizeof(struct cfg80211_bitrate_mask), + GFP_ATOMIC); + if (!si->mask) { + si->use_cfg_mask = false; + return; + } + + si->use_cfg_mask = true; + rtw_update_sta_info(br_data->rtwdev, si); +} + +static void rtw_ra_mask_info_update(struct rtw_dev *rtwdev, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw_iter_bitrate_mask_data br_data; + + br_data.rtwdev = rtwdev; + br_data.vif = vif; + br_data.mask = mask; + rtw_iterate_stas_atomic(rtwdev, rtw_ra_mask_info_update_iter, &br_data); +} + +static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct rtw_dev *rtwdev = hw->priv; + + rtw_ra_mask_info_update(rtwdev, vif, mask); + + return 0; +} + const struct ieee80211_ops rtw_ops = { .tx = rtw_ops_tx, .wake_tx_queue = rtw_ops_wake_tx_queue, @@ -705,5 +757,6 @@ const struct ieee80211_ops rtw_ops = { .set_rts_threshold = rtw_ops_set_rts_threshold, .sta_statistics = rtw_ops_sta_statistics, .flush = rtw_ops_flush, + .set_bitrate_mask = rtw_ops_set_bitrate_mask, }; EXPORT_SYMBOL(rtw_ops); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 47e74f0aec06..e53143132a9b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -612,12 +612,71 @@ static u8 get_rate_id(u8 wireless_set, enum rtw_bandwidth bw_mode, u8 tx_num) #define RA_MASK_OFDM_IN_HT_2G 0x00010 #define RA_MASK_OFDM_IN_HT_5G 0x00030 +static u64 rtw_update_rate_mask(struct rtw_dev *rtwdev, + struct rtw_sta_info *si, + u64 ra_mask, bool is_vht_enable, + u8 wireless_set) +{ + struct rtw_hal *hal = &rtwdev->hal; + const struct cfg80211_bitrate_mask *mask = si->mask; + u64 cfg_mask = GENMASK(63, 0); + u8 rssi_level, band; + + if (wireless_set != WIRELESS_CCK) { + rssi_level = si->rssi_level; + if (rssi_level == 0) + ra_mask &= 0xffffffffffffffffULL; + else if (rssi_level == 1) + ra_mask &= 0xfffffffffffffff0ULL; + else if (rssi_level == 2) + ra_mask &= 0xffffffffffffefe0ULL; + else if (rssi_level == 3) + ra_mask &= 0xffffffffffffcfc0ULL; + else if (rssi_level == 4) + ra_mask &= 0xffffffffffff8f80ULL; + else if (rssi_level >= 5) + ra_mask &= 0xffffffffffff0f00ULL; + } + + if (!si->use_cfg_mask) + return ra_mask; + + band = hal->current_band_type; + if (band == RTW_BAND_2G) { + band = NL80211_BAND_2GHZ; + cfg_mask = mask->control[band].legacy; + } else if (band == RTW_BAND_5G) { + band = NL80211_BAND_5GHZ; + cfg_mask = u64_encode_bits(mask->control[band].legacy, + RA_MASK_OFDM_RATES); + } + + if (!is_vht_enable) { + if (ra_mask & RA_MASK_HT_RATES_1SS) + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[0], + RA_MASK_HT_RATES_1SS); + if (ra_mask & RA_MASK_HT_RATES_2SS) + cfg_mask |= u64_encode_bits(mask->control[band].ht_mcs[1], + RA_MASK_HT_RATES_2SS); + } else { + if (ra_mask & RA_MASK_VHT_RATES_1SS) + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[0], + RA_MASK_VHT_RATES_1SS); + if (ra_mask & RA_MASK_VHT_RATES_2SS) + cfg_mask |= u64_encode_bits(mask->control[band].vht_mcs[1], + RA_MASK_VHT_RATES_2SS); + } + + ra_mask &= cfg_mask; + + return ra_mask; +} + void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) { struct ieee80211_sta *sta = si->sta; struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_hal *hal = &rtwdev->hal; - u8 rssi_level; u8 wireless_set; u8 bw_mode; u8 rate_id; @@ -710,21 +769,8 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) rate_id = get_rate_id(wireless_set, bw_mode, tx_num); - if (wireless_set != WIRELESS_CCK) { - rssi_level = si->rssi_level; - if (rssi_level == 0) - ra_mask &= 0xffffffffffffffffULL; - else if (rssi_level == 1) - ra_mask &= 0xfffffffffffffff0ULL; - else if (rssi_level == 2) - ra_mask &= 0xffffffffffffefe0ULL; - else if (rssi_level == 3) - ra_mask &= 0xffffffffffffcfc0ULL; - else if (rssi_level == 4) - ra_mask &= 0xffffffffffff8f80ULL; - else if (rssi_level >= 5) - ra_mask &= 0xffffffffffff0f00ULL; - } + ra_mask = rtw_update_rate_mask(rtwdev, si, ra_mask, is_vht_enable, + wireless_set); si->bw_mode = bw_mode; si->stbc_en = stbc_en; diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 14b35152fe9f..5e33b7e47a9d 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -646,6 +646,9 @@ struct rtw_sta_info { DECLARE_BITMAP(tid_ba, IEEE80211_NUM_TIDS); struct rtw_ra_report ra_report; + + bool use_cfg_mask; + struct cfg80211_bitrate_mask *mask; }; enum rtw_bfee_role { -- cgit v1.2.3-59-g8ed1b From 082a36dc9995d581db42f47055287e4974e3825c Mon Sep 17 00:00:00 2001 From: Tsang-Shian Lin Date: Tue, 22 Oct 2019 18:04:20 +0800 Subject: rtw88: add phy_info debugfs to show Tx/Rx physical status This commit adds several Tx/Rx physical information to phy_info debugfs for 8822B/8822C. By this debugfs, we can know physical information, such as Tx/Rx rate, RSSI, EVM,SNR, etc. The information is gotten from the packets of Tx/Rx path. It has no impact for the performance of 8822B/8822C. In the fields, we may meet different kinds of problems, but we may have no professional instrument to check them. At this moment, this debugfs is a good tool, and it may provide useful information for debug. Signed-off-by: Tsang-Shian Lin Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/debug.c | 174 ++++++++++++++++++++++---- drivers/net/wireless/realtek/rtw88/main.c | 37 +++++- drivers/net/wireless/realtek/rtw88/main.h | 58 +++++++++ drivers/net/wireless/realtek/rtw88/phy.c | 9 ++ drivers/net/wireless/realtek/rtw88/rtw8822b.c | 45 +++++++ drivers/net/wireless/realtek/rtw88/rtw8822b.h | 12 ++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 48 +++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.h | 12 ++ drivers/net/wireless/realtek/rtw88/rx.c | 69 +++++++++- 9 files changed, 431 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 6ad985e98e42..5a181e01ebef 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -498,12 +498,32 @@ static void rtw_print_vht_rate_txt(struct seq_file *m, u8 rate) seq_printf(m, " VHT%uSMCS%u", n_ss, mcs_n); } +static void rtw_print_rate(struct seq_file *m, u8 rate) +{ + switch (rate) { + case DESC_RATE1M...DESC_RATE11M: + rtw_print_cck_rate_txt(m, rate); + break; + case DESC_RATE6M...DESC_RATE54M: + rtw_print_ofdm_rate_txt(m, rate); + break; + case DESC_RATEMCS0...DESC_RATEMCS15: + rtw_print_ht_rate_txt(m, rate); + break; + case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT2SS_MCS9: + rtw_print_vht_rate_txt(m, rate); + break; + default: + seq_printf(m, " Unknown rate=0x%x\n", rate); + break; + } +} + static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) { struct rtw_debugfs_priv *debugfs_priv = m->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_hal *hal = &rtwdev->hal; - void (*print_rate)(struct seq_file *, u8) = NULL; u8 path, rate; struct rtw_power_params pwr_param = {0}; u8 bw = hal->current_band_width; @@ -528,30 +548,11 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) rate < DESC_RATEVHT1SS_MCS0) continue; - switch (rate) { - case DESC_RATE1M...DESC_RATE11M: - print_rate = rtw_print_cck_rate_txt; - break; - case DESC_RATE6M...DESC_RATE54M: - print_rate = rtw_print_ofdm_rate_txt; - break; - case DESC_RATEMCS0...DESC_RATEMCS15: - print_rate = rtw_print_ht_rate_txt; - break; - case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT2SS_MCS9: - print_rate = rtw_print_vht_rate_txt; - break; - default: - print_rate = NULL; - break; - } - rtw_get_tx_power_params(rtwdev, path, rate, bw, ch, regd, &pwr_param); seq_printf(m, "%4c ", path + 'A'); - if (print_rate) - print_rate(m, rate); + rtw_print_rate(m, rate); seq_printf(m, " %3u(0x%02x) %4u %4d (%4d %4d)\n", hal->tx_pwr_tbl[path][rate], hal->tx_pwr_tbl[path][rate], @@ -567,6 +568,132 @@ static int rtw_debugfs_get_tx_pwr_tbl(struct seq_file *m, void *v) return 0; } +static int rtw_debugfs_get_phy_info(struct seq_file *m, void *v) +{ + struct rtw_debugfs_priv *debugfs_priv = m->private; + struct rtw_dev *rtwdev = debugfs_priv->rtwdev; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_traffic_stats *stats = &rtwdev->stats; + struct rtw_pkt_count *last_cnt = &dm_info->last_pkt_count; + struct rtw_efuse *efuse = &rtwdev->efuse; + struct ewma_evm *ewma_evm = dm_info->ewma_evm; + struct ewma_snr *ewma_snr = dm_info->ewma_snr; + u8 ss, rate_id; + + seq_puts(m, "==========[Common Info]========\n"); + seq_printf(m, "Is link = %c\n", rtw_is_assoc(rtwdev) ? 'Y' : 'N'); + seq_printf(m, "Current CH(fc) = %u\n", rtwdev->hal.current_channel); + seq_printf(m, "Current BW = %u\n", rtwdev->hal.current_band_width); + seq_printf(m, "Current IGI = 0x%x\n", dm_info->igi_history[0]); + seq_printf(m, "TP {Tx, Rx} = {%u, %u}Mbps\n\n", + stats->tx_throughput, stats->rx_throughput); + + seq_puts(m, "==========[Tx Phy Info]========\n"); + seq_puts(m, "[Tx Rate] = "); + rtw_print_rate(m, dm_info->tx_rate); + seq_printf(m, "(0x%x)\n\n", dm_info->tx_rate); + + seq_puts(m, "==========[Rx Phy Info]========\n"); + seq_printf(m, "[Rx Beacon Count] = %u\n", last_cnt->num_bcn_pkt); + seq_puts(m, "[Rx Rate] = "); + rtw_print_rate(m, dm_info->curr_rx_rate); + seq_printf(m, "(0x%x)\n", dm_info->curr_rx_rate); + + seq_puts(m, "[Rx Rate Count]:\n"); + seq_printf(m, " * CCK = {%u, %u, %u, %u}\n", + last_cnt->num_qry_pkt[DESC_RATE1M], + last_cnt->num_qry_pkt[DESC_RATE2M], + last_cnt->num_qry_pkt[DESC_RATE5_5M], + last_cnt->num_qry_pkt[DESC_RATE11M]); + + seq_printf(m, " * OFDM = {%u, %u, %u, %u, %u, %u, %u, %u}\n", + last_cnt->num_qry_pkt[DESC_RATE6M], + last_cnt->num_qry_pkt[DESC_RATE9M], + last_cnt->num_qry_pkt[DESC_RATE12M], + last_cnt->num_qry_pkt[DESC_RATE18M], + last_cnt->num_qry_pkt[DESC_RATE24M], + last_cnt->num_qry_pkt[DESC_RATE36M], + last_cnt->num_qry_pkt[DESC_RATE48M], + last_cnt->num_qry_pkt[DESC_RATE54M]); + + for (ss = 0; ss < efuse->hw_cap.nss; ss++) { + rate_id = DESC_RATEMCS0 + ss * 8; + seq_printf(m, " * HT_MCS[%u:%u] = {%u, %u, %u, %u, %u, %u, %u, %u}\n", + ss * 8, ss * 8 + 7, + last_cnt->num_qry_pkt[rate_id], + last_cnt->num_qry_pkt[rate_id + 1], + last_cnt->num_qry_pkt[rate_id + 2], + last_cnt->num_qry_pkt[rate_id + 3], + last_cnt->num_qry_pkt[rate_id + 4], + last_cnt->num_qry_pkt[rate_id + 5], + last_cnt->num_qry_pkt[rate_id + 6], + last_cnt->num_qry_pkt[rate_id + 7]); + } + + for (ss = 0; ss < efuse->hw_cap.nss; ss++) { + rate_id = DESC_RATEVHT1SS_MCS0 + ss * 10; + seq_printf(m, " * VHT_MCS-%uss MCS[0:9] = {%u, %u, %u, %u, %u, %u, %u, %u, %u, %u}\n", + ss + 1, + last_cnt->num_qry_pkt[rate_id], + last_cnt->num_qry_pkt[rate_id + 1], + last_cnt->num_qry_pkt[rate_id + 2], + last_cnt->num_qry_pkt[rate_id + 3], + last_cnt->num_qry_pkt[rate_id + 4], + last_cnt->num_qry_pkt[rate_id + 5], + last_cnt->num_qry_pkt[rate_id + 6], + last_cnt->num_qry_pkt[rate_id + 7], + last_cnt->num_qry_pkt[rate_id + 8], + last_cnt->num_qry_pkt[rate_id + 9]); + } + + seq_printf(m, "[RSSI(dBm)] = {%d, %d}\n", + dm_info->rssi[RF_PATH_A] - 100, + dm_info->rssi[RF_PATH_B] - 100); + seq_printf(m, "[Rx EVM(dB)] = {-%d, -%d}\n", + dm_info->rx_evm_dbm[RF_PATH_A], + dm_info->rx_evm_dbm[RF_PATH_B]); + seq_printf(m, "[Rx SNR] = {%d, %d}\n", + dm_info->rx_snr[RF_PATH_A], + dm_info->rx_snr[RF_PATH_B]); + seq_printf(m, "[CFO_tail(KHz)] = {%d, %d}\n", + dm_info->cfo_tail[RF_PATH_A], + dm_info->cfo_tail[RF_PATH_B]); + + if (dm_info->curr_rx_rate >= DESC_RATE11M) { + seq_puts(m, "[Rx Average Status]:\n"); + seq_printf(m, " * OFDM, EVM: {-%d}, SNR: {%d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_OFDM]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_OFDM_A])); + seq_printf(m, " * 1SS, EVM: {-%d}, SNR: {%d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_1SS]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_1SS_A])); + seq_printf(m, " * 2SS, EVM: {-%d, -%d}, SNR: {%d, %d}\n", + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_2SS_A]), + (u8)ewma_evm_read(&ewma_evm[RTW_EVM_2SS_B]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_2SS_A]), + (u8)ewma_snr_read(&ewma_snr[RTW_SNR_2SS_B])); + } + + seq_puts(m, "[Rx Counter]:\n"); + seq_printf(m, " * CCA (CCK, OFDM, Total) = (%u, %u, %u)\n", + dm_info->cck_cca_cnt, + dm_info->ofdm_cca_cnt, + dm_info->total_cca_cnt); + seq_printf(m, " * False Alarm (CCK, OFDM, Total) = (%u, %u, %u)\n", + dm_info->cck_fa_cnt, + dm_info->ofdm_fa_cnt, + dm_info->total_fa_cnt); + seq_printf(m, " * CCK cnt (ok, err) = (%u, %u)\n", + dm_info->cck_ok_cnt, dm_info->cck_err_cnt); + seq_printf(m, " * OFDM cnt (ok, err) = (%u, %u)\n", + dm_info->ofdm_ok_cnt, dm_info->ofdm_err_cnt); + seq_printf(m, " * HT cnt (ok, err) = (%u, %u)\n", + dm_info->ht_ok_cnt, dm_info->ht_err_cnt); + seq_printf(m, " * VHT cnt (ok, err) = (%u, %u)\n", + dm_info->vht_ok_cnt, dm_info->vht_err_cnt); + return 0; +} + #define rtw_debug_impl_mac(page, addr) \ static struct rtw_debugfs_priv rtw_debug_priv_mac_ ##page = { \ .cb_read = rtw_debug_get_mac_page, \ @@ -653,6 +780,10 @@ static struct rtw_debugfs_priv rtw_debug_priv_rsvd_page = { .cb_read = rtw_debugfs_get_rsvd_page, }; +static struct rtw_debugfs_priv rtw_debug_priv_phy_info = { + .cb_read = rtw_debugfs_get_phy_info, +}; + #define rtw_debugfs_add_core(name, mode, fopname, parent) \ do { \ rtw_debug_priv_ ##name.rtwdev = rtwdev; \ @@ -682,6 +813,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev) rtw_debugfs_add_rw(rf_read); rtw_debugfs_add_rw(dump_cam); rtw_debugfs_add_rw(rsvd_page); + rtw_debugfs_add_r(phy_info); rtw_debugfs_add_r(mac_0); rtw_debugfs_add_r(mac_1); rtw_debugfs_add_r(mac_2); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index e53143132a9b..32e7328ce126 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -178,6 +178,7 @@ static void rtw_watch_dog_work(struct work_struct *work) { struct rtw_dev *rtwdev = container_of(work, struct rtw_dev, watch_dog_work.work); + struct rtw_traffic_stats *stats = &rtwdev->stats; struct rtw_watch_dog_iter_data data = {}; bool busy_traffic = test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags); bool ps_active; @@ -198,17 +199,24 @@ static void rtw_watch_dog_work(struct work_struct *work) if (busy_traffic != test_bit(RTW_FLAG_BUSY_TRAFFIC, rtwdev->flags)) rtw_coex_wl_status_change_notify(rtwdev); - if (rtwdev->stats.tx_cnt > RTW_LPS_THRESHOLD || - rtwdev->stats.rx_cnt > RTW_LPS_THRESHOLD) + if (stats->tx_cnt > RTW_LPS_THRESHOLD || + stats->rx_cnt > RTW_LPS_THRESHOLD) ps_active = true; else ps_active = false; + ewma_tp_add(&stats->tx_ewma_tp, + (u32)(stats->tx_unicast >> RTW_TP_SHIFT)); + ewma_tp_add(&stats->rx_ewma_tp, + (u32)(stats->rx_unicast >> RTW_TP_SHIFT)); + stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); + stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); + /* reset tx/rx statictics */ - rtwdev->stats.tx_unicast = 0; - rtwdev->stats.rx_unicast = 0; - rtwdev->stats.tx_cnt = 0; - rtwdev->stats.rx_cnt = 0; + stats->tx_unicast = 0; + stats->rx_unicast = 0; + stats->tx_cnt = 0; + stats->rx_cnt = 0; if (test_bit(RTW_FLAG_SCANNING, rtwdev->flags)) goto unlock; @@ -1281,6 +1289,21 @@ err_out: } EXPORT_SYMBOL(rtw_chip_info_setup); +static void rtw_stats_init(struct rtw_dev *rtwdev) +{ + struct rtw_traffic_stats *stats = &rtwdev->stats; + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + int i; + + ewma_tp_init(&stats->tx_ewma_tp); + ewma_tp_init(&stats->rx_ewma_tp); + + for (i = 0; i < RTW_EVM_NUM; i++) + ewma_evm_init(&dm_info->ewma_evm[i]); + for (i = 0; i < RTW_SNR_NUM; i++) + ewma_snr_init(&dm_info->ewma_snr[i]); +} + int rtw_core_init(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -1329,6 +1352,8 @@ int rtw_core_init(struct rtw_dev *rtwdev) rtw_add_rsvd_page(rtwdev, RSVD_BEACON, false); mutex_unlock(&rtwdev->mutex); + rtw_stats_init(rtwdev); + /* default rx filter setting */ rtwdev->hal.rcr = BIT_APP_FCS | BIT_APP_MIC | BIT_APP_ICV | BIT_HTC_LOC_CTRL | BIT_APP_PHYSTS | diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index 5e33b7e47a9d..d012eefcd0da 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -29,6 +29,8 @@ #define RTW_RF_PATH_MAX 4 #define HW_FEATURE_LEN 13 +#define RTW_TP_SHIFT 18 /* bytes/2s --> Mbps */ + extern bool rtw_bf_support; extern unsigned int rtw_fw_lps_deep_mode; extern unsigned int rtw_debug_mask; @@ -339,6 +341,32 @@ enum rtw_flags { NUM_OF_RTW_FLAGS, }; +enum rtw_evm { + RTW_EVM_OFDM = 0, + RTW_EVM_1SS, + RTW_EVM_2SS_A, + RTW_EVM_2SS_B, + /* keep it last */ + RTW_EVM_NUM +}; + +enum rtw_snr { + RTW_SNR_OFDM_A = 0, + RTW_SNR_OFDM_B, + RTW_SNR_OFDM_C, + RTW_SNR_OFDM_D, + RTW_SNR_1SS_A, + RTW_SNR_1SS_B, + RTW_SNR_1SS_C, + RTW_SNR_1SS_D, + RTW_SNR_2SS_A, + RTW_SNR_2SS_B, + RTW_SNR_2SS_C, + RTW_SNR_2SS_D, + /* keep it last */ + RTW_SNR_NUM +}; + /* the power index is represented by differences, which cck-1s & ht40-1s are * the base values, so for 1s's differences, there are only ht20 & ofdm */ @@ -527,10 +555,16 @@ struct rtw_rx_pkt_stat { s8 rx_power[RTW_RF_PATH_MAX]; u8 rssi; u8 rxsc; + s8 rx_snr[RTW_RF_PATH_MAX]; + u8 rx_evm[RTW_RF_PATH_MAX]; + s8 cfo_tail[RTW_RF_PATH_MAX]; + struct rtw_sta_info *si; struct ieee80211_vif *vif; }; +DECLARE_EWMA(tp, 10, 2); + struct rtw_traffic_stats { /* units in bytes */ u64 tx_unicast; @@ -543,6 +577,8 @@ struct rtw_traffic_stats { /* units in Mbps */ u32 tx_throughput; u32 rx_throughput; + struct ewma_tp tx_ewma_tp; + struct ewma_tp rx_ewma_tp; }; enum rtw_lps_mode { @@ -1251,10 +1287,21 @@ struct rtw_swing_table { const u8 *n[RTW_RF_PATH_MAX]; }; +struct rtw_pkt_count { + u16 num_bcn_pkt; + u16 num_qry_pkt[DESC_RATE_MAX]; +}; + +DECLARE_EWMA(evm, 10, 4); +DECLARE_EWMA(snr, 10, 4); + struct rtw_dm_info { u32 cck_fa_cnt; u32 ofdm_fa_cnt; u32 total_fa_cnt; + u32 cck_cca_cnt; + u32 ofdm_cca_cnt; + u32 total_cca_cnt; u32 cck_ok_cnt; u32 cck_err_cnt; @@ -1296,6 +1343,17 @@ struct rtw_dm_info { /* [bandwidth 0:20M/1:40M][number of path] */ u8 cck_pd_lv[2][RTW_RF_PATH_MAX]; u32 cck_fa_avg; + + /* save the last rx phy status for debug */ + s8 rx_snr[RTW_RF_PATH_MAX]; + u8 rx_evm_dbm[RTW_RF_PATH_MAX]; + s16 cfo_tail[RTW_RF_PATH_MAX]; + u8 rssi[RTW_RF_PATH_MAX]; + u8 curr_rx_rate; + struct rtw_pkt_count cur_pkt_count; + struct rtw_pkt_count last_pkt_count; + struct ewma_evm ewma_evm[RTW_EVM_NUM]; + struct ewma_snr ewma_snr[RTW_SNR_NUM]; }; struct rtw_efuse { diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 0fa8d91a882b..69e7edb629f4 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -222,10 +222,19 @@ static void rtw_phy_stat_rssi(struct rtw_dev *rtwdev) dm_info->min_rssi = data.min_rssi; } +static void rtw_phy_stat_rate_cnt(struct rtw_dev *rtwdev) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + + dm_info->last_pkt_count = dm_info->cur_pkt_count; + memset(&dm_info->cur_pkt_count, 0, sizeof(dm_info->cur_pkt_count)); +} + static void rtw_phy_statistics(struct rtw_dev *rtwdev) { rtw_phy_stat_rssi(rtwdev); rtw_phy_stat_false_alarm(rtwdev); + rtw_phy_stat_rate_cnt(rtwdev); } #define DIG_PERF_FA_TH_LOW 250 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 87a9178ba022..6f4e7326068c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -815,6 +815,7 @@ static void rtw8822b_config_trx_mode(struct rtw_dev *rtwdev, u8 tx_path, static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; s8 min_rx_power = -120; u8 pwdb = GET_PHY_STAT_P0_PWDB(phy_status); @@ -824,13 +825,19 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->bw = RTW_CHANNEL_WIDTH_20; pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], min_rx_power); + dm_info->rssi[RF_PATH_A] = pkt_stat->rssi; } static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; + s8 rx_evm; + u8 evm_dbm = 0; + u8 rssi; + int path; if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0) rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status); @@ -853,6 +860,34 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->signal_power = max3(pkt_stat->rx_power[RF_PATH_A], pkt_stat->rx_power[RF_PATH_B], min_rx_power); + + dm_info->curr_rx_rate = pkt_stat->rate; + + pkt_stat->rx_evm[RF_PATH_A] = GET_PHY_STAT_P1_RXEVM_A(phy_status); + pkt_stat->rx_evm[RF_PATH_B] = GET_PHY_STAT_P1_RXEVM_B(phy_status); + + pkt_stat->rx_snr[RF_PATH_A] = GET_PHY_STAT_P1_RXSNR_A(phy_status); + pkt_stat->rx_snr[RF_PATH_B] = GET_PHY_STAT_P1_RXSNR_B(phy_status); + + pkt_stat->cfo_tail[RF_PATH_A] = GET_PHY_STAT_P1_CFO_TAIL_A(phy_status); + pkt_stat->cfo_tail[RF_PATH_B] = GET_PHY_STAT_P1_CFO_TAIL_B(phy_status); + + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; + dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; + + rx_evm = pkt_stat->rx_evm[path]; + + if (rx_evm < 0) { + if (rx_evm == S8_MIN) + evm_dbm = 0; + else + evm_dbm = ((u8)-rx_evm >> 1); + } + dm_info->rx_evm_dbm[path] = evm_dbm; + } } static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, @@ -999,6 +1034,7 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev) u32 cck_fa_cnt; u32 ofdm_fa_cnt; u32 crc32_cnt; + u32 cca32_cnt; cck_enable = rtw_read32(rtwdev, 0x808) & BIT(28); cck_fa_cnt = rtw_read16(rtwdev, 0xa5c); @@ -1022,6 +1058,15 @@ static void rtw8822b_false_alarm_statistics(struct rtw_dev *rtwdev) dm_info->vht_ok_cnt = crc32_cnt & 0xffff; dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16; + cca32_cnt = rtw_read32(rtwdev, 0xf08); + dm_info->ofdm_cca_cnt = ((cca32_cnt & 0xffff0000) >> 16); + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) { + cca32_cnt = rtw_read32(rtwdev, 0xfcc); + dm_info->cck_cca_cnt = cca32_cnt & 0xffff; + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + } + rtw_write32_set(rtwdev, 0x9a4, BIT(17)); rtw_write32_clr(rtwdev, 0x9a4, BIT(17)); rtw_write32_clr(rtwdev, 0xa2c, BIT(15)); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.h b/drivers/net/wireless/realtek/rtw88/rtw8822b.h index 0cb93d7d4cfd..6211f4b547b9 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.h @@ -127,6 +127,18 @@ _rtw_write32s_mask(struct rtw_dev *rtwdev, u32 addr, u32 mask, u32 data) le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) #define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) #define REG_HTSTFWT 0x800 #define REG_RXPSEL 0x808 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index ae4417d6c272..b77905196ffb 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1643,6 +1643,8 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, u8 gain_a, gain_b; s8 rx_power[RTW_RF_PATH_MAX]; s8 min_rx_power = -120; + u8 rssi; + int path; rx_power[RF_PATH_A] = GET_PHY_STAT_P0_PWDB_A(phy_status); rx_power[RF_PATH_B] = GET_PHY_STAT_P0_PWDB_B(phy_status); @@ -1665,6 +1667,11 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->rx_power[RF_PATH_A] = rx_power[RF_PATH_A]; pkt_stat->rx_power[RF_PATH_B] = rx_power[RF_PATH_B]; + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + } + pkt_stat->rssi = rtw_phy_rf_power_2_rssi(pkt_stat->rx_power, 1); pkt_stat->bw = RTW_CHANNEL_WIDTH_20; pkt_stat->signal_power = max(pkt_stat->rx_power[RF_PATH_A], @@ -1674,8 +1681,13 @@ static void query_phy_status_page0(struct rtw_dev *rtwdev, u8 *phy_status, static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, struct rtw_rx_pkt_stat *pkt_stat) { + struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 rxsc, bw; s8 min_rx_power = -120; + s8 rx_evm; + u8 evm_dbm = 0; + u8 rssi; + int path; if (pkt_stat->rate > DESC_RATE11M && pkt_stat->rate < DESC_RATEMCS0) rxsc = GET_PHY_STAT_P1_L_RXSC(phy_status); @@ -1696,6 +1708,34 @@ static void query_phy_status_page1(struct rtw_dev *rtwdev, u8 *phy_status, pkt_stat->signal_power = max3(pkt_stat->rx_power[RF_PATH_A], pkt_stat->rx_power[RF_PATH_B], min_rx_power); + + dm_info->curr_rx_rate = pkt_stat->rate; + + pkt_stat->rx_evm[RF_PATH_A] = GET_PHY_STAT_P1_RXEVM_A(phy_status); + pkt_stat->rx_evm[RF_PATH_B] = GET_PHY_STAT_P1_RXEVM_B(phy_status); + + pkt_stat->rx_snr[RF_PATH_A] = GET_PHY_STAT_P1_RXSNR_A(phy_status); + pkt_stat->rx_snr[RF_PATH_B] = GET_PHY_STAT_P1_RXSNR_B(phy_status); + + pkt_stat->cfo_tail[RF_PATH_A] = GET_PHY_STAT_P1_CFO_TAIL_A(phy_status); + pkt_stat->cfo_tail[RF_PATH_B] = GET_PHY_STAT_P1_CFO_TAIL_B(phy_status); + + for (path = 0; path <= rtwdev->hal.rf_path_num; path++) { + rssi = rtw_phy_rf_power_2_rssi(&pkt_stat->rx_power[path], 1); + dm_info->rssi[path] = rssi; + dm_info->rx_snr[path] = pkt_stat->rx_snr[path] >> 1; + dm_info->cfo_tail[path] = (pkt_stat->cfo_tail[path] * 5) >> 1; + + rx_evm = pkt_stat->rx_evm[path]; + + if (rx_evm < 0) { + if (rx_evm == S8_MIN) + evm_dbm = 0; + else + evm_dbm = ((u8)-rx_evm >> 1); + } + dm_info->rx_evm_dbm[path] = evm_dbm; + } } static void query_phy_status(struct rtw_dev *rtwdev, u8 *phy_status, @@ -1850,6 +1890,7 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev) u32 cck_enable; u32 cck_fa_cnt; u32 crc32_cnt; + u32 cca32_cnt; u32 ofdm_fa_cnt; u32 ofdm_fa_cnt1, ofdm_fa_cnt2, ofdm_fa_cnt3, ofdm_fa_cnt4, ofdm_fa_cnt5; u16 parity_fail, rate_illegal, crc8_fail, mcs_fail, sb_search_fail, @@ -1894,6 +1935,13 @@ static void rtw8822c_false_alarm_statistics(struct rtw_dev *rtwdev) dm_info->vht_ok_cnt = crc32_cnt & 0xffff; dm_info->vht_err_cnt = (crc32_cnt & 0xffff0000) >> 16; + cca32_cnt = rtw_read32(rtwdev, 0x2c08); + dm_info->ofdm_cca_cnt = ((cca32_cnt & 0xffff0000) >> 16); + dm_info->cck_cca_cnt = cca32_cnt & 0xffff; + dm_info->total_cca_cnt = dm_info->ofdm_cca_cnt; + if (cck_enable) + dm_info->total_cca_cnt += dm_info->cck_cca_cnt; + rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 0); rtw_write32_mask(rtwdev, REG_CCANRX, BIT_CCK_FA_RST, 2); rtw_write32_mask(rtwdev, REG_CCANRX, BIT_OFDM_FA_RST, 0); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h index 438db74d8e7a..abd9f300bedd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h @@ -149,6 +149,18 @@ const struct rtw_table name ## _tbl = { \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(11, 8)) #define GET_PHY_STAT_P1_HT_RXSC(phy_stat) \ le32_get_bits(*((__le32 *)(phy_stat) + 0x01), GENMASK(15, 12)) +#define GET_PHY_STAT_P1_RXEVM_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXEVM_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x04), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_CFO_TAIL_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_CFO_TAIL_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x05), GENMASK(15, 8)) +#define GET_PHY_STAT_P1_RXSNR_A(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(7, 0)) +#define GET_PHY_STAT_P1_RXSNR_B(phy_stat) \ + le32_get_bits(*((__le32 *)(phy_stat) + 0x06), GENMASK(15, 8)) #define REG_ANAPARLDO_POW_MAC 0x0029 #define BIT_LDOE25_PON BIT(0) diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index d97d2c2c57c2..36887f998090 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -5,6 +5,7 @@ #include "main.h" #include "rx.h" #include "ps.h" +#include "debug.h" void rtw_rx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, struct sk_buff *skb) @@ -37,6 +38,60 @@ struct rtw_rx_addr_match_data { u8 *bssid; }; +static void rtw_rx_phy_stat(struct rtw_dev *rtwdev, + struct rtw_rx_pkt_stat *pkt_stat, + struct ieee80211_hdr *hdr) +{ + struct rtw_dm_info *dm_info = &rtwdev->dm_info; + struct rtw_pkt_count *cur_pkt_cnt = &dm_info->cur_pkt_count; + u8 rate_ss, rate_ss_evm, evm_id; + u8 i, idx; + + dm_info->curr_rx_rate = pkt_stat->rate; + + if (ieee80211_is_beacon(hdr->frame_control)) + cur_pkt_cnt->num_bcn_pkt++; + + switch (pkt_stat->rate) { + case DESC_RATE1M...DESC_RATE11M: + goto pkt_num; + case DESC_RATE6M...DESC_RATE54M: + rate_ss = 0; + rate_ss_evm = 1; + evm_id = RTW_EVM_OFDM; + break; + case DESC_RATEMCS0...DESC_RATEMCS7: + case DESC_RATEVHT1SS_MCS0...DESC_RATEVHT1SS_MCS9: + rate_ss = 1; + rate_ss_evm = 1; + evm_id = RTW_EVM_1SS; + break; + case DESC_RATEMCS8...DESC_RATEMCS15: + case DESC_RATEVHT2SS_MCS0...DESC_RATEVHT2SS_MCS9: + rate_ss = 2; + rate_ss_evm = 2; + evm_id = RTW_EVM_2SS_A; + break; + default: + rtw_warn(rtwdev, "unknown pkt rate = %d\n", pkt_stat->rate); + return; + } + + for (i = 0; i < rate_ss_evm; i++) { + idx = evm_id + i; + ewma_evm_add(&dm_info->ewma_evm[idx], + dm_info->rx_evm_dbm[i]); + } + + for (i = 0; i < rtwdev->hal.rf_path_num; i++) { + idx = RTW_SNR_OFDM_A + 4 * rate_ss + i; + ewma_snr_add(&dm_info->ewma_snr[idx], + dm_info->rx_snr[i]); + } +pkt_num: + cur_pkt_cnt->num_qry_pkt[pkt_stat->rate]++; +} + static void rtw_rx_addr_match_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -48,14 +103,16 @@ static void rtw_rx_addr_match_iter(void *data, u8 *mac, struct rtw_rx_pkt_stat *pkt_stat = iter_data->pkt_stat; u8 *bssid = iter_data->bssid; - if (ether_addr_equal(vif->bss_conf.bssid, bssid) && - (ether_addr_equal(vif->addr, hdr->addr1) || - ieee80211_is_beacon(hdr->frame_control))) - sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2, - vif->addr); - else + if (!ether_addr_equal(vif->bss_conf.bssid, bssid)) + return; + + if (!(ether_addr_equal(vif->addr, hdr->addr1) || + ieee80211_is_beacon(hdr->frame_control))) return; + rtw_rx_phy_stat(rtwdev, pkt_stat, hdr); + sta = ieee80211_find_sta_by_ifaddr(rtwdev->hw, hdr->addr2, + vif->addr); if (!sta) return; -- cgit v1.2.3-59-g8ed1b From 091c6e9c083f7ebaff00b37ad13562d51464d175 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 22 Oct 2019 17:47:03 -0700 Subject: rtlwifi: Remove unnecessary NULL check in rtl_regd_init When building with Clang + -Wtautological-pointer-compare: drivers/net/wireless/realtek/rtlwifi/regd.c:389:33: warning: comparison of address of 'rtlpriv->regd' equal to a null pointer is always false [-Wtautological-pointer-compare] if (wiphy == NULL || &rtlpriv->regd == NULL) ~~~~~~~~~^~~~ ~~~~ 1 warning generated. The address of an array member is never NULL unless it is the first struct member so remove the unnecessary check. This was addressed in the staging version of the driver in commit f986978b32b3 ("Staging: rtlwifi: remove unnecessary NULL check"). While we are here, fix the following checkpatch warning: CHECK: Comparison to NULL could be written "!wiphy" 35: FILE: drivers/net/wireless/realtek/rtlwifi/regd.c:389: + if (wiphy == NULL) Fixes: 0c8173385e54 ("rtl8192ce: Add new driver") Link:https://github.com/ClangBuiltLinux/linux/issues/750 Signed-off-by: Nathan Chancellor Acked-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/regd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/regd.c b/drivers/net/wireless/realtek/rtlwifi/regd.c index c10432cd703e..8be31e0ad878 100644 --- a/drivers/net/wireless/realtek/rtlwifi/regd.c +++ b/drivers/net/wireless/realtek/rtlwifi/regd.c @@ -386,7 +386,7 @@ int rtl_regd_init(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; struct country_code_to_enum_rd *country = NULL; - if (wiphy == NULL || &rtlpriv->regd == NULL) + if (!wiphy) return -EINVAL; /* init country_code from efuse channel plan */ -- cgit v1.2.3-59-g8ed1b From f64b06bd362a6d9e22a2a23dacd50882c1418eff Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Oct 2019 15:38:42 +0800 Subject: adm80211: remove set but not used variables 'mem_addr' and 'io_addr' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/admtek/adm8211.c:1784:16: warning: variable mem_addr set but not used [-Wunused-but-set-variable] drivers/net/wireless/admtek/adm8211.c:1785:15: warning: variable io_addr set but not used [-Wunused-but-set-variable] They are never used, so can be removed. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/admtek/adm8211.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index 46f1427e6e9e..ba326f6c1214 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1781,8 +1781,8 @@ static int adm8211_probe(struct pci_dev *pdev, { struct ieee80211_hw *dev; struct adm8211_priv *priv; - unsigned long mem_addr, mem_len; - unsigned int io_addr, io_len; + unsigned long mem_len; + unsigned int io_len; int err; u32 reg; u8 perm_addr[ETH_ALEN]; @@ -1794,9 +1794,7 @@ static int adm8211_probe(struct pci_dev *pdev, return err; } - io_addr = pci_resource_start(pdev, 0); io_len = pci_resource_len(pdev, 0); - mem_addr = pci_resource_start(pdev, 1); mem_len = pci_resource_len(pdev, 1); if (io_len < 256 || mem_len < 1024) { printk(KERN_ERR "%s (adm8211): Too short PCI resources\n", -- cgit v1.2.3-59-g8ed1b From d0c160b18ef5a353d8b9e1c7b616d1083c1b010b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Oct 2019 15:40:19 +0800 Subject: atmel: remove set but not used variable 'dev' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/atmel/atmel_cs.c:120:21: warning: variable dev set but not used [-Wunused-but-set-variable] It is never used, so can remove it. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/atmel/atmel_cs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/atmel/atmel_cs.c b/drivers/net/wireless/atmel/atmel_cs.c index 7afc9c5329fb..368eebefa741 100644 --- a/drivers/net/wireless/atmel/atmel_cs.c +++ b/drivers/net/wireless/atmel/atmel_cs.c @@ -117,11 +117,9 @@ static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) static int atmel_config(struct pcmcia_device *link) { - struct local_info *dev; int ret; const struct pcmcia_device_id *did; - dev = link->priv; did = dev_get_drvdata(&link->dev); dev_dbg(&link->dev, "atmel_config\n"); -- cgit v1.2.3-59-g8ed1b From 4fcef86091327d92008ca0328d45075343e7edea Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Oct 2019 15:53:42 +0800 Subject: rtl8xxxu: remove set but not used variable 'rate_mask' drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:4484:6: warning: variable rate_mask set but not used [-Wunused-but-set-variable] It is never used since commit a9bb0b515778 ("rtl8xxxu: Improve TX performance of RTL8723BU on rtl8xxxu driver") Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index f982f91b8bb6..899a940e2fb2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -4484,11 +4484,6 @@ static u16 rtl8xxxu_wireless_mode(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { u16 network_type = WIRELESS_MODE_UNKNOWN; - u32 rate_mask; - - rate_mask = (sta->supp_rates[0] & 0xfff) | - (sta->ht_cap.mcs.rx_mask[0] << 12) | - (sta->ht_cap.mcs.rx_mask[0] << 20); if (hw->conf.chandef.chan->band == NL80211_BAND_5GHZ) { if (sta->vht_cap.vht_supported) -- cgit v1.2.3-59-g8ed1b From b298800dd8ee7250bf04b4dbd151e1a971b6df91 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 23 Oct 2019 18:54:07 +0800 Subject: rtl8xxxu: fix warnings for symbol not declared Fix the following sparse warnings. sparse: symbol 'rtl8723bu_set_coex_with_type' was not declared. Should it be static? sparse: symbol 'rtl8723bu_update_bt_link_info' was not declared. Should it be static? sparse: symbol 'rtl8723bu_handle_bt_inquiry' was not declared. Should it be static? sparse: symbol 'rtl8723bu_handle_bt_info' was not declared. Should it be static? Signed-off-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 899a940e2fb2..bcb92831d376 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5189,6 +5189,7 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work) * cases which Realtek doesn't provide detail for these settings. Keep * this aligned with vendor driver for easier maintenance. */ +static void rtl8723bu_set_coex_with_type(struct rtl8xxxu_priv *priv, u8 type) { switch (type) { @@ -5240,6 +5241,7 @@ void rtl8723bu_set_coex_with_type(struct rtl8xxxu_priv *priv, u8 type) } } +static void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) { struct rtl8xxxu_btcoex *btcoex = &priv->bt_coex; @@ -5306,6 +5308,7 @@ void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) btcoex->bt_busy = false; } +static void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) { struct ieee80211_vif *vif; @@ -5331,6 +5334,7 @@ void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) } } +static void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) { struct ieee80211_vif *vif; -- cgit v1.2.3-59-g8ed1b From 1a64f8dc82b1a96baae3dc7eecbbbb6a315f1512 Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:22 +0000 Subject: net: aquantia: PTP skeleton declarations and callbacks Here we add basic function for PTP clock register/unregister. We also declare FW/HW capability bits used to control PTP feature on device. PTP device is created if network card has appropriate FW that has PTP enabled in config. HW supports timestamping for PTPv2 802.AS1 and PTPv2 IPv4 UDP packets. It also supports basic PTP callbacks for getting/setting time, adjusting frequency and time as well. Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Co-developed-by: Dmitry Bezrukov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/Makefile | 1 + drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 10 ++- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 5 +- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 84 +++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 22 ++++++ .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 85 +++++++++++++++++++++- 6 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.c create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_ptp.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index 131cab855be7..cd12d9d824ec 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -24,6 +24,7 @@ atlantic-objs := aq_main.o \ aq_ethtool.o \ aq_drvinfo.o \ aq_filters.o \ + aq_ptp.o \ hw_atl/hw_atl_a0.o \ hw_atl/hw_atl_b0.o \ hw_atl/hw_atl_utils.o \ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 137c1de4c6ec..d283d0bc75a3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_nic.c: Definition of common code for NIC. */ @@ -12,6 +12,7 @@ #include "aq_hw.h" #include "aq_pci_func.h" #include "aq_main.h" +#include "aq_ptp.h" #include #include @@ -331,6 +332,10 @@ int aq_nic_init(struct aq_nic_s *self) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw); + err = aq_ptp_init(self, self->irqvecs - 1); + if (err < 0) + goto err_exit; + netif_carrier_off(self->ndev); err_exit: @@ -972,6 +977,9 @@ void aq_nic_deinit(struct aq_nic_s *self) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_deinit(aq_vec); + aq_ptp_unregister(self); + aq_ptp_free(self); + if (likely(self->aq_fw_ops->deinit)) { mutex_lock(&self->fwreq_mutex); self->aq_fw_ops->deinit(self->aq_hw); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 255b54a6ae07..d0979bba7ed3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_nic.h: Declaration of common code for NIC. */ @@ -17,6 +17,7 @@ struct aq_ring_s; struct aq_hw_ops; struct aq_fw_s; struct aq_vec_s; +struct aq_ptp_s; struct aq_nic_cfg_s { const struct aq_hw_caps_s *aq_hw_caps; @@ -108,6 +109,8 @@ struct aq_nic_s { u32 irqvecs; /* mutex to serialize FW interface access operations */ struct mutex fwreq_mutex; + /* PTP support */ + struct aq_ptp_s *aq_ptp; struct aq_hw_rx_fltrs_s aq_hw_rx_fltrs; }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c new file mode 100644 index 000000000000..a320916cced3 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Aquantia Corporation Network Driver + * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved + */ + +/* File aq_ptp.c: + * Definition of functions for Linux PTP support. + */ + +#include +#include + +#include "aq_nic.h" +#include "aq_ptp.h" + +struct aq_ptp_s { + struct aq_nic_s *aq_nic; + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_info; +}; + +static struct ptp_clock_info aq_ptp_clock = { + .owner = THIS_MODULE, + .name = "atlantic ptp", + .n_ext_ts = 0, + .pps = 0, + .n_per_out = 0, + .n_pins = 0, + .pin_config = NULL, +}; + +int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) +{ + struct hw_atl_utils_mbox mbox; + struct aq_ptp_s *aq_ptp; + int err = 0; + + hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox); + + if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) { + aq_nic->aq_ptp = NULL; + return 0; + } + + aq_ptp = kzalloc(sizeof(*aq_ptp), GFP_KERNEL); + if (!aq_ptp) { + err = -ENOMEM; + goto err_exit; + } + + aq_ptp->aq_nic = aq_nic; + + aq_ptp->ptp_info = aq_ptp_clock; + + aq_nic->aq_ptp = aq_ptp; + + return 0; + +err_exit: + kfree(aq_ptp); + aq_nic->aq_ptp = NULL; + return err; +} + +void aq_ptp_unregister(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + ptp_clock_unregister(aq_ptp->ptp_clock); +} + +void aq_ptp_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + kfree(aq_ptp); + aq_nic->aq_ptp = NULL; +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h new file mode 100644 index 000000000000..cea238959b20 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Aquantia Corporation Network Driver + * Copyright (C) 2014-2019 Aquantia Corporation. All rights reserved + */ + +/* File aq_ptp.h: Declaration of PTP functions. + */ +#ifndef AQ_PTP_H +#define AQ_PTP_H + +#include +#include + +/* Common functions */ +int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec); + +void aq_ptp_unregister(struct aq_nic_s *aq_nic); +void aq_ptp_free(struct aq_nic_s *aq_nic); + +void aq_ptp_clock_init(struct aq_nic_s *aq_nic); + +#endif /* AQ_PTP_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 692bed70e104..7121248954df 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils.h: Declaration of common functions for Atlantic hardware @@ -168,6 +168,34 @@ struct __packed hw_atl_utils_mbox_header { u32 error; }; +struct __packed hw_aq_ptp_offset { + u16 ingress_100; + u16 egress_100; + u16 ingress_1000; + u16 egress_1000; + u16 ingress_2500; + u16 egress_2500; + u16 ingress_5000; + u16 egress_5000; + u16 ingress_10000; + u16 egress_10000; +}; + +enum gpio_pin_function { + GPIO_PIN_FUNCTION_NC, + GPIO_PIN_FUNCTION_VAUX_ENABLE, + GPIO_PIN_FUNCTION_EFUSE_BURN_ENABLE, + GPIO_PIN_FUNCTION_SFP_PLUS_DETECT, + GPIO_PIN_FUNCTION_TX_DISABLE, + GPIO_PIN_FUNCTION_RATE_SEL_0, + GPIO_PIN_FUNCTION_RATE_SEL_1, + GPIO_PIN_FUNCTION_TX_FAULT, + GPIO_PIN_FUNCTION_PTP0, + GPIO_PIN_FUNCTION_PTP1, + GPIO_PIN_FUNCTION_PTP2, + GPIO_PIN_FUNCTION_SIZE +}; + struct __packed hw_aq_info { u8 reserved[6]; u16 phy_fault_code; @@ -175,9 +203,23 @@ struct __packed hw_aq_info { u8 cable_len; u8 reserved1; u32 cable_diag_data[4]; - u8 reserved2[32]; + struct hw_aq_ptp_offset ptp_offset; + u8 reserved2[12]; u32 caps_lo; u32 caps_hi; + u32 reserved_datapath; + u32 reserved3[7]; + u32 reserved_simpleresp[3]; + u32 reserved_linkstat[7]; + u32 reserved_wakes_count; + u32 reserved_eee_stat[12]; + u32 tx_stuck_cnt; + u32 setting_address; + u32 setting_length; + u32 caps_ex; + enum gpio_pin_function gpio_pin[3]; + u32 pcie_aer_dump[18]; + u16 snr_margin[4]; }; struct __packed hw_atl_utils_mbox { @@ -372,7 +414,7 @@ enum hw_atl_fw2x_caps_hi { CAPS_HI_2P5GBASET_FD_EEE, CAPS_HI_5GBASET_FD_EEE, CAPS_HI_10GBASET_FD_EEE, - CAPS_HI_RESERVED5, + CAPS_HI_FW_REQUEST, CAPS_HI_RESERVED6, CAPS_HI_RESERVED7, CAPS_HI_RESERVED8, @@ -380,7 +422,7 @@ enum hw_atl_fw2x_caps_hi { CAPS_HI_CABLE_DIAG, CAPS_HI_TEMPERATURE, CAPS_HI_DOWNSHIFT, - CAPS_HI_PTP_AVB_EN, + CAPS_HI_PTP_AVB_EN_FW2X = 20, CAPS_HI_MEDIA_DETECT, CAPS_HI_LINK_DROP, CAPS_HI_SLEEP_PROXY, @@ -429,6 +471,41 @@ enum hw_atl_fw2x_ctrl { CTRL_FORCE_RECONNECT, }; +enum hw_atl_caps_ex { + CAPS_EX_LED_CONTROL = 0, + CAPS_EX_LED0_MODE_LO, + CAPS_EX_LED0_MODE_HI, + CAPS_EX_LED1_MODE_LO, + CAPS_EX_LED1_MODE_HI, + CAPS_EX_LED2_MODE_LO = 5, + CAPS_EX_LED2_MODE_HI, + CAPS_EX_RESERVED07, + CAPS_EX_RESERVED08, + CAPS_EX_RESERVED09, + CAPS_EX_RESERVED10 = 10, + CAPS_EX_RESERVED11, + CAPS_EX_RESERVED12, + CAPS_EX_RESERVED13, + CAPS_EX_RESERVED14, + CAPS_EX_RESERVED15 = 15, + CAPS_EX_PHY_PTP_EN, + CAPS_EX_MAC_PTP_EN, + CAPS_EX_EXT_CLK_EN, + CAPS_EX_SCHED_DMA_EN, + CAPS_EX_PTP_GPIO_EN = 20, + CAPS_EX_UPDATE_SETTINGS, + CAPS_EX_PHY_CTRL_TS_PIN, + CAPS_EX_SNR_OPERATING_MARGIN, + CAPS_EX_RESERVED24, + CAPS_EX_RESERVED25 = 25, + CAPS_EX_RESERVED26, + CAPS_EX_RESERVED27, + CAPS_EX_RESERVED28, + CAPS_EX_RESERVED29, + CAPS_EX_RESERVED30 = 30, + CAPS_EX_RESERVED31 +}; + struct aq_hw_s; struct aq_fw_ops; struct aq_hw_caps_s; -- cgit v1.2.3-59-g8ed1b From 593f7b43bd78c10f636088d3a067683e3ac376b1 Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Tue, 22 Oct 2019 09:53:25 +0000 Subject: net: aquantia: unify styling of bit enums Make some other bit-enums more clear about positioning, this helps on debugging and development Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 2 +- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 41 +++++++++++++--------- 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 52646855495e..32512539ae86 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils.c: Definition of common functions for Atlantic hardware diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 7121248954df..766e02c7fd4e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -386,38 +386,44 @@ enum hw_atl_fw2x_rate { FW2X_RATE_10G = 0x800, }; +/* 0x370 + * Link capabilities resolution register + */ enum hw_atl_fw2x_caps_lo { - CAPS_LO_10BASET_HD = 0x00, + CAPS_LO_10BASET_HD = 0, CAPS_LO_10BASET_FD, CAPS_LO_100BASETX_HD, CAPS_LO_100BASET4_HD, CAPS_LO_100BASET2_HD, - CAPS_LO_100BASETX_FD, + CAPS_LO_100BASETX_FD = 5, CAPS_LO_100BASET2_FD, CAPS_LO_1000BASET_HD, CAPS_LO_1000BASET_FD, CAPS_LO_2P5GBASET_FD, - CAPS_LO_5GBASET_FD, + CAPS_LO_5GBASET_FD = 10, CAPS_LO_10GBASET_FD, }; +/* 0x374 + * Status register + */ enum hw_atl_fw2x_caps_hi { - CAPS_HI_RESERVED1 = 0x00, + CAPS_HI_RESERVED1 = 0, CAPS_HI_10BASET_EEE, CAPS_HI_RESERVED2, CAPS_HI_PAUSE, CAPS_HI_ASYMMETRIC_PAUSE, - CAPS_HI_100BASETX_EEE, + CAPS_HI_100BASETX_EEE = 5, CAPS_HI_RESERVED3, CAPS_HI_RESERVED4, CAPS_HI_1000BASET_FD_EEE, CAPS_HI_2P5GBASET_FD_EEE, - CAPS_HI_5GBASET_FD_EEE, + CAPS_HI_5GBASET_FD_EEE = 10, CAPS_HI_10GBASET_FD_EEE, CAPS_HI_FW_REQUEST, CAPS_HI_RESERVED6, CAPS_HI_RESERVED7, - CAPS_HI_RESERVED8, + CAPS_HI_RESERVED8 = 15, CAPS_HI_RESERVED9, CAPS_HI_CABLE_DIAG, CAPS_HI_TEMPERATURE, @@ -427,47 +433,50 @@ enum hw_atl_fw2x_caps_hi { CAPS_HI_LINK_DROP, CAPS_HI_SLEEP_PROXY, CAPS_HI_WOL, - CAPS_HI_MAC_STOP, + CAPS_HI_MAC_STOP = 25, CAPS_HI_EXT_LOOPBACK, CAPS_HI_INT_LOOPBACK, CAPS_HI_EFUSE_AGENT, CAPS_HI_WOL_TIMER, - CAPS_HI_STATISTICS, + CAPS_HI_STATISTICS = 30, CAPS_HI_TRANSACTION_ID, }; +/* 0x36C + * Control register + */ enum hw_atl_fw2x_ctrl { - CTRL_RESERVED1 = 0x00, + CTRL_RESERVED1 = 0, CTRL_RESERVED2, CTRL_RESERVED3, CTRL_PAUSE, CTRL_ASYMMETRIC_PAUSE, - CTRL_RESERVED4, + CTRL_RESERVED4 = 5, CTRL_RESERVED5, CTRL_RESERVED6, CTRL_1GBASET_FD_EEE, CTRL_2P5GBASET_FD_EEE, - CTRL_5GBASET_FD_EEE, + CTRL_5GBASET_FD_EEE = 10, CTRL_10GBASET_FD_EEE, CTRL_THERMAL_SHUTDOWN, CTRL_PHY_LOGS, CTRL_EEE_AUTO_DISABLE, - CTRL_PFC, + CTRL_PFC = 15, CTRL_WAKE_ON_LINK, CTRL_CABLE_DIAG, CTRL_TEMPERATURE, CTRL_DOWNSHIFT, - CTRL_PTP_AVB, + CTRL_PTP_AVB = 20, CTRL_RESERVED7, CTRL_LINK_DROP, CTRL_SLEEP_PROXY, CTRL_WOL, - CTRL_MAC_STOP, + CTRL_MAC_STOP = 25, CTRL_EXT_LOOPBACK, CTRL_INT_LOOPBACK, CTRL_RESERVED8, CTRL_WOL_TIMER, - CTRL_STATISTICS, + CTRL_STATISTICS = 30, CTRL_FORCE_RECONNECT, }; -- cgit v1.2.3-59-g8ed1b From 910479a9f793f47b21a01564bf9f1672029cbdfe Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:27 +0000 Subject: net: aquantia: add basic ptp_clock callbacks Basic HW functions implemented for adjusting frequency, adjusting time, getting and setting time. With these callbacks we now do register ptp clock in the system. Firmware interface parts are defined for PTP requests and interactions. Enable/disable PTP counters in HW on clock register/unregister. Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Co-developed-by: Dmitry Bezrukov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 21 +++- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 3 + drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 125 +++++++++++++++++++++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 110 +++++++++++++++++- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 16 ++- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | 8 +- .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 18 ++- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 5 +- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 30 +++++ .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 97 ++++++++++++---- 10 files changed, 403 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 53d7478689a0..121e633fc25b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_hw.h: Declaration of abstract interface for NIC hardware specific @@ -15,6 +15,9 @@ #include "aq_rss.h" #include "hw_atl/hw_atl_utils.h" +#define AQ_HW_MAC_COUNTER_HZ 312500000ll +#define AQ_HW_PHY_COUNTER_HZ 160000000ll + #define AQ_RX_FIRST_LOC_FVLANID 0U #define AQ_RX_LAST_LOC_FVLANID 15U #define AQ_RX_FIRST_LOC_FETHERT 16U @@ -94,6 +97,7 @@ struct aq_stats_s { #define AQ_HW_FLAG_STOPPING 0x00000008U #define AQ_HW_FLAG_RESETTING 0x00000010U #define AQ_HW_FLAG_CLOSING 0x00000020U +#define AQ_HW_PTP_AVAILABLE 0x01000000U #define AQ_HW_LINK_DOWN 0x04000000U #define AQ_HW_FLAG_ERR_UNPLUG 0x40000000U #define AQ_HW_FLAG_ERR_HW 0x80000000U @@ -135,6 +139,7 @@ struct aq_hw_s { u32 rpc_addr; u32 rpc_tid; struct hw_atl_utils_fw_rpc rpc; + s64 ptp_clk_offset; }; struct aq_ring_s; @@ -235,6 +240,14 @@ struct aq_hw_ops { int (*hw_set_offload)(struct aq_hw_s *self, struct aq_nic_cfg_s *aq_nic_cfg); + void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp); + + int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta); + + int (*hw_adj_sys_clock)(struct aq_hw_s *self, s64 delta); + + int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts); + int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); }; @@ -267,6 +280,12 @@ struct aq_fw_ops { int (*set_power)(struct aq_hw_s *self, unsigned int power_state, u8 *mac); + int (*send_fw_request)(struct aq_hw_s *self, + const struct hw_fw_request_iface *fw_req, + size_t size); + + void (*enable_ptp)(struct aq_hw_s *self, int enable); + int (*set_eee_rate)(struct aq_hw_s *self, u32 speed); int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index d283d0bc75a3..dc9769fe762b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -146,6 +146,9 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) self->aq_hw->aq_link_status.mbps); aq_nic_update_interrupt_moderation_settings(self); + if (self->aq_ptp) + aq_ptp_clock_init(self); + /* Driver has to update flow control settings on RX block * on any link event. * We should query FW whether it negotiated FC. diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index a320916cced3..02c2a8cd1219 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -15,15 +15,108 @@ struct aq_ptp_s { struct aq_nic_s *aq_nic; + spinlock_t ptp_lock; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_info; }; +/* aq_ptp_adjfine + * @ptp: the ptp clock structure + * @ppb: parts per billion adjustment from base + * + * adjust the frequency of the ptp cycle counter by the + * indicated ppb from the base frequency. + */ +static int aq_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_hw_ops->hw_adj_clock_freq(aq_nic->aq_hw, + scaled_ppm_to_ppb(scaled_ppm)); + mutex_unlock(&aq_nic->fwreq_mutex); + + return 0; +} + +/* aq_ptp_adjtime + * @ptp: the ptp clock structure + * @delta: offset to adjust the cycle counter by + * + * adjust the timer by resetting the timecounter structure. + */ +static int aq_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, delta); + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + return 0; +} + +/* aq_ptp_gettime + * @ptp: the ptp clock structure + * @ts: timespec structure to hold the current time value + * + * read the timecounter and return the correct value on ns, + * after converting it into a struct timespec. + */ +static int aq_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + u64 ns; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &ns); + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + *ts = ns_to_timespec64(ns); + + return 0; +} + +/* aq_ptp_settime + * @ptp: the ptp clock structure + * @ts: the timespec containing the new time for the cycle counter + * + * reset the timecounter to use a new base value instead of the kernel + * wall timer value. + */ +static int aq_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + unsigned long flags; + u64 ns = timespec64_to_ns(ts); + u64 now; + + spin_lock_irqsave(&aq_ptp->ptp_lock, flags); + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &now); + aq_nic->aq_hw_ops->hw_adj_sys_clock(aq_nic->aq_hw, (s64)ns - (s64)now); + + spin_unlock_irqrestore(&aq_ptp->ptp_lock, flags); + + return 0; +} + static struct ptp_clock_info aq_ptp_clock = { .owner = THIS_MODULE, .name = "atlantic ptp", + .max_adj = 999999999, .n_ext_ts = 0, .pps = 0, + .adjfine = aq_ptp_adjfine, + .adjtime = aq_ptp_adjtime, + .gettime64 = aq_ptp_gettime, + .settime64 = aq_ptp_settime, .n_per_out = 0, .n_pins = 0, .pin_config = NULL, @@ -32,9 +125,20 @@ static struct ptp_clock_info aq_ptp_clock = { int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) { struct hw_atl_utils_mbox mbox; + struct ptp_clock *clock; struct aq_ptp_s *aq_ptp; int err = 0; + if (!aq_nic->aq_hw_ops->hw_get_ptp_ts) { + aq_nic->aq_ptp = NULL; + return 0; + } + + if (!aq_nic->aq_fw_ops->enable_ptp) { + aq_nic->aq_ptp = NULL; + return 0; + } + hw_atl_utils_mpi_read_stats(aq_nic->aq_hw, &mbox); if (!(mbox.info.caps_ex & BIT(CAPS_EX_PHY_PTP_EN))) { @@ -50,10 +154,26 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) aq_ptp->aq_nic = aq_nic; + spin_lock_init(&aq_ptp->ptp_lock); + aq_ptp->ptp_info = aq_ptp_clock; + clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev); + if (!clock || IS_ERR(clock)) { + netdev_err(aq_nic->ndev, "ptp_clock_register failed\n"); + err = PTR_ERR(clock); + goto err_exit; + } + aq_ptp->ptp_clock = clock; aq_nic->aq_ptp = aq_ptp; + /* enable ptp counter */ + aq_utils_obj_set(&aq_nic->aq_hw->flags, AQ_HW_PTP_AVAILABLE); + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 1); + aq_ptp_clock_init(aq_nic); + mutex_unlock(&aq_nic->fwreq_mutex); + return 0; err_exit: @@ -79,6 +199,11 @@ void aq_ptp_free(struct aq_nic_s *aq_nic) if (!aq_ptp) return; + /* disable ptp */ + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0); + mutex_unlock(&aq_nic->fwreq_mutex); + kfree(aq_ptp); aq_nic->aq_ptp = NULL; } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 2ad3fa6316ce..881caa8ee319 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_b0.c: Definition of Atlantic hardware specific functions. */ @@ -49,6 +49,8 @@ .mac_regs_count = 88, \ .hw_alive_check_addr = 0x10U +#define FRAC_PER_NS 0x100000000LL + const struct aq_hw_caps_s hw_atl_b0_caps_aqc100 = { DEFAULT_B0_BOARD_BASIC_CAPABILITIES, .media_type = AQ_HW_MEDIA_TYPE_FIBRE, @@ -1005,6 +1007,104 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +#define get_ptp_ts_val_u64(self, indx) \ + ((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff)) + +static void hw_atl_b0_get_ptp_ts(struct aq_hw_s *self, u64 *stamp) +{ + u64 ns; + + hw_atl_pcs_ptp_clock_read_enable(self, 1); + hw_atl_pcs_ptp_clock_read_enable(self, 0); + ns = (get_ptp_ts_val_u64(self, 0) + + (get_ptp_ts_val_u64(self, 1) << 16)) * NSEC_PER_SEC + + (get_ptp_ts_val_u64(self, 3) + + (get_ptp_ts_val_u64(self, 4) << 16)); + + *stamp = ns + self->ptp_clk_offset; +} + +static void hw_atl_b0_adj_params_get(u64 freq, s64 adj, u32 *ns, u32 *fns) +{ + /* For accuracy, the digit is extended */ + s64 base_ns = ((adj + NSEC_PER_SEC) * NSEC_PER_SEC); + u64 nsi_frac = 0; + u64 nsi; + + base_ns = div64_s64(base_ns, freq); + nsi = div64_u64(base_ns, NSEC_PER_SEC); + + if (base_ns != nsi * NSEC_PER_SEC) { + s64 divisor = div64_s64((s64)NSEC_PER_SEC * NSEC_PER_SEC, + base_ns - nsi * NSEC_PER_SEC); + nsi_frac = div64_s64(FRAC_PER_NS * NSEC_PER_SEC, divisor); + } + + *ns = (u32)nsi; + *fns = (u32)nsi_frac; +} + +static void +hw_atl_b0_mac_adj_param_calc(struct hw_fw_request_ptp_adj_freq *ptp_adj_freq, + u64 phyfreq, u64 macfreq) +{ + s64 adj_fns_val; + s64 fns_in_sec_phy = phyfreq * (ptp_adj_freq->fns_phy + + FRAC_PER_NS * ptp_adj_freq->ns_phy); + s64 fns_in_sec_mac = macfreq * (ptp_adj_freq->fns_mac + + FRAC_PER_NS * ptp_adj_freq->ns_mac); + s64 fault_in_sec_phy = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_phy; + s64 fault_in_sec_mac = FRAC_PER_NS * NSEC_PER_SEC - fns_in_sec_mac; + /* MAC MCP counter freq is macfreq / 4 */ + s64 diff_in_mcp_overflow = (fault_in_sec_mac - fault_in_sec_phy) * + 4 * FRAC_PER_NS; + + diff_in_mcp_overflow = div64_s64(diff_in_mcp_overflow, + AQ_HW_MAC_COUNTER_HZ); + adj_fns_val = (ptp_adj_freq->fns_mac + FRAC_PER_NS * + ptp_adj_freq->ns_mac) + diff_in_mcp_overflow; + + ptp_adj_freq->mac_ns_adj = div64_s64(adj_fns_val, FRAC_PER_NS); + ptp_adj_freq->mac_fns_adj = adj_fns_val - ptp_adj_freq->mac_ns_adj * + FRAC_PER_NS; +} + +static int hw_atl_b0_adj_sys_clock(struct aq_hw_s *self, s64 delta) +{ + self->ptp_clk_offset += delta; + + return 0; +} + +static int hw_atl_b0_set_sys_clock(struct aq_hw_s *self, u64 time, u64 ts) +{ + s64 delta = time - (self->ptp_clk_offset + ts); + + return hw_atl_b0_adj_sys_clock(self, delta); +} + +static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) +{ + struct hw_fw_request_iface fwreq; + size_t size; + + memset(&fwreq, 0, sizeof(fwreq)); + + fwreq.msg_id = HW_AQ_FW_REQUEST_PTP_ADJ_FREQ; + hw_atl_b0_adj_params_get(AQ_HW_MAC_COUNTER_HZ, ppb, + &fwreq.ptp_adj_freq.ns_mac, + &fwreq.ptp_adj_freq.fns_mac); + hw_atl_b0_adj_params_get(AQ_HW_PHY_COUNTER_HZ, ppb, + &fwreq.ptp_adj_freq.ns_phy, + &fwreq.ptp_adj_freq.fns_phy); + hw_atl_b0_mac_adj_param_calc(&fwreq.ptp_adj_freq, + AQ_HW_PHY_COUNTER_HZ, + AQ_HW_MAC_COUNTER_HZ); + + size = sizeof(fwreq.msg_id) + sizeof(fwreq.ptp_adj_freq); + return self->aq_fw_ops->send_fw_request(self, &fwreq, size); +} + static int hw_atl_b0_hw_fl3l4_clear(struct aq_hw_s *self, struct aq_rx_filter_l3l4 *data) { @@ -1177,6 +1277,12 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_get_regs = hw_atl_utils_hw_get_regs, .hw_get_hw_stats = hw_atl_utils_get_hw_stats, .hw_get_fw_version = hw_atl_utils_get_fw_version, - .hw_set_offload = hw_atl_b0_hw_offload_set, + + .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts, + .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock, + .hw_set_sys_clock = hw_atl_b0_set_sys_clock, + .hw_adj_clock_freq = hw_atl_b0_adj_clock_freq, + + .hw_set_offload = hw_atl_b0_hw_offload_set, .hw_set_fc = hw_atl_b0_set_fc, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 6f340695e6bd..eb982288fc52 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh.c: Definitions of bitfield and register access functions for @@ -1526,6 +1526,20 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw, glb_cpu_scratch_scp); } +void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw, + u32 ptp_clock_read_enable) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR, + HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK, + HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT, + ptp_clock_read_enable); +} + +u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_PCS_PTP_TS_VAL_ADDR(index)); +} + void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr) { aq_hw_write_reg_bit(aq_hw, HW_ATL_MCP_UP_FORCE_INTERRUPT_ADR, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index c3ee278c3747..7753ab860c95 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh.h: Declarations of bitfield and register access functions for @@ -715,6 +715,12 @@ void hw_atl_msm_reg_wr_strobe_set(struct aq_hw_s *aq_hw, u32 reg_wr_strobe); /* set pci register reset disable */ void hw_atl_pci_pci_reg_res_dis_set(struct aq_hw_s *aq_hw, u32 pci_reg_res_dis); +/* pcs */ +void hw_atl_pcs_ptp_clock_read_enable(struct aq_hw_s *aq_hw, + u32 ptp_clock_read_enable); + +u32 hw_atl_pcs_ptp_clock_get(struct aq_hw_s *aq_hw, u32 index); + /* set uP Force Interrupt */ void hw_atl_mcp_up_force_intr_set(struct aq_hw_s *aq_hw, u32 up_force_intr); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 35887ad89025..65fb74a4d5ea 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_llh_internal.h: Preprocessor definitions @@ -2440,6 +2440,22 @@ /* default value of bitfield register write strobe */ #define HW_ATL_MSM_REG_WR_STROBE_DEFAULT 0x0 +/* register address for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_ADR 0x00004628 +/* bitmask for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSK 0x00000010 +/* inverted bitmask for bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_MSKN 0xFFFFFFEF +/* lower bit position of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_SHIFT 4 +/* width of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_WIDTH 1 +/* default value of bitfield PTP Digital Clock Read Enable */ +#define HW_ATL_PCS_PTP_CLOCK_READ_ENABLE_DEFAULT 0x0 + +/* register address for ptp counter reading */ +#define HW_ATL_PCS_PTP_TS_VAL_ADDR(index) (0x00004900 + (index) * 0x4) + /* mif soft reset bitfield definitions * preprocessor definitions for the bitfield "soft reset". * port="pif_glb_res_i" diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 32512539ae86..6fc5640065bd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -327,8 +327,7 @@ err_exit: return err; } -static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, - u32 cnt) +int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt) { u32 val; int err = 0; @@ -964,4 +963,6 @@ const struct aq_fw_ops aq_fw_1x_ops = { .set_eee_rate = NULL, .get_eee_rate = NULL, .set_flow_control = NULL, + .send_fw_request = NULL, + .enable_ptp = NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 766e02c7fd4e..f2eb94f298e2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -279,6 +279,34 @@ struct __packed offload_info { u8 buf[0]; }; +/* Mailbox FW Request interface */ +struct __packed hw_fw_request_ptp_adj_freq { + u32 ns_mac; + u32 fns_mac; + u32 ns_phy; + u32 fns_phy; + u32 mac_ns_adj; + u32 mac_fns_adj; +}; + +struct __packed hw_fw_request_ptp_adj_clock { + u32 ns; + u32 sec; + int sign; +}; + +#define HW_AQ_FW_REQUEST_PTP_ADJ_FREQ 0x12 +#define HW_AQ_FW_REQUEST_PTP_ADJ_CLOCK 0x13 + +struct __packed hw_fw_request_iface { + u32 msg_id; + union { + /* PTP FW Request */ + struct hw_fw_request_ptp_adj_freq ptp_adj_freq; + struct hw_fw_request_ptp_adj_clock ptp_adj_clock; + }; +}; + enum hw_atl_rx_action_with_traffic { HW_ATL_RX_DISCARD, HW_ATL_RX_HOST, @@ -561,6 +589,8 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); +int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); + int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac); int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 7bc51f8d6f2f..f649ac949d06 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_utils_fw2x.c: Definition of firmware 2.x functions for @@ -17,14 +17,17 @@ #include "hw_atl_utils.h" #include "hw_atl_llh.h" -#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 +#define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 -#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 -#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 -#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 -#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C -#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 -#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 +#define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 +#define HW_ATL_FW2X_MPI_EFUSE_ADDR 0x364 +#define HW_ATL_FW2X_MPI_CONTROL_ADDR 0x368 +#define HW_ATL_FW2X_MPI_CONTROL2_ADDR 0x36C +#define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 +#define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 + +#define HW_ATL_FW3X_EXT_CONTROL_ADDR 0x378 +#define HW_ATL_FW3X_EXT_STATE_ADDR 0x37c #define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE) #define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE) @@ -444,6 +447,54 @@ err_exit: return err; } +static int aq_fw2x_send_fw_request(struct aq_hw_s *self, + const struct hw_fw_request_iface *fw_req, + size_t size) +{ + u32 ctrl2, orig_ctrl2; + u32 dword_cnt; + int err = 0; + u32 val; + + /* Write data to drvIface Mailbox */ + dword_cnt = size / sizeof(u32); + if (size % sizeof(u32)) + dword_cnt++; + err = hw_atl_utils_fw_upload_dwords(self, aq_fw2x_rpc_get(self), + (void *)fw_req, dword_cnt); + if (err < 0) + goto err_exit; + + /* Toggle statistics bit for FW to update */ + ctrl2 = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + orig_ctrl2 = ctrl2 & BIT(CAPS_HI_FW_REQUEST); + ctrl2 = ctrl2 ^ BIT(CAPS_HI_FW_REQUEST); + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, ctrl2); + + /* Wait FW to report back */ + err = readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, + orig_ctrl2 != (val & + BIT(CAPS_HI_FW_REQUEST)), + 1U, 10000U); + +err_exit: + return err; +} + +static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable) +{ + u32 ptp_opts = aq_hw_read_reg(self, HW_ATL_FW3X_EXT_STATE_ADDR); + u32 all_ptp_features = BIT(CAPS_EX_PHY_PTP_EN) | + BIT(CAPS_EX_PTP_GPIO_EN); + + if (enable) + ptp_opts |= all_ptp_features; + else + ptp_opts &= ~all_ptp_features; + + aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts); +} + static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) { u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -534,19 +585,21 @@ static u32 aq_fw2x_state2_get(struct aq_hw_s *self) } const struct aq_fw_ops aq_fw_2x_ops = { - .init = aq_fw2x_init, - .deinit = aq_fw2x_deinit, - .reset = NULL, - .renegotiate = aq_fw2x_renegotiate, - .get_mac_permanent = aq_fw2x_get_mac_permanent, - .set_link_speed = aq_fw2x_set_link_speed, - .set_state = aq_fw2x_set_state, + .init = aq_fw2x_init, + .deinit = aq_fw2x_deinit, + .reset = NULL, + .renegotiate = aq_fw2x_renegotiate, + .get_mac_permanent = aq_fw2x_get_mac_permanent, + .set_link_speed = aq_fw2x_set_link_speed, + .set_state = aq_fw2x_set_state, .update_link_status = aq_fw2x_update_link_status, - .update_stats = aq_fw2x_update_stats, - .get_phy_temp = aq_fw2x_get_phy_temp, - .set_power = aq_fw2x_set_power, - .set_eee_rate = aq_fw2x_set_eee_rate, - .get_eee_rate = aq_fw2x_get_eee_rate, - .set_flow_control = aq_fw2x_set_flow_control, - .get_flow_control = aq_fw2x_get_flow_control + .update_stats = aq_fw2x_update_stats, + .get_phy_temp = aq_fw2x_get_phy_temp, + .set_power = aq_fw2x_set_power, + .set_eee_rate = aq_fw2x_set_eee_rate, + .get_eee_rate = aq_fw2x_get_eee_rate, + .set_flow_control = aq_fw2x_set_flow_control, + .get_flow_control = aq_fw2x_get_flow_control, + .send_fw_request = aq_fw2x_send_fw_request, + .enable_ptp = aq_fw3x_enable_ptp, }; -- cgit v1.2.3-59-g8ed1b From 94ad94558b0fbf18dd6fb0987540af1693157556 Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:29 +0000 Subject: net: aquantia: add PTP rings infrastructure Add implementations of PTP rings alloc/free. PTP desing on this device uses two separate rings on a separate traffic class for traffic rx/tx. Third ring (hwts) is not a traffic ring, but is used only to receive timestamps of the transmitted packets. Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Co-developed-by: Dmitry Bezrukov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 4 + drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 16 ++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 235 +++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 8 + drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 26 ++- drivers/net/ethernet/aquantia/atlantic/aq_ring.h | 6 +- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 45 +++- .../aquantia/atlantic/hw_atl/hw_atl_b0_internal.h | 9 +- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 14 ++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | 6 + .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 8 + 11 files changed, 365 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 121e633fc25b..edc7d83ef5e1 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -240,6 +240,10 @@ struct aq_hw_ops { int (*hw_set_offload)(struct aq_hw_s *self, struct aq_nic_cfg_s *aq_nic_cfg); + int (*hw_tx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode); + + int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode); + void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp); int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index dc9769fe762b..ecca2c4cf140 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -339,6 +339,14 @@ int aq_nic_init(struct aq_nic_s *self) if (err < 0) goto err_exit; + err = aq_ptp_ring_alloc(self); + if (err < 0) + goto err_exit; + + err = aq_ptp_ring_init(self); + if (err < 0) + goto err_exit; + netif_carrier_off(self->ndev); err_exit: @@ -369,6 +377,10 @@ int aq_nic_start(struct aq_nic_s *self) goto err_exit; } + err = aq_ptp_ring_start(self); + if (err < 0) + goto err_exit; + err = self->aq_hw_ops->hw_start(self->aq_hw); if (err < 0) goto err_exit; @@ -965,6 +977,8 @@ int aq_nic_stop(struct aq_nic_s *self) self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_stop(aq_vec); + aq_ptp_ring_stop(self); + return self->aq_hw_ops->hw_stop(self->aq_hw); } @@ -981,6 +995,8 @@ void aq_nic_deinit(struct aq_nic_s *self) aq_vec_deinit(aq_vec); aq_ptp_unregister(self); + aq_ptp_ring_deinit(self); + aq_ptp_ring_free(self); aq_ptp_free(self); if (likely(self->aq_fw_ops->deinit)) { diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 02c2a8cd1219..f2fd0ca14a49 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -12,14 +12,55 @@ #include "aq_nic.h" #include "aq_ptp.h" +#include "aq_ring.h" + +struct ptp_skb_ring { + struct sk_buff **buff; + spinlock_t lock; + unsigned int size; + unsigned int head; + unsigned int tail; +}; struct aq_ptp_s { struct aq_nic_s *aq_nic; spinlock_t ptp_lock; + spinlock_t ptp_ring_lock; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_info; + + struct aq_ring_param_s ptp_ring_param; + + struct aq_ring_s ptp_tx; + struct aq_ring_s ptp_rx; + struct aq_ring_s hwts_rx; + + struct ptp_skb_ring skb_ring; }; +static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size) +{ + struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL); + + if (!buff) + return -ENOMEM; + + spin_lock_init(&ring->lock); + + ring->buff = buff; + ring->size = size; + ring->head = 0; + ring->tail = 0; + + return 0; +} + +static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring) +{ + kfree(ring->buff); + ring->buff = NULL; +} + /* aq_ptp_adjfine * @ptp: the ptp clock structure * @ppb: parts per billion adjustment from base @@ -107,6 +148,190 @@ static int aq_ptp_settime(struct ptp_clock_info *ptp, return 0; } +int aq_ptp_ring_init(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + err = aq_ring_init(&aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw, + &aq_ptp->ptp_tx, + &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + + err = aq_ring_init(&aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + + err = aq_ring_rx_fill(&aq_ptp->ptp_rx); + if (err < 0) + goto err_rx_free; + err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + 0U); + if (err < 0) + goto err_rx_free; + + err = aq_ring_init(&aq_ptp->hwts_rx); + if (err < 0) + goto err_rx_free; + err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw, + &aq_ptp->hwts_rx, + &aq_ptp->ptp_ring_param); + + return err; + +err_rx_free: + aq_ring_rx_deinit(&aq_ptp->ptp_rx); +err_exit: + return err; +} + +int aq_ptp_ring_start(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; + +err_exit: + return err; +} + +void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx); + aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx); + + aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx); +} + +void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp || !aq_ptp->ptp_tx.aq_nic || !aq_ptp->ptp_rx.aq_nic) + return; + + aq_ring_tx_clean(&aq_ptp->ptp_tx); + aq_ring_rx_deinit(&aq_ptp->ptp_rx); +} + +#define PTP_8TC_RING_IDX 8 +#define PTP_4TC_RING_IDX 16 +#define PTP_HWST_RING_IDX 31 + +int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + unsigned int tx_ring_idx, rx_ring_idx; + struct aq_ring_s *hwts = 0; + u32 tx_tc_mode, rx_tc_mode; + struct aq_ring_s *ring; + int err; + + if (!aq_ptp) + return 0; + + /* Index must to be 8 (8 TCs) or 16 (4 TCs). + * It depends from Traffic Class mode. + */ + aq_nic->aq_hw_ops->hw_tx_tc_mode_get(aq_nic->aq_hw, &tx_tc_mode); + if (tx_tc_mode == 0) + tx_ring_idx = PTP_8TC_RING_IDX; + else + tx_ring_idx = PTP_4TC_RING_IDX; + + ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic, + tx_ring_idx, &aq_nic->aq_nic_cfg); + if (!ring) { + err = -ENOMEM; + goto err_exit; + } + + aq_nic->aq_hw_ops->hw_rx_tc_mode_get(aq_nic->aq_hw, &rx_tc_mode); + if (rx_tc_mode == 0) + rx_ring_idx = PTP_8TC_RING_IDX; + else + rx_ring_idx = PTP_4TC_RING_IDX; + + ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic, + rx_ring_idx, &aq_nic->aq_nic_cfg); + if (!ring) { + err = -ENOMEM; + goto err_exit_ptp_tx; + } + + hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX, + aq_nic->aq_nic_cfg.rxds, + aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size); + if (!hwts) { + err = -ENOMEM; + goto err_exit_ptp_rx; + } + + err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds); + if (err != 0) { + err = -ENOMEM; + goto err_exit_hwts_rx; + } + + return 0; + +err_exit_hwts_rx: + aq_ring_free(&aq_ptp->hwts_rx); +err_exit_ptp_rx: + aq_ring_free(&aq_ptp->ptp_rx); +err_exit_ptp_tx: + aq_ring_free(&aq_ptp->ptp_tx); +err_exit: + return err; +} + +void aq_ptp_ring_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_ring_free(&aq_ptp->ptp_tx); + aq_ring_free(&aq_ptp->ptp_rx); + aq_ring_free(&aq_ptp->hwts_rx); + + aq_ptp_skb_ring_release(&aq_ptp->skb_ring); +} + static struct ptp_clock_info aq_ptp_clock = { .owner = THIS_MODULE, .name = "atlantic ptp", @@ -122,6 +347,15 @@ static struct ptp_clock_info aq_ptp_clock = { .pin_config = NULL, }; +void aq_ptp_clock_init(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct timespec64 ts; + + ktime_get_real_ts64(&ts); + aq_ptp_settime(&aq_ptp->ptp_info, &ts); +} + int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) { struct hw_atl_utils_mbox mbox; @@ -155,6 +389,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) aq_ptp->aq_nic = aq_nic; spin_lock_init(&aq_ptp->ptp_lock); + spin_lock_init(&aq_ptp->ptp_ring_lock); aq_ptp->ptp_info = aq_ptp_clock; clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index cea238959b20..32350f75e138 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -17,6 +17,14 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec); void aq_ptp_unregister(struct aq_nic_s *aq_nic); void aq_ptp_free(struct aq_nic_s *aq_nic); +int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic); +void aq_ptp_ring_free(struct aq_nic_s *aq_nic); + +int aq_ptp_ring_init(struct aq_nic_s *aq_nic); +int aq_ptp_ring_start(struct aq_nic_s *aq_nic); +void aq_ptp_ring_stop(struct aq_nic_s *aq_nic); +void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic); + void aq_ptp_clock_init(struct aq_nic_s *aq_nic); #endif /* AQ_PTP_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 76bdbe1596d6..8e84ff6eefe3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ring.c: Definition of functions for Rx/Tx rings. */ @@ -177,6 +177,30 @@ err_exit: return self; } +struct aq_ring_s * +aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic, + unsigned int idx, unsigned int size, unsigned int dx_size) +{ + struct device *dev = aq_nic_get_dev(aq_nic); + size_t sz = size * dx_size + AQ_CFG_RXDS_DEF; + + memset(self, 0, sizeof(*self)); + + self->aq_nic = aq_nic; + self->idx = idx; + self->size = size; + self->dx_size = dx_size; + + self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa, + GFP_KERNEL); + if (!self->dx_ring) { + aq_ring_free(self); + return NULL; + } + + return self; +} + int aq_ring_init(struct aq_ring_s *self) { self->hw_head = 0; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index 47abd09d06c2..068689f44bc9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ring.h: Declaration of functions for Rx/Tx rings. */ @@ -174,4 +174,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self, int budget); int aq_ring_rx_fill(struct aq_ring_s *self); +struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self, + struct aq_nic_s *aq_nic, unsigned int idx, + unsigned int size, unsigned int dx_size); + #endif /* AQ_RING_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 881caa8ee319..55c7f9985692 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -126,13 +126,16 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U); hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U); - hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, 0U); - hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, 0U); - hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, 0U); - hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, 0U); + tc = 0; + + /* TX Packet Scheduler Data TC0 */ + hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, tc); + hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, tc); + hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, tc); + hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, tc); - /* Tx buf size */ - buff_size = HW_ATL_B0_TXBUF_MAX; + /* Tx buf size TC0 */ + buff_size = HW_ATL_B0_TXBUF_MAX - HW_ATL_B0_PTP_TXBUF_SIZE; hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, buff_size, tc); hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self, @@ -143,10 +146,15 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) (buff_size * (1024 / 32U) * 50U) / 100U, tc); + /* Init TC2 for PTP_TX */ + tc = 2; + + hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_TXBUF_SIZE, + tc); /* QoS Rx buf size per TC */ tc = 0; - buff_size = HW_ATL_B0_RXBUF_MAX; + buff_size = HW_ATL_B0_RXBUF_MAX - HW_ATL_B0_PTP_RXBUF_SIZE; hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self, @@ -160,6 +168,14 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc); + /* Init TC2 for PTP_RX */ + tc = 2; + + hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, HW_ATL_B0_PTP_RXBUF_SIZE, + tc); + /* No flow control for PTP */ + hw_atl_rpb_rx_xoff_en_per_tc_set(self, 0U, tc); + /* QoS 802.1p priority -> TC mapping */ for (i_priority = 8U; i_priority--;) hw_atl_rpf_rpb_user_priority_tc_map_set(self, i_priority, 0U); @@ -1007,6 +1023,18 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +static int hw_atl_b0_tx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode) +{ + *tc_mode = hw_atl_rpb_tps_tx_tc_mode_get(self); + return aq_hw_err_from_flags(self); +} + +static int hw_atl_b0_rx_tc_mode_get(struct aq_hw_s *self, u32 *tc_mode) +{ + *tc_mode = hw_atl_rpb_rpf_rx_traf_class_mode_get(self); + return aq_hw_err_from_flags(self); +} + #define get_ptp_ts_val_u64(self, indx) \ ((u64)(hw_atl_pcs_ptp_clock_get(self, indx) & 0xffff)) @@ -1278,6 +1306,9 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_get_hw_stats = hw_atl_utils_get_hw_stats, .hw_get_fw_version = hw_atl_utils_get_fw_version, + .hw_tx_tc_mode_get = hw_atl_b0_tx_tc_mode_get, + .hw_rx_tc_mode_get = hw_atl_b0_rx_tc_mode_get, + .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts, .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock, .hw_set_sys_clock = hw_atl_b0_set_sys_clock, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h index 808d8cd4252a..7ab23a1751d3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File hw_atl_b0_internal.h: Definition of Atlantic B0 chip specific @@ -64,8 +64,11 @@ #define HW_ATL_B0_MPI_SPEED_MSK 0xFFFFU #define HW_ATL_B0_MPI_SPEED_SHIFT 16U -#define HW_ATL_B0_TXBUF_MAX 160U -#define HW_ATL_B0_RXBUF_MAX 320U +#define HW_ATL_B0_TXBUF_MAX 160U +#define HW_ATL_B0_PTP_TXBUF_SIZE 8U + +#define HW_ATL_B0_RXBUF_MAX 320U +#define HW_ATL_B0_PTP_RXBUF_SIZE 16U #define HW_ATL_B0_RSS_REDIRECTION_MAX 64U #define HW_ATL_B0_RSS_REDIRECTION_BITS 3U diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index eb982288fc52..368b5caf3c49 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -572,6 +572,13 @@ void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, rx_traf_class_mode); } +u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_RPB_RPF_RX_TC_MODE_ADR, + HW_ATL_RPB_RPF_RX_TC_MODE_MSK, + HW_ATL_RPB_RPF_RX_TC_MODE_SHIFT); +} + void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en) { aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_RX_BUF_EN_ADR, @@ -1290,6 +1297,13 @@ void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en) HW_ATL_TPB_TX_BUF_EN_SHIFT, tx_buff_en); } +u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_TPB_TX_TC_MODE_ADDR, + HW_ATL_TPB_TX_TC_MODE_MSK, + HW_ATL_TPB_TX_TC_MODE_SHIFT); +} + void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw, u32 tx_traf_class_mode) { diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 7753ab860c95..a579864b6ba1 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -292,6 +292,9 @@ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk); void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, u32 rx_traf_class_mode); +/* get rx traffic class mode */ +u32 hw_atl_rpb_rpf_rx_traf_class_mode_get(struct aq_hw_s *aq_hw); + /* set rx buffer enable */ void hw_atl_rpb_rx_buff_en_set(struct aq_hw_s *aq_hw, u32 rx_buff_en); @@ -605,6 +608,9 @@ void hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(struct aq_hw_s *aq_hw, void hw_atl_rpb_tps_tx_tc_mode_set(struct aq_hw_s *aq_hw, u32 tx_traf_class_mode); +/* get TX Traffic Class Mode */ +u32 hw_atl_rpb_tps_tx_tc_mode_get(struct aq_hw_s *aq_hw); + /* set tx buffer enable */ void hw_atl_tpb_tx_buff_en_set(struct aq_hw_s *aq_hw, u32 tx_buff_en); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index f2eb94f298e2..77132bda4696 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -44,6 +44,14 @@ struct __packed hw_atl_rxd_wb_s { u16 vlan; }; +/* Hardware rx HW TIMESTAMP writeback */ +struct __packed hw_atl_rxd_hwts_wb_s { + u32 sec_hw; + u32 ns; + u32 sec_lw0; + u32 sec_lw1; +}; + struct __packed hw_atl_stats_s { u32 uprc; u32 mprc; -- cgit v1.2.3-59-g8ed1b From 61cc502ef428d104f4c35baa3ea099ae80318275 Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Tue, 22 Oct 2019 09:53:32 +0000 Subject: net: aquantia: styling fixes on ptp related functions Checkpatch and styling fixes on parts of code touched by ptp Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 4 ++-- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 368b5caf3c49..d83f1a34a537 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -643,8 +643,8 @@ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, rx_pkt_buff_size_per_tc); } -void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, - u32 buffer) +void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, + u32 rx_xoff_en_per_tc, u32 buffer) { aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_RXBXOFF_EN_ADR(buffer), HW_ATL_RPB_RXBXOFF_EN_MSK, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index a579864b6ba1..b192702a7b8b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -309,7 +309,8 @@ void hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw, u32 buffer); /* set rx flow control mode */ -void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, u32 rx_flow_ctl_mode); +void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, + u32 rx_flow_ctl_mode); /* set rx packet buffer size (per tc) */ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, @@ -323,7 +324,8 @@ void hw_atl_rdm_rx_dma_desc_cache_init_tgl(struct aq_hw_s *aq_hw); u32 hw_atl_rdm_rx_dma_desc_cache_init_done_get(struct aq_hw_s *aq_hw); /* set rx xoff enable (per tc) */ -void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, +void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, + u32 rx_xoff_en_per_tc, u32 buffer); /* rpf */ @@ -629,7 +631,8 @@ void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_ /* set tx packet buffer size (per tc) */ void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, - u32 tx_pkt_buff_size_per_tc, u32 buffer); + u32 tx_pkt_buff_size_per_tc, + u32 buffer); /* set tx path pad insert enable */ void hw_atl_tpb_tx_path_scp_ins_en_set(struct aq_hw_s *aq_hw, u32 tx_path_scp_ins_en); -- cgit v1.2.3-59-g8ed1b From 04a1839950d92ab6519479bc95710e89ae6cbc77 Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:35 +0000 Subject: net: aquantia: implement data PTP datapath Here we do alloc/free IRQs for PTP rings. We also implement processing of PTP packets on TX and RX sides. Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Co-developed-by: Dmitry Bezrukov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 4 +- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 12 + drivers/net/ethernet/aquantia/atlantic/aq_main.c | 23 +- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 18 +- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 3 + .../net/ethernet/aquantia/atlantic/aq_pci_func.c | 5 +- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 534 ++++++++++++++++++++- drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 19 + drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 31 +- drivers/net/ethernet/aquantia/atlantic/aq_ring.h | 1 + .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 100 ++++ 11 files changed, 738 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 02f1b70c4e25..8c633caf79d2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_cfg.h: Definition of configuration parameters and constants. */ @@ -27,7 +27,7 @@ #define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2) -#define AQ_CFG_IRQ_MASK 0x1FFU +#define AQ_CFG_IRQ_MASK 0x3FFU #define AQ_CFG_VECS_MAX 8U #define AQ_CFG_TCS_MAX 8U diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index edc7d83ef5e1..5b0f42818033 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -244,6 +244,12 @@ struct aq_hw_ops { int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode); + int (*hw_ring_hwts_rx_fill)(struct aq_hw_s *self, + struct aq_ring_s *aq_ring); + + int (*hw_ring_hwts_rx_receive)(struct aq_hw_s *self, + struct aq_ring_s *ring); + void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp); int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta); @@ -252,6 +258,12 @@ struct aq_hw_ops { int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts); + u16 (*rx_extract_ts)(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp); + + int (*extract_hwts)(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp); + int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index bb65dd39f847..f630032af8e1 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_main.c: Main file for aQuantia Linux driver. */ @@ -10,10 +10,13 @@ #include "aq_nic.h" #include "aq_pci_func.h" #include "aq_ethtool.h" +#include "aq_ptp.h" #include "aq_filters.h" #include #include +#include +#include MODULE_LICENSE("GPL v2"); MODULE_VERSION(AQ_CFG_DRV_VERSION); @@ -93,6 +96,24 @@ static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); + if (unlikely(aq_utils_obj_test(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP))) { + /* Hardware adds the Timestamp for PTPv2 802.AS1 + * and PTPv2 IPv4 UDP. + * We have to push even general 320 port messages to the ptp + * queue explicitly. This is a limitation of current firmware + * and hardware PTP design of the chip. Otherwise ptp stream + * will fail to sync + */ + if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) || + unlikely((ip_hdr(skb)->version == 4) && + (ip_hdr(skb)->protocol == IPPROTO_UDP) && + ((udp_hdr(skb)->dest == htons(319)) || + (udp_hdr(skb)->dest == htons(320)))) || + unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588))) + return aq_ptp_xmit(aq_nic, skb); + } + + skb_tx_timestamp(skb); return aq_nic_xmit(aq_nic, skb); } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index ecca2c4cf140..65384f45805f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -146,8 +146,11 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) self->aq_hw->aq_link_status.mbps); aq_nic_update_interrupt_moderation_settings(self); - if (self->aq_ptp) + if (self->aq_ptp) { aq_ptp_clock_init(self); + aq_ptp_tm_offset_set(self, + self->aq_hw->aq_link_status.mbps); + } /* Driver has to update flow control settings on RX block * on any link event. @@ -196,6 +199,8 @@ static void aq_nic_service_task(struct work_struct *work) service_task); int err; + aq_ptp_service_task(self); + if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY)) return; @@ -408,6 +413,10 @@ int aq_nic_start(struct aq_nic_s *self) goto err_exit; } + err = aq_ptp_irq_alloc(self); + if (err < 0) + goto err_exit; + if (self->aq_nic_cfg.link_irq_vec) { int irqvec = pci_irq_vector(self->pdev, self->aq_nic_cfg.link_irq_vec); @@ -440,9 +449,8 @@ err_exit: return err; } -static unsigned int aq_nic_map_skb(struct aq_nic_s *self, - struct sk_buff *skb, - struct aq_ring_s *ring) +unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, + struct aq_ring_s *ring) { unsigned int ret = 0U; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; @@ -973,6 +981,8 @@ int aq_nic_stop(struct aq_nic_s *self) else aq_pci_func_free_irqs(self); + aq_ptp_irq_free(self); + for (i = 0U, aq_vec = self->aq_vec[0]; self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_stop(aq_vec); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index d0979bba7ed3..576432adda4c 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -54,6 +54,7 @@ struct aq_nic_cfg_s { #define AQ_NIC_FLAG_STOPPING 0x00000008U #define AQ_NIC_FLAG_RESETTING 0x00000010U #define AQ_NIC_FLAG_CLOSING 0x00000020U +#define AQ_NIC_PTP_DPATH_UP 0x02000000U #define AQ_NIC_LINK_DOWN 0x04000000U #define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U #define AQ_NIC_FLAG_ERR_HW 0x80000000U @@ -129,6 +130,8 @@ void aq_nic_cfg_start(struct aq_nic_s *self); int aq_nic_ndev_register(struct aq_nic_s *self); void aq_nic_ndev_free(struct aq_nic_s *self); int aq_nic_start(struct aq_nic_s *self); +unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, + struct aq_ring_s *ring); int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb); int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p); int aq_nic_get_regs_count(struct aq_nic_s *self); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 74b9f3f1da81..e82c96b50373 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_pci_func.c: Definition of PCI functions. */ @@ -269,6 +269,9 @@ static int aq_pci_probe(struct pci_dev *pdev, numvecs = min((u8)AQ_CFG_VECS_DEF, aq_nic_get_cfg(self)->aq_hw_caps->msix_irqs); numvecs = min(numvecs, num_online_cpus()); + /* Request IRQ vector for PTP */ + numvecs += 1; + numvecs += AQ_HW_SERVICE_IRQS; /*enable interrupts */ #if !AQ_CFG_FORCE_LEGACY_INT diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index f2fd0ca14a49..fbb1912a34d7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -8,12 +8,24 @@ */ #include +#include #include #include "aq_nic.h" #include "aq_ptp.h" #include "aq_ring.h" +#define AQ_PTP_TX_TIMEOUT (HZ * 10) + +enum ptp_speed_offsets { + ptp_offset_idx_10 = 0, + ptp_offset_idx_100, + ptp_offset_idx_1000, + ptp_offset_idx_2500, + ptp_offset_idx_5000, + ptp_offset_idx_10000, +}; + struct ptp_skb_ring { struct sk_buff **buff; spinlock_t lock; @@ -22,6 +34,12 @@ struct ptp_skb_ring { unsigned int tail; }; +struct ptp_tx_timeout { + spinlock_t lock; + bool active; + unsigned long tx_start; +}; + struct aq_ptp_s { struct aq_nic_s *aq_nic; spinlock_t ptp_lock; @@ -29,8 +47,16 @@ struct aq_ptp_s { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_info; + atomic_t offset_egress; + atomic_t offset_ingress; + struct aq_ring_param_s ptp_ring_param; + struct ptp_tx_timeout ptp_tx_timeout; + + unsigned int idx_vector; + struct napi_struct napi; + struct aq_ring_s ptp_tx; struct aq_ring_s ptp_rx; struct aq_ring_s hwts_rx; @@ -38,6 +64,101 @@ struct aq_ptp_s { struct ptp_skb_ring skb_ring; }; +struct ptp_tm_offset { + unsigned int mbps; + int egress; + int ingress; +}; + +static struct ptp_tm_offset ptp_offset[6]; + +void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int i, egress, ingress; + + if (!aq_ptp) + return; + + egress = 0; + ingress = 0; + + for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) { + if (mbps == ptp_offset[i].mbps) { + egress = ptp_offset[i].egress; + ingress = ptp_offset[i].ingress; + break; + } + } + + atomic_set(&aq_ptp->offset_egress, egress); + atomic_set(&aq_ptp->offset_ingress, ingress); +} + +static int __aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb) +{ + unsigned int next_head = (ring->head + 1) % ring->size; + + if (next_head == ring->tail) + return -ENOMEM; + + ring->buff[ring->head] = skb_get(skb); + ring->head = next_head; + + return 0; +} + +static int aq_ptp_skb_put(struct ptp_skb_ring *ring, struct sk_buff *skb) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&ring->lock, flags); + ret = __aq_ptp_skb_put(ring, skb); + spin_unlock_irqrestore(&ring->lock, flags); + + return ret; +} + +static struct sk_buff *__aq_ptp_skb_get(struct ptp_skb_ring *ring) +{ + struct sk_buff *skb; + + if (ring->tail == ring->head) + return NULL; + + skb = ring->buff[ring->tail]; + ring->tail = (ring->tail + 1) % ring->size; + + return skb; +} + +static struct sk_buff *aq_ptp_skb_get(struct ptp_skb_ring *ring) +{ + unsigned long flags; + struct sk_buff *skb; + + spin_lock_irqsave(&ring->lock, flags); + skb = __aq_ptp_skb_get(ring); + spin_unlock_irqrestore(&ring->lock, flags); + + return skb; +} + +static unsigned int aq_ptp_skb_buf_len(struct ptp_skb_ring *ring) +{ + unsigned long flags; + unsigned int len; + + spin_lock_irqsave(&ring->lock, flags); + len = (ring->head >= ring->tail) ? + ring->head - ring->tail : + ring->size - ring->tail + ring->head; + spin_unlock_irqrestore(&ring->lock, flags); + + return len; +} + static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size) { struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL); @@ -55,10 +176,75 @@ static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size) return 0; } +static void aq_ptp_skb_ring_clean(struct ptp_skb_ring *ring) +{ + struct sk_buff *skb; + + while ((skb = aq_ptp_skb_get(ring)) != NULL) + dev_kfree_skb_any(skb); +} + static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring) { - kfree(ring->buff); - ring->buff = NULL; + if (ring->buff) { + aq_ptp_skb_ring_clean(ring); + kfree(ring->buff); + ring->buff = NULL; + } +} + +static void aq_ptp_tx_timeout_init(struct ptp_tx_timeout *timeout) +{ + spin_lock_init(&timeout->lock); + timeout->active = false; +} + +static void aq_ptp_tx_timeout_start(struct aq_ptp_s *aq_ptp) +{ + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + + spin_lock_irqsave(&timeout->lock, flags); + timeout->active = true; + timeout->tx_start = jiffies; + spin_unlock_irqrestore(&timeout->lock, flags); +} + +static void aq_ptp_tx_timeout_update(struct aq_ptp_s *aq_ptp) +{ + if (!aq_ptp_skb_buf_len(&aq_ptp->skb_ring)) { + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + + spin_lock_irqsave(&timeout->lock, flags); + timeout->active = false; + spin_unlock_irqrestore(&timeout->lock, flags); + } +} + +static void aq_ptp_tx_timeout_check(struct aq_ptp_s *aq_ptp) +{ + struct ptp_tx_timeout *timeout = &aq_ptp->ptp_tx_timeout; + unsigned long flags; + bool timeout_flag; + + timeout_flag = false; + + spin_lock_irqsave(&timeout->lock, flags); + if (timeout->active) { + timeout_flag = time_is_before_jiffies(timeout->tx_start + + AQ_PTP_TX_TIMEOUT); + /* reset active flag if timeout detected */ + if (timeout_flag) + timeout->active = false; + } + spin_unlock_irqrestore(&timeout->lock, flags); + + if (timeout_flag) { + aq_ptp_skb_ring_clean(&aq_ptp->skb_ring); + netdev_err(aq_ptp->aq_nic->ndev, + "PTP Timeout. Clearing Tx Timestamp SKBs\n"); + } } /* aq_ptp_adjfine @@ -148,6 +334,263 @@ static int aq_ptp_settime(struct ptp_clock_info *ptp, return 0; } +static void aq_ptp_convert_to_hwtstamp(struct aq_ptp_s *aq_ptp, + struct skb_shared_hwtstamps *hwtstamp, + u64 timestamp) +{ + memset(hwtstamp, 0, sizeof(*hwtstamp)); + hwtstamp->hwtstamp = ns_to_ktime(timestamp); +} + +/* aq_ptp_tx_hwtstamp - utility function which checks for TX time stamp + * @adapter: the private adapter struct + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the hwtstamps structure which + * is passed up the network stack + */ +void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct sk_buff *skb = aq_ptp_skb_get(&aq_ptp->skb_ring); + struct skb_shared_hwtstamps hwtstamp; + + if (!skb) { + netdev_err(aq_nic->ndev, "have timestamp but tx_queus empty\n"); + return; + } + + timestamp += atomic_read(&aq_ptp->offset_egress); + aq_ptp_convert_to_hwtstamp(aq_ptp, &hwtstamp, timestamp); + skb_tstamp_tx(skb, &hwtstamp); + dev_kfree_skb_any(skb); + + aq_ptp_tx_timeout_update(aq_ptp); +} + +/* aq_ptp_rx_hwtstamp - utility function which checks for RX time stamp + * @adapter: pointer to adapter struct + * @skb: particular skb to send timestamp with + * + * if the timestamp is valid, we convert it into the timecounter ns + * value, then store that result into the hwtstamps structure which + * is passed up the network stack + */ +static void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct sk_buff *skb, + u64 timestamp) +{ + timestamp -= atomic_read(&aq_ptp->offset_ingress); + aq_ptp_convert_to_hwtstamp(aq_ptp, skb_hwtstamps(skb), timestamp); +} + +bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return false; + + return &aq_ptp->ptp_tx == ring || + &aq_ptp->ptp_rx == ring || &aq_ptp->hwts_rx == ring; +} + +u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p, + unsigned int len) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + u64 timestamp = 0; + u16 ret = aq_nic->aq_hw_ops->rx_extract_ts(aq_nic->aq_hw, + p, len, ×tamp); + + if (ret > 0) + aq_ptp_rx_hwtstamp(aq_ptp, skb, timestamp); + + return ret; +} + +static int aq_ptp_poll(struct napi_struct *napi, int budget) +{ + struct aq_ptp_s *aq_ptp = container_of(napi, struct aq_ptp_s, napi); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + bool was_cleaned = false; + int work_done = 0; + int err; + + /* Processing PTP TX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_tx_head_update(aq_nic->aq_hw, + &aq_ptp->ptp_tx); + if (err < 0) + goto err_exit; + + if (aq_ptp->ptp_tx.sw_head != aq_ptp->ptp_tx.hw_head) { + aq_ring_tx_clean(&aq_ptp->ptp_tx); + + was_cleaned = true; + } + + /* Processing HW_TIMESTAMP RX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_receive(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; + + if (aq_ptp->hwts_rx.sw_head != aq_ptp->hwts_rx.hw_head) { + aq_ring_hwts_rx_clean(&aq_ptp->hwts_rx, aq_nic); + + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + + was_cleaned = true; + } + + /* Processing PTP RX traffic */ + err = aq_nic->aq_hw_ops->hw_ring_rx_receive(aq_nic->aq_hw, + &aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + if (aq_ptp->ptp_rx.sw_head != aq_ptp->ptp_rx.hw_head) { + unsigned int sw_tail_old; + + err = aq_ring_rx_clean(&aq_ptp->ptp_rx, napi, &work_done, budget); + if (err < 0) + goto err_exit; + + sw_tail_old = aq_ptp->ptp_rx.sw_tail; + err = aq_ring_rx_fill(&aq_ptp->ptp_rx); + if (err < 0) + goto err_exit; + + err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw, + &aq_ptp->ptp_rx, + sw_tail_old); + if (err < 0) + goto err_exit; + } + + if (was_cleaned) + work_done = budget; + + if (work_done < budget) { + napi_complete_done(napi, work_done); + aq_nic->aq_hw_ops->hw_irq_enable(aq_nic->aq_hw, + 1 << aq_ptp->ptp_ring_param.vec_idx); + } + +err_exit: + return work_done; +} + +static irqreturn_t aq_ptp_isr(int irq, void *private) +{ + struct aq_ptp_s *aq_ptp = private; + int err = 0; + + if (!aq_ptp) { + err = -EINVAL; + goto err_exit; + } + napi_schedule(&aq_ptp->napi); + +err_exit: + return err >= 0 ? IRQ_HANDLED : IRQ_NONE; +} + +int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct aq_ring_s *ring = &aq_ptp->ptp_tx; + unsigned long irq_flags; + int err = NETDEV_TX_OK; + unsigned int frags; + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + goto err_exit; + } + + frags = skb_shinfo(skb)->nr_frags + 1; + /* Frags cannot be bigger 16KB + * because PTP usually works + * without Jumbo even in a background + */ + if (frags > AQ_CFG_SKB_FRAGS_MAX || frags > aq_ring_avail_dx(ring)) { + /* Drop packet because it doesn't make sence to delay it */ + dev_kfree_skb_any(skb); + goto err_exit; + } + + err = aq_ptp_skb_put(&aq_ptp->skb_ring, skb); + if (err) { + netdev_err(aq_nic->ndev, "SKB Ring is overflow (%u)!\n", + ring->size); + return NETDEV_TX_BUSY; + } + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + aq_ptp_tx_timeout_start(aq_ptp); + skb_tx_timestamp(skb); + + spin_lock_irqsave(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags); + frags = aq_nic_map_skb(aq_nic, skb, ring); + + if (likely(frags)) { + err = aq_nic->aq_hw_ops->hw_ring_tx_xmit(aq_nic->aq_hw, + ring, frags); + if (err >= 0) { + ++ring->stats.tx.packets; + ring->stats.tx.bytes += skb->len; + } + } else { + err = NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&aq_nic->aq_ptp->ptp_ring_lock, irq_flags); + +err_exit: + return err; +} + +void aq_ptp_service_task(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return; + + aq_ptp_tx_timeout_check(aq_ptp); +} + +int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic) +{ + struct pci_dev *pdev = aq_nic->pdev; + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + int err = 0; + + if (!aq_ptp) + return 0; + + if (pdev->msix_enabled || pdev->msi_enabled) { + err = request_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), + aq_ptp_isr, 0, aq_nic->ndev->name, aq_ptp); + } else { + err = -EINVAL; + goto err_exit; + } + +err_exit: + return err; +} + +void aq_ptp_irq_free(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + struct pci_dev *pdev = aq_nic->pdev; + + if (!aq_ptp) + return; + + free_irq(pci_irq_vector(pdev, aq_ptp->idx_vector), aq_ptp); +} + int aq_ptp_ring_init(struct aq_nic_s *aq_nic) { struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; @@ -189,6 +632,12 @@ int aq_ptp_ring_init(struct aq_nic_s *aq_nic) err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw, &aq_ptp->hwts_rx, &aq_ptp->ptp_ring_param); + if (err < 0) + goto err_exit; + err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw, + &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; return err; @@ -219,6 +668,8 @@ int aq_ptp_ring_start(struct aq_nic_s *aq_nic) if (err < 0) goto err_exit; + napi_enable(&aq_ptp->napi); + err_exit: return err; } @@ -234,6 +685,8 @@ void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx); aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx); + + napi_disable(&aq_ptp->napi); } void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) @@ -306,6 +759,12 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) goto err_exit_hwts_rx; } + aq_ptp->ptp_ring_param.vec_idx = aq_ptp->idx_vector; + aq_ptp->ptp_ring_param.cpu = aq_ptp->ptp_ring_param.vec_idx + + aq_nic_get_cfg(aq_nic)->aq_rss.base_cpu_number; + cpumask_set_cpu(aq_ptp->ptp_ring_param.cpu, + &aq_ptp->ptp_ring_param.affinity_mask); + return 0; err_exit_hwts_rx: @@ -347,6 +806,60 @@ static struct ptp_clock_info aq_ptp_clock = { .pin_config = NULL, }; +#define ptp_offset_init(__idx, __mbps, __egress, __ingress) do { \ + ptp_offset[__idx].mbps = (__mbps); \ + ptp_offset[__idx].egress = (__egress); \ + ptp_offset[__idx].ingress = (__ingress); } \ + while (0) + +static void aq_ptp_offset_init_from_fw(const struct hw_aq_ptp_offset *offsets) +{ + int i; + + /* Load offsets for PTP */ + for (i = 0; i < ARRAY_SIZE(ptp_offset); i++) { + switch (i) { + /* 100M */ + case ptp_offset_idx_100: + ptp_offset_init(i, 100, + offsets->egress_100, + offsets->ingress_100); + break; + /* 1G */ + case ptp_offset_idx_1000: + ptp_offset_init(i, 1000, + offsets->egress_1000, + offsets->ingress_1000); + break; + /* 2.5G */ + case ptp_offset_idx_2500: + ptp_offset_init(i, 2500, + offsets->egress_2500, + offsets->ingress_2500); + break; + /* 5G */ + case ptp_offset_idx_5000: + ptp_offset_init(i, 5000, + offsets->egress_5000, + offsets->ingress_5000); + break; + /* 10G */ + case ptp_offset_idx_10000: + ptp_offset_init(i, 10000, + offsets->egress_10000, + offsets->ingress_10000); + break; + } + } +} + +static void aq_ptp_offset_init(const struct hw_aq_ptp_offset *offsets) +{ + memset(ptp_offset, 0, sizeof(ptp_offset)); + + aq_ptp_offset_init_from_fw(offsets); +} + void aq_ptp_clock_init(struct aq_nic_s *aq_nic) { struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; @@ -380,6 +893,8 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) return 0; } + aq_ptp_offset_init(&mbox.info.ptp_offset); + aq_ptp = kzalloc(sizeof(*aq_ptp), GFP_KERNEL); if (!aq_ptp) { err = -ENOMEM; @@ -399,6 +914,15 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) goto err_exit; } aq_ptp->ptp_clock = clock; + aq_ptp_tx_timeout_init(&aq_ptp->ptp_tx_timeout); + + atomic_set(&aq_ptp->offset_egress, 0); + atomic_set(&aq_ptp->offset_ingress, 0); + + netif_napi_add(aq_nic_get_ndev(aq_nic), &aq_ptp->napi, + aq_ptp_poll, AQ_CFG_NAPI_WEIGHT); + + aq_ptp->idx_vector = idx_vec; aq_nic->aq_ptp = aq_ptp; @@ -439,6 +963,12 @@ void aq_ptp_free(struct aq_nic_s *aq_nic) aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0); mutex_unlock(&aq_nic->fwreq_mutex); + netif_napi_del(&aq_ptp->napi); kfree(aq_ptp); aq_nic->aq_ptp = NULL; } + +struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) +{ + return aq_ptp->ptp_clock; +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index 32350f75e138..2c84483fcac1 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -17,6 +17,9 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec); void aq_ptp_unregister(struct aq_nic_s *aq_nic); void aq_ptp_free(struct aq_nic_s *aq_nic); +int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic); +void aq_ptp_irq_free(struct aq_nic_s *aq_nic); + int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic); void aq_ptp_ring_free(struct aq_nic_s *aq_nic); @@ -25,6 +28,22 @@ int aq_ptp_ring_start(struct aq_nic_s *aq_nic); void aq_ptp_ring_stop(struct aq_nic_s *aq_nic); void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic); +void aq_ptp_service_task(struct aq_nic_s *aq_nic); + +void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, unsigned int mbps); + void aq_ptp_clock_init(struct aq_nic_s *aq_nic); +/* Traffic processing functions */ +int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb); +void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp); + +/* Return either ring is belong to PTP or not*/ +bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring); + +u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p, + unsigned int len); + +struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp); + #endif /* AQ_PTP_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 8e84ff6eefe3..f756cc0bbdf0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -10,6 +10,7 @@ #include "aq_nic.h" #include "aq_hw.h" #include "aq_hw_utils.h" +#include "aq_ptp.h" #include #include @@ -314,6 +315,7 @@ int aq_ring_rx_clean(struct aq_ring_s *self, self->sw_head = aq_ring_next_dx(self, self->sw_head), --budget, ++(*work_done)) { struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head]; + bool is_ptp_ring = aq_ptp_ring(self->aq_nic, self); struct aq_ring_buff_s *buff_ = NULL; struct sk_buff *skb = NULL; unsigned int next_ = 0U; @@ -378,6 +380,11 @@ int aq_ring_rx_clean(struct aq_ring_s *self, err = -ENOMEM; goto err_exit; } + if (is_ptp_ring) + buff->len -= + aq_ptp_extract_ts(self->aq_nic, skb, + aq_buf_vaddr(&buff->rxdata), + buff->len); skb_put(skb, buff->len); page_ref_inc(buff->rxdata.page); } else { @@ -386,6 +393,11 @@ int aq_ring_rx_clean(struct aq_ring_s *self, err = -ENOMEM; goto err_exit; } + if (is_ptp_ring) + buff->len -= + aq_ptp_extract_ts(self->aq_nic, skb, + aq_buf_vaddr(&buff->rxdata), + buff->len); hdr_len = buff->len; if (hdr_len > AQ_CFG_RX_HDR_SIZE) @@ -445,8 +457,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self, skb_set_hash(skb, buff->rss_hash, buff->is_hash_l4 ? PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_NONE); - - skb_record_rx_queue(skb, self->idx); + /* Send all PTP traffic to 0 queue */ + skb_record_rx_queue(skb, is_ptp_ring ? 0 : self->idx); ++self->stats.rx.packets; self->stats.rx.bytes += skb->len; @@ -458,6 +470,21 @@ err_exit: return err; } +void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic) +{ + while (self->sw_head != self->hw_head) { + u64 ns; + + aq_nic->aq_hw_ops->extract_hwts(aq_nic->aq_hw, + self->dx_ring + + (self->sw_head * self->dx_size), + self->dx_size, &ns); + aq_ptp_tx_hwtstamp(aq_nic, ns); + + self->sw_head = aq_ring_next_dx(self, self->sw_head); + } +} + int aq_ring_rx_fill(struct aq_ring_s *self) { unsigned int page_order = self->page_order; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index 068689f44bc9..be3702a4dcc9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -177,5 +177,6 @@ int aq_ring_rx_fill(struct aq_ring_s *self); struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic, unsigned int idx, unsigned int size, unsigned int dx_size); +void aq_ring_hwts_rx_clean(struct aq_ring_s *self, struct aq_nic_s *aq_nic); #endif /* AQ_RING_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 55c7f9985692..bd9e5a598657 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -682,6 +682,46 @@ static int hw_atl_b0_hw_ring_rx_fill(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +static int hw_atl_b0_hw_ring_hwts_rx_fill(struct aq_hw_s *self, + struct aq_ring_s *ring) +{ + unsigned int i; + + for (i = aq_ring_avail_dx(ring); i--; + ring->sw_tail = aq_ring_next_dx(ring, ring->sw_tail)) { + struct hw_atl_rxd_s *rxd = + (struct hw_atl_rxd_s *) + &ring->dx_ring[ring->sw_tail * HW_ATL_B0_RXD_SIZE]; + + rxd->buf_addr = ring->dx_ring_pa + ring->size * ring->dx_size; + rxd->hdr_addr = 0U; + } + /* Make sure descriptors are updated before bump tail*/ + wmb(); + + hw_atl_reg_rx_dma_desc_tail_ptr_set(self, ring->sw_tail, ring->idx); + + return aq_hw_err_from_flags(self); +} + +static int hw_atl_b0_hw_ring_hwts_rx_receive(struct aq_hw_s *self, + struct aq_ring_s *ring) +{ + while (ring->hw_head != ring->sw_tail) { + struct hw_atl_rxd_hwts_wb_s *hwts_wb = + (struct hw_atl_rxd_hwts_wb_s *) + (ring->dx_ring + (ring->hw_head * HW_ATL_B0_RXD_SIZE)); + + /* RxD is not done */ + if (!(hwts_wb->sec_lw0 & 0x1U)) + break; + + ring->hw_head = aq_ring_next_dx(ring, ring->hw_head); + } + + return aq_hw_err_from_flags(self); +} + static int hw_atl_b0_hw_ring_tx_head_update(struct aq_hw_s *self, struct aq_ring_s *ring) { @@ -1133,6 +1173,61 @@ static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) return self->aq_fw_ops->send_fw_request(self, &fwreq, size); } +static u16 hw_atl_b0_rx_extract_ts(struct aq_hw_s *self, u8 *p, + unsigned int len, u64 *timestamp) +{ + unsigned int offset = 14; + struct ethhdr *eth; + u64 sec; + u8 *ptr; + u32 ns; + + if (len <= offset || !timestamp) + return 0; + + /* The TIMESTAMP in the end of package has following format: + * (big-endian) + * struct { + * uint64_t sec; + * uint32_t ns; + * uint16_t stream_id; + * }; + */ + ptr = p + (len - offset); + memcpy(&sec, ptr, sizeof(sec)); + ptr += sizeof(sec); + memcpy(&ns, ptr, sizeof(ns)); + + sec = be64_to_cpu(sec) & 0xffffffffffffllu; + ns = be32_to_cpu(ns); + *timestamp = sec * NSEC_PER_SEC + ns + self->ptp_clk_offset; + + eth = (struct ethhdr *)p; + + return (eth->h_proto == htons(ETH_P_1588)) ? 12 : 14; +} + +static int hw_atl_b0_extract_hwts(struct aq_hw_s *self, u8 *p, unsigned int len, + u64 *timestamp) +{ + struct hw_atl_rxd_hwts_wb_s *hwts_wb = (struct hw_atl_rxd_hwts_wb_s *)p; + u64 tmp, sec, ns; + + sec = 0; + tmp = (hwts_wb->sec_lw0 >> 2) & 0x3ff; + sec += tmp; + tmp = (u64)((hwts_wb->sec_lw1 >> 16) & 0xffff) << 10; + sec += tmp; + tmp = (u64)(hwts_wb->sec_hw & 0xfff) << 26; + sec += tmp; + tmp = (u64)((hwts_wb->sec_hw >> 22) & 0x3ff) << 38; + sec += tmp; + ns = sec * NSEC_PER_SEC + hwts_wb->ns; + if (timestamp) + *timestamp = ns + self->ptp_clk_offset; + return 0; +} + static int hw_atl_b0_hw_fl3l4_clear(struct aq_hw_s *self, struct aq_rx_filter_l3l4 *data) { @@ -1309,11 +1404,16 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_tx_tc_mode_get = hw_atl_b0_tx_tc_mode_get, .hw_rx_tc_mode_get = hw_atl_b0_rx_tc_mode_get, + .hw_ring_hwts_rx_fill = hw_atl_b0_hw_ring_hwts_rx_fill, + .hw_ring_hwts_rx_receive = hw_atl_b0_hw_ring_hwts_rx_receive, + .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts, .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock, .hw_set_sys_clock = hw_atl_b0_set_sys_clock, .hw_adj_clock_freq = hw_atl_b0_adj_clock_freq, + .rx_extract_ts = hw_atl_b0_rx_extract_ts, + .extract_hwts = hw_atl_b0_extract_hwts, .hw_set_offload = hw_atl_b0_hw_offload_set, .hw_set_fc = hw_atl_b0_set_fc, }; -- cgit v1.2.3-59-g8ed1b From 5a1bf9ef51cfd9bbe12a5a03a12a47eeacc0ef64 Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Tue, 22 Oct 2019 09:53:38 +0000 Subject: net: aquantia: rx filters for ptp We implement HW filter reservation for PTP traffic. Special location in filters table is marked as reserved, because incoming ptp traffic should be directed only to PTP designated queue. This way HW will do PTP timestamping and proper processing. Co-developed-by: Egor Pomozov Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_filters.c | 17 ++-- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 44 +++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 8 +- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 14 ++++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 12 ++- .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 90 +++++++++++----------- 6 files changed, 131 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c index aee827f07c16..6102251bb909 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_filters.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_filters.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (C) 2014-2017 aQuantia Corporation. */ +/* Copyright (C) 2014-2019 aQuantia Corporation. */ /* File aq_filters.c: RX filters related functions. */ @@ -89,12 +89,14 @@ static int aq_check_approve_fl3l4(struct aq_nic_s *aq_nic, struct aq_hw_rx_fltrs_s *rx_fltrs, struct ethtool_rx_flow_spec *fsp) { + u32 last_location = AQ_RX_LAST_LOC_FL3L4 - + aq_nic->aq_hw_rx_fltrs.fl3l4.reserved_count; + if (fsp->location < AQ_RX_FIRST_LOC_FL3L4 || - fsp->location > AQ_RX_LAST_LOC_FL3L4) { + fsp->location > last_location) { netdev_err(aq_nic->ndev, "ethtool: location must be in range [%d, %d]", - AQ_RX_FIRST_LOC_FL3L4, - AQ_RX_LAST_LOC_FL3L4); + AQ_RX_FIRST_LOC_FL3L4, last_location); return -EINVAL; } if (rx_fltrs->fl3l4.is_ipv6 && rx_fltrs->fl3l4.active_ipv4) { @@ -124,12 +126,15 @@ aq_check_approve_fl2(struct aq_nic_s *aq_nic, struct aq_hw_rx_fltrs_s *rx_fltrs, struct ethtool_rx_flow_spec *fsp) { + u32 last_location = AQ_RX_LAST_LOC_FETHERT - + aq_nic->aq_hw_rx_fltrs.fet_reserved_count; + if (fsp->location < AQ_RX_FIRST_LOC_FETHERT || - fsp->location > AQ_RX_LAST_LOC_FETHERT) { + fsp->location > last_location) { netdev_err(aq_nic->ndev, "ethtool: location must be in range [%d, %d]", AQ_RX_FIRST_LOC_FETHERT, - AQ_RX_LAST_LOC_FETHERT); + last_location); return -EINVAL; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 65384f45805f..22e4a5587c15 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -13,6 +13,7 @@ #include "aq_pci_func.h" #include "aq_main.h" #include "aq_ptp.h" +#include "aq_filters.h" #include #include @@ -1105,3 +1106,46 @@ void aq_nic_shutdown(struct aq_nic_s *self) err_exit: rtnl_unlock(); } + +u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type) +{ + u8 location = 0xFF; + u32 fltr_cnt; + u32 n_bit; + + switch (type) { + case aq_rx_filter_ethertype: + location = AQ_RX_LAST_LOC_FETHERT - AQ_RX_FIRST_LOC_FETHERT - + self->aq_hw_rx_fltrs.fet_reserved_count; + self->aq_hw_rx_fltrs.fet_reserved_count++; + break; + case aq_rx_filter_l3l4: + fltr_cnt = AQ_RX_LAST_LOC_FL3L4 - AQ_RX_FIRST_LOC_FL3L4; + n_bit = fltr_cnt - self->aq_hw_rx_fltrs.fl3l4.reserved_count; + + self->aq_hw_rx_fltrs.fl3l4.active_ipv4 |= BIT(n_bit); + self->aq_hw_rx_fltrs.fl3l4.reserved_count++; + location = n_bit; + break; + default: + break; + } + + return location; +} + +void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type, + u32 location) +{ + switch (type) { + case aq_rx_filter_ethertype: + self->aq_hw_rx_fltrs.fet_reserved_count--; + break; + case aq_rx_filter_l3l4: + self->aq_hw_rx_fltrs.fl3l4.reserved_count--; + self->aq_hw_rx_fltrs.fl3l4.active_ipv4 &= ~BIT(location); + break; + default: + break; + } +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 576432adda4c..c2513b79b9e9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -18,6 +18,7 @@ struct aq_hw_ops; struct aq_fw_s; struct aq_vec_s; struct aq_ptp_s; +enum aq_rx_filter_type; struct aq_nic_cfg_s { const struct aq_hw_caps_s *aq_hw_caps; @@ -72,6 +73,7 @@ struct aq_hw_rx_fl3l4 { u8 active_ipv4; u8 active_ipv6:2; u8 is_ipv6; + u8 reserved_count; }; struct aq_hw_rx_fltrs_s { @@ -79,6 +81,8 @@ struct aq_hw_rx_fltrs_s { u16 active_filters; struct aq_hw_rx_fl2 fl2; struct aq_hw_rx_fl3l4 fl3l4; + /*filter ether type */ + u8 fet_reserved_count; }; struct aq_nic_s { @@ -154,5 +158,7 @@ u32 aq_nic_get_fw_version(struct aq_nic_s *self); int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); void aq_nic_shutdown(struct aq_nic_s *self); - +u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type); +void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type, + u32 location); #endif /* AQ_NIC_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index fbb1912a34d7..82409cb1f815 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -8,12 +8,14 @@ */ #include +#include #include #include #include "aq_nic.h" #include "aq_ptp.h" #include "aq_ring.h" +#include "aq_filters.h" #define AQ_PTP_TX_TIMEOUT (HZ * 10) @@ -62,6 +64,9 @@ struct aq_ptp_s { struct aq_ring_s hwts_rx; struct ptp_skb_ring skb_ring; + + struct aq_rx_filter_l3l4 udp_filter; + struct aq_rx_filter_l2 eth_type_filter; }; struct ptp_tm_offset { @@ -933,6 +938,11 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) aq_ptp_clock_init(aq_nic); mutex_unlock(&aq_nic->fwreq_mutex); + aq_ptp->eth_type_filter.location = + aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype); + aq_ptp->udp_filter.location = + aq_nic_reserve_filter(aq_nic, aq_rx_filter_l3l4); + return 0; err_exit: @@ -958,6 +968,10 @@ void aq_ptp_free(struct aq_nic_s *aq_nic) if (!aq_ptp) return; + aq_nic_release_filter(aq_nic, aq_rx_filter_ethertype, + aq_ptp->eth_type_filter.location); + aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4, + aq_ptp->udp_filter.location); /* disable ptp */ mutex_lock(&aq_nic->fwreq_mutex); aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index bd9e5a598657..56cec2ea0af0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1261,7 +1261,8 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self, hw_atl_b0_hw_fl3l4_clear(self, data); - if (data->cmd) { + if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_ADDR_L3 | + HW_ATL_RX_ENABLE_CMP_SRC_ADDR_L3)) { if (!data->is_ipv6) { hw_atl_rpfl3l4_ipv4_dest_addr_set(self, location, @@ -1278,8 +1279,13 @@ static int hw_atl_b0_hw_fl3l4_set(struct aq_hw_s *self, data->ip_src); } } - hw_atl_rpf_l4_dpd_set(self, data->p_dst, location); - hw_atl_rpf_l4_spd_set(self, data->p_src, location); + + if (data->cmd & (HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 | + HW_ATL_RX_ENABLE_CMP_SRC_PORT_L4)) { + hw_atl_rpf_l4_dpd_set(self, data->p_dst, location); + hw_atl_rpf_l4_spd_set(self, data->p_src, location); + } + hw_atl_rpfl3l4_cmd_set(self, location, data->cmd); return aq_hw_err_from_flags(self); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 65fb74a4d5ea..86c2d12b0dcd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -1308,6 +1308,52 @@ /* default value of bitfield et_val{f}[f:0] */ #define HW_ATL_RPF_ET_VALF_DEFAULT 0x0 +/* RX l3_l4_en{F} Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_l4_en{F}". + * Parameter: filter {F} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_l4_en_i[0]" + */ + +#define HW_ATL_RPF_L3_REG_CTRL_ADR(filter) (0x00005380 + (filter) * 0x4) + +/* RX rpf_l3_sa{D}[1F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_sa{D}[1F:0]". + * Parameter: location {D} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_sa0_i[31:0]" + */ + +/* Register address for bitfield pif_rpf_l3_sa0_i[31:0] */ +#define HW_ATL_RPF_L3_SRCA_ADR(filter) (0x000053B0 + (filter) * 0x4) +/* Bitmask for bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_MSK 0xFFFFFFFFu +/* Inverted bitmask for bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_MSKN 0xFFFFFFFFu +/* Lower bit position of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_SHIFT 0 +/* Width of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_WIDTH 32 +/* Default value of bitfield l3_sa0[1F:0] */ +#define HW_ATL_RPF_L3_SRCA_DEFAULT 0x0 + +/* RX rpf_l3_da{D}[1F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "l3_da{D}[1F:0]". + * Parameter: location {D} | stride size 0x4 | range [0, 7] + * PORT="pif_rpf_l3_da0_i[31:0]" + */ + + /* Register address for bitfield pif_rpf_l3_da0_i[31:0] */ +#define HW_ATL_RPF_L3_DSTA_ADR(filter) (0x000053B0 + (filter) * 0x4) +/* Bitmask for bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_MSK 0xFFFFFFFFu +/* Inverted bitmask for bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_MSKN 0xFFFFFFFFu +/* Lower bit position of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_SHIFT 0 +/* Width of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_WIDTH 32 +/* Default value of bitfield l3_da0[1F:0] */ +#define HW_ATL_RPF_L3_DSTA_DEFAULT 0x0 + /* RX l4_sp{D}[F:0] Bitfield Definitions * Preprocessor definitions for the bitfield "l4_sp{D}[F:0]". * Parameter: srcport {D} | stride size 0x4 | range [0, 7] @@ -2548,50 +2594,6 @@ /* default value of bitfield uP Force Interrupt */ #define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0 -#define HW_ATL_RX_CTRL_ADDR_BEGIN_FL3L4 0x00005380 -#define HW_ATL_RX_SRCA_ADDR_BEGIN_FL3L4 0x000053B0 -#define HW_ATL_RX_DESTA_ADDR_BEGIN_FL3L4 0x000053D0 - -#define HW_ATL_RPF_L3_REG_CTRL_ADR(location) (0x00005380 + (location) * 0x4) - -/* RX rpf_l3_sa{D}[1F:0] Bitfield Definitions - * Preprocessor definitions for the bitfield "l3_sa{D}[1F:0]". - * Parameter: location {D} | stride size 0x4 | range [0, 7] - * PORT="pif_rpf_l3_sa0_i[31:0]" - */ - -/* Register address for bitfield pif_rpf_l3_sa0_i[31:0] */ -#define HW_ATL_RPF_L3_SRCA_ADR(location) (0x000053B0 + (location) * 0x4) -/* Bitmask for bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_MSK 0xFFFFFFFFu -/* Inverted bitmask for bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_MSKN 0xFFFFFFFFu -/* Lower bit position of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_SHIFT 0 -/* Width of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_WIDTH 32 -/* Default value of bitfield l3_sa0[1F:0] */ -#define HW_ATL_RPF_L3_SRCA_DEFAULT 0x0 - -/* RX rpf_l3_da{D}[1F:0] Bitfield Definitions - * Preprocessor definitions for the bitfield "l3_da{D}[1F:0]". - * Parameter: location {D} | stride size 0x4 | range [0, 7] - * PORT="pif_rpf_l3_da0_i[31:0]" - */ - - /* Register address for bitfield pif_rpf_l3_da0_i[31:0] */ -#define HW_ATL_RPF_L3_DSTA_ADR(location) (0x000053B0 + (location) * 0x4) -/* Bitmask for bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_MSK 0xFFFFFFFFu -/* Inverted bitmask for bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_MSKN 0xFFFFFFFFu -/* Lower bit position of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_SHIFT 0 -/* Width of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_WIDTH 32 -/* Default value of bitfield l3_da0[1F:0] */ -#define HW_ATL_RPF_L3_DSTA_DEFAULT 0x0 - #define HW_ATL_FW_SM_RAM 0x2U #endif /* HW_ATL_LLH_INTERNAL_H */ -- cgit v1.2.3-59-g8ed1b From 7db3d07afd2c1337f784ba9d528c10e225f91aa8 Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:40 +0000 Subject: net: aquantia: add support for ptp ioctls Here we add support for PTP specific IOCTLs of HW timestamp get/set. These will use filters to configure flows onto the required queue ids. Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Signed-off-by: Egor Pomozov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_main.c | 82 ++++++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 63 ++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 6 ++ 3 files changed, 151 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index f630032af8e1..a26d4a69efad 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -218,6 +218,87 @@ static void aq_ndev_set_multicast_settings(struct net_device *ndev) (void)aq_nic_set_multicast_list(aq_nic, ndev); } +static int aq_ndev_config_hwtstamp(struct aq_nic_s *aq_nic, + struct hwtstamp_config *config) +{ + if (config->flags) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + case HWTSTAMP_TX_ON: + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_NONE: + break; + default: + return -ERANGE; + } + + return aq_ptp_hwtstamp_config_set(aq_nic->aq_ptp, config); +} + +static int aq_ndev_hwtstamp_set(struct aq_nic_s *aq_nic, struct ifreq *ifr) +{ + struct hwtstamp_config config; + int ret_val; + + if (!aq_nic->aq_ptp) + return -EOPNOTSUPP; + + if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) + return -EFAULT; + + ret_val = aq_ndev_config_hwtstamp(aq_nic, &config); + if (ret_val) + return ret_val; + + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int aq_ndev_hwtstamp_get(struct aq_nic_s *aq_nic, struct ifreq *ifr) +{ + struct hwtstamp_config config; + + if (!aq_nic->aq_ptp) + return -EOPNOTSUPP; + + aq_ptp_hwtstamp_config_get(aq_nic->aq_ptp, &config); + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int aq_ndev_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct aq_nic_s *aq_nic = netdev_priv(netdev); + + switch (cmd) { + case SIOCSHWTSTAMP: + return aq_ndev_hwtstamp_set(aq_nic, ifr); + + case SIOCGHWTSTAMP: + return aq_ndev_hwtstamp_get(aq_nic, ifr); + } + + return -EOPNOTSUPP; +} + static int aq_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) { @@ -255,6 +336,7 @@ static const struct net_device_ops aq_ndev_ops = { .ndo_change_mtu = aq_ndev_change_mtu, .ndo_set_mac_address = aq_ndev_set_mac_address, .ndo_set_features = aq_ndev_set_features, + .ndo_do_ioctl = aq_ndev_ioctl, .ndo_vlan_rx_add_vid = aq_ndo_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = aq_ndo_vlan_rx_kill_vid, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 82409cb1f815..56613792abc8 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -44,6 +44,7 @@ struct ptp_tx_timeout { struct aq_ptp_s { struct aq_nic_s *aq_nic; + struct hwtstamp_config hwtstamp_config; spinlock_t ptp_lock; spinlock_t ptp_ring_lock; struct ptp_clock *ptp_clock; @@ -388,6 +389,68 @@ static void aq_ptp_rx_hwtstamp(struct aq_ptp_s *aq_ptp, struct sk_buff *skb, aq_ptp_convert_to_hwtstamp(aq_ptp, skb_hwtstamps(skb), timestamp); } +void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + *config = aq_ptp->hwtstamp_config; +} + +static void aq_ptp_prepare_filters(struct aq_ptp_s *aq_ptp) +{ + aq_ptp->udp_filter.cmd = HW_ATL_RX_ENABLE_FLTR_L3L4 | + HW_ATL_RX_ENABLE_CMP_PROT_L4 | + HW_ATL_RX_UDP | + HW_ATL_RX_ENABLE_CMP_DEST_PORT_L4 | + HW_ATL_RX_HOST << HW_ATL_RX_ACTION_FL3F4_SHIFT | + HW_ATL_RX_ENABLE_QUEUE_L3L4 | + aq_ptp->ptp_rx.idx << HW_ATL_RX_QUEUE_FL3L4_SHIFT; + aq_ptp->udp_filter.p_dst = PTP_EV_PORT; + + aq_ptp->eth_type_filter.ethertype = ETH_P_1588; + aq_ptp->eth_type_filter.queue = aq_ptp->ptp_rx.idx; +} + +int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + const struct aq_hw_ops *hw_ops; + int err = 0; + + hw_ops = aq_nic->aq_hw_ops; + if (config->tx_type == HWTSTAMP_TX_ON || + config->rx_filter == HWTSTAMP_FILTER_PTP_V2_EVENT) { + aq_ptp_prepare_filters(aq_ptp); + if (hw_ops->hw_filter_l3l4_set) { + err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw, + &aq_ptp->udp_filter); + } + if (!err && hw_ops->hw_filter_l2_set) { + err = hw_ops->hw_filter_l2_set(aq_nic->aq_hw, + &aq_ptp->eth_type_filter); + } + aq_utils_obj_set(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + } else { + aq_ptp->udp_filter.cmd &= ~HW_ATL_RX_ENABLE_FLTR_L3L4; + if (hw_ops->hw_filter_l3l4_set) { + err = hw_ops->hw_filter_l3l4_set(aq_nic->aq_hw, + &aq_ptp->udp_filter); + } + if (!err && hw_ops->hw_filter_l2_clear) { + err = hw_ops->hw_filter_l2_clear(aq_nic->aq_hw, + &aq_ptp->eth_type_filter); + } + aq_utils_obj_clear(&aq_nic->flags, AQ_NIC_PTP_DPATH_UP); + } + + if (err) + return -EREMOTEIO; + + aq_ptp->hwtstamp_config = *config; + + return 0; +} + bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring) { struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index 2c84483fcac1..7a7f36f43ce0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -38,6 +38,12 @@ void aq_ptp_clock_init(struct aq_nic_s *aq_nic); int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb); void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp); +/* Must be to check available of PTP before call */ +void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config); +int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config); + /* Return either ring is belong to PTP or not*/ bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring); -- cgit v1.2.3-59-g8ed1b From 84989af0465b4a7898eb3a2392ea382cc219cb1d Mon Sep 17 00:00:00 2001 From: Egor Pomozov Date: Tue, 22 Oct 2019 09:53:42 +0000 Subject: net: aquantia: implement get_ts_info ethtool Ethtool callback with basic information on what PTP features are supported by the device. Signed-off-by: Egor Pomozov Co-developed-by: Sergey Samoilenko Signed-off-by: Sergey Samoilenko Co-developed-by: Dmitry Bezrukov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 35 +++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 24df132384fb..1ae8aabcc41a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * aQuantia Corporation Network Driver - * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved + * Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved */ /* File aq_ethtool.c: Definition of ethertool related functions. */ @@ -9,8 +9,11 @@ #include "aq_ethtool.h" #include "aq_nic.h" #include "aq_vec.h" +#include "aq_ptp.h" #include "aq_filters.h" +#include + static void aq_ethtool_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) { @@ -377,6 +380,35 @@ static int aq_ethtool_set_wol(struct net_device *ndev, return err; } +static int aq_ethtool_get_ts_info(struct net_device *ndev, + struct ethtool_ts_info *info) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + + ethtool_op_get_ts_info(ndev, info); + + if (!aq_nic->aq_ptp) + return 0; + + info->so_timestamping |= + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->tx_types = BIT(HWTSTAMP_TX_OFF) | + BIT(HWTSTAMP_TX_ON); + + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE); + + info->rx_filters |= BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); + + info->phc_index = ptp_clock_index(aq_ptp_get_ptp_clock(aq_nic->aq_ptp)); + + return 0; +} + static enum hw_atl_fw2x_rate eee_mask_to_ethtool_mask(u32 speed) { u32 rate = 0; @@ -604,4 +636,5 @@ const struct ethtool_ops aq_ethtool_ops = { .set_link_ksettings = aq_ethtool_set_link_ksettings, .get_coalesce = aq_ethtool_get_coalesce, .set_coalesce = aq_ethtool_set_coalesce, + .get_ts_info = aq_ethtool_get_ts_info, }; -- cgit v1.2.3-59-g8ed1b From dbcd6806af4200c830869fb5ccd1f193361c136f Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Tue, 22 Oct 2019 09:53:45 +0000 Subject: net: aquantia: add support for Phy access GPIO PIN control and access is done by direct phy manipulation. Here we add an aq_phy module which is able to access phy registers via MDIO access mailbox. Access is controlled via HW semaphore. Co-developed-by: Nikita Danilov Signed-off-by: Nikita Danilov Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/Makefile | 1 + drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 1 + drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 6 + drivers/net/ethernet/aquantia/atlantic/aq_phy.c | 147 +++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_phy.h | 32 +++++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 62 +++++++++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | 35 +++++ .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 115 ++++++++++++++++ 8 files changed, 399 insertions(+) create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_phy.c create mode 100644 drivers/net/ethernet/aquantia/atlantic/aq_phy.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index cd12d9d824ec..68c41141ede2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -25,6 +25,7 @@ atlantic-objs := aq_main.o \ aq_drvinfo.o \ aq_filters.o \ aq_ptp.o \ + aq_phy.o \ hw_atl/hw_atl_a0.o \ hw_atl/hw_atl_b0.o \ hw_atl/hw_atl_utils.o \ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 5b0f42818033..c36c0d7d038e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -140,6 +140,7 @@ struct aq_hw_s { u32 rpc_tid; struct hw_atl_utils_fw_rpc rpc; s64 ptp_clk_offset; + u16 phy_id; }; struct aq_ring_s; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 22e4a5587c15..1e12cedee11e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -12,6 +12,7 @@ #include "aq_hw.h" #include "aq_pci_func.h" #include "aq_main.h" +#include "aq_phy.h" #include "aq_ptp.h" #include "aq_filters.h" @@ -337,6 +338,11 @@ int aq_nic_init(struct aq_nic_s *self) if (err < 0) goto err_exit; + if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_TP) { + self->aq_hw->phy_id = HW_ATL_PHY_ID_MAX; + err = aq_phy_init(self->aq_hw); + } + for (i = 0U, aq_vec = self->aq_vec[0]; self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i]) aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_phy.c b/drivers/net/ethernet/aquantia/atlantic/aq_phy.c new file mode 100644 index 000000000000..51ae921e3e1f --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_phy.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* aQuantia Corporation Network Driver + * Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved + */ + +#include "aq_phy.h" + +bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw, + val, val == 0U, 10U, 100000U); + + if (err < 0) + return false; + + return true; +} + +u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr) +{ + u16 phy_addr = aq_hw->phy_id << 5 | mmd; + + /* Set Address register. */ + hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << + HW_ATL_MDIO_ADDRESS_SHIFT); + /* Send Address command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (3 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); + + /* Send Read command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (1 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + /* Read result. */ + aq_mdio_busy_wait(aq_hw); + + return (u16)hw_atl_glb_mdio_iface5_get(aq_hw); +} + +void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data) +{ + u16 phy_addr = aq_hw->phy_id << 5 | mmd; + + /* Set Address register. */ + hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << + HW_ATL_MDIO_ADDRESS_SHIFT); + /* Send Address command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (3 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); + + hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) << + HW_ATL_MDIO_WRITE_DATA_SHIFT); + /* Send Write command. */ + hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | + (2 << HW_ATL_MDIO_OP_MODE_SHIFT) | + ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << + HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); + + aq_mdio_busy_wait(aq_hw); +} + +u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, + val, val == 1U, 10U, 100000U); + + if (err < 0) { + err = 0xffff; + goto err_exit; + } + + err = aq_mdio_read_word(aq_hw, mmd, address); + + hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); + +err_exit: + return err; +} + +void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data) +{ + int err = 0; + u32 val; + + err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, + val, val == 1U, 10U, 100000U); + if (err < 0) + return; + + aq_mdio_write_word(aq_hw, mmd, address, data); + hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); +} + +bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw) +{ + u16 val; + + for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX; + ++aq_hw->phy_id) { + /* PMA Standard Device Identifier 2: Address 1.3 */ + val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); + + if (val != 0xffff) + return true; + } + + return false; +} + +bool aq_phy_init(struct aq_hw_s *aq_hw) +{ + u32 dev_id; + + if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX) + if (!aq_phy_init_phy_id(aq_hw)) + return false; + + /* PMA Standard Device Identifier: + * Address 1.2 = MSW, + * Address 1.3 = LSW + */ + dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2); + dev_id <<= 16; + dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); + + if (dev_id == 0xffffffff) { + aq_hw->phy_id = HW_ATL_PHY_ID_MAX; + return false; + } + + return true; +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_phy.h b/drivers/net/ethernet/aquantia/atlantic/aq_phy.h new file mode 100644 index 000000000000..84b72ad04a4a --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic/aq_phy.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* aQuantia Corporation Network Driver + * Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved + */ + +#ifndef AQ_PHY_H +#define AQ_PHY_H + +#include + +#include "hw_atl/hw_atl_llh.h" +#include "hw_atl/hw_atl_llh_internal.h" +#include "aq_hw_utils.h" +#include "aq_hw.h" + +#define HW_ATL_PHY_ID_MAX 32U + +bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw); + +u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr); + +void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data); + +u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address); + +void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data); + +bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw); + +bool aq_phy_init(struct aq_hw_s *aq_hw); + +#endif /* AQ_PHY_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index d83f1a34a537..6cadc9054544 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -1644,6 +1644,11 @@ u32 hw_atl_sem_ram_get(struct aq_hw_s *self) return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM); } +u32 hw_atl_sem_mdio_get(struct aq_hw_s *self) +{ + return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_MDIO); +} + u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp) { return aq_hw_read_reg(aq_hw, @@ -1659,3 +1664,60 @@ u32 hw_atl_scrpad25_get(struct aq_hw_s *self) { return hw_atl_scrpad_get(self, 0x18); } + +void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1), value); +} + +u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1)); +} + +void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2), value); +} + +u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2)); +} + +void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3), value); +} + +u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3)); +} + +void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4), value); +} + +u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4)); +} + +void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *aq_hw, u32 value) +{ + aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5), value); +} + +u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5)); +} + +u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw) +{ + return aq_hw_read_reg_bit(aq_hw, HW_ATL_MDIO_BUSY_ADR, + HW_ATL_MDIO_BUSY_MSK, + HW_ATL_MDIO_BUSY_SHIFT); +} diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index b192702a7b8b..5750b0c9cae7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -767,9 +767,44 @@ void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location, void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location, u32 *ipv6_dest); +/* set Global MDIO Interface 1 */ +void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 1 */ +u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 2 */ +void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 2 */ +u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 3 */ +void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 3 */ +u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 4 */ +void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 4 */ +u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *hw); + +/* set Global MDIO Interface 5 */ +void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *hw, u32 value); + +/* get Global MDIO Interface 5 */ +u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *hw); + +u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw); + /* get global microprocessor ram semaphore */ u32 hw_atl_sem_ram_get(struct aq_hw_s *self); +/* get global microprocessor mdio semaphore */ +u32 hw_atl_sem_mdio_get(struct aq_hw_s *self); + /* get global microprocessor scratch pad register */ u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 86c2d12b0dcd..ec3bcdcefc4d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -2594,6 +2594,121 @@ /* default value of bitfield uP Force Interrupt */ #define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0 +/* Preprocessor definitions for Global MDIO Interfaces + * Address: 0x00000280 + 0x4 * Number of interface + */ +#define HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN 0x00000280u + +#define HW_ATL_GLB_MDIO_IFACE_N_ADR(number) \ + (HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN + (((number) - 1) * 0x4)) + +/* MIF MDIO Busy Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Busy". + * PORT="mdio_pif_busy_o" + */ + +/* Register address for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_ADR 0x00000284 +/* Bitmask for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_MSK 0x80000000 +/* Inverted bitmask for bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_MSKN 0x7FFFFFFF +/* Lower bit position of bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_SHIFT 31 +/* Width of bitfield MDIO Busy */ +#define HW_ATL_MDIO_BUSY_WIDTH 1 + +/* MIF MDIO Execute Operation Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Execute Operation". + * PORT="pif_mdio_op_start_i" + */ + +/* Register address for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_ADR 0x00000284 +/* Bitmask for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_MSK 0x00008000 +/* Inverted bitmask for bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_MSKN 0xFFFF7FFF +/* Lower bit position of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_SHIFT 15 +/* Width of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_WIDTH 1 +/* Default value of bitfield MDIO Execute Operation */ +#define HW_ATL_MDIO_EXECUTE_OPERATION_DEFAULT 0x0 + +/* MIF Op Mode [1:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "Op Mode [1:0]". + * PORT="pif_mdio_mode_i[1:0]" + */ + +/* Register address for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_ADR 0x00000284 +/* Bitmask for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_MSK 0x00003000 +/* Inverted bitmask for bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_MSKN 0xFFFFCFFF +/* Lower bit position of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_SHIFT 12 +/* Width of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_WIDTH 2 +/* Default value of bitfield Op Mode [1:0] */ +#define HW_ATL_MDIO_OP_MODE_DEFAULT 0x0 + +/* MIF PHY address Bitfield Definitions + * Preprocessor definitions for the bitfield "PHY address". + * PORT="pif_mdio_phy_addr_i[9:0]" + */ + +/* Register address for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_ADR 0x00000284 +/* Bitmask for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_MSK 0x000003FF +/* Inverted bitmask for bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_MSKN 0xFFFFFC00 +/* Lower bit position of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_SHIFT 0 +/* Width of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_WIDTH 10 +/* Default value of bitfield PHY address */ +#define HW_ATL_MDIO_PHY_ADDRESS_DEFAULT 0x0 + +/* MIF MDIO WriteData [F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO WriteData [F:0]". + * PORT="pif_mdio_wdata_i[15:0]" + */ + +/* Register address for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_ADR 0x00000288 +/* Bitmask for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_MSK 0x0000FFFF +/* Inverted bitmask for bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_MSKN 0xFFFF0000 +/* Lower bit position of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_SHIFT 0 +/* Width of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_WIDTH 16 +/* Default value of bitfield MDIO WriteData [F:0] */ +#define HW_ATL_MDIO_WRITE_DATA_DEFAULT 0x0 + +/* MIF MDIO Address [F:0] Bitfield Definitions + * Preprocessor definitions for the bitfield "MDIO Address [F:0]". + * PORT="pif_mdio_addr_i[15:0]" + */ + +/* Register address for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_ADR 0x0000028C +/* Bitmask for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_MSK 0x0000FFFF +/* Inverted bitmask for bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_MSKN 0xFFFF0000 +/* Lower bit position of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_SHIFT 0 +/* Width of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_WIDTH 16 +/* Default value of bitfield MDIO Address [F:0] */ +#define HW_ATL_MDIO_ADDRESS_DEFAULT 0x0 + +#define HW_ATL_FW_SM_MDIO 0x0U #define HW_ATL_FW_SM_RAM 0x2U #endif /* HW_ATL_LLH_INTERNAL_H */ -- cgit v1.2.3-59-g8ed1b From 9c477032f7d0beafe592e65238d8fb79341e91dc Mon Sep 17 00:00:00 2001 From: Dmitry Bezrukov Date: Tue, 22 Oct 2019 09:53:47 +0000 Subject: net: aquantia: add support for PIN funcs Depending on FW configuration we can manage from 0 to 3 PINs for periodic output and from 0 to 1 ext ts PIN for getting TS for external event. Ext TS PIN functionality is implemented via periodic timestamps polling directly from PHY, because right now there is now way to receive the PIN trigger interrupt from phy. The polling interval is 15 milliseconds. Co-developed-by: Egor Pomozov Signed-off-by: Egor Pomozov Co-developed-by: Pavel Belous Signed-off-by: Pavel Belous Signed-off-by: Dmitry Bezrukov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 10 + drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 1 + drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 339 +++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 2 + .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 63 +++- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 8 + 6 files changed, 422 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index c36c0d7d038e..5246cf44ce51 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -259,6 +259,16 @@ struct aq_hw_ops { int (*hw_set_sys_clock)(struct aq_hw_s *self, u64 time, u64 ts); + int (*hw_ts_to_sys_clock)(struct aq_hw_s *self, u64 ts, u64 *time); + + int (*hw_gpio_pulse)(struct aq_hw_s *self, u32 index, u64 start, + u32 period); + + int (*hw_extts_gpio_enable)(struct aq_hw_s *self, u32 index, + u32 enable); + + int (*hw_get_sync_ts)(struct aq_hw_s *self, u64 *ts); + u16 (*rx_extract_ts)(struct aq_hw_s *self, u8 *p, unsigned int len, u64 *timestamp); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 1e12cedee11e..433adc099e44 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -152,6 +152,7 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) aq_ptp_clock_init(self); aq_ptp_tm_offset_set(self, self->aq_hw->aq_link_status.mbps); + aq_ptp_link_change(self); } /* Driver has to update flow control settings on RX block diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 56613792abc8..3ec08415e53e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -15,10 +15,13 @@ #include "aq_nic.h" #include "aq_ptp.h" #include "aq_ring.h" +#include "aq_phy.h" #include "aq_filters.h" #define AQ_PTP_TX_TIMEOUT (HZ * 10) +#define POLL_SYNC_TIMER_MS 15 + enum ptp_speed_offsets { ptp_offset_idx_10 = 0, ptp_offset_idx_100, @@ -68,6 +71,12 @@ struct aq_ptp_s { struct aq_rx_filter_l3l4 udp_filter; struct aq_rx_filter_l2 eth_type_filter; + + struct delayed_work poll_sync; + u32 poll_timeout_ms; + + bool extts_pin_enabled; + u64 last_sync1588_ts; }; struct ptp_tm_offset { @@ -348,6 +357,168 @@ static void aq_ptp_convert_to_hwtstamp(struct aq_ptp_s *aq_ptp, hwtstamp->hwtstamp = ns_to_ktime(timestamp); } +static int aq_ptp_hw_pin_conf(struct aq_nic_s *aq_nic, u32 pin_index, u64 start, + u64 period) +{ + if (period) + netdev_dbg(aq_nic->ndev, + "Enable GPIO %d pulsing, start time %llu, period %u\n", + pin_index, start, (u32)period); + else + netdev_dbg(aq_nic->ndev, + "Disable GPIO %d pulsing, start time %llu, period %u\n", + pin_index, start, (u32)period); + + /* Notify hardware of request to being sending pulses. + * If period is ZERO then pulsen is disabled. + */ + mutex_lock(&aq_nic->fwreq_mutex); + aq_nic->aq_hw_ops->hw_gpio_pulse(aq_nic->aq_hw, pin_index, + start, (u32)period); + mutex_unlock(&aq_nic->fwreq_mutex); + + return 0; +} + +static int aq_ptp_perout_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct ptp_clock_time *t = &rq->perout.period; + struct ptp_clock_time *s = &rq->perout.start; + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 start, period; + u32 pin_index = rq->perout.index; + + /* verify the request channel is there */ + if (pin_index >= ptp->n_per_out) + return -EINVAL; + + /* we cannot support periods greater + * than 4 seconds due to reg limit + */ + if (t->sec > 4 || t->sec < 0) + return -ERANGE; + + /* convert to unsigned 64b ns, + * verify we can put it in a 32b register + */ + period = on ? t->sec * NSEC_PER_SEC + t->nsec : 0; + + /* verify the value is in range supported by hardware */ + if (period > U32_MAX) + return -ERANGE; + /* convert to unsigned 64b ns */ + /* TODO convert to AQ time */ + start = on ? s->sec * NSEC_PER_SEC + s->nsec : 0; + + aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period); + + return 0; +} + +static int aq_ptp_pps_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 start, period; + u32 pin_index = 0; + u32 rest = 0; + + /* verify the request channel is there */ + if (pin_index >= ptp->n_per_out) + return -EINVAL; + + aq_nic->aq_hw_ops->hw_get_ptp_ts(aq_nic->aq_hw, &start); + div_u64_rem(start, NSEC_PER_SEC, &rest); + period = on ? NSEC_PER_SEC : 0; /* PPS - pulse per second */ + start = on ? start - rest + NSEC_PER_SEC * + (rest > 990000000LL ? 2 : 1) : 0; + + aq_ptp_hw_pin_conf(aq_nic, pin_index, start, period); + + return 0; +} + +static void aq_ptp_extts_pin_ctrl(struct aq_ptp_s *aq_ptp) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u32 enable = aq_ptp->extts_pin_enabled; + + if (aq_nic->aq_hw_ops->hw_extts_gpio_enable) + aq_nic->aq_hw_ops->hw_extts_gpio_enable(aq_nic->aq_hw, 0, + enable); +} + +static int aq_ptp_extts_pin_configure(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct aq_ptp_s *aq_ptp = container_of(ptp, struct aq_ptp_s, ptp_info); + + u32 pin_index = rq->extts.index; + + if (pin_index >= ptp->n_ext_ts) + return -EINVAL; + + aq_ptp->extts_pin_enabled = !!on; + if (on) { + aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS; + cancel_delayed_work_sync(&aq_ptp->poll_sync); + schedule_delayed_work(&aq_ptp->poll_sync, + msecs_to_jiffies(aq_ptp->poll_timeout_ms)); + } + + aq_ptp_extts_pin_ctrl(aq_ptp); + return 0; +} + +/* aq_ptp_gpio_feature_enable + * @ptp: the ptp clock structure + * @rq: the requested feature to change + * @on: whether to enable or disable the feature + */ +static int aq_ptp_gpio_feature_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + return aq_ptp_extts_pin_configure(ptp, rq, on); + case PTP_CLK_REQ_PEROUT: + return aq_ptp_perout_pin_configure(ptp, rq, on); + case PTP_CLK_REQ_PPS: + return aq_ptp_pps_pin_configure(ptp, rq, on); + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* aq_ptp_verify + * @ptp: the ptp clock structure + * @pin: index of the pin in question + * @func: the desired function to use + * @chan: the function channel index to use + */ +static int aq_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin, + enum ptp_pin_function func, unsigned int chan) +{ + /* verify the requested pin is there */ + if (!ptp->pin_config || pin >= ptp->n_pins) + return -EINVAL; + + /* enforce locked channels, no changing them */ + if (chan != ptp->pin_config[pin].chan) + return -EINVAL; + + /* we want to keep the functions locked as well */ + if (func != ptp->pin_config[pin].func) + return -EINVAL; + + return 0; +} + /* aq_ptp_tx_hwtstamp - utility function which checks for TX time stamp * @adapter: the private adapter struct * @@ -859,6 +1030,8 @@ void aq_ptp_ring_free(struct aq_nic_s *aq_nic) aq_ptp_skb_ring_release(&aq_ptp->skb_ring); } +#define MAX_PTP_GPIO_COUNT 4 + static struct ptp_clock_info aq_ptp_clock = { .owner = THIS_MODULE, .name = "atlantic ptp", @@ -870,7 +1043,9 @@ static struct ptp_clock_info aq_ptp_clock = { .gettime64 = aq_ptp_gettime, .settime64 = aq_ptp_settime, .n_per_out = 0, + .enable = aq_ptp_gpio_feature_enable, .n_pins = 0, + .verify = aq_ptp_verify, .pin_config = NULL, }; @@ -928,6 +1103,57 @@ static void aq_ptp_offset_init(const struct hw_aq_ptp_offset *offsets) aq_ptp_offset_init_from_fw(offsets); } +static void aq_ptp_gpio_init(struct ptp_clock_info *info, + struct hw_aq_info *hw_info) +{ + struct ptp_pin_desc pin_desc[MAX_PTP_GPIO_COUNT]; + u32 extts_pin_cnt = 0; + u32 out_pin_cnt = 0; + u32 i; + + memset(pin_desc, 0, sizeof(pin_desc)); + + for (i = 0; i < MAX_PTP_GPIO_COUNT - 1; i++) { + if (hw_info->gpio_pin[i] == + (GPIO_PIN_FUNCTION_PTP0 + out_pin_cnt)) { + snprintf(pin_desc[out_pin_cnt].name, + sizeof(pin_desc[out_pin_cnt].name), + "AQ_GPIO%d", i); + pin_desc[out_pin_cnt].index = out_pin_cnt; + pin_desc[out_pin_cnt].chan = out_pin_cnt; + pin_desc[out_pin_cnt++].func = PTP_PF_PEROUT; + } + } + + info->n_per_out = out_pin_cnt; + + if (hw_info->caps_ex & BIT(CAPS_EX_PHY_CTRL_TS_PIN)) { + extts_pin_cnt += 1; + + snprintf(pin_desc[out_pin_cnt].name, + sizeof(pin_desc[out_pin_cnt].name), + "AQ_GPIO%d", out_pin_cnt); + pin_desc[out_pin_cnt].index = out_pin_cnt; + pin_desc[out_pin_cnt].chan = 0; + pin_desc[out_pin_cnt].func = PTP_PF_EXTTS; + } + + info->n_pins = out_pin_cnt + extts_pin_cnt; + info->n_ext_ts = extts_pin_cnt; + + if (!info->n_pins) + return; + + info->pin_config = kcalloc(info->n_pins, sizeof(struct ptp_pin_desc), + GFP_KERNEL); + + if (!info->pin_config) + return; + + memcpy(info->pin_config, &pin_desc, + sizeof(struct ptp_pin_desc) * info->n_pins); +} + void aq_ptp_clock_init(struct aq_nic_s *aq_nic) { struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; @@ -937,6 +1163,8 @@ void aq_ptp_clock_init(struct aq_nic_s *aq_nic) aq_ptp_settime(&aq_ptp->ptp_info, &ts); } +static void aq_ptp_poll_sync_work_cb(struct work_struct *w); + int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) { struct hw_atl_utils_mbox mbox; @@ -975,6 +1203,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) spin_lock_init(&aq_ptp->ptp_ring_lock); aq_ptp->ptp_info = aq_ptp_clock; + aq_ptp_gpio_init(&aq_ptp->ptp_info, &mbox.info); clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev); if (!clock || IS_ERR(clock)) { netdev_err(aq_nic->ndev, "ptp_clock_register failed\n"); @@ -1001,6 +1230,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) aq_ptp_clock_init(aq_nic); mutex_unlock(&aq_nic->fwreq_mutex); + INIT_DELAYED_WORK(&aq_ptp->poll_sync, &aq_ptp_poll_sync_work_cb); aq_ptp->eth_type_filter.location = aq_nic_reserve_filter(aq_nic, aq_rx_filter_ethertype); aq_ptp->udp_filter.location = @@ -1009,6 +1239,8 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) return 0; err_exit: + if (aq_ptp) + kfree(aq_ptp->ptp_info.pin_config); kfree(aq_ptp); aq_nic->aq_ptp = NULL; return err; @@ -1035,11 +1267,14 @@ void aq_ptp_free(struct aq_nic_s *aq_nic) aq_ptp->eth_type_filter.location); aq_nic_release_filter(aq_nic, aq_rx_filter_l3l4, aq_ptp->udp_filter.location); + cancel_delayed_work_sync(&aq_ptp->poll_sync); /* disable ptp */ mutex_lock(&aq_nic->fwreq_mutex); aq_nic->aq_fw_ops->enable_ptp(aq_nic->aq_hw, 0); mutex_unlock(&aq_nic->fwreq_mutex); + kfree(aq_ptp->ptp_info.pin_config); + netif_napi_del(&aq_ptp->napi); kfree(aq_ptp); aq_nic->aq_ptp = NULL; @@ -1049,3 +1284,107 @@ struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) { return aq_ptp->ptp_clock; } + +/* PTP external GPIO nanoseconds count */ +static uint64_t aq_ptp_get_sync1588_ts(struct aq_nic_s *aq_nic) +{ + u64 ts = 0; + + if (aq_nic->aq_hw_ops->hw_get_sync_ts) + aq_nic->aq_hw_ops->hw_get_sync_ts(aq_nic->aq_hw, &ts); + + return ts; +} + +static void aq_ptp_start_work(struct aq_ptp_s *aq_ptp) +{ + if (aq_ptp->extts_pin_enabled) { + aq_ptp->poll_timeout_ms = POLL_SYNC_TIMER_MS; + aq_ptp->last_sync1588_ts = + aq_ptp_get_sync1588_ts(aq_ptp->aq_nic); + schedule_delayed_work(&aq_ptp->poll_sync, + msecs_to_jiffies(aq_ptp->poll_timeout_ms)); + } +} + +int aq_ptp_link_change(struct aq_nic_s *aq_nic) +{ + struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; + + if (!aq_ptp) + return 0; + + if (aq_nic->aq_hw->aq_link_status.mbps) + aq_ptp_start_work(aq_ptp); + else + cancel_delayed_work_sync(&aq_ptp->poll_sync); + + return 0; +} + +static bool aq_ptp_sync_ts_updated(struct aq_ptp_s *aq_ptp, u64 *new_ts) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 sync_ts2; + u64 sync_ts; + + sync_ts = aq_ptp_get_sync1588_ts(aq_nic); + + if (sync_ts != aq_ptp->last_sync1588_ts) { + sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic); + if (sync_ts != sync_ts2) { + sync_ts = sync_ts2; + sync_ts2 = aq_ptp_get_sync1588_ts(aq_nic); + if (sync_ts != sync_ts2) { + netdev_err(aq_nic->ndev, + "%s: Unable to get correct GPIO TS", + __func__); + sync_ts = 0; + } + } + + *new_ts = sync_ts; + return true; + } + return false; +} + +static int aq_ptp_check_sync1588(struct aq_ptp_s *aq_ptp) +{ + struct aq_nic_s *aq_nic = aq_ptp->aq_nic; + u64 sync_ts; + + /* Sync1588 pin was triggered */ + if (aq_ptp_sync_ts_updated(aq_ptp, &sync_ts)) { + if (aq_ptp->extts_pin_enabled) { + struct ptp_clock_event ptp_event; + u64 time = 0; + + aq_nic->aq_hw_ops->hw_ts_to_sys_clock(aq_nic->aq_hw, + sync_ts, &time); + ptp_event.index = aq_ptp->ptp_info.n_pins - 1; + ptp_event.timestamp = time; + + ptp_event.type = PTP_CLOCK_EXTTS; + ptp_clock_event(aq_ptp->ptp_clock, &ptp_event); + } + + aq_ptp->last_sync1588_ts = sync_ts; + } + + return 0; +} + +void aq_ptp_poll_sync_work_cb(struct work_struct *w) +{ + struct delayed_work *dw = to_delayed_work(w); + struct aq_ptp_s *aq_ptp = container_of(dw, struct aq_ptp_s, poll_sync); + + aq_ptp_check_sync1588(aq_ptp); + + if (aq_ptp->extts_pin_enabled) { + unsigned long timeout = msecs_to_jiffies(aq_ptp->poll_timeout_ms); + + schedule_delayed_work(&aq_ptp->poll_sync, timeout); + } +} diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index 7a7f36f43ce0..3de4682f7c06 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -52,4 +52,6 @@ u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, struct sk_buff *skb, u8 *p, struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp); +int aq_ptp_link_change(struct aq_nic_s *aq_nic); + #endif /* AQ_PTP_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 56cec2ea0af0..51ecf87e0198 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -10,6 +10,7 @@ #include "../aq_hw_utils.h" #include "../aq_ring.h" #include "../aq_nic.h" +#include "../aq_phy.h" #include "hw_atl_b0.h" #include "hw_atl_utils.h" #include "hw_atl_llh.h" @@ -1151,6 +1152,12 @@ static int hw_atl_b0_set_sys_clock(struct aq_hw_s *self, u64 time, u64 ts) return hw_atl_b0_adj_sys_clock(self, delta); } +int hw_atl_b0_ts_to_sys_clock(struct aq_hw_s *self, u64 ts, u64 *time) +{ + *time = self->ptp_clk_offset + ts; + return 0; +} + static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) { struct hw_fw_request_iface fwreq; @@ -1173,6 +1180,57 @@ static int hw_atl_b0_adj_clock_freq(struct aq_hw_s *self, s32 ppb) return self->aq_fw_ops->send_fw_request(self, &fwreq, size); } +static int hw_atl_b0_gpio_pulse(struct aq_hw_s *self, u32 index, + u64 start, u32 period) +{ + struct hw_fw_request_iface fwreq; + size_t size; + + memset(&fwreq, 0, sizeof(fwreq)); + + fwreq.msg_id = HW_AQ_FW_REQUEST_PTP_GPIO_CTRL; + fwreq.ptp_gpio_ctrl.index = index; + fwreq.ptp_gpio_ctrl.period = period; + /* Apply time offset */ + fwreq.ptp_gpio_ctrl.start = start - self->ptp_clk_offset; + + size = sizeof(fwreq.msg_id) + sizeof(fwreq.ptp_gpio_ctrl); + return self->aq_fw_ops->send_fw_request(self, &fwreq, size); +} + +static int hw_atl_b0_extts_gpio_enable(struct aq_hw_s *self, u32 index, + u32 enable) +{ + /* Enable/disable Sync1588 GPIO Timestamping */ + aq_phy_write_reg(self, MDIO_MMD_PCS, 0xc611, enable ? 0x71 : 0); + + return 0; +} + +static int hw_atl_b0_get_sync_ts(struct aq_hw_s *self, u64 *ts) +{ + u64 sec_l; + u64 sec_h; + u64 nsec_l; + u64 nsec_h; + + if (!ts) + return -1; + + /* PTP external GPIO clock seconds count 15:0 */ + sec_l = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc914); + /* PTP external GPIO clock seconds count 31:16 */ + sec_h = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc915); + /* PTP external GPIO clock nanoseconds count 15:0 */ + nsec_l = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc916); + /* PTP external GPIO clock nanoseconds count 31:16 */ + nsec_h = aq_phy_read_reg(self, MDIO_MMD_PCS, 0xc917); + + *ts = (nsec_h << 16) + nsec_l + ((sec_h << 16) + sec_l) * NSEC_PER_SEC; + + return 0; +} + static u16 hw_atl_b0_rx_extract_ts(struct aq_hw_s *self, u8 *p, unsigned int len, u64 *timestamp) { @@ -1416,8 +1474,11 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .hw_get_ptp_ts = hw_atl_b0_get_ptp_ts, .hw_adj_sys_clock = hw_atl_b0_adj_sys_clock, .hw_set_sys_clock = hw_atl_b0_set_sys_clock, + .hw_ts_to_sys_clock = hw_atl_b0_ts_to_sys_clock, .hw_adj_clock_freq = hw_atl_b0_adj_clock_freq, - + .hw_gpio_pulse = hw_atl_b0_gpio_pulse, + .hw_extts_gpio_enable = hw_atl_b0_extts_gpio_enable, + .hw_get_sync_ts = hw_atl_b0_get_sync_ts, .rx_extract_ts = hw_atl_b0_rx_extract_ts, .extract_hwts = hw_atl_b0_extract_hwts, .hw_set_offload = hw_atl_b0_hw_offload_set, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 77132bda4696..37e6b696009d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -288,6 +288,12 @@ struct __packed offload_info { }; /* Mailbox FW Request interface */ +struct __packed hw_fw_request_ptp_gpio_ctrl { + u32 index; + u32 period; + u64 start; +}; + struct __packed hw_fw_request_ptp_adj_freq { u32 ns_mac; u32 fns_mac; @@ -303,6 +309,7 @@ struct __packed hw_fw_request_ptp_adj_clock { int sign; }; +#define HW_AQ_FW_REQUEST_PTP_GPIO_CTRL 0x11 #define HW_AQ_FW_REQUEST_PTP_ADJ_FREQ 0x12 #define HW_AQ_FW_REQUEST_PTP_ADJ_CLOCK 0x13 @@ -310,6 +317,7 @@ struct __packed hw_fw_request_iface { u32 msg_id; union { /* PTP FW Request */ + struct hw_fw_request_ptp_gpio_ctrl ptp_gpio_ctrl; struct hw_fw_request_ptp_adj_freq ptp_adj_freq; struct hw_fw_request_ptp_adj_clock ptp_adj_clock; }; -- cgit v1.2.3-59-g8ed1b From 9b56beed1e8adc6b7b142bed5cf89531b9cf4a91 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Wed, 23 Oct 2019 12:08:40 +0300 Subject: fsl/fman: don't touch liodn base regs reserved on non-PAMU SoCs The liodn base registers are specific to PAMU based NXP systems and are reserved on SMMU based ones. Don't access them unless PAMU is compiled in. Signed-off-by: Laurentiu Tudor Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 210749bf1eac..934111def0be 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -634,6 +634,9 @@ static void set_port_liodn(struct fman *fman, u8 port_id, { u32 tmp; + iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + return; /* set LIODN base for this port */ tmp = ioread32be(&fman->dma_regs->fmdmplr[port_id / 2]); if (port_id % 2) { @@ -644,7 +647,6 @@ static void set_port_liodn(struct fman *fman, u8 port_id, tmp |= liodn_base << DMA_LIODN_SHIFT; } iowrite32be(tmp, &fman->dma_regs->fmdmplr[port_id / 2]); - iowrite32be(liodn_ofst, &fman->bmi_regs->fmbm_spliodn[port_id - 1]); } static void enable_rams_ecc(struct fman_fpm_regs __iomem *fpm_rg) @@ -1942,6 +1944,8 @@ static int fman_init(struct fman *fman) fman->liodn_offset[i] = ioread32be(&fman->bmi_regs->fmbm_spliodn[i - 1]); + if (!IS_ENABLED(CONFIG_FSL_PAMU)) + continue; liodn_base = ioread32be(&fman->dma_regs->fmdmplr[i / 2]); if (i % 2) { /* FMDM_PLR LSB holds LIODN base for odd ports */ -- cgit v1.2.3-59-g8ed1b From 5537b32985767632f0cba17706c2beb6ee76c089 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Wed, 23 Oct 2019 12:08:41 +0300 Subject: dpaa_eth: defer probing after qbman If the DPAA 1 Ethernet driver gets probed before the QBMan driver it will cause a boot crash. Add predictability in the probing order by deferring the Ethernet driver probe after QBMan and portals by using the recently introduced QBMan APIs. Signed-off-by: Laurentiu Tudor Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index b4b82b9c5cd6..75eeb2ef409f 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2773,6 +2773,37 @@ static int dpaa_eth_probe(struct platform_device *pdev) int err = 0, i, channel; struct device *dev; + err = bman_is_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(&pdev->dev, "failing probe due to bman probe error\n"); + return -ENODEV; + } + err = qman_is_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(&pdev->dev, "failing probe due to qman probe error\n"); + return -ENODEV; + } + err = bman_portals_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(&pdev->dev, + "failing probe due to bman portals probe error\n"); + return -ENODEV; + } + err = qman_portals_probed(); + if (!err) + return -EPROBE_DEFER; + if (err < 0) { + dev_err(&pdev->dev, + "failing probe due to qman portals probe error\n"); + return -ENODEV; + } + /* device used for DMA mapping */ dev = pdev->dev.parent; err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40)); -- cgit v1.2.3-59-g8ed1b From 1076aaeeeacfa998c71bfad42e5ac65b490fc456 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 23 Oct 2019 12:08:42 +0300 Subject: dpaa_eth: remove redundant code Condition was previously checked, removing duplicate code. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 75eeb2ef409f..8d5686d88d30 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -2304,10 +2304,6 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, return qman_cb_dqrr_consume; } - dpaa_bp = dpaa_bpid2pool(fd->bpid); - if (!dpaa_bp) - return qman_cb_dqrr_consume; - dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE); /* prefetch the first 64 bytes of the frame or the SGT start */ -- cgit v1.2.3-59-g8ed1b From 681e38380c79e6ed00232385a613b2216dc23d22 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Wed, 23 Oct 2019 12:08:43 +0300 Subject: fsl/fman: add API to get the device behind a fman port Add an API that retrieves the 'struct device' that the specified FMan port probed against. The new API will be used in a subsequent patch that corrects the DMA devices used by the dpaa_eth driver. Signed-off-by: Laurentiu Tudor Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman_port.c | 14 ++++++++++++++ drivers/net/ethernet/freescale/fman/fman_port.h | 2 ++ 2 files changed, 16 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index ee82ee1384eb..bd76c9730692 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -1728,6 +1728,20 @@ u32 fman_port_get_qman_channel_id(struct fman_port *port) } EXPORT_SYMBOL(fman_port_get_qman_channel_id); +/** + * fman_port_get_device + * port: Pointer to the FMan port device + * + * Get the 'struct device' associated to the specified FMan port device + * + * Return: pointer to associated 'struct device' + */ +struct device *fman_port_get_device(struct fman_port *port) +{ + return port->dev; +} +EXPORT_SYMBOL(fman_port_get_device); + int fman_port_get_hash_result_offset(struct fman_port *port, u32 *offset) { if (port->buffer_offsets.hash_result_offset == ILLEGAL_BASE) diff --git a/drivers/net/ethernet/freescale/fman/fman_port.h b/drivers/net/ethernet/freescale/fman/fman_port.h index 9dbb69f40121..82f12661a46d 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.h +++ b/drivers/net/ethernet/freescale/fman/fman_port.h @@ -157,4 +157,6 @@ int fman_port_get_tstamp(struct fman_port *port, const void *data, u64 *tstamp); struct fman_port *fman_port_bind(struct device *dev); +struct device *fman_port_get_device(struct fman_port *port); + #endif /* __FMAN_PORT_H */ -- cgit v1.2.3-59-g8ed1b From 060ad66f97954fa93ad495542c8a4f1b6c45aa34 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 23 Oct 2019 12:08:44 +0300 Subject: dpaa_eth: change DMA device The DPAA Ethernet driver is using the FMan MAC as the device for DMA mapping. This is not actually correct, as the real DMA device is the FMan port (the FMan Rx port for reception and the FMan Tx port for transmission). Changing the device used for DMA mapping to the Fman Rx and Tx port devices. Signed-off-by: Madalin Bucur Signed-off-by: Laurentiu Tudor Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 105 +++++++++++++------------ drivers/net/ethernet/freescale/dpaa/dpaa_eth.h | 8 +- 2 files changed, 62 insertions(+), 51 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 8d5686d88d30..e376c32fa003 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1335,15 +1335,15 @@ static void dpaa_fd_release(const struct net_device *net_dev, vaddr = phys_to_virt(qm_fd_addr(fd)); sgt = vaddr + qm_fd_get_offset(fd); - dma_unmap_single(dpaa_bp->dev, qm_fd_addr(fd), dpaa_bp->size, - DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, qm_fd_addr(fd), + dpaa_bp->size, DMA_FROM_DEVICE); dpaa_release_sgt_members(sgt); - addr = dma_map_single(dpaa_bp->dev, vaddr, dpaa_bp->size, - DMA_FROM_DEVICE); - if (dma_mapping_error(dpaa_bp->dev, addr)) { - dev_err(dpaa_bp->dev, "DMA mapping failed"); + addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, vaddr, + dpaa_bp->size, DMA_FROM_DEVICE); + if (dma_mapping_error(dpaa_bp->priv->rx_dma_dev, addr)) { + netdev_err(net_dev, "DMA mapping failed\n"); return; } bm_buffer_set64(&bmb, addr); @@ -1488,7 +1488,7 @@ return_error: static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp) { - struct device *dev = dpaa_bp->dev; + struct net_device *net_dev = dpaa_bp->priv->net_dev; struct bm_buffer bmb[8]; dma_addr_t addr; void *new_buf; @@ -1497,16 +1497,18 @@ static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp) for (i = 0; i < 8; i++) { new_buf = netdev_alloc_frag(dpaa_bp->raw_size); if (unlikely(!new_buf)) { - dev_err(dev, "netdev_alloc_frag() failed, size %zu\n", - dpaa_bp->raw_size); + netdev_err(net_dev, + "netdev_alloc_frag() failed, size %zu\n", + dpaa_bp->raw_size); goto release_previous_buffs; } new_buf = PTR_ALIGN(new_buf, SMP_CACHE_BYTES); - addr = dma_map_single(dev, new_buf, + addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, new_buf, dpaa_bp->size, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dpaa_bp->dev, "DMA map failed"); + if (unlikely(dma_mapping_error(dpaa_bp->priv->rx_dma_dev, + addr))) { + netdev_err(net_dev, "DMA map failed\n"); goto release_previous_buffs; } @@ -1634,7 +1636,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { nr_frags = skb_shinfo(skb)->nr_frags; - dma_unmap_single(dev, addr, + dma_unmap_single(priv->tx_dma_dev, addr, qm_fd_get_offset(fd) + DPAA_SGT_SIZE, dma_dir); @@ -1644,21 +1646,21 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, sgt = phys_to_virt(addr + qm_fd_get_offset(fd)); /* sgt[0] is from lowmem, was dma_map_single()-ed */ - dma_unmap_single(dev, qm_sg_addr(&sgt[0]), + dma_unmap_single(priv->tx_dma_dev, qm_sg_addr(&sgt[0]), qm_sg_entry_get_len(&sgt[0]), dma_dir); /* remaining pages were mapped with skb_frag_dma_map() */ for (i = 1; i <= nr_frags; i++) { WARN_ON(qm_sg_entry_is_ext(&sgt[i])); - dma_unmap_page(dev, qm_sg_addr(&sgt[i]), + dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[i]), qm_sg_entry_get_len(&sgt[i]), dma_dir); } /* Free the page frag that we allocated on Tx */ skb_free_frag(phys_to_virt(addr)); } else { - dma_unmap_single(dev, addr, + dma_unmap_single(priv->tx_dma_dev, addr, skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); } @@ -1762,8 +1764,8 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, goto free_buffers; count_ptr = this_cpu_ptr(dpaa_bp->percpu_count); - dma_unmap_single(dpaa_bp->dev, sg_addr, dpaa_bp->size, - DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, sg_addr, + dpaa_bp->size, DMA_FROM_DEVICE); if (!skb) { sz = dpaa_bp->size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); @@ -1853,7 +1855,6 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, int *offset) { struct net_device *net_dev = priv->net_dev; - struct device *dev = net_dev->dev.parent; enum dma_data_direction dma_dir; unsigned char *buffer_start; struct sk_buff **skbh; @@ -1889,9 +1890,9 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO); /* Map the entire buffer size that may be seen by FMan, but no more */ - addr = dma_map_single(dev, skbh, + addr = dma_map_single(priv->tx_dma_dev, skbh, skb_tail_pointer(skb) - buffer_start, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { if (net_ratelimit()) netif_err(priv, tx_err, net_dev, "dma_map_single() failed\n"); return -EINVAL; @@ -1907,7 +1908,6 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, const enum dma_data_direction dma_dir = DMA_TO_DEVICE; const int nr_frags = skb_shinfo(skb)->nr_frags; struct net_device *net_dev = priv->net_dev; - struct device *dev = net_dev->dev.parent; struct qm_sg_entry *sgt; struct sk_buff **skbh; int i, j, err, sz; @@ -1946,10 +1946,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; sgt[0].offset = 0; - addr = dma_map_single(dev, skb->data, + addr = dma_map_single(priv->tx_dma_dev, skb->data, skb_headlen(skb), dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sg0_map_failed; } @@ -1960,10 +1960,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, frag = &skb_shinfo(skb)->frags[i]; frag_len = skb_frag_size(frag); WARN_ON(!skb_frag_page(frag)); - addr = skb_frag_dma_map(dev, frag, 0, + addr = skb_frag_dma_map(priv->tx_dma_dev, frag, 0, frag_len, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sg_map_failed; } @@ -1986,10 +1986,10 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, skbh = (struct sk_buff **)buffer_start; *skbh = skb; - addr = dma_map_single(dev, buffer_start, + addr = dma_map_single(priv->tx_dma_dev, buffer_start, priv->tx_headroom + DPAA_SGT_SIZE, dma_dir); - if (unlikely(dma_mapping_error(dev, addr))) { - dev_err(dev, "DMA mapping failed"); + if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { + netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; goto sgt_map_failed; } @@ -2003,7 +2003,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, sgt_map_failed: sg_map_failed: for (j = 0; j < i; j++) - dma_unmap_page(dev, qm_sg_addr(&sgt[j]), + dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[j]), qm_sg_entry_get_len(&sgt[j]), dma_dir); sg0_map_failed: csum_failed: @@ -2304,7 +2304,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, return qman_cb_dqrr_consume; } - dma_unmap_single(dpaa_bp->dev, addr, dpaa_bp->size, DMA_FROM_DEVICE); + dma_unmap_single(dpaa_bp->priv->rx_dma_dev, addr, dpaa_bp->size, + DMA_FROM_DEVICE); /* prefetch the first 64 bytes of the frame or the SGT start */ vaddr = phys_to_virt(addr); @@ -2659,7 +2660,7 @@ static inline void dpaa_bp_free_pf(const struct dpaa_bp *bp, { dma_addr_t addr = bm_buf_addr(bmb); - dma_unmap_single(bp->dev, addr, bp->size, DMA_FROM_DEVICE); + dma_unmap_single(bp->priv->rx_dma_dev, addr, bp->size, DMA_FROM_DEVICE); skb_free_frag(phys_to_virt(addr)); } @@ -2769,25 +2770,27 @@ static int dpaa_eth_probe(struct platform_device *pdev) int err = 0, i, channel; struct device *dev; + dev = &pdev->dev; + err = bman_is_probed(); if (!err) return -EPROBE_DEFER; if (err < 0) { - dev_err(&pdev->dev, "failing probe due to bman probe error\n"); + dev_err(dev, "failing probe due to bman probe error\n"); return -ENODEV; } err = qman_is_probed(); if (!err) return -EPROBE_DEFER; if (err < 0) { - dev_err(&pdev->dev, "failing probe due to qman probe error\n"); + dev_err(dev, "failing probe due to qman probe error\n"); return -ENODEV; } err = bman_portals_probed(); if (!err) return -EPROBE_DEFER; if (err < 0) { - dev_err(&pdev->dev, + dev_err(dev, "failing probe due to bman portals probe error\n"); return -ENODEV; } @@ -2795,19 +2798,11 @@ static int dpaa_eth_probe(struct platform_device *pdev) if (!err) return -EPROBE_DEFER; if (err < 0) { - dev_err(&pdev->dev, + dev_err(dev, "failing probe due to qman portals probe error\n"); return -ENODEV; } - /* device used for DMA mapping */ - dev = pdev->dev.parent; - err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(40)); - if (err) { - dev_err(dev, "dma_coerce_mask_and_coherent() failed\n"); - return err; - } - /* Allocate this early, so we can store relevant information in * the private area */ @@ -2828,11 +2823,23 @@ static int dpaa_eth_probe(struct platform_device *pdev) mac_dev = dpaa_mac_dev_get(pdev); if (IS_ERR(mac_dev)) { - dev_err(dev, "dpaa_mac_dev_get() failed\n"); + netdev_err(net_dev, "dpaa_mac_dev_get() failed\n"); err = PTR_ERR(mac_dev); goto free_netdev; } + /* Devices used for DMA mapping */ + priv->rx_dma_dev = fman_port_get_device(mac_dev->port[RX]); + priv->tx_dma_dev = fman_port_get_device(mac_dev->port[TX]); + err = dma_coerce_mask_and_coherent(priv->rx_dma_dev, DMA_BIT_MASK(40)); + if (!err) + err = dma_coerce_mask_and_coherent(priv->tx_dma_dev, + DMA_BIT_MASK(40)); + if (err) { + netdev_err(net_dev, "dma_coerce_mask_and_coherent() failed\n"); + return err; + } + /* If fsl_fm_max_frm is set to a higher value than the all-common 1500, * we choose conservatively and let the user explicitly set a higher * MTU via ifconfig. Otherwise, the user may end up with different MTUs @@ -2859,7 +2866,7 @@ static int dpaa_eth_probe(struct platform_device *pdev) dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM); /* avoid runtime computations by keeping the usable size here */ dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size); - dpaa_bps[i]->dev = dev; + dpaa_bps[i]->priv = priv; err = dpaa_bp_alloc_pool(dpaa_bps[i]); if (err < 0) @@ -2982,7 +2989,7 @@ static int dpaa_remove(struct platform_device *pdev) struct device *dev; int err; - dev = pdev->dev.parent; + dev = &pdev->dev; net_dev = dev_get_drvdata(dev); priv = netdev_priv(net_dev); diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h index f7e59e8db075..1bdfead1d334 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h @@ -80,9 +80,11 @@ struct dpaa_fq_cbs { struct qman_fq egress_ern; }; +struct dpaa_priv; + struct dpaa_bp { - /* device used in the DMA mapping operations */ - struct device *dev; + /* used in the DMA mapping operations */ + struct dpaa_priv *priv; /* current number of buffers in the buffer pool alloted to each CPU */ int __percpu *percpu_count; /* all buffers allocated for this pool have this raw size */ @@ -153,6 +155,8 @@ struct dpaa_priv { u16 tx_headroom; struct net_device *net_dev; struct mac_device *mac_dev; + struct device *rx_dma_dev; + struct device *tx_dma_dev; struct qman_fq *egress_fqs[DPAA_ETH_TXQ_NUM]; struct qman_fq *conf_fqs[DPAA_ETH_TXQ_NUM]; -- cgit v1.2.3-59-g8ed1b From 2579bce4cf62980f8d4f6bf7d485da85dc677a91 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 23 Oct 2019 12:08:45 +0300 Subject: fsl/fman: remove unused struct member Remove unused struct member second_largest_buf_size. Also, an out of bounds access would have occurred in the removed code if there was only one buffer pool in use. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman_port.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fman/fman_port.c b/drivers/net/ethernet/freescale/fman/fman_port.c index bd76c9730692..87b26f063cc8 100644 --- a/drivers/net/ethernet/freescale/fman/fman_port.c +++ b/drivers/net/ethernet/freescale/fman/fman_port.c @@ -435,7 +435,6 @@ struct fman_port_cfg { struct fman_port_rx_pools_params { u8 num_of_pools; - u16 second_largest_buf_size; u16 largest_buf_size; }; @@ -946,8 +945,6 @@ static int set_ext_buffer_pools(struct fman_port *port) port->rx_pools_params.num_of_pools = ext_buf_pools->num_of_pools_used; port->rx_pools_params.largest_buf_size = sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 1]]; - port->rx_pools_params.second_largest_buf_size = - sizes_array[ordered_array[ext_buf_pools->num_of_pools_used - 2]]; /* FMBM_RMPD reg. - pool depletion */ if (buf_pool_depletion->pools_grp_mode_enable) { -- cgit v1.2.3-59-g8ed1b From 6e6583c91f947973b77995ffc487f7166c257911 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 23 Oct 2019 12:08:46 +0300 Subject: dpaa_eth: add newline in dev_err() msg Newline was missing at the end of the error message. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index e376c32fa003..d3214541c7c5 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -901,7 +901,7 @@ static void dpaa_fq_setup(struct dpaa_priv *priv, if (num_portals == 0) dev_err(priv->net_dev->dev.parent, - "No Qman software (affine) channels found"); + "No Qman software (affine) channels found\n"); /* Initialize each FQ in the list */ list_for_each_entry(fq, &priv->dpaa_fq_list, list) { -- cgit v1.2.3-59-g8ed1b From c03fe6d3b31c75e2d5903a668138adba71ac5241 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Mon, 8 Jul 2019 10:52:14 +0300 Subject: iwlwifi: dbg_ini: load external dbg cfg after internal cfg is loaded In the new API implementation the driver does not keep the internal and external debug configurations in separate structs so the last configuration that is loaded overrides the previous ones (this is true only in some of the TLVs e.g. the buffer allocation TLV). Load the external configuration after the internal is loaded so that user configuration will override the default coming with the FW. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index ff0519ea00a5..b0881e713b48 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1560,6 +1560,8 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) IWL_INFO(drv, "loaded firmware version %s op_mode %s\n", drv->fw.fw_version, op->name); + iwl_dbg_tlv_load_bin(drv->trans->dev, drv->trans); + /* add this device to the list of devices using this op_mode */ list_add_tail(&drv->list, &op->drv); @@ -1636,8 +1638,6 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) init_completion(&drv->request_firmware_complete); INIT_LIST_HEAD(&drv->list); - iwl_dbg_tlv_load_bin(drv->trans->dev, drv->trans); - #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the device debugfs entries. */ drv->dbgfs_drv = debugfs_create_dir(dev_name(trans->dev), -- cgit v1.2.3-59-g8ed1b From c9fe75e9f347044fda99a0da9c61983b153b8ed9 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 11:00:47 +0300 Subject: iwlwifi: dbg_ini: use new region TLV in dump flow Make dump flow use the new region TLV and update the region type enum. Temporarily remove monitor dumping support. Support will be readded in a future patch. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 142 +++++-- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 414 ++++++++------------- 2 files changed, 264 insertions(+), 292 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index ba586f148c14..dad0dea6725d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -219,18 +219,102 @@ struct iwl_fw_ini_region_cfg { } __packed; /* FW_DEBUG_TLV_REGION_CONFIG_API_S_VER_1 */ /** - * struct iwl_fw_ini_region_tlv - (IWL_UCODE_TLV_TYPE_REGIONS) - * defines memory regions to dump + * struct iwl_fw_ini_region_dev_addr - Configuration to read device addresses * - * @header: header - * @num_regions: how many different region section and IDs are coming next - * @region_config: list of dump configurations + * @size: size of each memory chunk + * @offset: offset to add to the base address of each chunk + */ +struct iwl_fw_ini_region_dev_addr { + __le32 size; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_DEVICE_ADDR_API_S_VER_1 */ + +/** + * struct iwl_fw_ini_region_fifos - Configuration to read Tx/Rx fifos + * + * @fid: fifos ids array. Used to determine what fifos to collect + * @hdr_only: if non zero, collect only the registers + * @offset: offset to add to the registers addresses + */ +struct iwl_fw_ini_region_fifos { + __le32 fid[2]; + __le32 hdr_only; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_REGION_FIFOS_API_S_VER_1 */ + +/** + * struct iwl_fw_ini_region_err_table - error table region data + * + * Configuration to read Umac/Lmac error table + * + * @version: version of the error table + * @base_addr: base address of the error table + * @size: size of the error table + * @offset: offset to add to &base_addr + */ +struct iwl_fw_ini_region_err_table { + __le32 version; + __le32 base_addr; + __le32 size; + __le32 offset; +} __packed; /* FW_TLV_DEBUG_REGION_ERROR_TABLE_API_S_VER_1 */ + +/** + * struct iwl_fw_ini_region_internal_buffer - internal buffer region data + * + * Configuration to read internal monitor buffer + * + * @alloc_id: allocation id one of &enum iwl_fw_ini_allocation_id + * @base_addr: internal buffer base address + * @size: size internal buffer size + */ +struct iwl_fw_ini_region_internal_buffer { + __le32 alloc_id; + __le32 base_addr; + __le32 size; +} __packed; /* FW_TLV_DEBUG_REGION_INTERNAL_BUFFER_API_S_VER_1 */ + +/** + * struct iwl_fw_ini_region_tlv - region TLV + * + * Configures parameters for region data collection + * + * @hdr: debug header + * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID + * @type: region type. One of &enum iwl_fw_ini_region_type + * @name: region name + * @dev_addr: device address configuration. Used by + * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, + * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, + * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, + * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and + * &IWL_FW_INI_REGION_RXF + * @err_table: error table configuration. Used by + * IWL_FW_INI_REGION_LMAC_ERROR_TABLE and + * IWL_FW_INI_REGION_UMAC_ERROR_TABLE + * @internal_buffer: internal monitor buffer configuration. Used by + * &IWL_FW_INI_REGION_INTERNAL_BUFFER + * @dram_alloc_id: dram allocation id. One of &enum iwl_fw_ini_allocation_id. + * Used by &IWL_FW_INI_REGION_DRAM_BUFFER + * @tlv_mask: tlv collection mask. Used by &IWL_FW_INI_REGION_TLV + * @addrs: array of addresses attached to the end of the region tlv */ struct iwl_fw_ini_region_tlv { - struct iwl_fw_ini_header header; - __le32 num_regions; - struct iwl_fw_ini_region_cfg region_config[]; -} __packed; /* FW_DEBUG_TLV_REGIONS_API_S_VER_1 */ + struct iwl_fw_ini_header hdr; + __le32 id; + __le32 type; + u8 name[IWL_FW_INI_MAX_NAME]; + union { + struct iwl_fw_ini_region_dev_addr dev_addr; + struct iwl_fw_ini_region_fifos fifos; + struct iwl_fw_ini_region_err_table err_table; + struct iwl_fw_ini_region_internal_buffer internal_buffer; + __le32 dram_alloc_id; + __le32 tlv_mask; + }; /* FW_TLV_DEBUG_REGION_CONF_PARAMS_API_U_VER_1 */ + __le32 addrs[]; +} __packed; /* FW_TLV_DEBUG_REGION_API_S_VER_1 */ /** * struct iwl_fw_ini_trigger @@ -452,42 +536,44 @@ enum iwl_fw_ini_debug_flow { * enum iwl_fw_ini_region_type * * @IWL_FW_INI_REGION_INVALID: invalid + * @IWL_FW_INI_REGION_TLV: uCode and debug TLVs + * @IWL_FW_INI_REGION_INTERNAL_BUFFER: monitor SMEM buffer + * @IWL_FW_INI_REGION_DRAM_BUFFER: monitor DRAM buffer + * @IWL_FW_INI_REGION_TXF: TX fifos + * @IWL_FW_INI_REGION_RXF: RX fifo + * @IWL_FW_INI_REGION_LMAC_ERROR_TABLE: lmac error table + * @IWL_FW_INI_REGION_UMAC_ERROR_TABLE: umac error table + * @IWL_FW_INI_REGION_RSP_OR_NOTIF: FW response or notification data * @IWL_FW_INI_REGION_DEVICE_MEMORY: device internal memory * @IWL_FW_INI_REGION_PERIPHERY_MAC: periphery registers of MAC * @IWL_FW_INI_REGION_PERIPHERY_PHY: periphery registers of PHY * @IWL_FW_INI_REGION_PERIPHERY_AUX: periphery registers of AUX - * @IWL_FW_INI_REGION_DRAM_BUFFER: DRAM buffer - * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory - * @IWL_FW_INI_REGION_INTERNAL_BUFFER: undefined - * @IWL_FW_INI_REGION_TXF: TX fifos - * @IWL_FW_INI_REGION_RXF: RX fifo * @IWL_FW_INI_REGION_PAGING: paging memory * @IWL_FW_INI_REGION_CSR: CSR registers - * @IWL_FW_INI_REGION_NOTIFICATION: FW notification data - * @IWL_FW_INI_REGION_DHC: dhc response to dump - * @IWL_FW_INI_REGION_LMAC_ERROR_TABLE: lmac error table - * @IWL_FW_INI_REGION_UMAC_ERROR_TABLE: umac error table + * @IWL_FW_INI_REGION_DRAM_IMR: IMR memory + * @IWL_FW_INI_REGION_PCI_IOSF_CONFIG: PCI/IOSF config * @IWL_FW_INI_REGION_NUM: number of region types */ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_INVALID, + IWL_FW_INI_REGION_TLV, + IWL_FW_INI_REGION_INTERNAL_BUFFER, + IWL_FW_INI_REGION_DRAM_BUFFER, + IWL_FW_INI_REGION_TXF, + IWL_FW_INI_REGION_RXF, + IWL_FW_INI_REGION_LMAC_ERROR_TABLE, + IWL_FW_INI_REGION_UMAC_ERROR_TABLE, + IWL_FW_INI_REGION_RSP_OR_NOTIF, IWL_FW_INI_REGION_DEVICE_MEMORY, IWL_FW_INI_REGION_PERIPHERY_MAC, IWL_FW_INI_REGION_PERIPHERY_PHY, IWL_FW_INI_REGION_PERIPHERY_AUX, - IWL_FW_INI_REGION_DRAM_BUFFER, - IWL_FW_INI_REGION_DRAM_IMR, - IWL_FW_INI_REGION_INTERNAL_BUFFER, - IWL_FW_INI_REGION_TXF, - IWL_FW_INI_REGION_RXF, IWL_FW_INI_REGION_PAGING, IWL_FW_INI_REGION_CSR, - IWL_FW_INI_REGION_NOTIFICATION, - IWL_FW_INI_REGION_DHC, - IWL_FW_INI_REGION_LMAC_ERROR_TABLE, - IWL_FW_INI_REGION_UMAC_ERROR_TABLE, + IWL_FW_INI_REGION_DRAM_IMR, + IWL_FW_INI_REGION_PCI_IOSF_CONFIG, IWL_FW_INI_REGION_NUM -}; /* FW_DEBUG_TLV_REGION_TYPE_E_VER_1 */ +}; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ /** * enum iwl_fw_ini_time_point diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 5c8602de9168..d279d4e96c1b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1054,19 +1054,29 @@ out: return dump_file; } +/** + * struct iwl_dump_ini_region_data - region data + * @reg_tlv: region TLV + */ +struct iwl_dump_ini_region_data { + struct iwl_ucode_tlv *reg_tlv; +}; + static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; u32 prph_val; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; - for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) { + 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 == 0x5a5a5a5a) return -EBUSY; @@ -1077,39 +1087,42 @@ static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; - for (i = 0; i < le32_to_cpu(reg->internal.range_data_size); i += 4) + range->range_data_size = reg->dev_addr.size; + for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) *val++ = cpu_to_le32(iwl_trans_read32(fwrt->trans, addr + i)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static int iwl_dump_ini_dev_mem_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; - u32 addr = le32_to_cpu(reg->start_addr[idx]) + le32_to_cpu(reg->offset); + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->internal.range_data_size; + range->range_data_size = reg->dev_addr.size; iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, - le32_to_cpu(reg->internal.range_data_size)); + le32_to_cpu(reg->dev_addr.size)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range_ptr, int idx) { /* increase idx by 1 since the pages are from 1 to @@ -1132,14 +1145,14 @@ static int _iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { struct iwl_fw_ini_error_dump_range *range; u32 page_size; if (!fwrt->trans->trans_cfg->gen2) - return _iwl_dump_ini_paging_iter(fwrt, reg, range_ptr, idx); + return _iwl_dump_ini_paging_iter(fwrt, range_ptr, idx); range = range_ptr; page_size = fwrt->trans->init_dram.paging[idx].size; @@ -1152,47 +1165,27 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } -static int -iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range_ptr, - int idx) -{ - struct iwl_fw_ini_error_dump_range *range = range_ptr; - u32 start_addr = iwl_read_umac_prph(fwrt->trans, - MON_BUFF_BASE_ADDR_VER2); - - if (start_addr == 0x5a5a5a5a) - return -EBUSY; - - range->dram_base_addr = cpu_to_le64(start_addr); - range->range_data_size = cpu_to_le32(fwrt->trans->dbg.fw_mon[idx].size); - - memcpy(range->data, fwrt->trans->dbg.fw_mon[idx].block, - fwrt->trans->dbg.fw_mon[idx].size); - - return sizeof(*range) + le32_to_cpu(range->range_data_size); -} - static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, int idx) + struct iwl_dump_ini_region_data *reg_data, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; struct iwl_fwrt_shared_mem_cfg *cfg = &fwrt->smem_cfg; int txf_num = cfg->num_txfifo_entries; int int_txf_num = ARRAY_SIZE(cfg->internal_txfifo_size); - u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid1); + u32 lmac_bitmap = le32_to_cpu(reg->fifos.fid[0]); if (!idx) { - if (le32_to_cpu(reg->offset) && - WARN_ONCE(cfg->num_lmacs == 1, - "Invalid lmac offset: 0x%x\n", - le32_to_cpu(reg->offset))) + if (le32_to_cpu(reg->fifos.offset) && cfg->num_lmacs == 1) { + IWL_ERR(fwrt, "WRT: Invalid lmac offset 0x%x\n", + le32_to_cpu(reg->fifos.offset)); return false; + } iter->internal_txf = 0; iter->fifo_size = 0; iter->fifo = -1; - if (le32_to_cpu(reg->offset)) + if (le32_to_cpu(reg->fifos.offset)) iter->lmac = 1; else iter->lmac = 0; @@ -1223,27 +1216,28 @@ static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data; - u32 offs = le32_to_cpu(reg->offset), addr; - u32 registers_size = - le32_to_cpu(reg->fifos.num_of_registers) * sizeof(*reg_dump); + u32 offs = le32_to_cpu(reg->fifos.offset), addr; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); + u32 registers_size = registers_num * sizeof(*reg_dump); __le32 *data; unsigned long flags; int i; - if (!iwl_ini_txf_iter(fwrt, reg, idx)) + if (!iwl_ini_txf_iter(fwrt, reg_data, idx)) return -EIO; if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) return -EBUSY; range->fifo_hdr.fifo_num = cpu_to_le32(iter->fifo); - range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers; + range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size); iwl_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo); @@ -1252,8 +1246,8 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, * read txf registers. for each register, write to the dump the * register address and its value */ - for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { - addr = le32_to_cpu(reg->start_addr[i]) + offs; + for (i = 0; i < registers_num; i++) { + addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, @@ -1262,7 +1256,7 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, reg_dump++; } - if (reg->fifos.header_only) { + if (reg->fifos.hdr_only) { range->range_data_size = cpu_to_le32(registers_size); goto out; } @@ -1293,11 +1287,12 @@ struct iwl_ini_rxf_data { }; static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, struct iwl_ini_rxf_data *data) { - u32 fid1 = le32_to_cpu(reg->fifos.fid1); - u32 fid2 = le32_to_cpu(reg->fifos.fid2); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 fid1 = le32_to_cpu(reg->fifos.fid[0]); + u32 fid2 = le32_to_cpu(reg->fifos.fid[1]); u32 fifo_idx; if (!data) @@ -1329,20 +1324,21 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, } static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, void *range_ptr, int idx) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; struct iwl_ini_rxf_data rxf_data; struct iwl_fw_ini_error_dump_register *reg_dump = (void *)range->data; - u32 offs = le32_to_cpu(reg->offset), addr; - u32 registers_size = - le32_to_cpu(reg->fifos.num_of_registers) * sizeof(*reg_dump); + u32 offs = le32_to_cpu(reg->fifos.offset), addr; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); + u32 registers_size = registers_num * sizeof(*reg_dump); __le32 *data; unsigned long flags; int i; - iwl_ini_get_rxf_data(fwrt, reg, &rxf_data); + iwl_ini_get_rxf_data(fwrt, reg_data, &rxf_data); if (!rxf_data.size) return -EIO; @@ -1350,15 +1346,15 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, return -EBUSY; range->fifo_hdr.fifo_num = cpu_to_le32(rxf_data.fifo_num); - range->fifo_hdr.num_of_registers = reg->fifos.num_of_registers; + range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(rxf_data.size + registers_size); /* * read rxf registers. for each register, write to the dump the * register address and its value */ - for (i = 0; i < le32_to_cpu(reg->fifos.num_of_registers); i++) { - addr = le32_to_cpu(reg->start_addr[i]) + offs; + for (i = 0; i < registers_num; i++) { + addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); reg_dump->data = cpu_to_le32(iwl_read_prph_no_grab(fwrt->trans, @@ -1367,7 +1363,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, reg_dump++; } - if (reg->fifos.header_only) { + if (reg->fifos.hdr_only) { range->range_data_size = cpu_to_le32(registers_size); goto out; } @@ -1398,9 +1394,10 @@ out: return sizeof(*range) + le32_to_cpu(range->range_data_size); } -static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) +static void * +iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) { struct iwl_fw_ini_error_dump *dump = data; @@ -1409,91 +1406,16 @@ static void *iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, return dump->ranges; } -static void -*iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - struct iwl_fw_ini_monitor_dump *data, - u32 write_ptr_addr, u32 write_ptr_msk, - u32 cycle_cnt_addr, u32 cycle_cnt_msk) -{ - u32 write_ptr, cycle_cnt; - unsigned long flags; - - if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) { - IWL_ERR(fwrt, "Failed to get monitor header\n"); - return NULL; - } - - write_ptr = iwl_read_prph_no_grab(fwrt->trans, write_ptr_addr); - cycle_cnt = iwl_read_prph_no_grab(fwrt->trans, cycle_cnt_addr); - - iwl_trans_release_nic_access(fwrt->trans, &flags); - - data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); - data->write_ptr = cpu_to_le32(write_ptr & write_ptr_msk); - data->cycle_cnt = cpu_to_le32(cycle_cnt & cycle_cnt_msk); - - return data->ranges; -} - -static void -*iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) -{ - struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; - u32 write_ptr_addr, write_ptr_msk, cycle_cnt_addr, cycle_cnt_msk; - - switch (fwrt->trans->trans_cfg->device_family) { - case IWL_DEVICE_FAMILY_9000: - case IWL_DEVICE_FAMILY_22000: - write_ptr_addr = MON_BUFF_WRPTR_VER2; - write_ptr_msk = -1; - cycle_cnt_addr = MON_BUFF_CYCLE_CNT_VER2; - cycle_cnt_msk = -1; - break; - default: - IWL_ERR(fwrt, "Unsupported device family %d\n", - fwrt->trans->trans_cfg->device_family); - return NULL; - } - - return iwl_dump_ini_mon_fill_header(fwrt, reg, mon_dump, write_ptr_addr, - write_ptr_msk, cycle_cnt_addr, - cycle_cnt_msk); -} - -static void -*iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, - void *data) -{ - struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; - const struct iwl_cfg *cfg = fwrt->trans->cfg; - - if (fwrt->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_9000 && - fwrt->trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22000) { - IWL_ERR(fwrt, "Unsupported device family %d\n", - fwrt->trans->trans_cfg->device_family); - return NULL; - } - - return iwl_dump_ini_mon_fill_header(fwrt, reg, mon_dump, - cfg->fw_mon_smem_write_ptr_addr, - cfg->fw_mon_smem_write_ptr_msk, - cfg->fw_mon_smem_cycle_cnt_ptr_addr, - cfg->fw_mon_smem_cycle_cnt_ptr_msk); - -} - static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { - return le32_to_cpu(reg->internal.num_of_ranges); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + + return iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); } static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { if (fwrt->trans->trans_cfg->gen2) return fwrt->trans->init_dram.paging_cnt; @@ -1501,54 +1423,52 @@ static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, return fwrt->num_of_paging_blk; } -static u32 iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) -{ - return 1; -} - static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { u32 num_of_fifos = 0; - while (iwl_ini_txf_iter(fwrt, reg, num_of_fifos)) + while (iwl_ini_txf_iter(fwrt, reg_data, num_of_fifos)) num_of_fifos++; return num_of_fifos; } -static u32 iwl_dump_ini_rxf_ranges(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 iwl_dump_ini_single_range(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { - /* Each Rx fifo needs a different offset and therefore, it's - * region can contain only one fifo, i.e. 1 memory range. - */ return 1; } static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { - return sizeof(struct iwl_fw_ini_error_dump) + - iwl_dump_ini_mem_ranges(fwrt, reg) * - (sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->internal.range_data_size)); + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 size = le32_to_cpu(reg->dev_addr.size); + u32 ranges = iwl_dump_ini_mem_ranges(fwrt, reg_data); + + if (!size || !ranges) + return 0; + + return sizeof(struct iwl_fw_ini_error_dump) + ranges * + (size + sizeof(struct iwl_fw_ini_error_dump_range)); } -static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) +static u32 +iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) { int i; u32 range_header_len = sizeof(struct iwl_fw_ini_error_dump_range); u32 size = sizeof(struct iwl_fw_ini_error_dump); if (fwrt->trans->trans_cfg->gen2) { - for (i = 0; i < iwl_dump_ini_paging_ranges(fwrt, reg); i++) + for (i = 0; i < iwl_dump_ini_paging_ranges(fwrt, reg_data); i++) size += range_header_len + fwrt->trans->init_dram.paging[i].size; } else { - for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg); i++) + for (i = 1; i <= iwl_dump_ini_paging_ranges(fwrt, reg_data); + i++) size += range_header_len + fwrt->fw_paging_db[i].fw_paging_size; } @@ -1556,61 +1476,43 @@ static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, return size; } -static u32 iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) -{ - u32 size = sizeof(struct iwl_fw_ini_monitor_dump) + - sizeof(struct iwl_fw_ini_error_dump_range); - - if (fwrt->trans->dbg.num_blocks) - size += fwrt->trans->dbg.fw_mon[0].size; - - return size; -} - -static u32 iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) -{ - return sizeof(struct iwl_fw_ini_monitor_dump) + - iwl_dump_ini_mem_ranges(fwrt, reg) * - (sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->internal.range_data_size)); -} - static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_txf_iter_data *iter = &fwrt->dump.txf_iter_data; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); u32 size = 0; u32 fifo_hdr = sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->fifos.num_of_registers) * - sizeof(struct iwl_fw_ini_error_dump_register); + registers_num * + sizeof(struct iwl_fw_ini_error_dump_register); - while (iwl_ini_txf_iter(fwrt, reg, size)) { + while (iwl_ini_txf_iter(fwrt, reg_data, size)) { size += fifo_hdr; - if (!reg->fifos.header_only) + if (!reg->fifos.hdr_only) size += iter->fifo_size; } - if (size) - size += sizeof(struct iwl_fw_ini_error_dump); + if (!size) + return 0; - return size; + return size + sizeof(struct iwl_fw_ini_error_dump); } static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg) + struct iwl_dump_ini_region_data *reg_data) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_ini_rxf_data rx_data; + u32 registers_num = iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); u32 size = sizeof(struct iwl_fw_ini_error_dump) + sizeof(struct iwl_fw_ini_error_dump_range) + - le32_to_cpu(reg->fifos.num_of_registers) * - sizeof(struct iwl_fw_ini_error_dump_register); + registers_num * sizeof(struct iwl_fw_ini_error_dump_register); - if (reg->fifos.header_only) + if (reg->fifos.hdr_only) return size; - iwl_ini_get_rxf_data(fwrt, reg, &rx_data); + iwl_ini_get_rxf_data(fwrt, reg_data, &rx_data); size += rx_data.size; return size; @@ -1627,14 +1529,15 @@ static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, */ struct iwl_dump_ini_mem_ops { u32 (*get_num_of_ranges)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg); + struct iwl_dump_ini_region_data *reg_data); u32 (*get_size)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg); + struct iwl_dump_ini_region_data *reg_data); void *(*fill_mem_hdr)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *data); + struct iwl_dump_ini_region_data *reg_data, + void *data); int (*fill_range)(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_region_cfg *reg, void *range, - int idx); + struct iwl_dump_ini_region_data *reg_data, + void *range, int idx); }; /** @@ -1649,20 +1552,22 @@ struct iwl_dump_ini_mem_ops { * @ops: memory dump operations */ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, - struct iwl_fw_ini_region_cfg *reg, + struct iwl_dump_ini_region_data *reg_data, const struct iwl_dump_ini_mem_ops *ops) { + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_error_dump_data *tlv; struct iwl_fw_ini_error_dump_header *header; - u32 num_of_ranges, i, type = le32_to_cpu(reg->region_type), size; + u32 type = le32_to_cpu(reg->type), id = le32_to_cpu(reg->id); + u32 num_of_ranges, i, size; void *range; if (!ops->get_num_of_ranges || !ops->get_size || !ops->fill_mem_hdr || !ops->fill_range) return 0; - size = ops->get_size(fwrt, reg); + size = ops->get_size(fwrt, reg_data); if (!size) return 0; @@ -1673,36 +1578,35 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, entry->size = sizeof(*tlv) + size; tlv = (void *)entry->data; - tlv->type = cpu_to_le32(type); + tlv->type = reg->type; tlv->len = cpu_to_le32(size); - IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + IWL_DEBUG_FW(fwrt, "WRT: Collecting region: id=%d, type=%d\n", id, + type); - num_of_ranges = ops->get_num_of_ranges(fwrt, reg); + num_of_ranges = ops->get_num_of_ranges(fwrt, reg_data); header = (void *)tlv->data; - header->region_id = reg->region_id; + header->region_id = reg->id; header->num_of_ranges = cpu_to_le32(num_of_ranges); - header->name_len = cpu_to_le32(min_t(int, IWL_FW_INI_MAX_NAME, - le32_to_cpu(reg->name_len))); - memcpy(header->name, reg->name, le32_to_cpu(header->name_len)); + header->name_len = cpu_to_le32(IWL_FW_INI_MAX_NAME); + memcpy(header->name, reg->name, IWL_FW_INI_MAX_NAME); - range = ops->fill_mem_hdr(fwrt, reg, header); + range = ops->fill_mem_hdr(fwrt, reg_data, header); if (!range) { IWL_ERR(fwrt, "WRT: Failed to fill region header: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + id, type); goto out_err; } for (i = 0; i < num_of_ranges; i++) { - int range_size = ops->fill_range(fwrt, reg, range, i); + int range_size = ops->fill_range(fwrt, reg_data, range, i); if (range_size < 0) { IWL_ERR(fwrt, "WRT: Failed to dump region: id=%d, type=%d\n", - le32_to_cpu(reg->region_id), type); + id, type); goto out_err; } range = range + range_size; @@ -1793,6 +1697,23 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { [IWL_FW_INI_REGION_INVALID] = {}, + [IWL_FW_INI_REGION_INTERNAL_BUFFER] = {}, + [IWL_FW_INI_REGION_DRAM_BUFFER] = {}, + [IWL_FW_INI_REGION_TXF] = { + .get_num_of_ranges = iwl_dump_ini_txf_ranges, + .get_size = iwl_dump_ini_txf_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_txf_iter, + }, + [IWL_FW_INI_REGION_RXF] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_rxf_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_rxf_iter, + }, + [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = {}, + [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = {}, + [IWL_FW_INI_REGION_RSP_OR_NOTIF] = {}, [IWL_FW_INI_REGION_DEVICE_MEMORY] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, @@ -1807,31 +1728,6 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { }, [IWL_FW_INI_REGION_PERIPHERY_PHY] = {}, [IWL_FW_INI_REGION_PERIPHERY_AUX] = {}, - [IWL_FW_INI_REGION_DRAM_BUFFER] = { - .get_num_of_ranges = iwl_dump_ini_mon_dram_ranges, - .get_size = iwl_dump_ini_mon_dram_get_size, - .fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header, - .fill_range = iwl_dump_ini_mon_dram_iter, - }, - [IWL_FW_INI_REGION_DRAM_IMR] = {}, - [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mon_smem_get_size, - .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, - }, - [IWL_FW_INI_REGION_TXF] = { - .get_num_of_ranges = iwl_dump_ini_txf_ranges, - .get_size = iwl_dump_ini_txf_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_txf_iter, - }, - [IWL_FW_INI_REGION_RXF] = { - .get_num_of_ranges = iwl_dump_ini_rxf_ranges, - .get_size = iwl_dump_ini_rxf_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_rxf_iter, - }, [IWL_FW_INI_REGION_PAGING] = { .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .get_num_of_ranges = iwl_dump_ini_paging_ranges, @@ -1844,26 +1740,16 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_csr_iter, }, - [IWL_FW_INI_REGION_NOTIFICATION] = {}, - [IWL_FW_INI_REGION_DHC] = {}, - [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mem_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, - }, - [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = { - .get_num_of_ranges = iwl_dump_ini_mem_ranges, - .get_size = iwl_dump_ini_mem_get_size, - .fill_mem_hdr = iwl_dump_ini_mem_fill_header, - .fill_range = iwl_dump_ini_dev_mem_iter, - }, + [IWL_FW_INI_REGION_DRAM_IMR] = {}, + [IWL_FW_INI_REGION_PCI_IOSF_CONFIG] = {}, }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_trigger *trigger, struct list_head *list) { + struct iwl_dump_ini_mem_ops empty_ops = {}; + struct iwl_dump_ini_region_data reg_data = {}; int i; u32 size = 0; @@ -1890,8 +1776,8 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; - size += iwl_dump_ini_mem(fwrt, list, reg, - &iwl_dump_ini_region_ops[reg_type]); + size += iwl_dump_ini_mem(fwrt, list, ®_data, + &empty_ops); } if (size) -- cgit v1.2.3-59-g8ed1b From 3b589d5624ce9f62b2bdca4223d0b41dcce48be3 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 11:38:36 +0300 Subject: iwlwifi: dbg_ini: use new trigger TLV in dump flow Make dump flow use the new trigger TLV. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 37 +++-- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 177 ++++++++------------- drivers/net/wireless/intel/iwlwifi/fw/dbg.h | 47 ++---- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 11 +- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 29 +++- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 3 + 6 files changed, 143 insertions(+), 161 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index dad0dea6725d..073a729cd4db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -351,18 +351,37 @@ struct iwl_fw_ini_trigger { } __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_API_S_VER_1 */ /** - * struct iwl_fw_ini_trigger_tlv - (IWL_UCODE_TLV_TYPE_TRIGGERS) - * Triggers that hold memory regions to dump in case a trigger fires + * struct iwl_fw_ini_trigger_tlv - trigger TLV * - * @header: header - * @num_triggers: how many different triggers section and IDs are coming next - * @trigger_config: list of trigger configurations + * Trigger that upon firing, determines what regions to collect + * + * @hdr: debug header + * @time_point: time point. One of &enum iwl_fw_ini_time_point + * @trigger_reason: trigger reason + * @apply_policy: uses &enum iwl_fw_ini_trigger_apply_policy + * @dump_delay: delay from trigger fire to dump, in usec + * @occurrences: max trigger fire occurrences allowed + * @reserved: unused + * @ignore_consec: ignore consecutive triggers, in usec + * @reset_fw: if non zero, will reset and reload the FW + * @multi_dut: initiate debug dump data on several DUTs + * @regions_mask: mask of regions to collect + * @data: trigger data */ struct iwl_fw_ini_trigger_tlv { - struct iwl_fw_ini_header header; - __le32 num_triggers; - struct iwl_fw_ini_trigger trigger_config[]; -} __packed; /* FW_TLV_DEBUG_TRIGGERS_API_S_VER_1 */ + struct iwl_fw_ini_header hdr; + __le32 time_point; + __le32 trigger_reason; + __le32 apply_policy; + __le32 dump_delay; + __le32 occurrences; + __le32 reserved; + __le32 ignore_consec; + __le32 reset_fw; + __le32 multi_dut; + __le64 regions_mask; + __le32 data[]; +} __packed; /* FW_TLV_DEBUG_TRIGGER_API_S_VER_1 */ #define IWL_FW_INI_MAX_IMG_NAME_LEN 32 #define IWL_FW_INI_MAX_DBG_CFG_NAME_LEN 64 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index d279d4e96c1b..b52ad6f050bd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1623,14 +1623,13 @@ out_err: } static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_trigger *trigger, + struct iwl_fw_ini_trigger_tlv *trigger, struct list_head *list) { struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_error_dump_data *tlv; struct iwl_fw_ini_dump_info *dump; - u32 reg_ids_size = le32_to_cpu(trigger->num_regions) * sizeof(__le32); - u32 size = sizeof(*tlv) + sizeof(*dump) + reg_ids_size; + u32 size = sizeof(*tlv) + sizeof(*dump); entry = kmalloc(sizeof(*entry) + size, GFP_KERNEL); if (!entry) @@ -1640,13 +1639,14 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, tlv = (void *)entry->data; tlv->type = cpu_to_le32(IWL_INI_DUMP_INFO_TYPE); - tlv->len = cpu_to_le32(sizeof(*dump) + reg_ids_size); + tlv->len = cpu_to_le32(size - sizeof(*tlv)); dump = (void *)tlv->data; dump->version = cpu_to_le32(IWL_INI_DUMP_VER); - dump->trigger_id = trigger->trigger_id; - dump->is_external_cfg = + dump->time_point = trigger->time_point; + dump->trigger_reason = trigger->trigger_reason; + dump->external_cfg_state = cpu_to_le32(fwrt->trans->dbg.external_ini_cfg); dump->ver_type = cpu_to_le32(fwrt->dump.fw_ver.type); @@ -1670,23 +1670,6 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, memcpy(dump->build_tag, fwrt->fw->human_readable, sizeof(dump->build_tag)); - dump->img_name_len = cpu_to_le32(sizeof(dump->img_name)); - memcpy(dump->img_name, fwrt->dump.img_name, sizeof(dump->img_name)); - - dump->internal_dbg_cfg_name_len = - cpu_to_le32(sizeof(dump->internal_dbg_cfg_name)); - memcpy(dump->internal_dbg_cfg_name, fwrt->dump.internal_dbg_cfg_name, - sizeof(dump->internal_dbg_cfg_name)); - - dump->external_dbg_cfg_name_len = - cpu_to_le32(sizeof(dump->external_dbg_cfg_name)); - - memcpy(dump->external_dbg_cfg_name, fwrt->dump.external_dbg_cfg_name, - sizeof(dump->external_dbg_cfg_name)); - - dump->regions_num = trigger->num_regions; - memcpy(dump->region_ids, trigger->data, reg_ids_size); - /* add dump info TLV to the beginning of the list since it needs to be * the first TLV in the dump */ @@ -1745,39 +1728,36 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, - struct iwl_fw_ini_trigger *trigger, + struct iwl_fwrt_dump_data *dump_data, struct list_head *list) { - struct iwl_dump_ini_mem_ops empty_ops = {}; + struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig; struct iwl_dump_ini_region_data reg_data = {}; int i; u32 size = 0; + u64 regions_mask = le64_to_cpu(trigger->regions_mask); - for (i = 0; i < le32_to_cpu(trigger->num_regions); i++) { - u32 reg_id = le32_to_cpu(trigger->data[i]), reg_type; - struct iwl_fw_ini_region_cfg *reg; + for (i = 0; i < 64; i++) { + u32 reg_type; + struct iwl_fw_ini_region_tlv *reg; - if (WARN_ON(reg_id >= ARRAY_SIZE(fwrt->dump.active_regs))) + if (!(BIT_ULL(i) & regions_mask)) continue; - reg = fwrt->dump.active_regs[reg_id]; - if (!reg) { + reg_data.reg_tlv = fwrt->trans->dbg.active_regions[i]; + if (!reg_data.reg_tlv) { IWL_WARN(fwrt, - "WRT: Unassigned region id %d, skipping\n", - reg_id); + "WRT: Unassigned region id %d, skipping\n", i); continue; } - /* currently the driver supports always on domain only */ - if (le32_to_cpu(reg->domain) != IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON) - continue; - - reg_type = le32_to_cpu(reg->region_type); + reg = (void *)reg_data.reg_tlv->data; + reg_type = le32_to_cpu(reg->type); if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; size += iwl_dump_ini_mem(fwrt, list, ®_data, - &empty_ops); + &iwl_dump_ini_region_ops[reg_type]); } if (size) @@ -1786,20 +1766,32 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, return size; } +static bool iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt, + struct iwl_fw_ini_trigger_tlv *trig) +{ + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); + u32 usec = le32_to_cpu(trig->ignore_consec); + + if (!iwl_trans_dbg_ini_valid(fwrt->trans) || + tp_id == IWL_FW_INI_TIME_POINT_INVALID || + tp_id >= IWL_FW_INI_TIME_POINT_NUM || + iwl_fw_dbg_no_trig_window(fwrt, tp_id, usec)) + return false; + + return true; +} + static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id trig_id, + struct iwl_fwrt_dump_data *dump_data, struct list_head *list) { + struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig; struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_ini_dump_file_hdr *hdr; - struct iwl_fw_ini_trigger *trigger; u32 size; - if (!iwl_fw_ini_trigger_on(fwrt, trig_id)) - return 0; - - trigger = fwrt->dump.active_trigs[trig_id].trig; - if (!trigger || !le32_to_cpu(trigger->num_regions)) + if (!trigger || !iwl_fw_ini_trigger_on(fwrt, trigger) || + !le64_to_cpu(trigger->regions_mask)) return 0; entry = kmalloc(sizeof(*entry) + sizeof(*hdr), GFP_KERNEL); @@ -1808,7 +1800,7 @@ static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, entry->size = sizeof(*hdr); - size = iwl_dump_ini_trigger(fwrt, trigger, list); + size = iwl_dump_ini_trigger(fwrt, dump_data, list); if (!size) { kfree(entry); return 0; @@ -1880,14 +1872,18 @@ static void iwl_dump_ini_list_free(struct list_head *list) } } -static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx) +static void iwl_fw_error_dump_data_free(struct iwl_fwrt_dump_data *dump_data) +{ + dump_data->trig = NULL; +} + +static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data) { - enum iwl_fw_ini_trigger_id trig_id = fwrt->dump.wks[wk_idx].ini_trig_id; struct list_head dump_list = LIST_HEAD_INIT(dump_list); struct scatterlist *sg_dump_data; - u32 file_len; + u32 file_len = iwl_dump_ini_file_gen(fwrt, dump_data, &dump_list); - file_len = iwl_dump_ini_file_gen(fwrt, trig_id, &dump_list); if (!file_len) goto out; @@ -1908,7 +1904,7 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, u8 wk_idx) iwl_dump_ini_list_free(&dump_list); out: - fwrt->dump.wks[wk_idx].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID; + iwl_fw_error_dump_data_free(dump_data); } const struct iwl_fw_dump_desc iwl_dump_desc_assert = { @@ -1923,15 +1919,9 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, bool monitor_only, unsigned int delay) { - u32 trig_type = le32_to_cpu(desc->trig_desc.type); - int ret; - if (iwl_trans_dbg_ini_valid(fwrt->trans)) { - ret = iwl_fw_dbg_ini_collect(fwrt, trig_type); - if (!ret) - iwl_fw_free_dump_desc(fwrt); - - return ret; + iwl_fw_free_dump_desc(fwrt); + return 0; } /* use wks[0] since dump flow prior to ini does not need to support @@ -2023,35 +2013,26 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); -int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id) +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data) { - struct iwl_fw_ini_active_triggers *active; + struct iwl_fw_ini_trigger_tlv *trig = dump_data->trig; + enum iwl_fw_ini_time_point tp_id = le32_to_cpu(trig->time_point); u32 occur, delay; unsigned long idx; - if (WARN_ON(!iwl_fw_ini_trigger_on(fwrt, id))) - return -EINVAL; - - if (!iwl_fw_ini_trigger_on(fwrt, id)) { + if (!iwl_fw_ini_trigger_on(fwrt, trig)) { IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", - id); + tp_id); return -EINVAL; } - active = &fwrt->dump.active_trigs[id]; - delay = le32_to_cpu(active->trig->dump_delay); - occur = le32_to_cpu(active->trig->occurrences); + delay = le32_to_cpu(trig->dump_delay); + occur = le32_to_cpu(trig->occurrences); if (!occur) return 0; - active->trig->occurrences = cpu_to_le32(--occur); - - if (le32_to_cpu(active->trig->force_restart)) { - IWL_WARN(fwrt, "WRT: Force restart: trigger %d fired.\n", id); - iwl_force_nmi(fwrt->trans); - return 0; - } + trig->occurrences = cpu_to_le32(--occur); /* Check there is an available worker. * ffz return value is undefined if no zero exists, @@ -2066,36 +2047,14 @@ int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, test_and_set_bit(fwrt->dump.wks[idx].idx, &fwrt->dump.active_wks)) return -EBUSY; - fwrt->dump.wks[idx].ini_trig_id = id; + fwrt->dump.wks[idx].dump_data = *dump_data; - IWL_WARN(fwrt, "WRT: Collecting data: ini trigger %d fired.\n", id); + IWL_WARN(fwrt, "WRT: Collecting data: ini trigger %d fired.\n", tp_id); schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); return 0; } -IWL_EXPORT_SYMBOL(_iwl_fw_dbg_ini_collect); - -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, u32 legacy_trigger_id) -{ - int id; - - switch (legacy_trigger_id) { - case FW_DBG_TRIGGER_FW_ASSERT: - case FW_DBG_TRIGGER_ALIVE_TIMEOUT: - case FW_DBG_TRIGGER_DRIVER: - id = IWL_FW_TRIGGER_ID_FW_ASSERT; - break; - case FW_DBG_TRIGGER_USER: - id = IWL_FW_TRIGGER_ID_USER_TRIGGER; - break; - default: - return -EIO; - } - - return _iwl_fw_dbg_ini_collect(fwrt, id); -} -IWL_EXPORT_SYMBOL(iwl_fw_dbg_ini_collect); int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, @@ -2104,6 +2063,9 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, int ret, len = 0; char buf[64]; + if (iwl_trans_dbg_ini_valid(fwrt->trans)) + return 0; + if (fmt) { va_list ap; @@ -2207,7 +2169,7 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n"); if (iwl_trans_dbg_ini_valid(fwrt->trans)) - iwl_fw_error_ini_dump(fwrt, wk_idx); + iwl_fw_error_ini_dump(fwrt, &fwrt->dump.wks[wk_idx].dump_data); else iwl_fw_error_dump(fwrt); IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection done\n"); @@ -2220,11 +2182,10 @@ out: void iwl_fw_error_dump_wk(struct work_struct *work) { - struct iwl_fw_runtime *fwrt; - typeof(fwrt->dump.wks[0]) *wks; - - wks = container_of(work, typeof(fwrt->dump.wks[0]), wk.work); - fwrt = container_of(wks, struct iwl_fw_runtime, dump.wks[wks->idx]); + struct iwl_fwrt_wk_data *wks = + container_of(work, typeof(*wks), wk.work); + struct iwl_fw_runtime *fwrt = + container_of(wks, typeof(*fwrt), dump.wks[wks->idx]); /* assumes the op mode mutex is locked in dump_start since * iwl_fw_dbg_collect_sync can't run in parallel diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index e3b5dd34643f..179f2905d56b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -114,9 +114,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, bool monitor_only, unsigned int delay); int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig_type); -int _iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id); -int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, u32 legacy_trigger_id); +int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data); int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig, const char *str, size_t len, struct iwl_fw_dbg_trigger_tlv *trigger); @@ -222,29 +221,6 @@ _iwl_fw_dbg_trigger_on(struct iwl_fw_runtime *fwrt, _iwl_fw_dbg_trigger_on((fwrt), (wdev), (id)); \ }) -static inline bool -iwl_fw_ini_trigger_on(struct iwl_fw_runtime *fwrt, - enum iwl_fw_ini_trigger_id id) -{ - struct iwl_fw_ini_trigger *trig; - u32 usec; - - if (!iwl_trans_dbg_ini_valid(fwrt->trans) || - id == IWL_FW_TRIGGER_ID_INVALID || id >= IWL_FW_TRIGGER_ID_NUM || - !fwrt->dump.active_trigs[id].active) - return false; - - trig = fwrt->dump.active_trigs[id].trig; - usec = le32_to_cpu(trig->ignore_consec); - - if (iwl_fw_dbg_no_trig_window(fwrt, id, usec)) { - IWL_WARN(fwrt, "Trigger %d fired in no-collect window\n", id); - return false; - } - - return true; -} - static inline void _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt, struct wireless_dev *wdev, @@ -315,10 +291,8 @@ static inline void iwl_fw_flush_dumps(struct iwl_fw_runtime *fwrt) int i; iwl_dbg_tlv_del_timers(fwrt->trans); - for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) { + for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) flush_delayed_work(&fwrt->dump.wks[i].wk); - fwrt->dump.wks[i].ini_trig_id = IWL_FW_TRIGGER_ID_INVALID; - } } #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -381,12 +355,21 @@ static inline void iwl_fw_umac_set_alive_err_table(struct iwl_trans *trans, static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt) { - if (iwl_trans_dbg_ini_valid(fwrt->trans) && fwrt->trans->dbg.hw_error) { - _iwl_fw_dbg_ini_collect(fwrt, IWL_FW_TRIGGER_ID_FW_HW_ERROR); + enum iwl_fw_ini_time_point tp_id; + + if (!iwl_trans_dbg_ini_valid(fwrt->trans)) { + iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0); + return; + } + + if (fwrt->trans->dbg.hw_error) { + tp_id = IWL_FW_INI_TIME_POINT_FW_HW_ERROR; fwrt->trans->dbg.hw_error = false; } else { - iwl_fw_dbg_collect_desc(fwrt, &iwl_dump_desc_assert, false, 0); + tp_id = IWL_FW_INI_TIME_POINT_FW_ASSERT; } + + iwl_dbg_tlv_time_point(fwrt, tp_id, NULL); } void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 2e763678dbdb..2ccf04dacd52 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -381,10 +381,9 @@ struct iwl_fw_ini_error_dump_register { /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version - * @trigger_id: trigger id that caused the dump collection - * @trigger_reason: not supported yet - * @is_external_cfg: 1 if an external debug configuration was loaded - * and 0 otherwise + * @time_point: time point that caused the dump collection + * @trigger_reason: reason of the trigger + * @external_cfg_state: &enum iwl_ini_cfg_state * @ver_type: FW version type * @ver_subtype: FW version subype * @hw_step: HW step @@ -410,9 +409,9 @@ struct iwl_fw_ini_error_dump_register { */ struct iwl_fw_ini_dump_info { __le32 version; - __le32 trigger_id; + __le32 time_point; __le32 trigger_reason; - __le32 is_external_cfg; + __le32 external_cfg_state; __le32 ver_type; __le32 ver_subtype; __le32 hw_step; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index be436c18a047..f3c56a2c2531 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -90,6 +90,27 @@ struct iwl_fwrt_shared_mem_cfg { #define IWL_FW_RUNTIME_DUMP_WK_NUM 5 +/** + * struct iwl_fwrt_dump_data - dump data + * @trig: trigger the worker was scheduled upon + * @fw_pkt: packet received from FW + */ +struct iwl_fwrt_dump_data { + struct iwl_fw_ini_trigger_tlv *trig; + struct iwl_rx_packet *fw_pkt; +}; + +/** + * struct iwl_fwrt_wk_data - dump worker data struct + * @idx: index of the worker + * @wk: worker + */ +struct iwl_fwrt_wk_data { + u8 idx; + struct delayed_work wk; + struct iwl_fwrt_dump_data dump_data; +}; + /** * struct iwl_txf_iter_data - Tx fifo iterator data struct * @fifo: fifo number @@ -141,17 +162,13 @@ struct iwl_fw_runtime { struct { const struct iwl_fw_dump_desc *desc; bool monitor_only; - struct { - u8 idx; - enum iwl_fw_ini_trigger_id ini_trig_id; - struct delayed_work wk; - } wks[IWL_FW_RUNTIME_DUMP_WK_NUM]; + struct iwl_fwrt_wk_data wks[IWL_FW_RUNTIME_DUMP_WK_NUM]; unsigned long active_wks; u8 conf; /* ts of the beginning of a non-collect fw dbg data period */ - unsigned long non_collect_ts_start[IWL_FW_TRIGGER_ID_NUM]; + unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM]; u32 *d3_debug_data; struct iwl_fw_ini_region_cfg *active_regs[IWL_FW_INI_MAX_REGION_ID]; struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM]; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index a31408188ed0..b1fb17515398 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -710,6 +710,7 @@ struct iwl_self_init_dram { * @fw_mon: address of the buffers for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location + * @active_regions: active regions */ struct iwl_trans_debug { u8 n_dest_reg; @@ -731,6 +732,8 @@ struct iwl_trans_debug { bool hw_error; enum iwl_fw_ini_buffer_location ini_dest; + + struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID]; }; /** -- cgit v1.2.3-59-g8ed1b From 69f0e5059b09613ccba74cef831f2560b2a7affe Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Mon, 22 Jul 2019 15:31:13 +0300 Subject: iwlwifi: dbg: remove multi buffers infra Legacy DRAM monitor does not support multi buffers. Remove this infra. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 6 +- .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 13 +-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 112 +++++++++------------ 3 files changed, 56 insertions(+), 75 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index b1fb17515398..640530371194 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -706,8 +706,7 @@ struct iwl_self_init_dram { * pointers was recevied via TLV. uses enum &iwl_error_event_table_status * @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state * @external_ini_cfg: external debug cfg state. Uses &enum iwl_ini_cfg_state - * @num_blocks: number of blocks in fw_mon - * @fw_mon: address of the buffers for firmware monitor + * @fw_mon: DRAM buffer for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location * @active_regions: active regions @@ -727,8 +726,7 @@ struct iwl_trans_debug { enum iwl_ini_cfg_state internal_ini_cfg; enum iwl_ini_cfg_state external_ini_cfg; - int num_blocks; - struct iwl_dram_data fw_mon[IWL_FW_INI_ALLOCATION_NUM]; + struct iwl_dram_data fw_mon; bool hw_error; enum iwl_fw_ini_buffer_location ini_dest; 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 75fa8a6aafee..2c8ce41718a2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -96,13 +96,14 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, cpu_to_le64(trans_pcie->rxq->bd_dma); /* Configure debug, for integration */ - if (!iwl_trans_dbg_ini_valid(trans)) + if (iwl_trans_dbg_ini_valid(trans)) { iwl_pcie_alloc_fw_monitor(trans, 0); - if (trans->dbg.num_blocks) { - prph_sc_ctrl->hwm_cfg.hwm_base_addr = - cpu_to_le64(trans->dbg.fw_mon[0].physical); - prph_sc_ctrl->hwm_cfg.hwm_size = - cpu_to_le32(trans->dbg.fw_mon[0].size); + if (trans->dbg.fw_mon.size) { + prph_sc_ctrl->hwm_cfg.hwm_base_addr = + cpu_to_le64(trans->dbg.fw_mon.physical); + prph_sc_ctrl->hwm_cfg.hwm_size = + cpu_to_le32(trans->dbg.fw_mon.size); + } } /* allocate ucode sections in dram and set addresses */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index f8a1f985a1d8..464dc709c710 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -190,32 +190,36 @@ static void iwl_trans_pcie_sw_reset(struct iwl_trans *trans) static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) { - int i; + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; - for (i = 0; i < trans->dbg.num_blocks; i++) { - dma_free_coherent(trans->dev, trans->dbg.fw_mon[i].size, - trans->dbg.fw_mon[i].block, - trans->dbg.fw_mon[i].physical); - trans->dbg.fw_mon[i].block = NULL; - trans->dbg.fw_mon[i].physical = 0; - trans->dbg.fw_mon[i].size = 0; - trans->dbg.num_blocks--; - } + if (!fw_mon->size) + return; + + dma_free_coherent(trans->dev, fw_mon->size, fw_mon->block, + fw_mon->physical); + + fw_mon->block = NULL; + fw_mon->physical = 0; + fw_mon->size = 0; } static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, u8 max_power, u8 min_power) { - void *cpu_addr = NULL; - dma_addr_t phys = 0; + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; + void *block = NULL; + dma_addr_t physical = 0; u32 size = 0; u8 power; + if (fw_mon->size) + return; + for (power = max_power; power >= min_power; power--) { size = BIT(power); - cpu_addr = dma_alloc_coherent(trans->dev, size, &phys, - GFP_KERNEL | __GFP_NOWARN); - if (!cpu_addr) + block = dma_alloc_coherent(trans->dev, size, &physical, + GFP_KERNEL | __GFP_NOWARN); + if (!block) continue; IWL_INFO(trans, @@ -224,7 +228,7 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, break; } - if (WARN_ON_ONCE(!cpu_addr)) + if (WARN_ON_ONCE(!block)) return; if (power != max_power) @@ -233,10 +237,9 @@ static void iwl_pcie_alloc_fw_monitor_block(struct iwl_trans *trans, (unsigned long)BIT(power - 10), (unsigned long)BIT(max_power - 10)); - trans->dbg.fw_mon[trans->dbg.num_blocks].block = cpu_addr; - trans->dbg.fw_mon[trans->dbg.num_blocks].physical = phys; - trans->dbg.fw_mon[trans->dbg.num_blocks].size = size; - trans->dbg.num_blocks++; + fw_mon->block = block; + fw_mon->physical = physical; + fw_mon->size = size; } void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) @@ -253,11 +256,7 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) max_power)) return; - /* - * This function allocats the default fw monitor. - * The optional additional ones will be allocated in runtime - */ - if (trans->dbg.num_blocks) + if (trans->dbg.fw_mon.size) return; iwl_pcie_alloc_fw_monitor_block(trans, max_power, 11); @@ -894,23 +893,11 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, void iwl_pcie_apply_destination(struct iwl_trans *trans) { const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg.dest_tlv; + const struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; int i; - if (iwl_trans_dbg_ini_valid(trans)) { - if (!trans->dbg.num_blocks) - return; - - IWL_DEBUG_FW(trans, - "WRT: Applying DRAM buffer[0] destination\n"); - iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, - trans->dbg.fw_mon[0].physical >> - MON_BUFF_SHIFT_VER2); - iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size - 256) >> - MON_BUFF_SHIFT_VER2); + if (iwl_trans_dbg_ini_valid(trans)) return; - } IWL_INFO(trans, "Applying debug destination %s\n", get_fw_dbg_mode_string(dest->monitor_mode)); @@ -959,20 +946,17 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) } monitor: - if (dest->monitor_mode == EXTERNAL_MODE && trans->dbg.fw_mon[0].size) { + if (dest->monitor_mode == EXTERNAL_MODE && fw_mon->size) { iwl_write_prph(trans, le32_to_cpu(dest->base_reg), - trans->dbg.fw_mon[0].physical >> - dest->base_shift); + fw_mon->physical >> dest->base_shift); if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_8000) iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size - 256) >> - dest->end_shift); + (fw_mon->physical + fw_mon->size - + 256) >> dest->end_shift); else iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size) >> - dest->end_shift); + (fw_mon->physical + fw_mon->size) >> + dest->end_shift); } } @@ -1006,14 +990,14 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, /* supported for 7000 only for the moment */ if (iwlwifi_mod_params.fw_monitor && trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_pcie_alloc_fw_monitor(trans, 0); + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; - if (trans->dbg.fw_mon[0].size) { + iwl_pcie_alloc_fw_monitor(trans, 0); + if (fw_mon->size) { iwl_write_prph(trans, MON_BUFF_BASE_ADDR, - trans->dbg.fw_mon[0].physical >> 4); + fw_mon->physical >> 4); iwl_write_prph(trans, MON_BUFF_END_ADDR, - (trans->dbg.fw_mon[0].physical + - trans->dbg.fw_mon[0].size) >> 4); + (fw_mon->physical + fw_mon->size) >> 4); } } else if (iwl_pcie_dbg_on(trans)) { iwl_pcie_apply_destination(trans); @@ -2801,7 +2785,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, { struct iwl_trans *trans = file->private_data; struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - void *cpu_addr = (void *)trans->dbg.fw_mon[0].block, *curr_buf; + void *cpu_addr = (void *)trans->dbg.fw_mon.block, *curr_buf; struct cont_rec *data = &trans_pcie->fw_mon_data; u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt; ssize_t size, bytes_copied = 0; @@ -2840,7 +2824,7 @@ static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, } else if (data->prev_wrap_cnt == wrap_cnt - 1 && write_ptr < data->prev_wr_ptr) { - size = trans->dbg.fw_mon[0].size - data->prev_wr_ptr; + size = trans->dbg.fw_mon.size - data->prev_wr_ptr; curr_buf = cpu_addr + data->prev_wr_ptr; b_full = iwl_write_to_user_buf(user_buf, count, curr_buf, &size, @@ -3087,10 +3071,11 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, struct iwl_fw_error_dump_data **data, u32 monitor_len) { + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; u32 len = 0; if (trans->dbg.dest_tlv || - (trans->dbg.num_blocks && + (fw_mon->size && (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_7000 || trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210))) { struct iwl_fw_error_dump_fw_mon *fw_mon_data; @@ -3101,12 +3086,9 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, iwl_trans_pcie_dump_pointers(trans, fw_mon_data); len += sizeof(**data) + sizeof(*fw_mon_data); - if (trans->dbg.num_blocks) { - memcpy(fw_mon_data->data, - trans->dbg.fw_mon[0].block, - trans->dbg.fw_mon[0].size); - - monitor_len = trans->dbg.fw_mon[0].size; + if (fw_mon->size) { + memcpy(fw_mon_data->data, fw_mon->block, fw_mon->size); + monitor_len = fw_mon->size; } else if (trans->dbg.dest_tlv->monitor_mode == SMEM_MODE) { u32 base = le32_to_cpu(fw_mon_data->fw_mon_base_ptr); /* @@ -3145,11 +3127,11 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len) { - if (trans->dbg.num_blocks) { + if (trans->dbg.fw_mon.size) { *len += sizeof(struct iwl_fw_error_dump_data) + sizeof(struct iwl_fw_error_dump_fw_mon) + - trans->dbg.fw_mon[0].size; - return trans->dbg.fw_mon[0].size; + trans->dbg.fw_mon.size; + return trans->dbg.fw_mon.size; } else if (trans->dbg.dest_tlv) { u32 base, end, cfg_reg, monitor_len; -- cgit v1.2.3-59-g8ed1b From 593fae3e5e9050f70b757bb6849edb8e6ec040c5 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 12:34:49 +0300 Subject: iwlwifi: dbg_ini: add monitor dumping support Allow collecting monitor data in ini debug mode. Implement both SMEM and DRAM monitor regions dumping. For DRAM monitor, support DBGC1, DBGC2 and DBGC3 and support several DRAM fragments per DBGC. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 55 +++++- drivers/net/wireless/intel/iwlwifi/cfg/9000.c | 25 ++- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 41 ++--- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 202 ++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 2 + drivers/net/wireless/intel/iwlwifi/iwl-config.h | 28 ++- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 7 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 15 ++ .../wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c | 78 ++++++-- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 41 ++++- 10 files changed, 440 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 5e355c4957df..435cb8013a23 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -54,6 +54,7 @@ #include #include #include "iwl-config.h" +#include "iwl-prph.h" /* Highest firmware API version supported */ #define IWL_22000_UCODE_API_MAX 50 @@ -183,23 +184,49 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .min_umac_error_event_table = 0x400000, \ .d3_debug_data_base_addr = 0x401000, \ .d3_debug_data_length = 60 * 1024, \ - .fw_mon_smem_write_ptr_addr = 0xa0c16c, \ - .fw_mon_smem_write_ptr_msk = 0xfffff, \ - .fw_mon_smem_cycle_cnt_ptr_addr = 0xa0c174, \ - .fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff + .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_22500 \ IWL_DEVICE_22000_COMMON, \ .trans.device_family = IWL_DEVICE_FAMILY_22000, \ .trans.base_params = &iwl_22000_base_params, \ .trans.csr = &iwl_csr_v1, \ - .gp2_reg_addr = 0xa02c68 + .gp2_reg_addr = 0xa02c68, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } #define IWL_DEVICE_22560 \ IWL_DEVICE_22000_COMMON, \ .trans.device_family = IWL_DEVICE_FAMILY_22560, \ .trans.base_params = &iwl_22560_base_params, \ - .trans.csr = &iwl_csr_v2 + .trans.csr = &iwl_csr_v2, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } #define IWL_DEVICE_AX210 \ IWL_DEVICE_22000_COMMON, \ @@ -209,7 +236,21 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .trans.csr = &iwl_csr_v1, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ - .min_256_ba_txq_size = 512 + .min_256_ba_txq_size = 512, \ + .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 iwl22000_2ac_cfg_hr = { .name = "Intel(R) Dual Band Wireless AC 22000", diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index e8372b67df03..e9155b9b5ee4 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -55,6 +55,7 @@ #include #include "iwl-config.h" #include "fw/file.h" +#include "iwl-prph.h" /* Highest firmware API version supported */ #define IWL9000_UCODE_API_MAX 46 @@ -149,10 +150,26 @@ static const struct iwl_tt_params iwl9000_tt_params = { .ht_params = &iwl9000_ht_params, \ .nvm_ver = IWL9000_NVM_VERSION, \ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \ - .fw_mon_smem_write_ptr_addr = 0xa0476c, \ - .fw_mon_smem_write_ptr_msk = 0xfffff, \ - .fw_mon_smem_cycle_cnt_ptr_addr = 0xa04774, \ - .fw_mon_smem_cycle_cnt_ptr_msk = 0xfffff + .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, \ + }, \ + }, \ + .mon_dram_regs = { \ + .write_ptr = { \ + .addr = MON_BUFF_WRPTR_VER2, \ + .mask = 0xffffffff, \ + }, \ + .cycle_cnt = { \ + .addr = MON_BUFF_CYCLE_CNT_VER2, \ + .mask = 0xffffffff, \ + }, \ + } const struct iwl_cfg iwl9160_2ac_cfg = { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 073a729cd4db..2754060dc4c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -73,28 +73,6 @@ struct iwl_fw_ini_header { u8 data[]; } __packed; /* FW_DEBUG_TLV_HEADER_S */ -/** - * struct iwl_fw_ini_allocation_tlv - (IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION) - * buffer allocation TLV - for debug - * - * @iwl_fw_ini_header: header - * @allocation_id: &enum iwl_fw_ini_allocation_id - to bind allocation and hcmd - * if needed (DBGC1/DBGC2/SDFX/...) - * @buffer_location: type of iwl_fw_ini_buffer_location - * @size: size in bytes - * @max_fragments: the maximum allowed fragmentation in the desired memory - * allocation above - * @min_frag_size: the minimum allowed fragmentation size in bytes - */ -struct iwl_fw_ini_allocation_tlv { - struct iwl_fw_ini_header header; - __le32 allocation_id; - __le32 buffer_location; - __le32 size; - __le32 max_fragments; - __le32 min_frag_size; -} __packed; /* FW_DEBUG_TLV_BUFFER_ALLOCATION_TLV_S_VER_1 */ - /** * enum iwl_fw_ini_dbg_domain - debug domains * allows to send host cmd or collect memory region if a given domain is enabled @@ -350,6 +328,25 @@ struct iwl_fw_ini_trigger { __le32 data[]; } __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_API_S_VER_1 */ +/** + * struct iwl_fw_ini_allocation_tlv - Allocates DRAM buffers + * + * @hdr: debug header + * @alloc_id: allocation id. One of &enum iwl_fw_ini_allocation_id + * @buf_location: buffer location. One of &enum iwl_fw_ini_buffer_location + * @req_size: requested buffer size + * @max_frags_num: maximum number of fragments + * @min_size: minimum buffer size + */ +struct iwl_fw_ini_allocation_tlv { + struct iwl_fw_ini_header hdr; + __le32 alloc_id; + __le32 buf_location; + __le32 req_size; + __le32 max_frags_num; + __le32 min_size; +} __packed; /* FW_TLV_DEBUG_BUFFER_ALLOCATION_API_S_VER_1 */ + /** * struct iwl_fw_ini_trigger_tlv - trigger TLV * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index b52ad6f050bd..6726c347431e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1165,6 +1165,42 @@ static int iwl_dump_ini_paging_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + struct iwl_dram_data *frag; + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); + + frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx]; + + range->dram_base_addr = cpu_to_le64(frag->physical); + range->range_data_size = cpu_to_le32(frag->size); + + memcpy(range->data, frag->block, frag->size); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + +static int iwl_dump_ini_mon_smem_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 addr = le32_to_cpu(reg->internal_buffer.base_addr); + + range->internal_base_addr = cpu_to_le32(addr); + range->range_data_size = reg->internal_buffer.size; + iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, + le32_to_cpu(reg->internal_buffer.size)); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + static bool iwl_ini_txf_iter(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, int idx) { @@ -1406,6 +1442,88 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, return dump->ranges; } +/** + * mask_apply_and_normalize - applies mask on val and normalize the result + * + * The normalization is based on the first set bit in the mask + * + * @val: value + * @mask: mask to apply and to normalize with + */ +static u32 mask_apply_and_normalize(u32 val, u32 mask) +{ + return (val & mask) >> (ffs(mask) - 1); +} + +static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id, + const struct iwl_fw_mon_reg *reg_info) +{ + u32 val, offs; + + /* The header addresses of DBGCi is calculate as follows: + * DBGC1 address + (0x100 * i) + */ + offs = (alloc_id - IWL_FW_INI_ALLOCATION_ID_DBGC1) * 0x100; + + if (!reg_info || !reg_info->addr || !reg_info->mask) + return 0; + + val = iwl_read_prph_no_grab(fwrt->trans, reg_info->addr + offs); + + return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask)); +} + +static void * +iwl_dump_ini_mon_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + struct iwl_fw_ini_monitor_dump *data, + const struct iwl_fw_mon_regs *addrs) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); + unsigned long flags; + + if (!iwl_trans_grab_nic_access(fwrt->trans, &flags)) { + IWL_ERR(fwrt, "Failed to get monitor header\n"); + return NULL; + } + + data->write_ptr = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->write_ptr); + data->cycle_cnt = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->cycle_cnt); + data->cur_frag = iwl_get_mon_reg(fwrt, alloc_id, + &addrs->cur_frag); + + iwl_trans_release_nic_access(fwrt->trans, &flags); + + data->header.version = cpu_to_le32(IWL_INI_DUMP_VER); + + return data->ranges; +} + +static void * +iwl_dump_ini_mon_dram_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) +{ + struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; + + return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + &fwrt->trans->cfg->mon_dram_regs); +} + +static void * +iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) +{ + struct iwl_fw_ini_monitor_dump *mon_dump = (void *)data; + + return iwl_dump_ini_mon_fill_header(fwrt, reg_data, mon_dump, + &fwrt->trans->cfg->mon_smem_regs); +} + static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -1423,6 +1541,27 @@ static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, return fwrt->num_of_paging_blk; } +static u32 +iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_mon *fw_mon; + u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); + int i; + + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + if (!fw_mon->frags[i].size) + break; + + ranges++; + } + + return ranges; +} + static u32 iwl_dump_ini_txf_ranges(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -1476,6 +1615,55 @@ iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, return size; } +static u32 +iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_mon *fw_mon; + u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); + int i; + + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + struct iwl_dram_data *frag = &fw_mon->frags[i]; + + if (!frag->size) + break; + + size += sizeof(struct iwl_fw_ini_error_dump_range) + frag->size; + } + + if (size) + size += sizeof(struct iwl_fw_ini_monitor_dump); + + return size; +} + +static u32 +iwl_dump_ini_mon_smem_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 alloc_id = le32_to_cpu(reg->internal_buffer.alloc_id), size; + + fw_mon_cfg = &fwrt->trans->dbg.fw_mon_cfg[alloc_id]; + if (le32_to_cpu(fw_mon_cfg->buf_location) != + IWL_FW_INI_LOCATION_SRAM_PATH) + return 0; + + size = le32_to_cpu(reg->internal_buffer.size); + if (!size) + return 0; + + size += sizeof(struct iwl_fw_ini_monitor_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; +} + static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -1680,8 +1868,18 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { [IWL_FW_INI_REGION_INVALID] = {}, - [IWL_FW_INI_REGION_INTERNAL_BUFFER] = {}, - [IWL_FW_INI_REGION_DRAM_BUFFER] = {}, + [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_mon_smem_get_size, + .fill_mem_hdr = iwl_dump_ini_mon_smem_fill_header, + .fill_range = iwl_dump_ini_mon_smem_iter, + }, + [IWL_FW_INI_REGION_DRAM_BUFFER] = { + .get_num_of_ranges = iwl_dump_ini_mon_dram_ranges, + .get_size = iwl_dump_ini_mon_dram_get_size, + .fill_mem_hdr = iwl_dump_ini_mon_dram_fill_header, + .fill_range = iwl_dump_ini_mon_dram_iter, + }, [IWL_FW_INI_REGION_TXF] = { .get_num_of_ranges = iwl_dump_ini_txf_ranges, .get_size = iwl_dump_ini_txf_get_size, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 2ccf04dacd52..629af3f9c683 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -456,12 +456,14 @@ struct iwl_fw_error_dump_rb { * @header: header of the region * @write_ptr: write pointer position in the buffer * @cycle_cnt: cycles count + * @cur_frag: current fragment in use * @ranges: the memory ranges of this this region */ struct iwl_fw_ini_monitor_dump { struct iwl_fw_ini_error_dump_header header; __le32 write_ptr; __le32 cycle_cnt; + __le32 cur_frag; struct iwl_fw_ini_error_dump_range ranges[]; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 214495a7165f..1b027a138b6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -359,6 +359,28 @@ struct iwl_cfg_trans_params { bisr_workaround:1; }; +/** + * struct iwl_fw_mon_reg - FW monitor register info + * @addr: register address + * @mask: register mask + */ +struct iwl_fw_mon_reg { + u32 addr; + u32 mask; +}; + +/** + * struct iwl_fw_mon_regs - FW monitor registers + * @write_ptr: write pointer register + * @cycle_cnt: cycle count register + * @cur_frag: current fragment in use + */ +struct iwl_fw_mon_regs { + struct iwl_fw_mon_reg write_ptr; + struct iwl_fw_mon_reg cycle_cnt; + struct iwl_fw_mon_reg cur_frag; +}; + /** * struct iwl_cfg * @trans: the trans-specific configuration part @@ -471,12 +493,10 @@ struct iwl_cfg { u32 d3_debug_data_base_addr; u32 d3_debug_data_length; u32 min_txq_size; - u32 fw_mon_smem_write_ptr_addr; - u32 fw_mon_smem_write_ptr_msk; - u32 fw_mon_smem_cycle_cnt_ptr_addr; - u32 fw_mon_smem_cycle_cnt_ptr_msk; u32 gp2_reg_addr; u32 min_256_ba_txq_size; + const struct iwl_fw_mon_regs mon_dram_regs; + const struct iwl_fw_mon_regs mon_smem_regs; }; extern const struct iwl_csr_params iwl_csr_v1; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index f47e0f97acf8..de5ae35d84ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -374,6 +374,7 @@ #define DBGC_CUR_DBGBUF_STATUS (0xd03c1c) #define DBGC_DBGBUF_WRAP_AROUND (0xd03c2c) #define DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK (0x00ffffff) +#define DBGC_CUR_DBGBUF_STATUS_IDX_MSK (0x0f000000) #define MON_DMARB_RD_CTL_ADDR (0xa03c60) #define MON_DMARB_RD_DATA_ADDR (0xa03c5c) @@ -381,6 +382,12 @@ #define DBGC_IN_SAMPLE (0xa03c00) #define DBGC_OUT_CTRL (0xa03c0c) +/* M2S registers */ +#define LDBG_M2S_BUF_WPTR (0xa0476c) +#define LDBG_M2S_BUF_WRAP_CNT (0xa04774) +#define LDBG_M2S_BUF_WPTR_VAL_MSK (0x000fffff) +#define LDBG_M2S_BUF_WRAP_CNT_VAL_MSK (0x000fffff) + /* enable the ID buf for read */ #define WFPM_PS_CTL_CLR 0xA0300C #define WFMP_MAC_ADDR_0 0xA03080 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 640530371194..b9ee6c83af87 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -678,6 +678,16 @@ struct iwl_dram_data { int size; }; +/** + * struct iwl_fw_mon - fw monitor per allocation id + * @num_frags: number of fragments + * @frags: an array of DRAM buffer fragments + */ +struct iwl_fw_mon { + u32 num_frags; + struct iwl_dram_data *frags; +}; + /** * struct iwl_self_init_dram - dram data used by self init process * @fw: lmac and umac dram data @@ -706,6 +716,8 @@ struct iwl_self_init_dram { * pointers was recevied via TLV. uses enum &iwl_error_event_table_status * @internal_ini_cfg: internal debug cfg state. Uses &enum iwl_ini_cfg_state * @external_ini_cfg: external debug cfg state. Uses &enum iwl_ini_cfg_state + * @fw_mon_cfg: debug buffer allocation configuration + * @fw_mon_ini: DRAM buffer fragments per allocation id * @fw_mon: DRAM buffer for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location @@ -726,6 +738,9 @@ struct iwl_trans_debug { enum iwl_ini_cfg_state internal_ini_cfg; enum iwl_ini_cfg_state external_ini_cfg; + struct iwl_fw_ini_allocation_tlv fw_mon_cfg[IWL_FW_INI_ALLOCATION_NUM]; + struct iwl_fw_mon fw_mon_ini[IWL_FW_INI_ALLOCATION_NUM]; + struct iwl_dram_data fw_mon; bool hw_error; 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 2c8ce41718a2..d2274251921d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -55,6 +55,66 @@ #include "internal.h" #include "iwl-prph.h" +static void +iwl_pcie_ctxt_info_dbg_enable(struct iwl_trans *trans, + struct iwl_prph_scratch_hwm_cfg *dbg_cfg, + u32 *control_flags) +{ + enum iwl_fw_ini_allocation_id alloc_id = IWL_FW_INI_ALLOCATION_ID_DBGC1; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 dbg_flags = 0; + + if (!iwl_trans_dbg_ini_valid(trans)) { + struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; + + iwl_pcie_alloc_fw_monitor(trans, 0); + + if (fw_mon->size) { + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; + + IWL_DEBUG_FW(trans, + "WRT: Applying DRAM buffer destination\n"); + + dbg_cfg->hwm_base_addr = cpu_to_le64(fw_mon->physical); + dbg_cfg->hwm_size = cpu_to_le32(fw_mon->size); + } + + goto out; + } + + fw_mon_cfg = &trans->dbg.fw_mon_cfg[alloc_id]; + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_SRAM_PATH) { + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL; + + IWL_DEBUG_FW(trans, + "WRT: Applying SMEM buffer destination\n"); + + goto out; + } + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_DRAM_PATH && + trans->dbg.fw_mon_ini[alloc_id].num_frags) { + struct iwl_dram_data *frag = + &trans->dbg.fw_mon_ini[alloc_id].frags[0]; + + dbg_flags |= IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; + + IWL_DEBUG_FW(trans, + "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + dbg_cfg->hwm_base_addr = cpu_to_le64(frag->physical); + dbg_cfg->hwm_size = cpu_to_le32(frag->size); + } + +out: + if (dbg_flags) + *control_flags |= IWL_PRPH_SCRATCH_EARLY_DEBUG_EN | dbg_flags; +} + int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, const struct fw_img *fw) { @@ -86,25 +146,15 @@ int iwl_pcie_ctxt_info_gen3_init(struct iwl_trans *trans, control_flags = IWL_PRPH_SCRATCH_RB_SIZE_4K | IWL_PRPH_SCRATCH_MTR_MODE | (IWL_PRPH_MTR_FORMAT_256B & - IWL_PRPH_SCRATCH_MTR_FORMAT) | - IWL_PRPH_SCRATCH_EARLY_DEBUG_EN | - IWL_PRPH_SCRATCH_EDBG_DEST_DRAM; - prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags); + IWL_PRPH_SCRATCH_MTR_FORMAT); /* initialize RX default queue */ prph_sc_ctrl->rbd_cfg.free_rbd_addr = cpu_to_le64(trans_pcie->rxq->bd_dma); - /* Configure debug, for integration */ - if (iwl_trans_dbg_ini_valid(trans)) { - iwl_pcie_alloc_fw_monitor(trans, 0); - if (trans->dbg.fw_mon.size) { - prph_sc_ctrl->hwm_cfg.hwm_base_addr = - cpu_to_le64(trans->dbg.fw_mon.physical); - prph_sc_ctrl->hwm_cfg.hwm_size = - cpu_to_le32(trans->dbg.fw_mon.size); - } - } + iwl_pcie_ctxt_info_dbg_enable(trans, &prph_sc_ctrl->hwm_cfg, + &control_flags); + prph_sc_ctrl->control.control_flags = cpu_to_le32(control_flags); /* allocate ucode sections in dram and set addresses */ ret = iwl_pcie_init_fw_sec(trans, fw, &prph_scratch->dram); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 464dc709c710..871b0b9244f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -890,14 +890,53 @@ static int iwl_pcie_load_cpu_sections(struct iwl_trans *trans, return 0; } +static void iwl_pcie_apply_destination_ini(struct iwl_trans *trans) +{ + enum iwl_fw_ini_allocation_id alloc_id = IWL_FW_INI_ALLOCATION_ID_DBGC1; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg = + &trans->dbg.fw_mon_cfg[alloc_id]; + struct iwl_dram_data *frag; + + if (!iwl_trans_dbg_ini_valid(trans)) + return; + + if (le32_to_cpu(fw_mon_cfg->buf_location) == + IWL_FW_INI_LOCATION_SRAM_PATH) { + IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n"); + /* set sram monitor by enabling bit 7 */ + iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM); + + return; + } + + if (le32_to_cpu(fw_mon_cfg->buf_location) != + IWL_FW_INI_LOCATION_DRAM_PATH || + !trans->dbg.fw_mon_ini[alloc_id].num_frags) + return; + + frag = &trans->dbg.fw_mon_ini[alloc_id].frags[0]; + + IWL_DEBUG_FW(trans, "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, + frag->physical >> MON_BUFF_SHIFT_VER2); + iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, + (frag->physical + frag->size - 256) >> + MON_BUFF_SHIFT_VER2); +} + void iwl_pcie_apply_destination(struct iwl_trans *trans) { const struct iwl_fw_dbg_dest_tlv_v1 *dest = trans->dbg.dest_tlv; const struct iwl_dram_data *fw_mon = &trans->dbg.fw_mon; int i; - if (iwl_trans_dbg_ini_valid(trans)) + if (iwl_trans_dbg_ini_valid(trans)) { + iwl_pcie_apply_destination_ini(trans); return; + } IWL_INFO(trans, "Applying debug destination %s\n", get_fw_dbg_mode_string(dest->monitor_mode)); -- cgit v1.2.3-59-g8ed1b From a77e3d2829e2a73c3d76b2e776214788fc0ebfe8 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 12:47:13 +0300 Subject: iwlwifi: dbg_ini: add error tables dumping support Allow to collect error table data. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 61 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 11 ++++ 2 files changed, 70 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 6726c347431e..a2761f5881b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1430,6 +1430,25 @@ out: return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_region_err_table *err_table = ®->err_table; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + u32 addr = le32_to_cpu(err_table->base_addr) + + le32_to_cpu(err_table->offset); + + range->internal_base_addr = cpu_to_le32(addr); + range->range_data_size = err_table->size; + iwl_trans_read_mem_bytes(fwrt->trans, addr, range->data, + le32_to_cpu(err_table->size)); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + static void * iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, @@ -1524,6 +1543,20 @@ iwl_dump_ini_mon_smem_fill_header(struct iwl_fw_runtime *fwrt, &fwrt->trans->cfg->mon_smem_regs); } +static void * +iwl_dump_ini_err_table_fill_header(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_err_table_dump *dump = data; + + dump->header.version = cpu_to_le32(IWL_INI_DUMP_VER); + dump->version = reg->err_table.version; + + return dump->ranges; +} + static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -1706,6 +1739,20 @@ static u32 iwl_dump_ini_rxf_get_size(struct iwl_fw_runtime *fwrt, return size; } +static u32 +iwl_dump_ini_err_table_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 size = le32_to_cpu(reg->err_table.size); + + if (size) + size += sizeof(struct iwl_fw_ini_err_table_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; +} + /** * struct iwl_dump_ini_mem_ops - ini memory dump operations * @get_num_of_ranges: returns the number of memory ranges in the region. @@ -1892,8 +1939,18 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_rxf_iter, }, - [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = {}, - [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = {}, + [IWL_FW_INI_REGION_LMAC_ERROR_TABLE] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_err_table_get_size, + .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, + .fill_range = iwl_dump_ini_err_table_iter, + }, + [IWL_FW_INI_REGION_UMAC_ERROR_TABLE] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_err_table_get_size, + .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, + .fill_range = iwl_dump_ini_err_table_iter, + }, [IWL_FW_INI_REGION_RSP_OR_NOTIF] = {}, [IWL_FW_INI_REGION_DEVICE_MEMORY] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 629af3f9c683..7be1c4b54503 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -434,7 +434,18 @@ struct iwl_fw_ini_dump_info { u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; __le32 regions_num; __le32 region_ids[]; +} __packed; +/** + * struct iwl_fw_ini_err_table_dump - ini error table dump + * @header: header of the region + * @version: error table version + * @ranges: the memory ranges of this this region + */ +struct iwl_fw_ini_err_table_dump { + struct iwl_fw_ini_error_dump_header header; + __le32 version; + struct iwl_fw_ini_error_dump_range ranges[]; } __packed; /** -- cgit v1.2.3-59-g8ed1b From 677d25b237b307898a76bc0acd7cf854d39f02f2 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 12:50:25 +0300 Subject: iwlwifi: dbg_ini: use new API in dump info Make dump info region use new API. debug_info_tlv_list list will be initialize in a future patch once the driver will start using it. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 39 ++++++++++------------ drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 25 ++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 36 +++++++++++--------- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 4 --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 8 ++--- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 ++ 6 files changed, 68 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 2754060dc4c6..9f110bf6b71b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -60,6 +60,8 @@ #include +#define IWL_FW_INI_MAX_CFG_NAME 64 + /** * struct iwl_fw_ini_header: Common Header for all debug group TLV's structures * @@ -294,6 +296,21 @@ struct iwl_fw_ini_region_tlv { __le32 addrs[]; } __packed; /* FW_TLV_DEBUG_REGION_API_S_VER_1 */ +/** + * struct iwl_fw_ini_debug_info_tlv + * + * debug configuration name for a specific image + * + * @hdr: debug header + * @image_type: image type + * @debug_cfg_name: debug configuration name + */ +struct iwl_fw_ini_debug_info_tlv { + struct iwl_fw_ini_header hdr; + __le32 image_type; + u8 debug_cfg_name[IWL_FW_INI_MAX_CFG_NAME]; +} __packed; /* FW_TLV_DEBUG_INFO_API_S_VER_1 */ + /** * struct iwl_fw_ini_trigger * @@ -380,28 +397,6 @@ struct iwl_fw_ini_trigger_tlv { __le32 data[]; } __packed; /* FW_TLV_DEBUG_TRIGGER_API_S_VER_1 */ -#define IWL_FW_INI_MAX_IMG_NAME_LEN 32 -#define IWL_FW_INI_MAX_DBG_CFG_NAME_LEN 64 - -/** - * struct iwl_fw_ini_debug_info_tlv - (IWL_UCODE_TLV_TYPE_DEBUG_INFO) - * - * holds image name and debug configuration name - * - * @header: header - * @img_name_len: length of the image name string - * @img_name: image name string - * @dbg_cfg_name_len : length of the debug configuration name string - * @dbg_cfg_name: debug configuration name string - */ -struct iwl_fw_ini_debug_info_tlv { - struct iwl_fw_ini_header header; - __le32 img_name_len; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - __le32 dbg_cfg_name_len; - u8 dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; -} __packed; /* FW_DEBUG_TLV_INFO_API_S_VER_1 */ - /** * enum iwl_fw_ini_trigger_id * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index a2761f5881b9..aed7f9d9ebec 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1864,7 +1864,15 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_dump_entry *entry; struct iwl_fw_error_dump_data *tlv; struct iwl_fw_ini_dump_info *dump; + struct iwl_dbg_tlv_node *node; + struct iwl_fw_ini_dump_cfg_name *cfg_name; u32 size = sizeof(*tlv) + sizeof(*dump); + u32 num_of_cfg_names = 0; + + list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { + size += sizeof(*cfg_name); + num_of_cfg_names++; + } entry = kmalloc(sizeof(*entry) + size, GFP_KERNEL); if (!entry) @@ -1901,10 +1909,27 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, dump->umac_major = cpu_to_le32(fwrt->dump.fw_ver.umac_major); dump->umac_minor = cpu_to_le32(fwrt->dump.fw_ver.umac_minor); + dump->fw_mon_mode = cpu_to_le32(fwrt->trans->dbg.ini_dest); + dump->regions_mask = trigger->regions_mask; + dump->build_tag_len = cpu_to_le32(sizeof(dump->build_tag)); memcpy(dump->build_tag, fwrt->fw->human_readable, sizeof(dump->build_tag)); + cfg_name = dump->cfg_names; + dump->num_of_cfg_names = cpu_to_le32(num_of_cfg_names); + list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { + struct iwl_fw_ini_debug_info_tlv *debug_info = + (void *)node->tlv.data; + + cfg_name->image_type = debug_info->image_type; + cfg_name->cfg_name_len = + cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME); + memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name, + sizeof(cfg_name->cfg_name)); + cfg_name++; + } + /* add dump info TLV to the beginning of the list since it needs to be * the first TLV in the dump */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index 7be1c4b54503..a7bf17e5ca9c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -379,6 +379,18 @@ struct iwl_fw_ini_error_dump_register { __le32 data; } __packed; +/** + * struct iwl_fw_ini_dump_cfg_name - configuration name + * @image_type: image type the configuration is related to + * @cfg_name_len: length of the configuration name + * @cfg_name: name of the configuraiton + */ +struct iwl_fw_ini_dump_cfg_name { + __le32 image_type; + __le32 cfg_name_len; + u8 cfg_name[IWL_FW_INI_MAX_CFG_NAME]; +} __packed; + /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version * @time_point: time point that caused the dump collection @@ -396,16 +408,12 @@ struct iwl_fw_ini_error_dump_register { * @lmac_minor: lmac minor version * @umac_major: umac major version * @umac_minor: umac minor version + * @fw_mon_mode: FW monitor mode &enum iwl_fw_ini_buffer_location + * @regions_mask: bitmap mask of regions ids in the dump * @build_tag_len: length of the build tag * @build_tag: build tag string - * @img_name_len: length of the FW image name - * @img_name: FW image name - * @internal_dbg_cfg_name_len: length of the internal debug configuration name - * @internal_dbg_cfg_name: internal debug configuration name - * @external_dbg_cfg_name_len: length of the external debug configuration name - * @external_dbg_cfg_name: external debug configuration name - * @regions_num: number of region ids - * @region_ids: region ids the trigger configured to collect + * @num_of_cfg_names: number of configuration name structs + * @cfg_names: configuration names */ struct iwl_fw_ini_dump_info { __le32 version; @@ -424,16 +432,12 @@ struct iwl_fw_ini_dump_info { __le32 lmac_minor; __le32 umac_major; __le32 umac_minor; + __le32 fw_mon_mode; + __le64 regions_mask; __le32 build_tag_len; u8 build_tag[FW_VER_HUMAN_READABLE_SZ]; - __le32 img_name_len; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - __le32 internal_dbg_cfg_name_len; - u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - __le32 external_dbg_cfg_name_len; - u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - __le32 regions_num; - __le32 region_ids[]; + __le32 num_of_cfg_names; + struct iwl_fw_ini_dump_cfg_name cfg_names[]; } __packed; /** diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index f3c56a2c2531..6c2ade4c7a0c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -177,10 +177,6 @@ struct iwl_fw_runtime { struct iwl_txf_iter_data txf_iter_data; - u8 img_name[IWL_FW_INI_MAX_IMG_NAME_LEN]; - u8 internal_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - u8 external_dbg_cfg_name[IWL_FW_INI_MAX_DBG_CFG_NAME_LEN]; - struct { u8 type; u8 subtype; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index e257ad358c94..521aa6ba17e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -65,11 +65,11 @@ #include /** - * struct iwl_apply_point_data - * @list: list to go through the TLVs of the apply point - * @tlv: a debug TLV + * struct iwl_dbg_tlv_node - debug TLV node + * @list: list of &struct iwl_dbg_tlv_node + * @tlv: debug TLV */ -struct iwl_apply_point_data { +struct iwl_dbg_tlv_node { struct list_head list; struct iwl_ucode_tlv tlv; }; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index b9ee6c83af87..9dd74fe9a0bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -722,6 +722,7 @@ struct iwl_self_init_dram { * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location * @active_regions: active regions + * @debug_info_tlv_list: list of debug info TLVs */ struct iwl_trans_debug { u8 n_dest_reg; @@ -747,6 +748,7 @@ struct iwl_trans_debug { enum iwl_fw_ini_buffer_location ini_dest; struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID]; + struct list_head debug_info_tlv_list; }; /** -- cgit v1.2.3-59-g8ed1b From a9248de42464e546b624e3fc6a8b04b991af3591 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 13:41:44 +0300 Subject: iwlwifi: dbg_ini: add TLV allocation new API support Add new debug TLVs API preprocessing. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 50 +++-- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 +- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 224 ++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 11 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 3 + drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 + 6 files changed, 256 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 9f110bf6b71b..21e1de9166cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -62,19 +62,6 @@ #define IWL_FW_INI_MAX_CFG_NAME 64 -/** - * struct iwl_fw_ini_header: Common Header for all debug group TLV's structures - * - * @tlv_version: version info - * @apply_point: &enum iwl_fw_ini_apply_point - * @data: TLV data followed - */ -struct iwl_fw_ini_header { - __le32 tlv_version; - __le32 apply_point; - u8 data[]; -} __packed; /* FW_DEBUG_TLV_HEADER_S */ - /** * enum iwl_fw_ini_dbg_domain - debug domains * allows to send host cmd or collect memory region if a given domain is enabled @@ -103,22 +90,17 @@ struct iwl_fw_ini_hcmd { } __packed; /* FW_DEBUG_TLV_HCMD_DATA_API_S_VER_1 */ /** - * struct iwl_fw_ini_hcmd_tlv - (IWL_UCODE_TLV_TYPE_HCMD) - * Generic Host command pass through TLV + * struct iwl_fw_ini_header - Common Header for all ini debug TLV's structures * - * @header: header - * @domain: send command only if the specific domain is enabled - * &enum iwl_fw_ini_dbg_domain - * @period_msec: period in which the hcmd will be sent to FW. Measured in msec - * (0 = one time command). - * @hcmd: a variable length host-command to be sent to apply the configuration. + * @version: TLV version + * @domain: domain of the TLV. One of &enum iwl_fw_ini_dbg_domain + * @data: TLV data */ -struct iwl_fw_ini_hcmd_tlv { - struct iwl_fw_ini_header header; +struct iwl_fw_ini_header { + __le32 version; __le32 domain; - __le32 period_msec; - struct iwl_fw_ini_hcmd hcmd; -} __packed; /* FW_DEBUG_TLV_HCMD_API_S_VER_1 */ + u8 data[]; +} __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ #define IWL_FW_INI_MAX_REGION_ID 64 #define IWL_FW_INI_MAX_NAME 32 @@ -397,6 +379,22 @@ struct iwl_fw_ini_trigger_tlv { __le32 data[]; } __packed; /* FW_TLV_DEBUG_TRIGGER_API_S_VER_1 */ +/** + * struct iwl_fw_ini_hcmd_tlv - Generic Host command pass through TLV + * + * @hdr: debug header + * @time_point: time point. One of &enum iwl_fw_ini_time_point + * @period_msec: interval at which the hcmd will be sent to the FW. + * Measured in msec (0 = one time command) + * @hcmd: a variable length host-command to be sent to apply the configuration + */ +struct iwl_fw_ini_hcmd_tlv { + struct iwl_fw_ini_header hdr; + __le32 time_point; + __le32 period_msec; + struct iwl_fw_ini_hcmd hcmd; +} __packed; /* FW_TLV_DEBUG_HCMD_API_S_VER_1 */ + /** * enum iwl_fw_ini_trigger_id * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 423cc0cf8e78..105fd37f7da5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -93,7 +93,7 @@ struct iwl_ucode_header { } u; }; -#define IWL_UCODE_INI_TLV_GROUP 0x1000000 +#define IWL_UCODE_TLV_DEBUG_BASE 0x1000005 /* * new TLV uCode file layout @@ -151,7 +151,6 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_FW_RECOVERY_INFO = 57, IWL_UCODE_TLV_FW_FSEQ_VERSION = 60, - IWL_UCODE_TLV_DEBUG_BASE = IWL_UCODE_INI_TLV_GROUP, IWL_UCODE_TLV_TYPE_DEBUG_INFO = IWL_UCODE_TLV_DEBUG_BASE + 0, IWL_UCODE_TLV_TYPE_BUFFER_ALLOCATION = IWL_UCODE_TLV_DEBUG_BASE + 1, IWL_UCODE_TLV_TYPE_HCMD = IWL_UCODE_TLV_DEBUG_BASE + 2, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 3d7f8ff8ef58..651e1fee2763 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -104,12 +104,27 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_TRIGGER] = {.min_ver = 1, .max_ver = 1,}, }; +static int iwl_dbg_tlv_add(struct iwl_ucode_tlv *tlv, struct list_head *list) +{ + u32 len = le32_to_cpu(tlv->length); + struct iwl_dbg_tlv_node *node; + + node = kzalloc(sizeof(*node) + len, GFP_KERNEL); + if (!node) + return -ENOMEM; + + memcpy(&node->tlv, tlv, sizeof(node->tlv) + len); + list_add_tail(&node->list, list); + + return 0; +} + static bool iwl_dbg_tlv_ver_support(struct iwl_ucode_tlv *tlv) { struct iwl_fw_ini_header *hdr = (void *)&tlv->data[0]; u32 type = le32_to_cpu(tlv->type); u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE; - u32 ver = le32_to_cpu(hdr->tlv_version); + u32 ver = le32_to_cpu(hdr->version); if (ver < dbg_ver_table[tlv_idx].min_ver || ver > dbg_ver_table[tlv_idx].max_ver) @@ -118,27 +133,169 @@ static bool iwl_dbg_tlv_ver_support(struct iwl_ucode_tlv *tlv) return true; } +static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_debug_info_tlv *debug_info = (void *)tlv->data; + + if (le32_to_cpu(tlv->length) != sizeof(*debug_info)) + return -EINVAL; + + IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", + debug_info->debug_cfg_name); + + return iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list); +} + +static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_allocation_tlv *alloc = (void *)tlv->data; + u32 buf_location = le32_to_cpu(alloc->buf_location); + u32 alloc_id = le32_to_cpu(alloc->alloc_id); + + if (le32_to_cpu(tlv->length) != sizeof(*alloc) || + (buf_location != IWL_FW_INI_LOCATION_SRAM_PATH && + buf_location != IWL_FW_INI_LOCATION_DRAM_PATH)) + return -EINVAL; + + if ((buf_location == IWL_FW_INI_LOCATION_SRAM_PATH && + alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) || + (buf_location == IWL_FW_INI_LOCATION_DRAM_PATH && + (alloc_id == IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM))) { + IWL_ERR(trans, + "WRT: Invalid allocation id %u for allocation TLV\n", + alloc_id); + return -EINVAL; + } + + trans->dbg.fw_mon_cfg[alloc_id] = *alloc; + + return 0; +} + +static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_hcmd_tlv *hcmd = (void *)tlv->data; + u32 tp = le32_to_cpu(hcmd->time_point); + + if (le32_to_cpu(tlv->length) <= sizeof(*hcmd)) + return -EINVAL; + + /* Host commands can not be sent in early time point since the FW + * is not ready + */ + if (tp == IWL_FW_INI_TIME_POINT_INVALID || + tp >= IWL_FW_INI_TIME_POINT_NUM || + tp == IWL_FW_INI_TIME_POINT_EARLY) { + IWL_ERR(trans, + "WRT: Invalid time point %u for host command TLV\n", + tp); + return -EINVAL; + } + + return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list); +} + +static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)tlv->data; + struct iwl_ucode_tlv **active_reg; + u32 id = le32_to_cpu(reg->id); + u32 type = le32_to_cpu(reg->type); + u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); + + if (le32_to_cpu(tlv->length) < sizeof(*reg)) + return -EINVAL; + + if (id >= IWL_FW_INI_MAX_REGION_ID) { + IWL_ERR(trans, "WRT: Invalid region id %u\n", id); + return -EINVAL; + } + + if (type <= IWL_FW_INI_REGION_INVALID || + type >= IWL_FW_INI_REGION_NUM) { + IWL_ERR(trans, "WRT: Invalid region type %u\n", type); + return -EINVAL; + } + + active_reg = &trans->dbg.active_regions[id]; + if (*active_reg) { + IWL_WARN(trans, "WRT: Overriding region id %u\n", id); + + kfree(*active_reg); + } + + *active_reg = kmemdup(tlv, tlv_len, GFP_KERNEL); + if (!*active_reg) + return -ENOMEM; + + IWL_DEBUG_FW(trans, "WRT: Enabling region id %u type %u\n", id, type); + + return 0; +} + +static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) +{ + struct iwl_fw_ini_trigger_tlv *trig = (void *)tlv->data; + u32 tp = le32_to_cpu(trig->time_point); + + if (le32_to_cpu(tlv->length) < sizeof(*trig)) + return -EINVAL; + + if (tp <= IWL_FW_INI_TIME_POINT_INVALID || + tp >= IWL_FW_INI_TIME_POINT_NUM) { + IWL_ERR(trans, + "WRT: Invalid time point %u for trigger TLV\n", + tp); + return -EINVAL; + } + + if (!le32_to_cpu(trig->occurrences)) + trig->occurrences = cpu_to_le32(-1); + + return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); +} + +static int (*dbg_tlv_alloc[])(struct iwl_trans *trans, + struct iwl_ucode_tlv *tlv) = { + [IWL_DBG_TLV_TYPE_DEBUG_INFO] = iwl_dbg_tlv_alloc_debug_info, + [IWL_DBG_TLV_TYPE_BUF_ALLOC] = iwl_dbg_tlv_alloc_buf_alloc, + [IWL_DBG_TLV_TYPE_HCMD] = iwl_dbg_tlv_alloc_hcmd, + [IWL_DBG_TLV_TYPE_REGION] = iwl_dbg_tlv_alloc_region, + [IWL_DBG_TLV_TYPE_TRIGGER] = iwl_dbg_tlv_alloc_trigger, +}; + void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, bool ext) { struct iwl_fw_ini_header *hdr = (void *)&tlv->data[0]; u32 type = le32_to_cpu(tlv->type); - u32 pnt = le32_to_cpu(hdr->apply_point); u32 tlv_idx = type - IWL_UCODE_TLV_DEBUG_BASE; enum iwl_ini_cfg_state *cfg_state = ext ? &trans->dbg.external_ini_cfg : &trans->dbg.internal_ini_cfg; + int ret; - IWL_DEBUG_FW(trans, "WRT: read TLV 0x%x, apply point %d\n", - type, pnt); - - if (tlv_idx >= IWL_DBG_TLV_TYPE_NUM) { - IWL_ERR(trans, "WRT: Unsupported TLV 0x%x\n", type); + if (tlv_idx >= ARRAY_SIZE(dbg_tlv_alloc) || !dbg_tlv_alloc[tlv_idx]) { + IWL_ERR(trans, "WRT: Unsupported TLV type 0x%x\n", type); goto out_err; } if (!iwl_dbg_tlv_ver_support(tlv)) { IWL_ERR(trans, "WRT: Unsupported TLV 0x%x version %u\n", type, - le32_to_cpu(hdr->tlv_version)); + le32_to_cpu(hdr->version)); + goto out_err; + } + + ret = dbg_tlv_alloc[tlv_idx](trans, tlv); + if (ret) { + IWL_ERR(trans, + "WRT: Failed to allocate TLV 0x%x, ret %d, (ext=%d)\n", + type, ret, ext); goto out_err; } @@ -159,7 +316,41 @@ IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers); void iwl_dbg_tlv_free(struct iwl_trans *trans) { - /* will be used again later */ + struct iwl_dbg_tlv_node *tlv_node, *tlv_node_tmp; + int i; + + iwl_dbg_tlv_del_timers(trans); + + for (i = 0; i < ARRAY_SIZE(trans->dbg.active_regions); i++) { + struct iwl_ucode_tlv **active_reg = + &trans->dbg.active_regions[i]; + + kfree(*active_reg); + *active_reg = NULL; + } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, + &trans->dbg.debug_info_tlv_list, list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + + for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &trans->dbg.time_point[i]; + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->trig_list, + list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, &tp->hcmd_list, + list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } + } } static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data, @@ -205,6 +396,21 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) release_firmware(fw); } +void iwl_dbg_tlv_init(struct iwl_trans *trans) +{ + int i; + + INIT_LIST_HEAD(&trans->dbg.debug_info_tlv_list); + + for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) { + struct iwl_dbg_tlv_time_point_data *tp = + &trans->dbg.time_point[i]; + + INIT_LIST_HEAD(&tp->trig_list); + INIT_LIST_HEAD(&tp->hcmd_list); + } +} + void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 521aa6ba17e2..64c0638998f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -82,6 +82,16 @@ union iwl_dbg_tlv_tp_data { struct iwl_rx_packet *fw_pkt; }; +/** + * struct iwl_dbg_tlv_time_point_data + * @trig_list: list of triggers + * @hcmd_list: list of host commands + */ +struct iwl_dbg_tlv_time_point_data { + struct list_head trig_list; + struct list_head hcmd_list; +}; + struct iwl_trans; struct iwl_fw_runtime; @@ -89,6 +99,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans); void iwl_dbg_tlv_free(struct iwl_trans *trans); void iwl_dbg_tlv_alloc(struct iwl_trans *trans, struct iwl_ucode_tlv *tlv, bool ext); +void iwl_dbg_tlv_init(struct iwl_trans *trans); void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 9dd74fe9a0bb..63031c030600 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -723,6 +723,7 @@ struct iwl_self_init_dram { * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location * @active_regions: active regions * @debug_info_tlv_list: list of debug info TLVs + * @time_point: array of debug time points */ struct iwl_trans_debug { u8 n_dest_reg; @@ -749,6 +750,8 @@ struct iwl_trans_debug { struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID]; struct list_head debug_info_tlv_list; + struct iwl_dbg_tlv_time_point_data + time_point[IWL_FW_INI_TIME_POINT_NUM]; }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 871b0b9244f9..cd1091704de0 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -3614,6 +3614,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, mutex_init(&trans_pcie->fw_mon_data.mutex); #endif + iwl_dbg_tlv_init(trans); + return trans; out_free_ict: -- cgit v1.2.3-59-g8ed1b From cf29c5b66b9f83939367d90679eb68cdfa2f0356 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 14:26:49 +0300 Subject: iwlwifi: dbg_ini: implement time point handling Calculate active triggers list and implement time points handling. Also allow to override the debug domain via iwl-dbg-cfg.ini by setting FW_DBG_DOMAIN field. Reported-by: kbuild test robot Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/Makefile | 3 +- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 31 ++- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 3 + drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 13 + drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 280 ++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h | 3 + drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 4 + 7 files changed, 323 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index ff41987a7e35..0aae3fa4128c 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -14,7 +14,8 @@ iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o cfg/9000.o cfg/22000.o iwlwifi-objs += iwl-dbg-tlv.o iwlwifi-objs += iwl-trans.o iwlwifi-objs += fw/notif-wait.o -iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o fw/dbg.o +iwlwifi-objs += fw/dbg.o +iwlwifi-$(CONFIG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o iwlwifi-$(CONFIG_ACPI) += fw/acpi.o iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += fw/debugfs.o diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 21e1de9166cf..4d1b084da4b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -61,18 +61,7 @@ #include #define IWL_FW_INI_MAX_CFG_NAME 64 - -/** - * enum iwl_fw_ini_dbg_domain - debug domains - * allows to send host cmd or collect memory region if a given domain is enabled - * - * @IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON: the default domain, always on - * @IWL_FW_INI_DBG_DOMAIN_REPORT_PS: power save domain - */ -enum iwl_fw_ini_dbg_domain { - IWL_FW_INI_DBG_DOMAIN_ALWAYS_ON = 0, - IWL_FW_INI_DBG_DOMAIN_REPORT_PS, -}; /* FW_DEBUG_TLV_DOMAIN_API_E_VER_1 */ +#define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 /** * struct iwl_fw_ini_hcmd @@ -652,4 +641,22 @@ enum iwl_fw_ini_time_point { IWL_FW_INI_TIME_POINT_NUM, }; /* FW_TLV_DEBUG_TIME_POINT_API_E */ +/** + * enum iwl_fw_ini_trigger_apply_policy - Determines how to apply triggers + * + * @IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT: match by time point + * @IWL_FW_INI_APPLY_POLICY_MATCH_DATA: match by trigger data + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS: override regions mask. + * Append otherwise + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG: override trigger configuration + * @IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA: override trigger data. + * Append otherwise + */ +enum iwl_fw_ini_trigger_apply_policy { + IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT = BIT(0), + IWL_FW_INI_APPLY_POLICY_MATCH_DATA = BIT(1), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS = BIT(8), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG = BIT(9), + IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA = BIT(10), +}; #endif diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index aed7f9d9ebec..c4b79f4f4736 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2301,6 +2301,9 @@ int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, u32 occur, delay; unsigned long idx; + if (test_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status)) + return -EBUSY; + if (!iwl_fw_ini_trigger_on(fwrt, trig)) { IWL_WARN(fwrt, "WRT: Trigger %d is not active, aborting dump\n", tp_id); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 6c2ade4c7a0c..87adbd3dd764 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -67,6 +67,8 @@ #include "fw/api/paging.h" #include "iwl-eeprom-parse.h" +#define IWL_FW_DBG_DOMAIN IWL_FW_INI_DOMAIN_ALWAYS_ON + struct iwl_fw_runtime_ops { int (*dump_start)(void *ctx); void (*dump_end)(void *ctx); @@ -125,6 +127,14 @@ struct iwl_txf_iter_data { u8 internal_txf; }; +/** + * enum iwl_fw_runtime_status - fw runtime status flags + * @STATUS_GEN_ACTIVE_TRIGS: generating active trigger list + */ +enum iwl_fw_runtime_status { + STATUS_GEN_ACTIVE_TRIGS, +}; + /** * struct iwl_fw_runtime - runtime data for firmware * @fw: firmware image @@ -138,6 +148,7 @@ struct iwl_txf_iter_data { * @smem_cfg: saved firmware SMEM configuration * @cur_fw_img: current firmware image, must be maintained by * the driver by calling &iwl_fw_set_current_image() + * @status: &enum iwl_fw_runtime_status * @dump: debug dump data */ struct iwl_fw_runtime { @@ -158,6 +169,8 @@ struct iwl_fw_runtime { /* memory configuration */ struct iwl_fwrt_shared_mem_cfg smem_cfg; + unsigned long status; + /* debug */ struct { const struct iwl_fw_dump_desc *desc; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 651e1fee2763..1cec10a60cba 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -350,6 +350,12 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans) list_del(&tlv_node->list); kfree(tlv_node); } + + list_for_each_entry_safe(tlv_node, tlv_node_tmp, + &tp->active_trig_list, list) { + list_del(&tlv_node->list); + kfree(tlv_node); + } } } @@ -408,13 +414,285 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans) INIT_LIST_HEAD(&tp->trig_list); INIT_LIST_HEAD(&tp->hcmd_list); + INIT_LIST_HEAD(&tp->active_trig_list); + } +} + +static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt, + struct list_head *hcmd_list) +{ + struct iwl_dbg_tlv_node *node; + + list_for_each_entry(node, hcmd_list, list) { + struct iwl_fw_ini_hcmd_tlv *hcmd = (void *)node->tlv.data; + struct iwl_fw_ini_hcmd *hcmd_data = &hcmd->hcmd; + u32 domain = le32_to_cpu(hcmd->hdr.domain); + u16 hcmd_len = le32_to_cpu(node->tlv.length) - sizeof(*hcmd); + struct iwl_host_cmd cmd = { + .id = WIDE_ID(hcmd_data->group, hcmd_data->id), + .len = { hcmd_len, }, + .data = { hcmd_data->data, }, + }; + + if (domain != IWL_FW_INI_DOMAIN_ALWAYS_ON && + !(domain & fwrt->trans->dbg.domains_bitmap)) + continue; + + iwl_trans_send_cmd(fwrt->trans, &cmd); + } +} + +static bool is_trig_data_contained(struct iwl_ucode_tlv *new, + struct iwl_ucode_tlv *old) +{ + struct iwl_fw_ini_trigger_tlv *new_trig = (void *)new->data; + struct iwl_fw_ini_trigger_tlv *old_trig = (void *)old->data; + __le32 *new_data = new_trig->data, *old_data = old_trig->data; + u32 new_dwords_num = iwl_tlv_array_len(new, new_trig, data); + u32 old_dwords_num = iwl_tlv_array_len(new, new_trig, data); + int i, j; + + for (i = 0; i < new_dwords_num; i++) { + bool match = false; + + for (j = 0; j < old_dwords_num; j++) { + if (new_data[i] == old_data[j]) { + match = true; + break; + } + } + if (!match) + return false; + } + + return true; +} + +static int iwl_dbg_tlv_override_trig_node(struct iwl_fw_runtime *fwrt, + struct iwl_ucode_tlv *trig_tlv, + struct iwl_dbg_tlv_node *node) +{ + struct iwl_ucode_tlv *node_tlv = &node->tlv; + struct iwl_fw_ini_trigger_tlv *node_trig = (void *)node_tlv->data; + struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data; + u32 policy = le32_to_cpu(trig->apply_policy); + u32 size = le32_to_cpu(trig_tlv->length); + u32 trig_data_len = size - sizeof(*trig); + u32 offset = 0; + + if (!(policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_DATA)) { + u32 data_len = le32_to_cpu(node_tlv->length) - + sizeof(*node_trig); + + IWL_DEBUG_FW(fwrt, + "WRT: Appending trigger data (time point %u)\n", + le32_to_cpu(trig->time_point)); + + offset += data_len; + size += data_len; + } else { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger data (time point %u)\n", + le32_to_cpu(trig->time_point)); + } + + if (size != le32_to_cpu(node_tlv->length)) { + struct list_head *prev = node->list.prev; + struct iwl_dbg_tlv_node *tmp; + + list_del(&node->list); + + tmp = krealloc(node, sizeof(*node) + size, GFP_KERNEL); + if (!tmp) { + IWL_WARN(fwrt, + "WRT: No memory to override trigger (time point %u)\n", + le32_to_cpu(trig->time_point)); + + list_add(&node->list, prev); + + return -ENOMEM; + } + + list_add(&tmp->list, prev); + node_tlv = &tmp->tlv; + node_trig = (void *)node_tlv->data; + } + + memcpy(node_trig->data + offset, trig->data, trig_data_len); + node_tlv->length = cpu_to_le32(size); + + if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG) { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger configuration (time point %u)\n", + le32_to_cpu(trig->time_point)); + + /* the first 11 dwords are configuration related */ + memcpy(node_trig, trig, sizeof(__le32) * 11); + } + + if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_REGIONS) { + IWL_DEBUG_FW(fwrt, + "WRT: Overriding trigger regions (time point %u)\n", + le32_to_cpu(trig->time_point)); + + node_trig->regions_mask = trig->regions_mask; + } else { + IWL_DEBUG_FW(fwrt, + "WRT: Appending trigger regions (time point %u)\n", + le32_to_cpu(trig->time_point)); + + node_trig->regions_mask |= trig->regions_mask; + } + + return 0; +} + +static int +iwl_dbg_tlv_add_active_trigger(struct iwl_fw_runtime *fwrt, + struct list_head *trig_list, + struct iwl_ucode_tlv *trig_tlv) +{ + struct iwl_fw_ini_trigger_tlv *trig = (void *)trig_tlv->data; + struct iwl_dbg_tlv_node *node, *match = NULL; + u32 policy = le32_to_cpu(trig->apply_policy); + + list_for_each_entry(node, trig_list, list) { + if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_TIME_POINT)) + break; + + if (!(policy & IWL_FW_INI_APPLY_POLICY_MATCH_DATA) || + is_trig_data_contained(trig_tlv, &node->tlv)) { + match = node; + break; + } } + + if (!match) { + IWL_DEBUG_FW(fwrt, "WRT: Enabling trigger (time point %u)\n", + le32_to_cpu(trig->time_point)); + return iwl_dbg_tlv_add(trig_tlv, trig_list); + } + + return iwl_dbg_tlv_override_trig_node(fwrt, trig_tlv, match); +} + +static void +iwl_dbg_tlv_gen_active_trig_list(struct iwl_fw_runtime *fwrt, + struct iwl_dbg_tlv_time_point_data *tp) +{ + struct iwl_dbg_tlv_node *node, *tmp; + struct list_head *trig_list = &tp->trig_list; + struct list_head *active_trig_list = &tp->active_trig_list; + + list_for_each_entry_safe(node, tmp, active_trig_list, list) { + list_del(&node->list); + kfree(node); + } + + list_for_each_entry(node, trig_list, list) { + struct iwl_ucode_tlv *tlv = &node->tlv; + struct iwl_fw_ini_trigger_tlv *trig = (void *)tlv->data; + u32 domain = le32_to_cpu(trig->hdr.domain); + + if (domain != IWL_FW_INI_DOMAIN_ALWAYS_ON && + !(domain & fwrt->trans->dbg.domains_bitmap)) + continue; + + iwl_dbg_tlv_add_active_trigger(fwrt, active_trig_list, tlv); + } +} + +int iwl_dbg_tlv_gen_active_trigs(struct iwl_fw_runtime *fwrt, u32 new_domain) +{ + int i; + + if (test_and_set_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status)) + return -EBUSY; + + iwl_fw_flush_dumps(fwrt); + + fwrt->trans->dbg.domains_bitmap = new_domain; + + 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]; + + iwl_dbg_tlv_gen_active_trig_list(fwrt, tp); + } + + clear_bit(STATUS_GEN_ACTIVE_TRIGS, &fwrt->status); + + return 0; +} + +static int +iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, + struct list_head *active_trig_list, + union iwl_dbg_tlv_tp_data *tp_data, + bool (*data_check)(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + union iwl_dbg_tlv_tp_data *tp_data, + u32 trig_data)) +{ + struct iwl_dbg_tlv_node *node; + + list_for_each_entry(node, active_trig_list, list) { + struct iwl_fwrt_dump_data dump_data = { + .trig = (void *)node->tlv.data, + }; + u32 num_data = iwl_tlv_array_len(&node->tlv, dump_data.trig, + data); + int ret, i; + + if (!num_data) { + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + if (ret) + return ret; + } + + for (i = 0; i < num_data; i++) { + if (!data_check || + data_check(fwrt, &dump_data, tp_data, + le32_to_cpu(dump_data.trig->data[i]))) { + ret = iwl_fw_dbg_ini_collect(fwrt, &dump_data); + if (ret) + return ret; + + break; + } + } + } + + return 0; } void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data) { - /* will be used later */ + struct list_head *hcmd_list, *trig_list; + + if (!iwl_trans_dbg_ini_valid(fwrt->trans) || + tp_id == IWL_FW_INI_TIME_POINT_INVALID || + tp_id >= IWL_FW_INI_TIME_POINT_NUM) + return; + + hcmd_list = &fwrt->trans->dbg.time_point[tp_id].hcmd_list; + trig_list = &fwrt->trans->dbg.time_point[tp_id].active_trig_list; + + switch (tp_id) { + case IWL_FW_INI_TIME_POINT_EARLY: + iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + default: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + } } IWL_EXPORT_SYMBOL(iwl_dbg_tlv_time_point); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h index 64c0638998f2..f18946872569 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.h @@ -85,10 +85,12 @@ union iwl_dbg_tlv_tp_data { /** * struct iwl_dbg_tlv_time_point_data * @trig_list: list of triggers + * @active_trig_list: list of active triggers * @hcmd_list: list of host commands */ struct iwl_dbg_tlv_time_point_data { struct list_head trig_list; + struct list_head active_trig_list; struct list_head hcmd_list; }; @@ -103,6 +105,7 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans); void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data); +int iwl_dbg_tlv_gen_active_trigs(struct iwl_fw_runtime *fwrt, u32 new_domain); void iwl_dbg_tlv_del_timers(struct iwl_trans *trans); #endif /* __iwl_dbg_tlv_h__*/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 63031c030600..59debf6e1b9d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -724,6 +724,8 @@ struct iwl_self_init_dram { * @active_regions: active regions * @debug_info_tlv_list: list of debug info TLVs * @time_point: array of debug time points + * @domains_bitmap: bitmap of active domains other than + * &IWL_FW_INI_DOMAIN_ALWAYS_ON */ struct iwl_trans_debug { u8 n_dest_reg; @@ -752,6 +754,8 @@ struct iwl_trans_debug { struct list_head debug_info_tlv_list; struct iwl_dbg_tlv_time_point_data time_point[IWL_FW_INI_TIME_POINT_NUM]; + + u32 domains_bitmap; }; /** -- cgit v1.2.3-59-g8ed1b From 14124b25780db542b2bc31aadecc37a2a6534f40 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 14:37:45 +0300 Subject: iwlwifi: dbg_ini: implement monitor allocation flow Allow allocating fragmented buffers for several allocation IDs. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 249 ++++++++++++++++++++++- 1 file changed, 248 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 1cec10a60cba..c657acf61fe9 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -314,6 +314,34 @@ void iwl_dbg_tlv_del_timers(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers); +static void iwl_dbg_tlv_fragments_free(struct iwl_trans *trans, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + int i; + + if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return; + + fw_mon = &trans->dbg.fw_mon_ini[alloc_id]; + + for (i = 0; i < fw_mon->num_frags; i++) { + struct iwl_dram_data *frag = &fw_mon->frags[i]; + + dma_free_coherent(trans->dev, frag->size, frag->block, + frag->physical); + + frag->physical = 0; + frag->block = NULL; + frag->size = 0; + } + + kfree(fw_mon->frags); + fw_mon->frags = NULL; + fw_mon->num_frags = 0; +} + void iwl_dbg_tlv_free(struct iwl_trans *trans) { struct iwl_dbg_tlv_node *tlv_node, *tlv_node_tmp; @@ -357,6 +385,9 @@ void iwl_dbg_tlv_free(struct iwl_trans *trans) kfree(tlv_node); } } + + for (i = 0; i < ARRAY_SIZE(trans->dbg.fw_mon_ini); i++) + iwl_dbg_tlv_fragments_free(trans, i); } static int iwl_dbg_tlv_parse_bin(struct iwl_trans *trans, const u8 *data, @@ -418,6 +449,187 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans) } } +static int iwl_dbg_tlv_alloc_fragment(struct iwl_fw_runtime *fwrt, + struct iwl_dram_data *frag, u32 pages) +{ + void *block = NULL; + dma_addr_t physical; + + if (!frag || frag->size || !pages) + return -EIO; + + while (pages) { + block = dma_alloc_coherent(fwrt->dev, pages * PAGE_SIZE, + &physical, + GFP_KERNEL | __GFP_NOWARN); + if (block) + break; + + IWL_WARN(fwrt, "WRT: Failed to allocate fragment size %lu\n", + pages * PAGE_SIZE); + + pages = DIV_ROUND_UP(pages, 2); + } + + if (!block) + return -ENOMEM; + + frag->physical = physical; + frag->block = block; + frag->size = pages * PAGE_SIZE; + + return pages; +} + +static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg; + u32 num_frags, remain_pages, frag_pages; + int i; + + if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return -EIO; + + 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 != + cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH)) + return 0; + + num_frags = le32_to_cpu(fw_mon_cfg->max_frags_num); + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) { + if (alloc_id != IWL_FW_INI_ALLOCATION_ID_DBGC1) + return -EIO; + num_frags = 1; + } + + remain_pages = DIV_ROUND_UP(le32_to_cpu(fw_mon_cfg->req_size), + PAGE_SIZE); + num_frags = min_t(u32, num_frags, BUF_ALLOC_MAX_NUM_FRAGS); + num_frags = min_t(u32, num_frags, remain_pages); + frag_pages = DIV_ROUND_UP(remain_pages, num_frags); + + fw_mon->frags = kcalloc(num_frags, sizeof(*fw_mon->frags), GFP_KERNEL); + if (!fw_mon->frags) + return -ENOMEM; + + for (i = 0; i < num_frags; i++) { + int pages = min_t(u32, frag_pages, remain_pages); + + IWL_DEBUG_FW(fwrt, + "WRT: Allocating DRAM buffer (alloc_id=%u, fragment=%u, size=0x%lx)\n", + alloc_id, i, pages * PAGE_SIZE); + + pages = iwl_dbg_tlv_alloc_fragment(fwrt, &fw_mon->frags[i], + pages); + if (pages < 0) { + u32 alloc_size = le32_to_cpu(fw_mon_cfg->req_size) - + (remain_pages * PAGE_SIZE); + + if (alloc_size < le32_to_cpu(fw_mon_cfg->min_size)) { + iwl_dbg_tlv_fragments_free(fwrt->trans, + alloc_id); + return pages; + } + break; + } + + remain_pages -= pages; + fw_mon->num_frags++; + } + + return 0; +} + +static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt, + enum iwl_fw_ini_allocation_id alloc_id) +{ + struct iwl_fw_mon *fw_mon; + u32 remain_frags, num_commands; + int i, fw_mon_idx = 0; + + if (!fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) + return 0; + + if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= IWL_FW_INI_ALLOCATION_NUM) + return -EIO; + + if (le32_to_cpu(fwrt->trans->dbg.fw_mon_cfg[alloc_id].buf_location) != + IWL_FW_INI_LOCATION_DRAM_PATH) + return 0; + + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; + + /* the first fragment of DBGC1 is given to the FW via register + * or context info + */ + if (alloc_id == IWL_FW_INI_ALLOCATION_ID_DBGC1) + fw_mon_idx++; + + remain_frags = fw_mon->num_frags - fw_mon_idx; + if (!remain_frags) + return 0; + + num_commands = DIV_ROUND_UP(remain_frags, BUF_ALLOC_MAX_NUM_FRAGS); + + IWL_DEBUG_FW(fwrt, "WRT: Applying DRAM destination (alloc_id=%u)\n", + alloc_id); + + for (i = 0; i < num_commands; i++) { + u32 num_frags = min_t(u32, remain_frags, + BUF_ALLOC_MAX_NUM_FRAGS); + struct iwl_buf_alloc_cmd data = { + .alloc_id = cpu_to_le32(alloc_id), + .num_frags = cpu_to_le32(num_frags), + .buf_location = + cpu_to_le32(IWL_FW_INI_LOCATION_DRAM_PATH), + }; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DEBUG_GROUP, BUFFER_ALLOCATION), + .data[0] = &data, + .len[0] = sizeof(data), + }; + int ret, j; + + for (j = 0; j < num_frags; j++) { + struct iwl_buf_alloc_frag *frag = &data.frags[j]; + struct iwl_dram_data *fw_mon_frag = + &fw_mon->frags[fw_mon_idx++]; + + frag->addr = cpu_to_le64(fw_mon_frag->physical); + frag->size = cpu_to_le32(fw_mon_frag->size); + } + ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); + if (ret) + return ret; + + remain_frags -= num_frags; + } + + return 0; +} + +static void iwl_dbg_tlv_apply_buffers(struct iwl_fw_runtime *fwrt) +{ + int ret, i; + + for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) { + ret = iwl_dbg_tlv_apply_buffer(fwrt, i); + if (ret) + IWL_WARN(fwrt, + "WRT: Failed to apply DRAM buffer for allocation id %d, ret=%d\n", + i, ret); + } +} + static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt, struct list_head *hcmd_list) { @@ -670,6 +882,36 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, return 0; } +static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) +{ + enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest; + int ret, i; + + iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN); + + *ini_dest = IWL_FW_INI_LOCATION_INVALID; + for (i = 0; i < IWL_FW_INI_ALLOCATION_NUM; i++) { + struct iwl_fw_ini_allocation_tlv *fw_mon_cfg = + &fwrt->trans->dbg.fw_mon_cfg[i]; + u32 dest = le32_to_cpu(fw_mon_cfg->buf_location); + + if (dest == IWL_FW_INI_LOCATION_INVALID) + continue; + + if (*ini_dest == IWL_FW_INI_LOCATION_INVALID) + *ini_dest = dest; + + if (dest != *ini_dest) + continue; + + ret = iwl_dbg_tlv_alloc_fragments(fwrt, i); + if (ret) + IWL_WARN(fwrt, + "WRT: Failed to allocate DRAM buffer for allocation id %d, ret=%d\n", + i, ret); + } +} + void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data) @@ -686,7 +928,12 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, switch (tp_id) { case IWL_FW_INI_TIME_POINT_EARLY: - iwl_dbg_tlv_gen_active_trigs(fwrt, IWL_FW_DBG_DOMAIN); + iwl_dbg_tlv_init_cfg(fwrt); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); + break; + case IWL_FW_INI_TIME_POINT_AFTER_ALIVE: + iwl_dbg_tlv_apply_buffers(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); break; default: -- cgit v1.2.3-59-g8ed1b From 60e8abd9d3e91916a25783a3e62980083b1acfaf Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 15:10:59 +0300 Subject: iwlwifi: dbg_ini: add periodic trigger new API support Enable periodic trigger. Allows the driver to trigger dump collection in constant intervals. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 105 ++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 2 + 2 files changed, 106 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index c657acf61fe9..f813b2333565 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -95,6 +95,20 @@ struct iwl_dbg_tlv_ver_data { int max_ver; }; +/** + * struct iwl_dbg_tlv_timer_node - timer node struct + * @list: list of &struct iwl_dbg_tlv_timer_node + * @timer: timer + * @fwrt: &struct iwl_fw_runtime + * @tlv: TLV attach to the timer node + */ +struct iwl_dbg_tlv_timer_node { + struct list_head list; + struct timer_list timer; + struct iwl_fw_runtime *fwrt; + struct iwl_ucode_tlv *tlv; +}; + static const struct iwl_dbg_tlv_ver_data dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_DEBUG_INFO] = {.min_ver = 1, .max_ver = 1,}, @@ -310,7 +324,14 @@ out_err: void iwl_dbg_tlv_del_timers(struct iwl_trans *trans) { - /* will be used later */ + struct list_head *timer_list = &trans->dbg.periodic_trig_list; + struct iwl_dbg_tlv_timer_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, timer_list, list) { + del_timer(&node->timer); + list_del(&node->list); + kfree(node); + } } IWL_EXPORT_SYMBOL(iwl_dbg_tlv_del_timers); @@ -438,6 +459,7 @@ void iwl_dbg_tlv_init(struct iwl_trans *trans) int i; INIT_LIST_HEAD(&trans->dbg.debug_info_tlv_list); + INIT_LIST_HEAD(&trans->dbg.periodic_trig_list); for (i = 0; i < ARRAY_SIZE(trans->dbg.time_point); i++) { struct iwl_dbg_tlv_time_point_data *tp = @@ -654,6 +676,83 @@ static void iwl_dbg_tlv_send_hcmds(struct iwl_fw_runtime *fwrt, } } +static void iwl_dbg_tlv_periodic_trig_handler(struct timer_list *t) +{ + struct iwl_dbg_tlv_timer_node *timer_node = + from_timer(timer_node, t, timer); + struct iwl_fwrt_dump_data dump_data = { + .trig = (void *)timer_node->tlv->data, + }; + int ret; + + ret = iwl_fw_dbg_ini_collect(timer_node->fwrt, &dump_data); + if (!ret || ret == -EBUSY) { + u32 occur = le32_to_cpu(dump_data.trig->occurrences); + u32 collect_interval = le32_to_cpu(dump_data.trig->data[0]); + + if (!occur) + return; + + mod_timer(t, jiffies + msecs_to_jiffies(collect_interval)); + } +} + +static void iwl_dbg_tlv_set_periodic_trigs(struct iwl_fw_runtime *fwrt) +{ + struct iwl_dbg_tlv_node *node; + struct list_head *trig_list = + &fwrt->trans->dbg.time_point[IWL_FW_INI_TIME_POINT_PERIODIC].active_trig_list; + + list_for_each_entry(node, trig_list, list) { + struct iwl_fw_ini_trigger_tlv *trig = (void *)node->tlv.data; + struct iwl_dbg_tlv_timer_node *timer_node; + u32 occur = le32_to_cpu(trig->occurrences), collect_interval; + u32 min_interval = 100; + + if (!occur) + continue; + + /* make sure there is at least one dword of data for the + * interval value + */ + if (le32_to_cpu(node->tlv.length) < + sizeof(*trig) + sizeof(__le32)) { + IWL_ERR(fwrt, + "WRT: Invalid periodic trigger data was not given\n"); + continue; + } + + if (le32_to_cpu(trig->data[0]) < min_interval) { + IWL_WARN(fwrt, + "WRT: Override min interval from %u to %u msec\n", + le32_to_cpu(trig->data[0]), min_interval); + trig->data[0] = cpu_to_le32(min_interval); + } + + collect_interval = le32_to_cpu(trig->data[0]); + + timer_node = kzalloc(sizeof(*timer_node), GFP_KERNEL); + if (!timer_node) { + IWL_ERR(fwrt, + "WRT: Failed to allocate periodic trigger\n"); + continue; + } + + timer_node->fwrt = fwrt; + timer_node->tlv = &node->tlv; + timer_setup(&timer_node->timer, + iwl_dbg_tlv_periodic_trig_handler, 0); + + list_add_tail(&timer_node->list, + &fwrt->trans->dbg.periodic_trig_list); + + IWL_DEBUG_FW(fwrt, "WRT: Enabling periodic trigger\n"); + + mod_timer(&timer_node->timer, + jiffies + msecs_to_jiffies(collect_interval)); + } +} + static bool is_trig_data_contained(struct iwl_ucode_tlv *new, struct iwl_ucode_tlv *old) { @@ -936,6 +1035,10 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); break; + case IWL_FW_INI_TIME_POINT_PERIODIC: + iwl_dbg_tlv_set_periodic_trigs(fwrt); + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + break; default: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 59debf6e1b9d..32e522991068 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -724,6 +724,7 @@ struct iwl_self_init_dram { * @active_regions: active regions * @debug_info_tlv_list: list of debug info TLVs * @time_point: array of debug time points + * @periodic_trig_list: periodic triggers list * @domains_bitmap: bitmap of active domains other than * &IWL_FW_INI_DOMAIN_ALWAYS_ON */ @@ -754,6 +755,7 @@ struct iwl_trans_debug { struct list_head debug_info_tlv_list; struct iwl_dbg_tlv_time_point_data time_point[IWL_FW_INI_TIME_POINT_NUM]; + struct list_head periodic_trig_list; u32 domains_bitmap; }; -- cgit v1.2.3-59-g8ed1b From 068893b7a28f0728fc6da17906df95f3bb6f9aa3 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Wed, 24 Jul 2019 18:52:23 +0300 Subject: iwlwifi: dbg_ini: support domain changing via debugfs Allow to change or read the debug domain bitmap at runtime via fw_dbg_domain debugfs. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/debugfs.c | 35 +++++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 5 ++++ 2 files changed, 40 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index c1aa4360736b..ca3b1a461dea 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -320,10 +320,45 @@ out: FWRT_DEBUGFS_WRITE_FILE_OPS(send_hcmd, 512); +static ssize_t iwl_dbgfs_fw_dbg_domain_write(struct iwl_fw_runtime *fwrt, + char *buf, size_t count) +{ + u32 new_domain; + int ret; + + if (!iwl_trans_fw_running(fwrt->trans)) + return -EIO; + + ret = kstrtou32(buf, 0, &new_domain); + if (ret) + return ret; + + if (new_domain != fwrt->trans->dbg.domains_bitmap) { + ret = iwl_dbg_tlv_gen_active_trigs(fwrt, new_domain); + if (ret) + return ret; + + iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_PERIODIC, + NULL); + } + + return count; +} + +static ssize_t iwl_dbgfs_fw_dbg_domain_read(struct iwl_fw_runtime *fwrt, + size_t size, char *buf) +{ + return scnprintf(buf, size, "0x%08x\n", + fwrt->trans->dbg.domains_bitmap); +} + +FWRT_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_domain, 20); + void iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) { INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk); FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200); FWRT_DEBUGFS_ADD_FILE(send_hcmd, dbgfs_dir, 0200); + FWRT_DEBUGFS_ADD_FILE(fw_dbg_domain, dbgfs_dir, 0600); } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 32e522991068..8cadad7364ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1249,6 +1249,11 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans) iwl_op_mode_nic_error(trans->op_mode); } +static inline bool iwl_trans_fw_running(struct iwl_trans *trans) +{ + return trans->state == IWL_TRANS_FW_ALIVE; +} + static inline void iwl_trans_sync_nmi(struct iwl_trans *trans) { if (trans->ops->sync_nmi) -- cgit v1.2.3-59-g8ed1b From 3ed34fbf9d3bfce7c82851242ea86a8c1209f14e Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 15:22:25 +0300 Subject: iwlwifi: dbg_ini: support FW response/notification region type Allow the driver to collect FW response/notification region type during dump and allow triggering dump collection for a given FW response/notification. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 53 +++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/fw/error-dump.h | 3 ++ drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 32 +++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index c4b79f4f4736..ce77ed17ede0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1057,9 +1057,11 @@ out: /** * struct iwl_dump_ini_region_data - region data * @reg_tlv: region TLV + * @dump_data: dump data */ struct iwl_dump_ini_region_data { struct iwl_ucode_tlv *reg_tlv; + struct iwl_fwrt_dump_data *dump_data; }; static int iwl_dump_ini_prph_iter(struct iwl_fw_runtime *fwrt, @@ -1449,6 +1451,27 @@ iwl_dump_ini_err_table_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int iwl_dump_ini_fw_pkt_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, int idx) +{ + struct iwl_fw_ini_error_dump_range *range = range_ptr; + struct iwl_rx_packet *pkt = reg_data->dump_data->fw_pkt; + u32 pkt_len; + + if (!pkt) + return -EIO; + + pkt_len = iwl_rx_packet_payload_len(pkt); + + memcpy(&range->fw_pkt_hdr, &pkt->hdr, sizeof(range->fw_pkt_hdr)); + range->range_data_size = cpu_to_le32(pkt_len); + + memcpy(range->data, pkt->data, pkt_len); + + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + static void * iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, @@ -1753,6 +1776,23 @@ iwl_dump_ini_err_table_get_size(struct iwl_fw_runtime *fwrt, return size; } +static u32 +iwl_dump_ini_fw_pkt_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + u32 size = 0; + + if (!reg_data->dump_data->fw_pkt) + return 0; + + size += iwl_rx_packet_payload_len(reg_data->dump_data->fw_pkt); + if (size) + size += sizeof(struct iwl_fw_ini_error_dump) + + sizeof(struct iwl_fw_ini_error_dump_range); + + return size; +} + /** * struct iwl_dump_ini_mem_ops - ini memory dump operations * @get_num_of_ranges: returns the number of memory ranges in the region. @@ -1976,7 +2016,12 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_err_table_fill_header, .fill_range = iwl_dump_ini_err_table_iter, }, - [IWL_FW_INI_REGION_RSP_OR_NOTIF] = {}, + [IWL_FW_INI_REGION_RSP_OR_NOTIF] = { + .get_num_of_ranges = iwl_dump_ini_single_range, + .get_size = iwl_dump_ini_fw_pkt_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_fw_pkt_iter, + }, [IWL_FW_INI_REGION_DEVICE_MEMORY] = { .get_num_of_ranges = iwl_dump_ini_mem_ranges, .get_size = iwl_dump_ini_mem_get_size, @@ -2012,7 +2057,9 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, struct list_head *list) { struct iwl_fw_ini_trigger_tlv *trigger = dump_data->trig; - struct iwl_dump_ini_region_data reg_data = {}; + struct iwl_dump_ini_region_data reg_data = { + .dump_data = dump_data, + }; int i; u32 size = 0; u64 regions_mask = le64_to_cpu(trigger->regions_mask); @@ -2155,6 +2202,8 @@ static void iwl_dump_ini_list_free(struct list_head *list) static void iwl_fw_error_dump_data_free(struct iwl_fwrt_dump_data *dump_data) { dump_data->trig = NULL; + kfree(dump_data->fw_pkt); + dump_data->fw_pkt = NULL; } static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index a7bf17e5ca9c..f008e1bbfdf4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -65,6 +65,7 @@ #define __fw_error_dump_h__ #include +#include "fw/api/cmdhdr.h" #define IWL_FW_ERROR_DUMP_BARKER 0x14789632 #define IWL_FW_INI_ERROR_DUMP_BARKER 0x14789633 @@ -327,6 +328,7 @@ struct iwl_fw_ini_fifo_hdr { * @dram_base_addr: base address of dram monitor range * @page_num: page number of memory range * @fifo_hdr: fifo header of memory range + * @fw_pkt: FW packet header of memory range * @data: the actual memory */ struct iwl_fw_ini_error_dump_range { @@ -336,6 +338,7 @@ struct iwl_fw_ini_error_dump_range { __le64 dram_base_addr; __le32 page_num; struct iwl_fw_ini_fifo_hdr fifo_hdr; + struct iwl_cmd_header fw_pkt_hdr; }; __le32 data[]; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index f813b2333565..4f2a4d88f399 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -940,6 +940,33 @@ int iwl_dbg_tlv_gen_active_trigs(struct iwl_fw_runtime *fwrt, u32 new_domain) return 0; } +static bool iwl_dbg_tlv_check_fw_pkt(struct iwl_fw_runtime *fwrt, + struct iwl_fwrt_dump_data *dump_data, + union iwl_dbg_tlv_tp_data *tp_data, + u32 trig_data) +{ + struct iwl_rx_packet *pkt = tp_data->fw_pkt; + struct iwl_cmd_header *wanted_hdr = (void *)&trig_data; + + if (pkt && ((wanted_hdr->cmd == 0 && wanted_hdr->group_id == 0) || + (pkt->hdr.cmd == wanted_hdr->cmd && + pkt->hdr.group_id == wanted_hdr->group_id))) { + struct iwl_rx_packet *fw_pkt = + kmemdup(pkt, + sizeof(*pkt) + iwl_rx_packet_payload_len(pkt), + GFP_ATOMIC); + + if (!fw_pkt) + return false; + + dump_data->fw_pkt = fw_pkt; + + return true; + } + + return false; +} + static int iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, struct list_head *active_trig_list, @@ -1039,6 +1066,11 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, iwl_dbg_tlv_set_periodic_trigs(fwrt); iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); break; + case IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF: + iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); + iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, + iwl_dbg_tlv_check_fw_pkt); + break; default: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, NULL); -- cgit v1.2.3-59-g8ed1b From e8d9e982bf9bf0e6f99099f1f09a37563b2b95b5 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 15:24:54 +0300 Subject: iwlwifi: dbg_ini: rename external debug configuration file Rename the external configuration file to align to the debug SAS. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 4f2a4d88f399..1934df7fccb8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -445,7 +445,7 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) if (!iwlwifi_mod_params.enable_ini) return; - res = request_firmware(&fw, "iwl-dbg-tlv.ini", dev); + res = request_firmware(&fw, "iwl-debug-yoyo.bin", dev); if (res) return; -- cgit v1.2.3-59-g8ed1b From b87384af8d6701c0fe6ffbe885feb200150b1ee4 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Tue, 23 Jul 2019 15:27:14 +0300 Subject: iwlwifi: dbg_ini: remove old API and some related code Remove unused code of the old debug ini API. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h | 228 +-------------------- drivers/net/wireless/intel/iwlwifi/fw/img.h | 12 -- drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 12 -- 3 files changed, 2 insertions(+), 250 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h index 4d1b084da4b1..b9d7ed93311c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/dbg-tlv.h @@ -60,6 +60,8 @@ #include +#define IWL_FW_INI_MAX_REGION_ID 64 +#define IWL_FW_INI_MAX_NAME 32 #define IWL_FW_INI_MAX_CFG_NAME 64 #define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 @@ -91,84 +93,6 @@ struct iwl_fw_ini_header { u8 data[]; } __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ -#define IWL_FW_INI_MAX_REGION_ID 64 -#define IWL_FW_INI_MAX_NAME 32 - -/** - * struct iwl_fw_ini_region_cfg_dhc - defines dhc response to dump. - * - * @id_and_grp: id and group of dhc response. - * @desc: dhc response descriptor. - */ -struct iwl_fw_ini_region_cfg_dhc { - __le32 id_and_grp; - __le32 desc; -} __packed; /* FW_DEBUG_TLV_REGION_DHC_API_S_VER_1 */ - -/** - * struct iwl_fw_ini_region_cfg_internal - meta data of internal memory region - * - * @num_of_range: the amount of ranges in the region - * @range_data_size: size of the data to read per range, in bytes. - */ -struct iwl_fw_ini_region_cfg_internal { - __le32 num_of_ranges; - __le32 range_data_size; -} __packed; /* FW_DEBUG_TLV_REGION_NIC_INTERNAL_RANGES_S */ - -/** - * struct iwl_fw_ini_region_cfg_fifos - meta data of fifos region - * - * @fid1: fifo id 1 - bitmap of lmac tx/rx fifos to include in the region - * @fid2: fifo id 2 - bitmap of umac rx fifos to include in the region. - * It is unused for tx. - * @num_of_registers: number of prph registers in the region, each register is - * 4 bytes size. - * @header_only: none zero value indicates that this region does not include - * fifo data and includes only the given registers. - */ -struct iwl_fw_ini_region_cfg_fifos { - __le32 fid1; - __le32 fid2; - __le32 num_of_registers; - __le32 header_only; -} __packed; /* FW_DEBUG_TLV_REGION_FIFOS_S */ - -/** - * struct iwl_fw_ini_region_cfg - * - * @region_id: ID of this dump configuration - * @region_type: &enum iwl_fw_ini_region_type - * @domain: dump this region only if the specific domain is enabled - * &enum iwl_fw_ini_dbg_domain - * @name_len: name length - * @name: file name to use for this region - * @internal: used in case the region uses internal memory. - * @allocation_id: For DRAM type field substitutes for allocation_id - * @fifos: used in case of fifos region. - * @dhc_desc: dhc response descriptor. - * @notif_id_and_grp: dump this region only if the specific notification - * occurred. - * @offset: offset to use for each memory base address - * @start_addr: array of addresses. - */ -struct iwl_fw_ini_region_cfg { - __le32 region_id; - __le32 region_type; - __le32 domain; - __le32 name_len; - u8 name[IWL_FW_INI_MAX_NAME]; - union { - struct iwl_fw_ini_region_cfg_internal internal; - __le32 allocation_id; - struct iwl_fw_ini_region_cfg_fifos fifos; - struct iwl_fw_ini_region_cfg_dhc dhc_desc; - __le32 notif_id_and_grp; - }; /* FW_DEBUG_TLV_REGION_EXT_INT_PARAMS_API_U_VER_1 */ - __le32 offset; - __le32 start_addr[]; -} __packed; /* FW_DEBUG_TLV_REGION_CONFIG_API_S_VER_1 */ - /** * struct iwl_fw_ini_region_dev_addr - Configuration to read device addresses * @@ -282,40 +206,6 @@ struct iwl_fw_ini_debug_info_tlv { u8 debug_cfg_name[IWL_FW_INI_MAX_CFG_NAME]; } __packed; /* FW_TLV_DEBUG_INFO_API_S_VER_1 */ -/** - * struct iwl_fw_ini_trigger - * - * @trigger_id: &enum iwl_fw_ini_trigger_id - * @override_trig: determines how apply trigger in case a trigger with the - * same id is already in use. Using the first 2 bytes: - * Byte 0: if 0, override trigger configuration, otherwise use the - * existing configuration. - * Byte 1: if 0, override trigger regions, otherwise append regions to - * existing trigger. - * @dump_delay: delay from trigger fire to dump, in usec - * @occurrences: max amount of times to be fired - * @reserved: to align to FW struct - * @ignore_consec: ignore consecutive triggers, in usec - * @force_restart: force FW restart - * @multi_dut: initiate debug dump data on several DUTs - * @trigger_data: generic data to be utilized per trigger - * @num_regions: number of dump regions defined for this trigger - * @data: region IDs - */ -struct iwl_fw_ini_trigger { - __le32 trigger_id; - __le32 override_trig; - __le32 dump_delay; - __le32 occurrences; - __le32 reserved; - __le32 ignore_consec; - __le32 force_restart; - __le32 multi_dut; - __le32 trigger_data; - __le32 num_regions; - __le32 data[]; -} __packed; /* FW_TLV_DEBUG_TRIGGER_CONFIG_API_S_VER_1 */ - /** * struct iwl_fw_ini_allocation_tlv - Allocates DRAM buffers * @@ -384,101 +274,6 @@ struct iwl_fw_ini_hcmd_tlv { struct iwl_fw_ini_hcmd hcmd; } __packed; /* FW_TLV_DEBUG_HCMD_API_S_VER_1 */ -/** - * enum iwl_fw_ini_trigger_id - * - * @IWL_FW_TRIGGER_ID_FW_ASSERT: FW assert - * @IWL_FW_TRIGGER_ID_FW_HW_ERROR: HW assert - * @IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG: TFD queue hang - * @IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER: FW debug notification - * @IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFICATION: FW generic notification - * @IWL_FW_TRIGGER_ID_USER_TRIGGER: User trigger - * @IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER: triggers periodically - * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY: peer inactivity - * @IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED: TX latency - * threshold was crossed - * @IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED: TX failed - * @IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER: Deauth initiated by host - * @IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST: stop GO request - * @IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST: start GO request - * @IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST: join P2P group request - * @IWL_FW_TRIGGER_ID_HOST_SCAN_START: scan started event - * @IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED: undefined - * @IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS: undefined - * @IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG: undefined - * @IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED: BAR frame was received - * @IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED: agg TX failed - * @IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED: EAPOL TX failed - * @IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED: suspicious TX response - * @IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT: received suspicious auth - * @IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE: roaming was completed - * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED: fast assoc failed - * @IWL_FW_TRIGGER_ID_HOST_D3_START: D3 start - * @IWL_FW_TRIGGER_ID_HOST_D3_END: D3 end - * @IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS: missed beacon events - * @IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS: P2P missed beacon events - * @IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES: undefined - * @IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED: undefined - * @IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED: authentication / association - * failed - * @IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE: scan complete event - * @IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT: scan abort complete - * @IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE: nic alive message was received - * @IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE: CSA was completed - * @IWL_FW_TRIGGER_ID_NUM: number of trigger IDs - */ -enum iwl_fw_ini_trigger_id { - IWL_FW_TRIGGER_ID_INVALID = 0, - - /* Errors triggers */ - IWL_FW_TRIGGER_ID_FW_ASSERT = 1, - IWL_FW_TRIGGER_ID_FW_HW_ERROR = 2, - IWL_FW_TRIGGER_ID_FW_TFD_Q_HANG = 3, - - /* FW triggers */ - IWL_FW_TRIGGER_ID_FW_DEBUG_HOST_TRIGGER = 4, - IWL_FW_TRIGGER_ID_FW_GENERIC_NOTIFICATION = 5, - - /* User trigger */ - IWL_FW_TRIGGER_ID_USER_TRIGGER = 6, - - /* periodic uses the data field for the interval time */ - IWL_FW_TRIGGER_ID_PERIODIC_TRIGGER = 7, - - /* Host triggers */ - IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_INACTIVITY = 8, - IWL_FW_TRIGGER_ID_HOST_TX_LATENCY_THRESHOLD_CROSSED = 9, - IWL_FW_TRIGGER_ID_HOST_TX_RESPONSE_STATUS_FAILED = 10, - IWL_FW_TRIGGER_ID_HOST_OS_REQ_DEAUTH_PEER = 11, - IWL_FW_TRIGGER_ID_HOST_STOP_GO_REQUEST = 12, - IWL_FW_TRIGGER_ID_HOST_START_GO_REQUEST = 13, - IWL_FW_TRIGGER_ID_HOST_JOIN_GROUP_REQUEST = 14, - IWL_FW_TRIGGER_ID_HOST_SCAN_START = 15, - IWL_FW_TRIGGER_ID_HOST_SCAN_SUBMITTED = 16, - IWL_FW_TRIGGER_ID_HOST_SCAN_PARAMS = 17, - IWL_FW_TRIGGER_ID_HOST_CHECK_FOR_HANG = 18, - IWL_FW_TRIGGER_ID_HOST_BAR_RECEIVED = 19, - IWL_FW_TRIGGER_ID_HOST_AGG_TX_RESPONSE_STATUS_FAILED = 20, - IWL_FW_TRIGGER_ID_HOST_EAPOL_TX_RESPONSE_FAILED = 21, - IWL_FW_TRIGGER_ID_HOST_FAKE_TX_RESPONSE_SUSPECTED = 22, - IWL_FW_TRIGGER_ID_HOST_AUTH_REQ_FROM_ASSOC_CLIENT = 23, - IWL_FW_TRIGGER_ID_HOST_ROAM_COMPLETE = 24, - IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAST_FAILED = 25, - IWL_FW_TRIGGER_ID_HOST_D3_START = 26, - IWL_FW_TRIGGER_ID_HOST_D3_END = 27, - IWL_FW_TRIGGER_ID_HOST_BSS_MISSED_BEACONS = 28, - IWL_FW_TRIGGER_ID_HOST_P2P_CLIENT_MISSED_BEACONS = 29, - IWL_FW_TRIGGER_ID_HOST_PEER_CLIENT_TX_FAILURES = 30, - IWL_FW_TRIGGER_ID_HOST_TX_WFD_ACTION_FRAME_FAILED = 31, - IWL_FW_TRIGGER_ID_HOST_AUTH_ASSOC_FAILED = 32, - IWL_FW_TRIGGER_ID_HOST_SCAN_COMPLETE = 33, - IWL_FW_TRIGGER_ID_HOST_SCAN_ABORT = 34, - IWL_FW_TRIGGER_ID_HOST_NIC_ALIVE = 35, - IWL_FW_TRIGGER_ID_HOST_CHANNEL_SWITCH_COMPLETE = 36, - - IWL_FW_TRIGGER_ID_NUM, -}; /* FW_DEBUG_TLV_TRIGGER_ID_E_VER_1 */ - /** * enum iwl_fw_ini_allocation_id * @@ -486,9 +281,6 @@ enum iwl_fw_ini_trigger_id { * @IWL_FW_INI_ALLOCATION_ID_DBGC1: allocation meant for DBGC1 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC2: allocation meant for DBGC2 configuration * @IWL_FW_INI_ALLOCATION_ID_DBGC3: allocation meant for DBGC3 configuration - * @IWL_FW_INI_ALLOCATION_ID_SDFX: for SDFX module - * @IWL_FW_INI_ALLOCATION_ID_FW_DUMP: used for crash and runtime dumps - * @IWL_FW_INI_ALLOCATION_ID_USER_DEFINED: for future user scenarios * @IWL_FW_INI_ALLOCATION_NUM: number of allocation ids */ enum iwl_fw_ini_allocation_id { @@ -496,9 +288,6 @@ enum iwl_fw_ini_allocation_id { IWL_FW_INI_ALLOCATION_ID_DBGC1, IWL_FW_INI_ALLOCATION_ID_DBGC2, IWL_FW_INI_ALLOCATION_ID_DBGC3, - IWL_FW_INI_ALLOCATION_ID_SDFX, - IWL_FW_INI_ALLOCATION_ID_FW_DUMP, - IWL_FW_INI_ALLOCATION_ID_USER_DEFINED, IWL_FW_INI_ALLOCATION_NUM, }; /* FW_DEBUG_TLV_ALLOCATION_ID_E_VER_1 */ @@ -517,19 +306,6 @@ enum iwl_fw_ini_buffer_location { IWL_FW_INI_LOCATION_NPK_PATH, }; /* FW_DEBUG_TLV_BUFFER_LOCATION_E_VER_1 */ -/** - * enum iwl_fw_ini_debug_flow - * - * @IWL_FW_INI_DEBUG_INVALID: invalid - * @IWL_FW_INI_DEBUG_DBTR_FLOW: undefined - * @IWL_FW_INI_DEBUG_TB2DTF_FLOW: undefined - */ -enum iwl_fw_ini_debug_flow { - IWL_FW_INI_DEBUG_INVALID, - IWL_FW_INI_DEBUG_DBTR_FLOW, - IWL_FW_INI_DEBUG_TB2DTF_FLOW, -}; /* FW_DEBUG_TLV_FLOW_E_VER_1 */ - /** * enum iwl_fw_ini_region_type * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index 039576d71276..dbeab093171e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -227,18 +227,6 @@ struct iwl_fw_dbg { u32 dump_mask; }; -/** - * struct iwl_fw_ini_active_triggers - * @active: is this trigger active - * @size: allocated memory size of the trigger - * @trig: trigger - */ -struct iwl_fw_ini_active_triggers { - bool active; - size_t size; - struct iwl_fw_ini_trigger *trig; -}; - /** * struct iwl_fw - variables associated with the firmware * diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 87adbd3dd764..ec2ab0281f18 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -183,8 +183,6 @@ struct iwl_fw_runtime { /* ts of the beginning of a non-collect fw dbg data period */ unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM]; u32 *d3_debug_data; - struct iwl_fw_ini_region_cfg *active_regs[IWL_FW_INI_MAX_REGION_ID]; - struct iwl_fw_ini_active_triggers active_trigs[IWL_FW_TRIGGER_ID_NUM]; u32 lmac_err_id[MAX_NUM_LMAC]; u32 umac_err_id; @@ -220,16 +218,6 @@ static inline void iwl_fw_runtime_free(struct iwl_fw_runtime *fwrt) kfree(fwrt->dump.d3_debug_data); fwrt->dump.d3_debug_data = NULL; - for (i = 0; i < IWL_FW_TRIGGER_ID_NUM; i++) { - struct iwl_fw_ini_active_triggers *active = - &fwrt->dump.active_trigs[i]; - - active->active = false; - active->size = 0; - kfree(active->trig); - active->trig = NULL; - } - iwl_dbg_tlv_del_timers(fwrt->trans); for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) cancel_delayed_work_sync(&fwrt->dump.wks[i].wk); -- cgit v1.2.3-59-g8ed1b From eae7550b9d9c95fc84b430ecaeaef99bc71bbf5c Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Thu, 25 Jul 2019 13:25:07 +0300 Subject: iwlwifi: dbg_ini: support FW notification dumping in case of missed beacon Pass the FW notification packet to the dump collection flow to allow the driver to include it in the dump file if requested. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 1934df7fccb8..f266647dc08c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -1067,6 +1067,7 @@ void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); break; case IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF: + case IWL_FW_INI_TIME_POINT_MISSED_BEACONS: iwl_dbg_tlv_send_hcmds(fwrt, hcmd_list); iwl_dbg_tlv_tp_trigger(fwrt, trig_list, tp_data, iwl_dbg_tlv_check_fw_pkt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9c417dd06291..70bb150ee0ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1404,6 +1404,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, u32 rx_missed_bcon, rx_missed_bcon_since_rx; struct ieee80211_vif *vif; u32 id = le32_to_cpu(mb->mac_id); + union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; IWL_DEBUG_INFO(mvm, "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", @@ -1432,7 +1433,7 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, ieee80211_beacon_loss(vif); iwl_dbg_tlv_time_point(&mvm->fwrt, - IWL_FW_INI_TIME_POINT_MISSED_BEACONS, NULL); + IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); trigger = iwl_fw_dbg_trigger_on(&mvm->fwrt, ieee80211_vif_to_wdev(vif), FW_DBG_TRIGGER_MISSED_BEACONS); -- cgit v1.2.3-59-g8ed1b From ee4cce9b9d6421d037ffc002536b918fd7f4aff3 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Sun, 28 Jul 2019 20:09:22 +0300 Subject: iwlwifi: mvm: consider ieee80211 station max amsdu value debugfs amsdu_len sets only the max_amsdu_len for ieee80211 station so take it into consideration while getting max amsdu Fixes: af2984e9e625 ("iwlwifi: mvm: add a debugfs entry to set a fixed size AMSDU for all TX packets") Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 8 +++++++- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 8f50e2b121bd..098d48153a38 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -350,7 +350,13 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, u16 size = le32_to_cpu(notif->amsdu_size); int i; - if (WARN_ON(sta->max_amsdu_len < size)) + /* + * In debug sta->max_amsdu_len < size + * so also check with orig_amsdu_len which holds the original + * data before debugfs changed the value + */ + if (WARN_ON(sta->max_amsdu_len < size && + mvmsta->orig_amsdu_len < size)) goto out; mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 8a059da7a1fa..e3b2a2bf3863 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -935,7 +935,12 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, !(mvmsta->amsdu_enabled & BIT(tid))) return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); - max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid); + /* + * Take the min of ieee80211 station and mvm station + */ + max_amsdu_len = + min_t(unsigned int, sta->max_amsdu_len, + iwl_mvm_max_amsdu_size(mvm, sta, tid)); /* * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not -- cgit v1.2.3-59-g8ed1b From d3b4dc014c9ccad665a676ffb55ce7980663a6e0 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Tue, 23 Jul 2019 18:27:45 +0300 Subject: iwlwifi: mvm: add support for new version for D0I3_END_CMD During D3 state there are some flows which requires FW reset. Add new API to support it. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/d3.h | 8 +++++++ drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 29 +++++++++++++++++++++++++- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 4 ++++ drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 27 ++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 4c3219e7beb6..3643b6ba6385 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -64,6 +64,14 @@ #ifndef __iwl_fw_api_d3_h__ #define __iwl_fw_api_d3_h__ +/** + * enum iwl_d0i3_flags - d0i3 flags + * @IWL_D0I3_RESET_REQUIRE: FW require reset upon resume + */ +enum iwl_d0i3_flags { + IWL_D0I3_RESET_REQUIRE = BIT(0), +}; + /** * enum iwl_d3_wakeup_flags - D3 manager wakeup flags * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 86c2c587e755..1a9d83d6230f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1955,12 +1955,39 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) } if (d0i3_first) { - ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, 0, 0, NULL); + struct iwl_host_cmd cmd = { + .id = D0I3_END_CMD, + .flags = CMD_WANT_SKB, + }; + int len; + + ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret < 0) { IWL_ERR(mvm, "Failed to send D0I3_END_CMD first (%d)\n", ret); goto err; } + switch (mvm->cmd_ver.d0i3_resp) { + case 0: + break; + case 1: + len = iwl_rx_packet_payload_len(cmd.resp_pkt); + if (len != sizeof(u32)) { + IWL_ERR(mvm, + "Error with D0I3_END_CMD response size (%d)\n", + len); + goto err; + } + if (IWL_D0I3_RESET_REQUIRE & + le32_to_cpu(*(__le32 *)cmd.resp_pkt->data)) { + iwl_write32(mvm->trans, CSR_RESET, + CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_free_resp(&cmd); + } + break; + default: + WARN_ON(1); + } } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 843d00bf2bd5..43257579ab48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1122,6 +1122,10 @@ struct iwl_mvm { int responses[IWL_MVM_TOF_MAX_APS]; } ftm_initiator; + struct { + u8 d0i3_resp; + } cmd_ver; + struct ieee80211_vif *nan_vif; #define IWL_MAX_BAID 32 struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3acbd5b7ab4b..cc4b5554c715 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -608,6 +608,27 @@ static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = { .d3_debug_enable = iwl_mvm_d3_debug_enable, }; +static u8 iwl_mvm_lookup_notif_ver(struct iwl_mvm *mvm, u8 grp, u8 cmd, u8 def) +{ + const struct iwl_fw_cmd_version *entry; + unsigned int i; + + if (!mvm->fw->ucode_capa.cmd_versions || + !mvm->fw->ucode_capa.n_cmd_versions) + return def; + + entry = mvm->fw->ucode_capa.cmd_versions; + for (i = 0; i < mvm->fw->ucode_capa.n_cmd_versions; i++, entry++) { + if (entry->group == grp && entry->cmd == cmd) { + if (entry->notif_ver == IWL_FW_CMD_VER_UNKNOWN) + return def; + return entry->notif_ver; + } + } + + return def; +} + static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -722,6 +743,12 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, INIT_DELAYED_WORK(&mvm->cs_tx_unblock_dwork, iwl_mvm_tx_unblock_dwork); + mvm->cmd_ver.d0i3_resp = + iwl_mvm_lookup_notif_ver(mvm, LEGACY_GROUP, D0I3_END_CMD, 0); + /* we only support version 1 */ + if (WARN_ON_ONCE(mvm->cmd_ver.d0i3_resp > 1)) + goto out_free; + /* * Populate the state variables that the transport layer needs * to know about. -- cgit v1.2.3-59-g8ed1b From c327ae2fe12f613dee91a8513b39fd2dba46a7b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Jul 2019 13:21:46 +0200 Subject: iwlwifi: mvm: remove leftover rs_remove_sta_debugfs() prototype This prototype is no longer used, remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 428642e66658..7cd62c5622ce 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -445,10 +445,6 @@ int iwl_mvm_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm); #endif -#ifdef CONFIG_MAC80211_DEBUGFS -void rs_remove_sta_debugfs(void *mvm, void *mvm_sta); -#endif - void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta); void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update); -- cgit v1.2.3-59-g8ed1b From fe959c7b20495fe05de5f65ea0968a7b128afa9e Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 11 Jul 2019 21:44:42 +0300 Subject: iwlwifi: mvm: use the new session protection command The firmware has now a new session protection command. This new API allows the firmware to manage the protection needed for association. It'll also remove the event when the association is complete. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 14 +- .../net/wireless/intel/iwlwifi/fw/api/time-event.h | 80 ++++++++- drivers/net/wireless/intel/iwlwifi/fw/file.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 33 +++- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 4 + .../net/wireless/intel/iwlwifi/mvm/time-event.c | 189 ++++++++++++++++++++- .../net/wireless/intel/iwlwifi/mvm/time-event.h | 21 ++- 7 files changed, 331 insertions(+), 11 deletions(-) (limited to 'drivers/net') 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 6b4d59daacd6..69786343aff4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,6 +77,16 @@ enum iwl_mac_conf_subcmd_ids { * @CHANNEL_SWITCH_TIME_EVENT_CMD: &struct iwl_chan_switch_te_cmd */ CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4, + /** + * @SESSION_PROTECTION_CMD: &struct iwl_mvm_session_prot_cmd + */ + SESSION_PROTECTION_CMD = 0x5, + + /** + * @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif + */ + SESSION_PROTECTION_NOTIF = 0xFB, + /** * @PROBE_RESPONSE_DATA_NOTIF: &struct iwl_probe_resp_data_notif */ 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 4621ef93a2cf..416e817d7b4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -393,4 +393,80 @@ struct iwl_hs20_roc_res { __le32 status; } __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ +/** + * enum iwl_mvm_session_prot_conf_id - session protection's configurations + * @SESSION_PROTECT_CONF_ASSOC: Start a session protection for association. + * The firmware will allocate two events. + * Valid for BSS_STA and P2P_STA. + * * A rather short event that can't be fragmented and with a very + * high priority. If every goes well (99% of the cases) the + * association should complete within this first event. During + * that event, no other activity will happen in the firmware, + * which is why it can't be too long. + * The length of this event is hard-coded in the firmware: 300TUs. + * * Another event which can be much longer (it's duration is + * configurable by the driver) which has a slightly lower + * priority and that can be fragmented allowing other activities + * to run while this event is running. + * The firmware will automatically remove both events once the driver sets + * the BSS MAC as associated. Neither of the events will be removed + * for the P2P_STA MAC. + * Only the duration is configurable for this protection. + * @SESSION_PROTECT_CONF_GO_CLIENT_ASSOC: not used + * @SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV: Schedule the P2P Device to be in + * listen mode. Will be fragmented. Valid only on the P2P Device MAC. + * Valid only on the P2P Device MAC. The firmware will take into account + * the duration, the interval and the repetition count. + * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be be + * able to run the GO Negotiation. Will not be fragmented and not + * repetitive. Valid only on the P2P Device MAC. Only the duration will + * be taken into account. + */ +enum iwl_mvm_session_prot_conf_id { + SESSION_PROTECT_CONF_ASSOC, + SESSION_PROTECT_CONF_GO_CLIENT_ASSOC, + SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV, + SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION, +}; /* SESSION_PROTECTION_CONF_ID_E_VER_1 */ + +/** + * 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 + * @conf_id: see &enum iwl_mvm_session_prot_conf_id + * @duration_tu: the duration of the whole protection in TUs. + * @repetition_count: not used + * @interval: not used + * + * Note: the session protection will always be scheduled to start as + * early as possible, but the maximum delay is configuration dependent. + * The firmware supports only one concurrent session protection per vif. + * Adding a new session protection will remove any currently running session. + */ +struct iwl_mvm_session_prot_cmd { + /* COMMON_INDEX_HDR_API_S_VER_1 hdr */ + __le32 id_and_color; + __le32 action; + __le32 conf_id; + __le32 duration_tu; + __le32 repetition_count; + __le32 interval; +} __packed; /* SESSION_PROTECTION_CMD_API_S_VER_1 */ + +/** + * struct iwl_mvm_session_prot_notif - session protection started / ended + * @mac_id: the mac id for which the session protection started / ended + * @status: 1 means success, 0 means failure + * @start: 1 means the session protection started, 0 means it ended + * + * Note that any session protection will always get two notifications: start + * and end even the firmware could not schedule it. + */ +struct iwl_mvm_session_prot_notif { + __le32 mac_id; + __le32 status; + __le32 start; +} __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_1 */ + #endif /* __iwl_fw_api_time_event_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 105fd37f7da5..07628566cb4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -445,6 +445,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_CS_MODIFY = (__force iwl_ucode_tlv_capa_t)49, IWL_UCODE_TLV_CAPA_SET_LTR_GEN2 = (__force iwl_ucode_tlv_capa_t)50, IWL_UCODE_TLV_CAPA_SET_PPAG = (__force iwl_ucode_tlv_capa_t)52, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD = (__force iwl_ucode_tlv_capa_t)54, /* set 2 */ IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE = (__force iwl_ucode_tlv_capa_t)64, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index cd1b10042fbf..8465dfe5d90b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -2280,7 +2280,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, } if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, - &mvm->status)) { + &mvm->status) && + !fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { /* * If we're restarting then the firmware will * obviously have lost synchronisation with @@ -2294,6 +2296,10 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, * * Set a large maximum delay to allow for more * than a single interface. + * + * For new firmware versions, rely on the + * firmware. This is relevant for DCM scenarios + * only anyway. */ u32 dur = (11 * vif->bss_conf.beacon_int) / 10; iwl_mvm_protect_session(mvm, vif, dur, dur, @@ -2384,8 +2390,11 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, /* * We received a beacon from the associated AP so * remove the session protection. + * A firmware with the new API will remove it automatically. */ - iwl_mvm_stop_session_protection(mvm, vif); + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_stop_session_protection(mvm, vif); iwl_mvm_sf_update(mvm, vif, false); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0)); @@ -3255,8 +3264,22 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, duration = req_duration; mutex_lock(&mvm->mutex); - /* Try really hard to protect the session and hear a beacon */ - iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false); + /* Try really hard to protect the session and hear a beacon + * The new session protection command allows us to protect the + * session for a much longer time since the firmware will internally + * create two events: a 300TU one with a very high priority that + * won't be fragmented which should be enough for 99% of the cases, + * and another one (which we configure here to be 900TU long) which + * will have a slightly lower priority, but more importantly, can be + * fragmented so that it'll allow other activities to run. + */ + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + iwl_mvm_schedule_session_protection(mvm, vif, 900, + min_duration); + else + iwl_mvm_protect_session(mvm, vif, duration, + min_duration, 500, false); mutex_unlock(&mvm->mutex); } @@ -3848,7 +3871,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(mvm, "enter\n"); mutex_lock(&mvm->mutex); - iwl_mvm_stop_roc(mvm); + iwl_mvm_stop_roc(mvm, vif); mutex_unlock(&mvm->mutex); IWL_DEBUG_MAC80211(mvm, "leave\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index cc4b5554c715..dcdc195ac1d6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -263,6 +263,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(TIME_EVENT_NOTIFICATION, iwl_mvm_rx_time_event_notif, RX_HANDLER_SYNC), + RX_HANDLER_GRP(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF, + iwl_mvm_rx_session_protect_notif, RX_HANDLER_SYNC), RX_HANDLER(MCC_CHUB_UPDATE_CMD, iwl_mvm_rx_chub_update_mcc, RX_HANDLER_ASYNC_LOCKED), @@ -432,6 +434,8 @@ static const struct iwl_hcmd_names iwl_mvm_system_names[] = { */ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(CHANNEL_SWITCH_TIME_EVENT_CMD), + HCMD_NAME(SESSION_PROTECTION_CMD), + HCMD_NAME(SESSION_PROTECTION_NOTIF), HCMD_NAME(CHANNEL_SWITCH_NOA_NOTIF), }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index a06bc63fb516..51b138673ddb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -734,6 +734,11 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, return; } +/* + * When the firmware supports the session protection API, + * this is not needed since it'll automatically remove the + * session protection after association + beacon reception. + */ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -757,6 +762,101 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, iwl_mvm_remove_time_event(mvm, mvmvif, te_data); } +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_mvm_session_prot_notif *notif = (void *)pkt->data; + struct ieee80211_vif *vif; + + rcu_read_lock(); + vif = iwl_mvm_rcu_dereference_vif_id(mvm, le32_to_cpu(notif->mac_id), + true); + + if (!vif) + goto out_unlock; + + /* The vif is not a P2P_DEVICE, maintain its time_event_data */ + if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = + &mvmvif->time_event_data; + + if (!le32_to_cpu(notif->status)) { + iwl_mvm_te_check_disconnect(mvm, vif, + "Session protection failure"); + iwl_mvm_te_clear_data(mvm, te_data); + } + + if (le32_to_cpu(notif->start)) { + spin_lock_bh(&mvm->time_event_lock); + te_data->running = le32_to_cpu(notif->start); + te_data->end_jiffies = + TU_TO_EXP_TIME(te_data->duration); + spin_unlock_bh(&mvm->time_event_lock); + } else { + /* + * By now, we should have finished association + * and know the dtim period. + */ + iwl_mvm_te_check_disconnect(mvm, vif, + "No beacon heard and the session protection is over already..."); + iwl_mvm_te_clear_data(mvm, te_data); + } + + goto out_unlock; + } + + if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) { + /* End TE, notify mac80211 */ + ieee80211_remain_on_channel_expired(mvm->hw); + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + iwl_mvm_roc_finished(mvm); + } else if (le32_to_cpu(notif->start)) { + set_bit(IWL_MVM_STATUS_ROC_RUNNING, &mvm->status); + ieee80211_ready_on_channel(mvm->hw); /* Start TE */ + } + + out_unlock: + rcu_read_unlock(); +} + +static int +iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int duration, + enum ieee80211_roc_type type) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + + lockdep_assert_held(&mvm->mutex); + + switch (type) { + case IEEE80211_ROC_TYPE_NORMAL: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_DEVICE_DISCOV); + break; + case IEEE80211_ROC_TYPE_MGMT_TX: + cmd.conf_id = + cpu_to_le32(SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION); + break; + default: + WARN_ONCE(1, "Got an invalid ROC type\n"); + return -EINVAL; + } + + return iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); +} + int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum ieee80211_roc_type type) { @@ -770,6 +870,12 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EBUSY; } + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) + return iwl_mvm_start_p2p_roc_session_protection(mvm, vif, + duration, + type); + time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); time_cmd.id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); @@ -847,11 +953,44 @@ void iwl_mvm_cleanup_roc_te(struct iwl_mvm *mvm) __iwl_mvm_remove_time_event(mvm, te_data, &uid); } -void iwl_mvm_stop_roc(struct iwl_mvm *mvm) +static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvmvif) +{ + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + int ret; + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); +} + +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif; struct iwl_mvm_time_event_data *te_data; + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + iwl_mvm_cancel_session_protection(mvm, mvmvif); + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); + + iwl_mvm_roc_finished(mvm); + + return; + } + te_data = iwl_mvm_get_roc_te(mvm); if (!te_data) { IWL_WARN(mvm, "No remain on channel event\n"); @@ -916,3 +1055,51 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); } + +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; + + struct iwl_mvm_session_prot_cmd cmd = { + .id_and_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_ADD), + .conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC), + .duration_tu = cpu_to_le32(MSEC_TO_TU(duration)), + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + spin_lock_bh(&mvm->time_event_lock); + if (te_data->running && + time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) { + IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n", + jiffies_to_msecs(te_data->end_jiffies - jiffies)); + spin_unlock_bh(&mvm->time_event_lock); + + return; + } + + iwl_mvm_te_clear_data(mvm, te_data); + te_data->duration = le32_to_cpu(cmd.duration_tu); + spin_unlock_bh(&mvm->time_event_lock); + + IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", + le32_to_cpu(cmd.duration_tu)); + + ret = iwl_mvm_send_cmd_pdu(mvm, iwl_cmd_id(SESSION_PROTECTION_CMD, + MAC_CONF_GROUP, 0), + 0, sizeof(cmd), &cmd); + if (ret) { + IWL_ERR(mvm, + "Couldn't send the SESSION_PROTECTION_CMD: %d\n", ret); + spin_lock_bh(&mvm->time_event_lock); + iwl_mvm_te_clear_data(mvm, te_data); + spin_unlock_bh(&mvm->time_event_lock); + } +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 1dd3d01245ea..df6832b79666 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,6 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright (C) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -178,12 +180,13 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /** * iwl_mvm_stop_roc - stop remain on channel functionality * @mvm: the mvm component + * @vif: the virtual interface for which the roc is stopped * * This function can be used to cancel an ongoing ROC session. * The function is async, it will instruct the FW to stop serving the ROC * session, but will not wait for the actual stopping of the session. */ -void iwl_mvm_stop_roc(struct iwl_mvm *mvm); +void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif); /** * iwl_mvm_remove_time_event - general function to clean up of time event @@ -242,4 +245,20 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) return !!te_data->uid; } +/** + * iwl_mvm_schedule_session_protection - schedule a session protection + * @mvm: the mvm component + * @vif: the virtual interface for which the protection issued + * @duration: the duration of the protection + */ +void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + u32 duration, u32 min_duration); + +/** + * iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF + */ +void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); + #endif /* __time_event_h__ */ -- cgit v1.2.3-59-g8ed1b From 7f2ea52123426b05cd83aec35a4abfb93f66be2b Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 26 Jul 2019 22:18:38 +0800 Subject: iwlwifi: mvm: fix old-style declaration There expect the 'static' keyword to come first in a declaration, and we get warnings like this with "make W=1": drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c:427:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c:434:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 8465dfe5d90b..a7d5bd1c1206 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -339,14 +339,14 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) return ret; } -const static u8 he_if_types_ext_capa_sta[] = { +static const u8 he_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, }; -const static struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { +static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { { .iftype = NL80211_IFTYPE_STATION, .extended_capabilities = he_if_types_ext_capa_sta, -- cgit v1.2.3-59-g8ed1b From 449a29d0feada2810ffca692b7dee8470073c3d5 Mon Sep 17 00:00:00 2001 From: Lior Cohen Date: Thu, 18 Jul 2019 11:37:48 +0300 Subject: iwlwifi: mvm: add notification for missed VAP A missed VAP notification will be sent from umac when the station is out of sync with its associated non-transmitted BSSID. The notification will be sent only if the transmitted BSSID is an EMA-AP one. The driver will consider this notification as connection loss. Signed-off-by: Lior Cohen Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 19 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 23 ++++++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 2 ++ 3 files changed, 44 insertions(+) (limited to 'drivers/net') 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 69786343aff4..e7a1acedbcf1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -77,6 +77,10 @@ enum iwl_mac_conf_subcmd_ids { * @CHANNEL_SWITCH_TIME_EVENT_CMD: &struct iwl_chan_switch_te_cmd */ CHANNEL_SWITCH_TIME_EVENT_CMD = 0x4, + /** + * @MISSED_VAP_NOTIF: &struct iwl_missed_vap_notif + */ + MISSED_VAP_NOTIF = 0xFA, /** * @SESSION_PROTECTION_CMD: &struct iwl_mvm_session_prot_cmd */ @@ -140,6 +144,21 @@ struct iwl_probe_resp_data_notif { u8 reserved[3]; } __packed; /* PROBE_RESPONSE_DATA_NTFY_API_S_VER_1 */ +/** + * struct iwl_missed_vap_notif - notification of missing vap detection + * + * @mac_id: the mac for which the ucode sends the notification for + * @num_beacon_intervals_elapsed: beacons elpased with no vap profile inside + * @profile_periodicity: beacons period to have our profile inside + * @reserved: reserved for alignment purposes + */ +struct iwl_missed_vap_notif { + __le32 mac_id; + u8 num_beacon_intervals_elapsed; + u8 profile_periodicity; + u8 reserved[2]; +} __packed; /* MISSED_VAP_NTFY_API_S_VER_1 */ + /** * struct iwl_channel_switch_noa_notif - Channel switch NOA notification * diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 70bb150ee0ca..d9c23cd96336 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -1610,3 +1610,26 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, out_unlock: rcu_read_unlock(); } + +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_missed_vap_notif *mb = (void *)pkt->data; + struct ieee80211_vif *vif; + u32 id = le32_to_cpu(mb->mac_id); + + IWL_DEBUG_INFO(mvm, + "missed_vap notify mac_id=%u, num_beacon_intervals_elapsed=%u, profile_periodicity=%u\n", + le32_to_cpu(mb->mac_id), + mb->num_beacon_intervals_elapsed, + mb->profile_periodicity); + + rcu_read_lock(); + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + if (vif) + iwl_mvm_connection_loss(mvm, vif, "missed vap beacon"); + + rcu_read_unlock(); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 43257579ab48..f0246969dca0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1680,6 +1680,8 @@ void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_missed_vap_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); /* Bindings */ -- cgit v1.2.3-59-g8ed1b From 3b445ed9b72a8d1614a78aa31245f8c5eb9e595d Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Sun, 4 Aug 2019 10:57:16 +0300 Subject: iwlwifi: dbg_ini: add user trigger support Allow to fire user trigger in ini mode Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index ad18c2f1a806..b6db1f8f40cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1375,6 +1375,9 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, if (count == 0) return 0; + iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, + NULL); + iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, (count - 1), NULL); -- cgit v1.2.3-59-g8ed1b From 6abe1e2e39048ce26cbad276841b9b1b2a7e627a Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Sun, 4 Aug 2019 14:06:45 +0300 Subject: iwlwifi: dbg_ini: use vzalloc to allocate dumping memory regions During dump flow, the driver allocates spaces to store the memory regions that will be included in the dump. These regions can be very large so in order to avoid allocation failure, use vzalloc instead. The kmalloc uses GFP_KERNEL and the driver does not make any use of the fact that the memory is contiguous so the same functionality is maintained. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index ce77ed17ede0..007a722cf1c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1846,7 +1846,7 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, if (!size) return 0; - entry = kmalloc(sizeof(*entry) + sizeof(*tlv) + size, GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + size); if (!entry) return 0; @@ -1892,7 +1892,7 @@ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, return entry->size; out_err: - kfree(entry); + vfree(entry); return 0; } @@ -1914,7 +1914,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, num_of_cfg_names++; } - entry = kmalloc(sizeof(*entry) + size, GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + size); if (!entry) return 0; @@ -2121,7 +2121,7 @@ static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, !le64_to_cpu(trigger->regions_mask)) return 0; - entry = kmalloc(sizeof(*entry) + sizeof(*hdr), GFP_KERNEL); + entry = vzalloc(sizeof(*entry) + sizeof(*hdr)); if (!entry) return 0; @@ -2129,7 +2129,7 @@ static u32 iwl_dump_ini_file_gen(struct iwl_fw_runtime *fwrt, size = iwl_dump_ini_trigger(fwrt, dump_data, list); if (!size) { - kfree(entry); + vfree(entry); return 0; } @@ -2195,7 +2195,7 @@ static void iwl_dump_ini_list_free(struct list_head *list) list_entry(list->next, typeof(*entry), list); list_del(&entry->list); - kfree(entry); + vfree(entry); } } -- cgit v1.2.3-59-g8ed1b From 3717f91a81afde5c2b7143f0d1bafb389cfb6fad Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Wed, 31 Jul 2019 09:06:31 +0300 Subject: iwlwifi: mvm: create function to convert nl80211 band to phy band Create the function and use it. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +-- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 22 ++++++++++++++++++---- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 20 ++++++-------------- 3 files changed, 25 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index a7d5bd1c1206..e879c02ca4db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3636,8 +3636,7 @@ static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info(mvm, &aux_roc_req.channel_info, channel->hw_value, - (channel->band == NL80211_BAND_2GHZ) ? - PHY_BAND_24 : PHY_BAND_5, + iwl_mvm_phy_band_from_nl80211(channel->band), PHY_VHT_CHANNEL_MODE20, 0); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index f0246969dca0..d9c437682a5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -2077,6 +2077,19 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct dentry *dir); #endif +static inline u8 iwl_mvm_phy_band_from_nl80211(enum nl80211_band band) +{ + switch (band) { + case NL80211_BAND_2GHZ: + return PHY_BAND_24; + case NL80211_BAND_5GHZ: + return PHY_BAND_5; + default: + WARN_ONCE(1, "Unsupported band (%u)\n", band); + return PHY_BAND_5; + } +} + /* Channel info utils */ static inline bool iwl_mvm_has_ultra_hb_channel(struct iwl_mvm *mvm) { @@ -2125,11 +2138,12 @@ iwl_mvm_set_chan_info_chandef(struct iwl_mvm *mvm, struct iwl_fw_channel_info *ci, struct cfg80211_chan_def *chandef) { + enum nl80211_band band = chandef->chan->band; + iwl_mvm_set_chan_info(mvm, ci, chandef->chan->hw_value, - (chandef->chan->band == NL80211_BAND_2GHZ ? - PHY_BAND_24 : PHY_BAND_5), - iwl_mvm_get_channel_width(chandef), - iwl_mvm_get_ctrl_pos(chandef)); + iwl_mvm_phy_band_from_nl80211(band), + iwl_mvm_get_channel_width(chandef), + iwl_mvm_get_ctrl_pos(chandef)); } #endif /* __IWL_MVM_H__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index f6b3045badbd..2f92f6516415 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -79,9 +79,6 @@ #define IWL_SCAN_NUM_OF_FRAGS 3 #define IWL_SCAN_LAST_2_4_CHN 14 -#define IWL_SCAN_BAND_5_2 0 -#define IWL_SCAN_BAND_2_4 1 - /* adaptive dwell max budget time [TU] for full scan */ #define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 /* adaptive dwell max budget time [TU] for directed scan */ @@ -196,14 +193,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) return cpu_to_le16(rx_chain); } -static __le32 iwl_mvm_scan_rxon_flags(enum nl80211_band band) -{ - if (band == NL80211_BAND_2GHZ) - return cpu_to_le32(PHY_BAND_24); - else - return cpu_to_le32(PHY_BAND_5); -} - static inline __le32 iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum nl80211_band band, bool no_cck) @@ -981,6 +970,7 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->fw->ucode_capa.n_scan_channels); u32 ssid_bitmap = 0; int i; + u8 band; lockdep_assert_held(&mvm->mutex); @@ -1000,7 +990,8 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd->scan_flags = cpu_to_le32(iwl_mvm_scan_lmac_flags(mvm, params, vif)); - cmd->flags = iwl_mvm_scan_rxon_flags(params->channels[0]->band); + band = iwl_mvm_phy_band_from_nl80211(params->channels[0]->band); + cmd->flags = cpu_to_le32(band); cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | MAC_FILTER_IN_BEACON); iwl_mvm_scan_fill_tx_cmd(mvm, cmd->tx_cmd, params->no_cck); @@ -1402,9 +1393,10 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); channel_cfg[i].v1.channel_num = channels[i]->hw_value; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { + enum nl80211_band band = channels[i]->band; + channel_cfg[i].v2.band = - channels[i]->hw_value <= IWL_SCAN_LAST_2_4_CHN ? - IWL_SCAN_BAND_2_4 : IWL_SCAN_BAND_5_2; + iwl_mvm_phy_band_from_nl80211(band); channel_cfg[i].v2.iter_count = 1; channel_cfg[i].v2.iter_interval = 0; } else { -- cgit v1.2.3-59-g8ed1b From d558b7f834707b6acdfd3f91c8524598db8456f0 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Sun, 28 Jul 2019 13:51:07 +0300 Subject: iwlwifi: mvm: Invert the condition for OFDM rate OFDM rate used for all bands except to band 2.4 which use CCK rate. Inverting the condition help that in future we won't need to expand the condition for more bands. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 7 +++---- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 7 +++++-- drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index d9c23cd96336..b78992e341d5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -855,11 +855,10 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct ieee80211_tx_info *info, struct ieee80211_vif *vif) { u8 rate; - - if (info->band == NL80211_BAND_5GHZ || vif->p2p) - rate = IWL_FIRST_OFDM_RATE; - else + if (info->band == NL80211_BAND_2GHZ && !vif->p2p) rate = IWL_FIRST_CCK_RATE; + else + rate = IWL_FIRST_OFDM_RATE; return rate; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index e3b2a2bf3863..f4778a6a40b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -341,8 +341,11 @@ static u32 iwl_mvm_get_tx_rate(struct iwl_mvm *mvm, rate_idx = rate_lowest_index( &mvm->nvm_data->bands[info->band], sta); - /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ - if (info->band == NL80211_BAND_5GHZ) + /* + * For non 2 GHZ band, remap mac80211 rate + * indices into driver indices + */ + if (info->band != NL80211_BAND_2GHZ) rate_idx += IWL_FIRST_OFDM_RATE; /* For 2.4 GHZ band, check that there is no need to remap */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 8686107da116..6096276cb0d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -217,7 +217,7 @@ int iwl_mvm_legacy_rate_to_mac80211_idx(u32 rate_n_flags, int band_offset = 0; /* Legacy rate format, search for match in table */ - if (band == NL80211_BAND_5GHZ) + if (band != NL80211_BAND_2GHZ) band_offset = IWL_FIRST_OFDM_RATE; for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) if (fw_rate_idx_to_plcp[idx] == rate) -- cgit v1.2.3-59-g8ed1b From e878325a801d2cfd1f0fffdb3380b9aca7f8cc86 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Wed, 31 Jul 2019 11:19:26 +0300 Subject: iwlwifi: nvm: create function to convert channel index to nl80211_band Create function to convert channel index to nl80211_band and use it. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 26 ++++++++++++++-------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index c8972f6e38ba..b0a0901ce0f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -256,12 +256,12 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, #undef CHECK_AND_PRINT_I } -static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, +static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, u32 nvm_flags, const struct iwl_cfg *cfg) { u32 flags = IEEE80211_CHAN_NO_HT40; - if (!is_5ghz && (nvm_flags & NVM_CHANNEL_40MHZ)) { + if (band == NL80211_BAND_2GHZ && (nvm_flags & NVM_CHANNEL_40MHZ)) { if (ch_num <= LAST_2GHZ_HT_PLUS) flags &= ~IEEE80211_CHAN_NO_HT40PLUS; if (ch_num >= FIRST_2GHZ_HT_MINUS) @@ -299,6 +299,13 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, bool is_5ghz, return flags; } +static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx) +{ + if (ch_idx >= NUM_2GHZ_CHANNELS) + return NL80211_BAND_5GHZ; + return NL80211_BAND_2GHZ; +} + static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, struct iwl_nvm_data *data, const void * const nvm_ch_flags, @@ -308,7 +315,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, int n_channels = 0; struct ieee80211_channel *channel; u32 ch_flags; - int num_of_ch, num_2ghz_channels = NUM_2GHZ_CHANNELS; + int num_of_ch; const u16 *nvm_chan; if (cfg->uhb_supported) { @@ -323,7 +330,8 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, } for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { - bool is_5ghz = (ch_idx >= num_2ghz_channels); + enum nl80211_band band = + iwl_nl80211_band_from_channel_idx(ch_idx); if (v4) ch_flags = @@ -332,12 +340,13 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, ch_flags = __le16_to_cpup((__le16 *)nvm_ch_flags + ch_idx); - if (is_5ghz && !data->sku_cap_band_52ghz_enable) + if (band == NL80211_BAND_5GHZ && + !data->sku_cap_band_52ghz_enable) continue; /* workaround to disable wide channels in 5GHz */ if ((sbands_flags & IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ) && - is_5ghz) { + band == NL80211_BAND_5GHZ) { ch_flags &= ~(NVM_CHANNEL_40MHZ | NVM_CHANNEL_80MHZ | NVM_CHANNEL_160MHZ); @@ -362,8 +371,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, n_channels++; channel->hw_value = nvm_chan[ch_idx]; - channel->band = is_5ghz ? - NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; + channel->band = band; channel->center_freq = ieee80211_channel_to_frequency( channel->hw_value, channel->band); @@ -379,7 +387,7 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, /* don't put limitations in case we're using LAR */ if (!(sbands_flags & IWL_NVM_SBANDS_FLAGS_LAR)) channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx], - ch_idx, is_5ghz, + ch_idx, band, ch_flags, cfg); else channel->flags = 0; -- cgit v1.2.3-59-g8ed1b From 65b9425ce9aa107f758ad0a491af5ef635567315 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Thu, 1 Aug 2019 14:00:24 +0300 Subject: iwlwifi: rx: use new api to get band from rx mpdu The FW introduce new API to get the band from the rx mpdu, use this new API. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 5 +++++ drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 6 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 23 +++++++++++++++++++++-- 4 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index a93449db7bb2..88bc7733065f 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -260,6 +260,11 @@ enum iwl_rx_mpdu_amsdu_info { IWL_RX_MPDU_AMSDU_LAST_SUBFRAME = 0x80, }; +#define RX_MPDU_BAND_POS 6 +#define RX_MPDU_BAND_MASK 0xC0 +#define BAND_IN_RX_STATUS(_val) \ + (((_val) & RX_MPDU_BAND_MASK) >> RX_MPDU_BAND_POS) + enum iwl_rx_l3_proto_values { IWL_RX_L3_TYPE_NONE, IWL_RX_L3_TYPE_IPV4, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 07628566cb4a..6de20e76b63c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -322,6 +322,8 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_SAR_TABLE_VER = (__force iwl_ucode_tlv_api_t)55, IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57, IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER = (__force iwl_ucode_tlv_api_t)58, + IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, + NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index d9c437682a5a..a25712cce4ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1409,6 +1409,12 @@ static inline bool iwl_mvm_is_scan_ext_chan_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER); } +static inline bool iwl_mvm_is_band_in_rx_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_BAND_IN_RX_DATA); +} + static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 77b03b757193..b488cd702058 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1542,6 +1542,19 @@ static void iwl_mvm_decode_lsig(struct sk_buff *skb, } } +static inline u8 iwl_mvm_nl80211_band_from_rx_msdu(u8 phy_band) +{ + switch (phy_band) { + case PHY_BAND_24: + return NL80211_BAND_2GHZ; + case PHY_BAND_5: + return NL80211_BAND_5GHZ; + default: + WARN_ONCE(1, "Unsupported phy band (%u)\n", phy_band); + return NL80211_BAND_5GHZ; + } +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -1678,8 +1691,14 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, } rx_status->device_timestamp = gp2_on_air_rise; - rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : - NL80211_BAND_2GHZ; + if (iwl_mvm_is_band_in_rx_supported(mvm)) { + u8 band = BAND_IN_RX_STATUS(desc->mac_phy_idx); + + rx_status->band = iwl_mvm_nl80211_band_from_rx_msdu(band); + } else { + rx_status->band = channel > 14 ? NL80211_BAND_5GHZ : + NL80211_BAND_2GHZ; + } rx_status->freq = ieee80211_channel_to_frequency(channel, rx_status->band); iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a, -- cgit v1.2.3-59-g8ed1b From 5c70e97142542c4d22e8892568c035bc95049258 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Thu, 24 Oct 2019 17:19:48 +0800 Subject: rtw88: fix GENMASK_ULL for u64 This fixes compile warning: In file included from include/linux/bitops.h:5:0, from include/linux/kernel.h:12, from include/asm-generic/bug.h:19, from arch/mips/include/asm/bug.h:42, from include/linux/bug.h:5, from include/net/mac80211.h:16, from drivers/net/wireless/realtek/rtw88/main.h:8, from drivers/net/wireless/realtek/rtw88/main.c:5: drivers/net/wireless/realtek/rtw88/main.c: In function 'rtw_update_rate_mask': include/linux/bits.h:23:11: warning: right shift count is negative [-Wshift-count-negative] (~UL(0) >> (BITS_PER_LONG - 1 - (h)))) ^ drivers/net/wireless/realtek/rtw88/main.c:622:17: note: in expansion of macro 'GENMASK' u64 cfg_mask = GENMASK(63, 0); ^~~~~~~ Reported-by: kbuild test robot Fixes: f39e9bd49a3d ("rtw88: add set_bitrate_mask support") Signed-off-by: Yan-Hsuan Chuang Reported-by: kbuild test robot Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 32e7328ce126..7c1b89c4fb6c 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -627,7 +627,7 @@ static u64 rtw_update_rate_mask(struct rtw_dev *rtwdev, { struct rtw_hal *hal = &rtwdev->hal; const struct cfg80211_bitrate_mask *mask = si->mask; - u64 cfg_mask = GENMASK(63, 0); + u64 cfg_mask = GENMASK_ULL(63, 0); u8 rssi_level, band; if (wireless_set != WIRELESS_CCK) { -- cgit v1.2.3-59-g8ed1b From ff9246571a2e79944d6d4d22de4f717081beb5d3 Mon Sep 17 00:00:00 2001 From: Sylwia Wnuczko Date: Fri, 20 Sep 2019 02:17:15 -0700 Subject: i40e: Fix for persistent lldp support This patch fixes function to read NVM module data and uses it to read current LLDP agent configuration from NVM API version 1.8. Signed-off-by: Sylwia Wnuczko Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_dcb.h | 3 ++ drivers/net/ethernet/intel/i40e/i40e_nvm.c | 61 +++++++++++++----------- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 10 ++-- 4 files changed, 44 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 200a1cb3b536..9de503c5f99b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -889,7 +889,9 @@ i40e_status i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change) ret = i40e_read_nvm_module_data(hw, I40E_SR_EMP_SR_SETTINGS_PTR, - offset, 1, + offset, + I40E_LLDP_CURRENT_STATUS_OFFSET, + I40E_LLDP_CURRENT_STATUS_SIZE, &lldp_cfg.adminstatus); } else { ret = i40e_read_lldp_cfg(hw, &lldp_cfg); diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.h b/drivers/net/ethernet/intel/i40e/i40e_dcb.h index 2a80c5daa376..ba86ad833bee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.h +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.h @@ -32,6 +32,9 @@ #define I40E_CEE_MAX_FEAT_TYPE 3 #define I40E_LLDP_CURRENT_STATUS_XL710_OFFSET 0x2B #define I40E_LLDP_CURRENT_STATUS_X722_OFFSET 0x31 +#define I40E_LLDP_CURRENT_STATUS_OFFSET 1 +#define I40E_LLDP_CURRENT_STATUS_SIZE 1 + /* Defines for LLDP TLV header */ #define I40E_LLDP_TLV_LEN_SHIFT 0 #define I40E_LLDP_TLV_LEN_MASK (0x01FF << I40E_LLDP_TLV_LEN_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index e4d8d20baf3b..7164f4ad8120 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -323,20 +323,24 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, /** * i40e_read_nvm_module_data - Reads NVM Buffer to specified memory location - * @hw: pointer to the HW structure + * @hw: Pointer to the HW structure * @module_ptr: Pointer to module in words with respect to NVM beginning - * @offset: offset in words from module start + * @module_offset: Offset in words from module start + * @data_offset: Offset in words from reading data area start * @words_data_size: Words to read from NVM * @data_ptr: Pointer to memory location where resulting buffer will be stored **/ -i40e_status i40e_read_nvm_module_data(struct i40e_hw *hw, - u8 module_ptr, u16 offset, - u16 words_data_size, - u16 *data_ptr) +enum i40e_status_code i40e_read_nvm_module_data(struct i40e_hw *hw, + u8 module_ptr, + u16 module_offset, + u16 data_offset, + u16 words_data_size, + u16 *data_ptr) { i40e_status status; + u16 specific_ptr = 0; u16 ptr_value = 0; - u32 flat_offset; + u32 offset = 0; if (module_ptr != 0) { status = i40e_read_nvm_word(hw, module_ptr, &ptr_value); @@ -352,36 +356,35 @@ i40e_status i40e_read_nvm_module_data(struct i40e_hw *hw, /* Pointer not initialized */ if (ptr_value == I40E_NVM_INVALID_PTR_VAL || - ptr_value == I40E_NVM_INVALID_VAL) + ptr_value == I40E_NVM_INVALID_VAL) { + i40e_debug(hw, I40E_DEBUG_ALL, "Pointer not initialized.\n"); return I40E_ERR_BAD_PTR; + } /* Check whether the module is in SR mapped area or outside */ if (ptr_value & I40E_PTR_TYPE) { /* Pointer points outside of the Shared RAM mapped area */ - ptr_value &= ~I40E_PTR_TYPE; + i40e_debug(hw, I40E_DEBUG_ALL, + "Reading nvm data failed. Pointer points outside of the Shared RAM mapped area.\n"); - /* PtrValue in 4kB units, need to convert to words */ - ptr_value /= 2; - flat_offset = ((u32)ptr_value * 0x1000) + (u32)offset; - status = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); - if (!status) { - status = i40e_aq_read_nvm(hw, 0, 2 * flat_offset, - 2 * words_data_size, - data_ptr, true, NULL); - i40e_release_nvm(hw); - if (status) { - i40e_debug(hw, I40E_DEBUG_ALL, - "Reading nvm aq failed.Error code: %d.\n", - status); - return I40E_ERR_NVM; - } - } else { - return I40E_ERR_NVM; - } + return I40E_ERR_PARAM; } else { /* Read from the Shadow RAM */ - status = i40e_read_nvm_buffer(hw, ptr_value + offset, - &words_data_size, data_ptr); + + status = i40e_read_nvm_word(hw, ptr_value + module_offset, + &specific_ptr); + if (status) { + i40e_debug(hw, I40E_DEBUG_ALL, + "Reading nvm word failed.Error code: %d.\n", + status); + return I40E_ERR_NVM; + } + + offset = ptr_value + module_offset + specific_ptr + + data_offset; + + status = i40e_read_nvm_buffer(hw, offset, &words_data_size, + data_ptr); if (status) { i40e_debug(hw, I40E_DEBUG_ALL, "Reading nvm buffer failed.Error code: %d.\n", diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 5250441bf75b..7effe5010e32 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -315,10 +315,12 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, void i40e_release_nvm(struct i40e_hw *hw); i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data); -i40e_status i40e_read_nvm_module_data(struct i40e_hw *hw, - u8 module_ptr, u16 offset, - u16 words_data_size, - u16 *data_ptr); +enum i40e_status_code i40e_read_nvm_module_data(struct i40e_hw *hw, + u8 module_ptr, + u16 module_offset, + u16 data_offset, + u16 words_data_size, + u16 *data_ptr); i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data); i40e_status i40e_update_nvm_checksum(struct i40e_hw *hw); -- cgit v1.2.3-59-g8ed1b From e42b7e9cefca9dd008cbafffca97285cf264f72d Mon Sep 17 00:00:00 2001 From: Jaroslaw Gawin Date: Fri, 20 Sep 2019 02:17:17 -0700 Subject: i40e: Wrong 'Advertised FEC modes' after set FEC to AUTO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix display of parameters "Configured FEC encodings:" and "Advertised FEC modes:" in ethtool. Implemented by setting proper FEC bits in “advertising” bitmask of link_modes struct and “fec” bitmask in ethtool_fecparam struct. Without this patch wrong FEC settings can be shown. Signed-off-by: Jaroslaw Gawin Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 13 ++++++++--- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 32 +++++++++++++------------- 2 files changed, 26 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index d37c6e0e5f08..f1d67267c983 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2570,9 +2570,16 @@ noinline_for_stack i40e_status i40e_update_link_info(struct i40e_hw *hw) if (status) return status; - hw->phy.link_info.req_fec_info = - abilities.fec_cfg_curr_mod_ext_info & - (I40E_AQ_REQUEST_FEC_KR | I40E_AQ_REQUEST_FEC_RS); + if (abilities.fec_cfg_curr_mod_ext_info & + I40E_AQ_ENABLE_FEC_AUTO) + hw->phy.link_info.req_fec_info = + (I40E_AQ_REQUEST_FEC_KR | + I40E_AQ_REQUEST_FEC_RS); + else + hw->phy.link_info.req_fec_info = + abilities.fec_cfg_curr_mod_ext_info & + (I40E_AQ_REQUEST_FEC_KR | + I40E_AQ_REQUEST_FEC_RS); memcpy(hw->phy.link_info.module_type, &abilities.module_type, sizeof(hw->phy.link_info.module_type)); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 41e1240acaea..b577e6adf3bf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -722,7 +722,14 @@ static void i40e_get_settings_link_up_fec(u8 req_fec_info, ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); - if (I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) { + if ((I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) && + (I40E_AQ_SET_FEC_REQUEST_KR & req_fec_info)) { + ethtool_link_ksettings_add_link_mode(ks, advertising, + FEC_NONE); + ethtool_link_ksettings_add_link_mode(ks, advertising, + FEC_BASER); + ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); + } else if (I40E_AQ_SET_FEC_REQUEST_RS & req_fec_info) { ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS); } else if (I40E_AQ_SET_FEC_REQUEST_KR & req_fec_info) { ethtool_link_ksettings_add_link_mode(ks, advertising, @@ -730,12 +737,6 @@ static void i40e_get_settings_link_up_fec(u8 req_fec_info, } else { ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE); - if (I40E_AQ_SET_FEC_AUTO & req_fec_info) { - ethtool_link_ksettings_add_link_mode(ks, advertising, - FEC_RS); - ethtool_link_ksettings_add_link_mode(ks, advertising, - FEC_BASER); - } } } @@ -1437,6 +1438,7 @@ static int i40e_get_fec_param(struct net_device *netdev, struct i40e_hw *hw = &pf->hw; i40e_status status = 0; int err = 0; + u8 fec_cfg; /* Get the current phy config */ memset(&abilities, 0, sizeof(abilities)); @@ -1448,18 +1450,16 @@ static int i40e_get_fec_param(struct net_device *netdev, } fecparam->fec = 0; - if (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_AUTO) + fec_cfg = abilities.fec_cfg_curr_mod_ext_info; + if (fec_cfg & I40E_AQ_SET_FEC_AUTO) fecparam->fec |= ETHTOOL_FEC_AUTO; - if ((abilities.fec_cfg_curr_mod_ext_info & - I40E_AQ_SET_FEC_REQUEST_RS) || - (abilities.fec_cfg_curr_mod_ext_info & - I40E_AQ_SET_FEC_ABILITY_RS)) + else if (fec_cfg & (I40E_AQ_SET_FEC_REQUEST_RS | + I40E_AQ_SET_FEC_ABILITY_RS)) fecparam->fec |= ETHTOOL_FEC_RS; - if ((abilities.fec_cfg_curr_mod_ext_info & - I40E_AQ_SET_FEC_REQUEST_KR) || - (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_ABILITY_KR)) + else if (fec_cfg & (I40E_AQ_SET_FEC_REQUEST_KR | + I40E_AQ_SET_FEC_ABILITY_KR)) fecparam->fec |= ETHTOOL_FEC_BASER; - if (abilities.fec_cfg_curr_mod_ext_info == 0) + if (fec_cfg == 0) fecparam->fec |= ETHTOOL_FEC_OFF; if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) -- cgit v1.2.3-59-g8ed1b From a3e09ded6a6d4b4cbdeb8c1ec4c7cf60798b3ce0 Mon Sep 17 00:00:00 2001 From: Piotr Azarewicz Date: Fri, 20 Sep 2019 02:17:18 -0700 Subject: i40e: Extract detection of HW flags into a function Move code detecting HW flags based on device type and FW API version into a single function. Signed-off-by: Piotr Azarewicz Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 71 ++++++++++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_common.c | 4 -- 2 files changed, 58 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index 72c04881d290..9f0a4e92a231 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -507,6 +507,59 @@ shutdown_arq_out: return ret_code; } +/** + * i40e_set_hw_flags - set HW flags + * @hw: pointer to the hardware structure + **/ +static void i40e_set_hw_flags(struct i40e_hw *hw) +{ + struct i40e_adminq_info *aq = &hw->aq; + + hw->flags = 0; + + switch (hw->mac.type) { + case I40E_MAC_XL710: + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710)) { + hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE; + hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + /* The ability to RX (not drop) 802.1ad frames */ + hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE; + } + break; + case I40E_MAC_X722: + hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE | + I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; + + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722)) + hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; + /* fall through */ + default: + break; + } + + /* Newer versions of firmware require lock when reading the NVM */ + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= 5)) + hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; + + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= 8)) { + hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT; + hw->flags |= I40E_HW_FLAG_DROP_MODE; + } + + if (aq->api_maj_ver > 1 || + (aq->api_maj_ver == 1 && + aq->api_min_ver >= 9)) + hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED; +} + /** * i40e_init_adminq - main initialization routine for Admin Queue * @hw: pointer to the hardware structure @@ -571,6 +624,11 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) if (ret_code != I40E_SUCCESS) goto init_adminq_free_arq; + /* Some features were introduced in different FW API version + * for different MAC type. + */ + i40e_set_hw_flags(hw); + /* get the NVM version info */ i40e_read_nvm_word(hw, I40E_SR_NVM_DEV_STARTER_VERSION, &hw->nvm.version); @@ -596,25 +654,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE; } - /* Newer versions of firmware require lock when reading the NVM */ - if (hw->aq.api_maj_ver > 1 || - (hw->aq.api_maj_ver == 1 && - hw->aq.api_min_ver >= 5)) - hw->flags |= I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; - /* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */ if (hw->aq.api_maj_ver > 1 || (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver >= 7)) hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE; - if (hw->aq.api_maj_ver > 1 || - (hw->aq.api_maj_ver == 1 && - hw->aq.api_min_ver >= 8)) { - hw->flags |= I40E_HW_FLAG_FW_LLDP_PERSISTENT; - hw->flags |= I40E_HW_FLAG_DROP_MODE; - } - if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) { ret_code = I40E_ERR_FIRMWARE_API_VERSION; goto init_adminq_free_arq; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index f1d67267c983..fe553bb23d7a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -933,10 +933,6 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw) else hw->pf_id = (u8)(func_rid & 0x7); - if (hw->mac.type == I40E_MAC_X722) - hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE | - I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK; - status = i40e_init_nvm(hw); return status; } -- cgit v1.2.3-59-g8ed1b From 0514db37dd78bb8b7a02bb6fc1c000a74014be54 Mon Sep 17 00:00:00 2001 From: Piotr Azarewicz Date: Fri, 20 Sep 2019 02:17:19 -0700 Subject: i40e: Extend PHY access with page change flag Currently FW use MDIO I/F number corresponded with current PF for PHY access. This code allow to specify used MDIO I/F number. Add new field - command flags with only one flag for now. Added flag tells FW that it shouldn't change page while accessing QSFP module, as it was set manually. Signed-off-by: Piotr Azarewicz Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 8 ++- drivers/net/ethernet/intel/i40e/i40e_common.c | 70 ++++++++++++++++++----- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8 +-- drivers/net/ethernet/intel/i40e/i40e_prototype.h | 26 ++++++--- drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + 5 files changed, 87 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 530613f31527..a23f89fb33ee 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -2249,7 +2249,13 @@ struct i40e_aqc_phy_register_access { #define I40E_AQ_PHY_REG_ACCESS_EXTERNAL 1 #define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE 2 u8 dev_address; - u8 reserved1[2]; + u8 cmd_flags; +#define I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE 0x01 +#define I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER 0x02 +#define I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_SHIFT 2 +#define I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_MASK (0x3 << \ + I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_SHIFT) + u8 reserved1; __le32 reg_address; __le32 reg_value; u8 reserved2[4]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index fe553bb23d7a..ed8608b874f4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -5046,7 +5046,7 @@ static enum i40e_status_code i40e_led_get_reg(struct i40e_hw *hw, u16 led_addr, status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, - I40E_PHY_COM_REG_PAGE, + I40E_PHY_COM_REG_PAGE, true, I40E_PHY_LED_PROV_REG_1, reg_val, NULL); } else { @@ -5079,7 +5079,7 @@ static enum i40e_status_code i40e_led_set_reg(struct i40e_hw *hw, u16 led_addr, status = i40e_aq_set_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, - I40E_PHY_COM_REG_PAGE, + I40E_PHY_COM_REG_PAGE, true, I40E_PHY_LED_PROV_REG_1, reg_val, NULL); } else { @@ -5118,7 +5118,7 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr, status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL, - I40E_PHY_COM_REG_PAGE, + I40E_PHY_COM_REG_PAGE, true, I40E_PHY_LED_PROV_REG_1, ®_val_aq, NULL); if (status == I40E_SUCCESS) @@ -5323,20 +5323,49 @@ do_retry: } /** - * i40e_aq_set_phy_register + * i40e_mdio_if_number_selection - MDIO I/F number selection + * @hw: pointer to the hw struct + * @set_mdio: use MDIO I/F number specified by mdio_num + * @mdio_num: MDIO I/F number + * @cmd: pointer to PHY Register command structure + **/ +static void i40e_mdio_if_number_selection(struct i40e_hw *hw, bool set_mdio, + u8 mdio_num, + struct i40e_aqc_phy_register_access *cmd) +{ + if (set_mdio && cmd->phy_interface == I40E_AQ_PHY_REG_ACCESS_EXTERNAL) { + if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED) + cmd->cmd_flags |= + I40E_AQ_PHY_REG_ACCESS_SET_MDIO_IF_NUMBER | + ((mdio_num << + I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_SHIFT) & + I40E_AQ_PHY_REG_ACCESS_MDIO_IF_NUMBER_MASK); + else + i40e_debug(hw, I40E_DEBUG_PHY, + "MDIO I/F number selection not supported by current FW version.\n"); + } +} + +/** + * i40e_aq_set_phy_register_ext * @hw: pointer to the hw struct * @phy_select: select which phy should be accessed * @dev_addr: PHY device address + * @set_mdio: use MDIO I/F number specified by mdio_num + * @mdio_num: MDIO I/F number * @reg_addr: PHY register address * @reg_val: new register value * @cmd_details: pointer to command details structure or NULL * * Write the external PHY register. + * NOTE: In common cases MDIO I/F number should not be changed, thats why you + * may use simple wrapper i40e_aq_set_phy_register. **/ -i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 reg_val, - struct i40e_asq_cmd_details *cmd_details) +enum i40e_status_code i40e_aq_set_phy_register_ext(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, bool page_change, + bool set_mdio, u8 mdio_num, + u32 reg_addr, u32 reg_val, + struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; struct i40e_aqc_phy_register_access *cmd = @@ -5351,26 +5380,36 @@ i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw, cmd->reg_address = cpu_to_le32(reg_addr); cmd->reg_value = cpu_to_le32(reg_val); + i40e_mdio_if_number_selection(hw, set_mdio, mdio_num, cmd); + + if (!page_change) + cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE; + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); return status; } /** - * i40e_aq_get_phy_register + * i40e_aq_get_phy_register_ext * @hw: pointer to the hw struct * @phy_select: select which phy should be accessed * @dev_addr: PHY device address + * @set_mdio: use MDIO I/F number specified by mdio_num + * @mdio_num: MDIO I/F number * @reg_addr: PHY register address * @reg_val: read register value * @cmd_details: pointer to command details structure or NULL * * Read the external PHY register. + * NOTE: In common cases MDIO I/F number should not be changed, thats why you + * may use simple wrapper i40e_aq_get_phy_register. **/ -i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 *reg_val, - struct i40e_asq_cmd_details *cmd_details) +enum i40e_status_code i40e_aq_get_phy_register_ext(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, bool page_change, + bool set_mdio, u8 mdio_num, + u32 reg_addr, u32 *reg_val, + struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; struct i40e_aqc_phy_register_access *cmd = @@ -5384,6 +5423,11 @@ i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw, cmd->dev_address = dev_addr; cmd->reg_address = cpu_to_le32(reg_addr); + i40e_mdio_if_number_selection(hw, set_mdio, mdio_num, cmd); + + if (!page_change) + cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE; + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); if (!status) *reg_val = le32_to_cpu(cmd->reg_value); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b577e6adf3bf..2ceb87fa853c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5112,7 +5112,7 @@ static int i40e_get_module_info(struct net_device *netdev, case I40E_MODULE_TYPE_SFP: status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, - I40E_I2C_EEPROM_DEV_ADDR, + I40E_I2C_EEPROM_DEV_ADDR, true, I40E_MODULE_SFF_8472_COMP, &sff8472_comp, NULL); if (status) @@ -5120,7 +5120,7 @@ static int i40e_get_module_info(struct net_device *netdev, status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, - I40E_I2C_EEPROM_DEV_ADDR, + I40E_I2C_EEPROM_DEV_ADDR, true, I40E_MODULE_SFF_8472_SWAP, &sff8472_swap, NULL); if (status) @@ -5152,7 +5152,7 @@ static int i40e_get_module_info(struct net_device *netdev, /* Read from memory page 0. */ status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, - 0, + 0, true, I40E_MODULE_REVISION_ADDR, &sff8636_rev, NULL); if (status) @@ -5223,7 +5223,7 @@ static int i40e_get_module_eeprom(struct net_device *netdev, status = i40e_aq_get_phy_register(hw, I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, - addr, offset, &value, NULL); + true, addr, offset, &value, NULL); if (status) return -EIO; data[i] = value; diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 7effe5010e32..bbb478f09093 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -411,14 +411,24 @@ i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw, u32 reg_addr, u32 reg_val, struct i40e_asq_cmd_details *cmd_details); void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val); -i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 reg_val, - struct i40e_asq_cmd_details *cmd_details); -i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw, - u8 phy_select, u8 dev_addr, - u32 reg_addr, u32 *reg_val, - struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code +i40e_aq_set_phy_register_ext(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, bool page_change, + bool set_mdio, u8 mdio_num, + u32 reg_addr, u32 reg_val, + struct i40e_asq_cmd_details *cmd_details); +enum i40e_status_code +i40e_aq_get_phy_register_ext(struct i40e_hw *hw, + u8 phy_select, u8 dev_addr, bool page_change, + bool set_mdio, u8 mdio_num, + u32 reg_addr, u32 *reg_val, + struct i40e_asq_cmd_details *cmd_details); + +/* Convenience wrappers for most common use case */ +#define i40e_aq_set_phy_register(hw, ps, da, pc, ra, rv, cd) \ + i40e_aq_set_phy_register_ext(hw, ps, da, pc, false, 0, ra, rv, cd) +#define i40e_aq_get_phy_register(hw, ps, da, pc, ra, rv, cd) \ + i40e_aq_get_phy_register_ext(hw, ps, da, pc, false, 0, ra, rv, cd) i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw, u16 reg, u8 phy_addr, u16 *value); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index b43ec94a0f29..6ea2867ff60f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -624,6 +624,7 @@ struct i40e_hw { #define I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK BIT_ULL(3) #define I40E_HW_FLAG_FW_LLDP_STOPPABLE BIT_ULL(4) #define I40E_HW_FLAG_FW_LLDP_PERSISTENT BIT_ULL(5) +#define I40E_HW_FLAG_AQ_PHY_ACCESS_EXTENDED BIT_ULL(6) #define I40E_HW_FLAG_DROP_MODE BIT_ULL(7) u64 flags; -- cgit v1.2.3-59-g8ed1b From 998e5166e604fd37afe94352f7b8c2d816b11049 Mon Sep 17 00:00:00 2001 From: Nicholas Nunley Date: Fri, 20 Sep 2019 02:17:21 -0700 Subject: i40e: initialize ITRN registers with correct values Since commit 92418fb14750 ("i40e/i40evf: Use usec value instead of reg value for ITR defines") the driver tracks the interrupt throttling intervals in single usec units, although the actual ITRN/ITR0 registers are programmed in 2 usec units. Most register programming flows in the driver correctly handle the conversion, although it is currently not applied when the registers are initialized to their default values. Most of the time this doesn't present a problem since the default values are usually immediately overwritten through the standard adaptive throttling mechanism, or updated manually by the user, but if adaptive throttling is disabled and the interval values are left alone then the incorrect value will persist. Since the intended default interval of 50 usecs (vs. 100 usecs as programmed) performs better for most traffic workloads, this can lead to performance regressions. This patch adds the correct conversion when writing the initial values to the ITRN registers. Signed-off-by: Nicholas Nunley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6031223eafab..339925af0206 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -3534,14 +3534,14 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi) q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[i]->itr_setting); wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), - q_vector->rx.target_itr); + q_vector->rx.target_itr >> 1); q_vector->rx.current_itr = q_vector->rx.target_itr; q_vector->tx.next_update = jiffies + 1; q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[i]->itr_setting); wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), - q_vector->tx.target_itr); + q_vector->tx.target_itr >> 1); q_vector->tx.current_itr = q_vector->tx.target_itr; wr32(hw, I40E_PFINT_RATEN(vector - 1), @@ -3646,11 +3646,11 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi) /* set the ITR configuration */ q_vector->rx.next_update = jiffies + 1; q_vector->rx.target_itr = ITR_TO_REG(vsi->rx_rings[0]->itr_setting); - wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr); + wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.target_itr >> 1); q_vector->rx.current_itr = q_vector->rx.target_itr; q_vector->tx.next_update = jiffies + 1; q_vector->tx.target_itr = ITR_TO_REG(vsi->tx_rings[0]->itr_setting); - wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr); + wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.target_itr >> 1); q_vector->tx.current_itr = q_vector->tx.target_itr; i40e_enable_misc_int_causes(pf); @@ -11396,7 +11396,7 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) /* associate no queues to the misc vector */ wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST); - wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K); + wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K >> 1); i40e_flush(hw); -- cgit v1.2.3-59-g8ed1b From cdb89f15bd4667bfc492b7d5afc6ba2902b54d4e Mon Sep 17 00:00:00 2001 From: Piotr Kwapulinski Date: Fri, 20 Sep 2019 02:17:22 -0700 Subject: i40e: allow ethtool to report SW and FW versions in recovery mode Let ethtool print driver and firmware versions when NIC is in recovery mode. Assign i40e_get_drvinfo() operation to ethtool recovery mode operations. Previously ethtool did not report driver and firmware versions when NIC was in recovery mode. Signed-off-by: Piotr Kwapulinski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 2ceb87fa853c..d24d8731bef0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5242,6 +5242,7 @@ static int i40e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) } static const struct ethtool_ops i40e_ethtool_recovery_mode_ops = { + .get_drvinfo = i40e_get_drvinfo, .set_eeprom = i40e_set_eeprom, .get_eeprom_len = i40e_get_eeprom_len, .get_eeprom = i40e_get_eeprom, -- cgit v1.2.3-59-g8ed1b From d80a476f4a12a84feaebfed993f3039fdc9c1249 Mon Sep 17 00:00:00 2001 From: Damian Milosek Date: Fri, 20 Sep 2019 02:17:23 -0700 Subject: i40e: Fix LED blinking flow for X710T*L devices Add X710T*L device specific operations (in port LED detection and handling of GLGEN_GPIO_CTL.PIN_FUNC field) to enable LED blinking. Signed-off-by: Damian Milosek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 29 ++++++++++++++++++++++++--- drivers/net/ethernet/intel/i40e/i40e_devids.h | 2 ++ 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index ed8608b874f4..8b25a6d9c81d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1437,9 +1437,9 @@ static u32 i40e_led_is_mine(struct i40e_hw *hw, int idx) u32 gpio_val = 0; u32 port; - if (!hw->func_caps.led[idx]) + if (!I40E_IS_X710TL_DEVICE(hw->device_id) && + !hw->func_caps.led[idx]) return 0; - gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(idx)); port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK) >> I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT; @@ -1458,8 +1458,15 @@ static u32 i40e_led_is_mine(struct i40e_hw *hw, int idx) #define I40E_FILTER_ACTIVITY 0xE #define I40E_LINK_ACTIVITY 0xC #define I40E_MAC_ACTIVITY 0xD +#define I40E_FW_LED BIT(4) +#define I40E_LED_MODE_VALID (I40E_GLGEN_GPIO_CTL_LED_MODE_MASK >> \ + I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) + #define I40E_LED0 22 +#define I40E_PIN_FUNC_SDP 0x0 +#define I40E_PIN_FUNC_LED 0x1 + /** * i40e_led_get - return current on/off mode * @hw: pointer to the hw struct @@ -1504,8 +1511,10 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) { int i; - if (mode & 0xfffffff0) + if (mode & ~I40E_LED_MODE_VALID) { hw_dbg(hw, "invalid mode passed in %X\n", mode); + return; + } /* as per the documentation GPIO 22-29 are the LED * GPIO pins named LED0..LED7 @@ -1515,6 +1524,20 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) if (!gpio_val) continue; + + if (I40E_IS_X710TL_DEVICE(hw->device_id)) { + u32 pin_func = 0; + + if (mode & I40E_FW_LED) + pin_func = I40E_PIN_FUNC_SDP; + else + pin_func = I40E_PIN_FUNC_LED; + + gpio_val &= ~I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK; + gpio_val |= ((pin_func << + I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) & + I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK); + } gpio_val &= ~I40E_GLGEN_GPIO_CTL_LED_MODE_MASK; /* this & is a bit of paranoia, but serves as a range check */ gpio_val |= ((mode << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) & diff --git a/drivers/net/ethernet/intel/i40e/i40e_devids.h b/drivers/net/ethernet/intel/i40e/i40e_devids.h index bac4da031f9b..bf15a868292f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_devids.h +++ b/drivers/net/ethernet/intel/i40e/i40e_devids.h @@ -23,6 +23,8 @@ #define I40E_DEV_ID_10G_BASE_T_BC 0x15FF #define I40E_DEV_ID_10G_B 0x104F #define I40E_DEV_ID_10G_SFP 0x104E +#define I40E_IS_X710TL_DEVICE(d) \ + ((d) == I40E_DEV_ID_10G_BASE_T_BC) #define I40E_DEV_ID_KX_X722 0x37CE #define I40E_DEV_ID_QSFP_X722 0x37CF #define I40E_DEV_ID_SFP_X722 0x37D0 -- cgit v1.2.3-59-g8ed1b From 621650cabee54886291c4fa59544b9e30b016f92 Mon Sep 17 00:00:00 2001 From: Aleksandr Loktionov Date: Fri, 20 Sep 2019 02:17:24 -0700 Subject: i40e: Refactoring VF MAC filters counting to make more reliable This patch prepares ground for the next VF MAC address change fix. It lets untrusted VF to delete any VF mac filter, but it still doesn't let untrusted VF to add mac filter not setup by PF. It removes information duplication in num_mac mac filters counter. And improves exact h/w mac filters usage checking in the i40e_check_vf_permission() function by counting mac2add_cnt. It also improves logging because now all mac addresses will be validated first and corresponding messages will be logged. Signed-off-by: Aleksandr Loktionov Tested-by: Andrew Bowers --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 19 +++++++++ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 45 +++++++++------------- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 1 - 4 files changed, 39 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 2af9f6308f84..cb6367334ca7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1118,6 +1118,7 @@ struct i40e_mac_filter *i40e_add_mac_filter(struct i40e_vsi *vsi, const u8 *macaddr); int i40e_del_mac_filter(struct i40e_vsi *vsi, const u8 *macaddr); bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi); +int i40e_count_filters(struct i40e_vsi *vsi); struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr); void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); #ifdef CONFIG_I40E_DCB diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 339925af0206..2e4df0bd8d37 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1109,6 +1109,25 @@ void i40e_update_stats(struct i40e_vsi *vsi) i40e_update_vsi_stats(vsi); } +/** + * i40e_count_filters - counts VSI mac filters + * @vsi: the VSI to be searched + * + * Returns count of mac filters + **/ +int i40e_count_filters(struct i40e_vsi *vsi) +{ + struct i40e_mac_filter *f; + struct hlist_node *h; + int bkt; + int cnt = 0; + + hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) + ++cnt; + + return cnt; +} + /** * i40e_find_filter - Search VSI filter list for specific mac/vlan filter * @vsi: the VSI to be searched diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 3d2440838822..a2710664d653 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -955,7 +955,6 @@ static void i40e_free_vf_res(struct i40e_vf *vf) i40e_vsi_release(pf->vsi[vf->lan_vsi_idx]); vf->lan_vsi_idx = 0; vf->lan_vsi_id = 0; - vf->num_mac = 0; } /* do the accounting and remove additional ADq VSI's */ @@ -2548,20 +2547,12 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, struct virtchnl_ether_addr_list *al) { struct i40e_pf *pf = vf->pf; + struct i40e_vsi *vsi = pf->vsi[vf->lan_vsi_idx]; + int mac2add_cnt = 0; int i; - /* If this VF is not privileged, then we can't add more than a limited - * number of addresses. Check to make sure that the additions do not - * push us over the limit. - */ - if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) && - (vf->num_mac + al->num_elements) > I40E_VC_MAX_MAC_ADDR_PER_VF) { - dev_err(&pf->pdev->dev, - "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n"); - return -EPERM; - } - for (i = 0; i < al->num_elements; i++) { + struct i40e_mac_filter *f; u8 *addr = al->list[i].addr; if (is_broadcast_ether_addr(addr) || @@ -2585,8 +2576,24 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n"); return -EPERM; } + + /*count filters that really will be added*/ + f = i40e_find_mac(vsi, addr); + if (!f) + ++mac2add_cnt; } + /* If this VF is not privileged, then we can't add more than a limited + * number of addresses. Check to make sure that the additions do not + * push us over the limit. + */ + if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) && + (i40e_count_filters(vsi) + mac2add_cnt) > + I40E_VC_MAX_MAC_ADDR_PER_VF) { + dev_err(&pf->pdev->dev, + "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n"); + return -EPERM; + } return 0; } @@ -2640,8 +2647,6 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg) ret = I40E_ERR_PARAM; spin_unlock_bh(&vsi->mac_filter_hash_lock); goto error_param; - } else { - vf->num_mac++; } } } @@ -2689,16 +2694,6 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg) ret = I40E_ERR_INVALID_MAC_ADDR; goto error_param; } - - if (vf->pf_set_mac && - ether_addr_equal(al->list[i].addr, - vf->default_lan_addr.addr)) { - dev_err(&pf->pdev->dev, - "MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n", - vf->default_lan_addr.addr, vf->vf_id); - ret = I40E_ERR_PARAM; - goto error_param; - } } vsi = pf->vsi[vf->lan_vsi_idx]; @@ -2709,8 +2704,6 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg) ret = I40E_ERR_INVALID_MAC_ADDR; spin_unlock_bh(&vsi->mac_filter_hash_lock); goto error_param; - } else { - vf->num_mac--; } spin_unlock_bh(&vsi->mac_filter_hash_lock); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 7164b9bb294f..1ce06240a702 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -101,7 +101,6 @@ struct i40e_vf { bool link_up; /* only valid if VF link is forced */ bool queues_enabled; /* true if the VF queues are enabled */ bool spoofchk; - u16 num_mac; u16 num_vlan; /* ADq related variables */ -- cgit v1.2.3-59-g8ed1b From 27d461333459d282ffa4a2bdb6b215a59d493a8f Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Wed, 25 Sep 2019 10:48:30 -0500 Subject: i40e: prevent memory leak in i40e_setup_macvlans In i40e_setup_macvlans if i40e_setup_channel fails the allocated memory for ch should be released. Signed-off-by: Navid Emamdoost Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2e4df0bd8d37..141575ada588 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7187,6 +7187,7 @@ static int i40e_setup_macvlans(struct i40e_vsi *vsi, u16 macvlan_cnt, u16 qcnt, ch->num_queue_pairs = qcnt; if (!i40e_setup_channel(pf, vsi, ch)) { ret = -EINVAL; + kfree(ch); goto err_free; } ch->parent_vsi = vsi; -- cgit v1.2.3-59-g8ed1b From 8e484ebb1edc8329e1f7c527d556038a395f654e Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Wed, 23 Oct 2019 21:24:44 +0800 Subject: r8152: check the pointer rtl_fw->fw before using it Fix the pointer rtl_fw->fw would be used before checking in rtl8152_apply_firmware() that causes the following kernel oops. Unable to handle kernel NULL pointer dereference at virtual address 00000002 pgd = (ptrval) [00000002] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 131 Comm: kworker/0:2 Not tainted 5.4.0-rc1-00539-g9370f2d05a2a #6788 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) Workqueue: events_long rtl_hw_phy_work_func_t PC is at rtl8152_apply_firmware+0x14/0x464 LR is at r8153_hw_phy_cfg+0x24/0x17c pc : [] lr : [] psr: a0000013 sp : e75c9e60 ip : 60000013 fp : c11b7614 r10: e883b91c r9 : 00000000 r8 : fffffffe r7 : e883b640 r6 : fffffffe r5 : fffffffe r4 : e883b640 r3 : 736cfe7c r2 : 736cfe7c r1 : 000052f8 r0 : e883b640 Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 6640006a DAC: 00000051 Process kworker/0:2 (pid: 131, stack limit = 0x(ptrval)) Stack: (0xe75c9e60 to 0xe75ca000) ... [] (rtl8152_apply_firmware) from [] (r8153_hw_phy_cfg+0x24/0x17c) [] (r8153_hw_phy_cfg) from [] (rtl_hw_phy_work_func_t+0x220/0x3e4) [] (rtl_hw_phy_work_func_t) from [] (process_one_work+0x22c/0x7c8) [] (process_one_work) from [] (worker_thread+0x44/0x520) [] (worker_thread) from [] (kthread+0x130/0x164) [] (kthread) from [] (ret_from_fork+0x14/0x20) Exception stack(0xe75c9fb0 to 0xe75c9ff8) ... Fixes: 9370f2d05a2a ("r8152: support request_firmware for RTL8153") Reported-by: Marek Szyprowski Tested-by: Marek Szyprowski Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index d3c30ccc8577..283b35a76cf0 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4000,8 +4000,8 @@ static void rtl8152_fw_mac_apply(struct r8152 *tp, struct fw_mac *mac) static void rtl8152_apply_firmware(struct r8152 *tp) { struct rtl_fw *rtl_fw = &tp->rtl_fw; - const struct firmware *fw = rtl_fw->fw; - struct fw_header *fw_hdr = (struct fw_header *)fw->data; + const struct firmware *fw; + struct fw_header *fw_hdr; struct fw_phy_patch_key *key; u16 key_addr = 0; int i; @@ -4009,6 +4009,9 @@ static void rtl8152_apply_firmware(struct r8152 *tp) if (IS_ERR_OR_NULL(rtl_fw->fw)) return; + fw = rtl_fw->fw; + fw_hdr = (struct fw_header *)fw->data; + if (rtl_fw->pre_fw) rtl_fw->pre_fw(tp); -- cgit v1.2.3-59-g8ed1b From 5a7f08c2abb0efc9d17aff2fc75d6d3b85e622e4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 23 Oct 2019 17:48:45 +0300 Subject: net: phy: dp83867: enable robust auto-mdix The link detection timeouts can be observed (or link might not be detected at all) when dp83867 PHY is configured in manual mode (speed/duplex). CFG3[9] Robust Auto-MDIX option allows to significantly improve link detection in case dp83867 is configured in manual mode and reduce link detection time. As per DM: "If link partners are configured to operational modes that are not supported by normal Auto MDI/MDIX mode (like Auto-Neg versus Force 100Base-TX or Force 100Base-TX versus Force 100Base-TX), this Robust Auto MDI/MDIX mode allows MDI/MDIX resolution and prevents deadlock." Hence, enable this option by default as there are no known reasons not to do so. Signed-off-by: Grygorii Strashko Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 37fceaf9fa10..cf4455bbf888 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -95,6 +95,10 @@ #define DP83867_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8) #define DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 +/* CFG3 bits */ +#define DP83867_CFG3_INT_OE BIT(7) +#define DP83867_CFG3_ROBUST_AUTO_MDIX BIT(9) + /* CFG4 bits */ #define DP83867_CFG4_PORT_MIRROR_EN BIT(0) @@ -410,12 +414,13 @@ static int dp83867_config_init(struct phy_device *phydev) phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val); } + val = phy_read(phydev, DP83867_CFG3); /* Enable Interrupt output INT_OE in CFG3 register */ - if (phy_interrupt_is_valid(phydev)) { - val = phy_read(phydev, DP83867_CFG3); - val |= BIT(7); - phy_write(phydev, DP83867_CFG3, val); - } + if (phy_interrupt_is_valid(phydev)) + val |= DP83867_CFG3_INT_OE; + + val |= DP83867_CFG3_ROBUST_AUTO_MDIX; + phy_write(phydev, DP83867_CFG3, val); if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP) dp83867_config_port_mirroring(phydev); -- cgit v1.2.3-59-g8ed1b From ef87f7da6b28dfaf7aac435350fe287cc667124a Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 23 Oct 2019 17:48:46 +0300 Subject: net: phy: dp83867: move dt parsing to probe Move DT parsing code to probe dp83867_probe() as it's one time operation. Signed-off-by: Grygorii Strashko Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index cf4455bbf888..5816a06a9439 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -299,7 +299,7 @@ static int dp83867_probe(struct phy_device *phydev) phydev->priv = dp83867; - return 0; + return dp83867_of_init(phydev); } static int dp83867_config_init(struct phy_device *phydev) @@ -308,10 +308,6 @@ static int dp83867_config_init(struct phy_device *phydev) int ret, val, bs; u16 delay; - ret = dp83867_of_init(phydev); - if (ret) - return ret; - /* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */ if (dp83867->rxctrl_strap_quirk) phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4, -- cgit v1.2.3-59-g8ed1b From 7cb83b21fd3bb9a27b1a00a2a8b436761e969f0b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 23 Oct 2019 21:09:34 +0200 Subject: r8169: align fix_features callback with vendor driver This patch aligns the fix_features callback with the vendor driver and also disables IPv6 HW checksumming and TSO if jumbo packets are used on RTL8101/RTL8168/RTL8125. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index c317af9c60e9..43ffd4f49c09 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1558,7 +1558,7 @@ static netdev_features_t rtl8169_fix_features(struct net_device *dev, if (dev->mtu > JUMBO_1K && tp->mac_version > RTL_GIGA_MAC_VER_06) - features &= ~NETIF_F_IP_CSUM; + features &= ~(NETIF_F_CSUM_MASK | NETIF_F_ALL_TSO); return features; } -- cgit v1.2.3-59-g8ed1b From e4b5c7a582a75f1de54620447854bc5a29011637 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 23 Oct 2019 21:36:14 +0200 Subject: r8169: improve rtl8169_rx_fill We have only one user of the error path, so we can inline it. In addition the call to rtl8169_make_unusable_by_asic() can be removed because rtl8169_alloc_rx_data() didn't call rtl8169_mark_to_asic() yet for the respective index if returning NULL. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 43ffd4f49c09..91978ce92e20 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5493,18 +5493,15 @@ static int rtl8169_rx_fill(struct rtl8169_private *tp) data = rtl8169_alloc_rx_data(tp, tp->RxDescArray + i); if (!data) { - rtl8169_make_unusable_by_asic(tp->RxDescArray + i); - goto err_out; + rtl8169_rx_clear(tp); + return -ENOMEM; } tp->Rx_databuff[i] = data; } rtl8169_mark_as_last_descriptor(tp->RxDescArray + NUM_RX_DESC - 1); - return 0; -err_out: - rtl8169_rx_clear(tp); - return -ENOMEM; + return 0; } static int rtl8169_init_ring(struct rtl8169_private *tp) -- cgit v1.2.3-59-g8ed1b From 5c28f213ef7937832e0666605edff09ea214ac65 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:48:55 -0700 Subject: ionic: fix up struct name comments Fix up struct names in the ionic_if.h comments Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_if.h | 196 ++++++++++++------------- 1 file changed, 98 insertions(+), 98 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h index 5bfdda19f64d..dbdb7c5ae8f1 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_if.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h @@ -111,7 +111,7 @@ struct ionic_admin_cmd { }; /** - * struct admin_comp - General admin command completion format + * struct ionic_admin_comp - General admin command completion format * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -134,7 +134,7 @@ static inline u8 color_match(u8 color, u8 done_color) } /** - * struct nop_cmd - NOP command + * struct ionic_nop_cmd - NOP command * @opcode: opcode */ struct ionic_nop_cmd { @@ -143,7 +143,7 @@ struct ionic_nop_cmd { }; /** - * struct nop_comp - NOP command completion + * struct ionic_nop_comp - NOP command completion * @status: The status of the command (enum status_code) */ struct ionic_nop_comp { @@ -152,7 +152,7 @@ struct ionic_nop_comp { }; /** - * struct dev_init_cmd - Device init command + * struct ionic_dev_init_cmd - Device init command * @opcode: opcode * @type: device type */ @@ -172,7 +172,7 @@ struct ionic_dev_init_comp { }; /** - * struct dev_reset_cmd - Device reset command + * struct ionic_dev_reset_cmd - Device reset command * @opcode: opcode */ struct ionic_dev_reset_cmd { @@ -192,7 +192,7 @@ struct ionic_dev_reset_comp { #define IONIC_IDENTITY_VERSION_1 1 /** - * struct dev_identify_cmd - Driver/device identify command + * struct ionic_dev_identify_cmd - Driver/device identify command * @opcode: opcode * @ver: Highest version of identify supported by driver */ @@ -284,7 +284,7 @@ enum ionic_lif_type { }; /** - * struct lif_identify_cmd - lif identify command + * struct ionic_lif_identify_cmd - lif identify command * @opcode: opcode * @type: lif type (enum lif_type) * @ver: version of identify returned by device @@ -297,7 +297,7 @@ struct ionic_lif_identify_cmd { }; /** - * struct lif_identify_comp - lif identify command completion + * struct ionic_lif_identify_comp - lif identify command completion * @status: status of the command (enum status_code) * @ver: version of identify returned by device */ @@ -325,7 +325,7 @@ enum ionic_logical_qtype { }; /** - * struct lif_logical_qtype - Descriptor of logical to hardware queue type. + * struct ionic_lif_logical_qtype - Descriptor of logical to hardware queue type. * @qtype: Hardware Queue Type. * @qid_count: Number of Queue IDs of the logical type. * @qid_base: Minimum Queue ID of the logical type. @@ -349,7 +349,7 @@ enum ionic_lif_state { * @name: lif name * @mtu: mtu * @mac: station mac address - * @features: features (enum eth_hw_features) + * @features: features (enum ionic_eth_hw_features) * @queue_count: queue counts per queue-type */ union ionic_lif_config { @@ -367,7 +367,7 @@ union ionic_lif_config { }; /** - * struct lif_identity - lif identity information (type-specific) + * struct ionic_lif_identity - lif identity information (type-specific) * * @capabilities LIF capabilities * @@ -441,11 +441,11 @@ union ionic_lif_identity { }; /** - * struct lif_init_cmd - LIF init command + * struct ionic_lif_init_cmd - LIF init command * @opcode: opcode * @type: LIF type (enum lif_type) * @index: LIF index - * @info_pa: destination address for lif info (struct lif_info) + * @info_pa: destination address for lif info (struct ionic_lif_info) */ struct ionic_lif_init_cmd { u8 opcode; @@ -457,7 +457,7 @@ struct ionic_lif_init_cmd { }; /** - * struct lif_init_comp - LIF init command completion + * struct ionic_lif_init_comp - LIF init command completion * @status: The status of the command (enum status_code) */ struct ionic_lif_init_comp { @@ -468,7 +468,7 @@ struct ionic_lif_init_comp { }; /** - * struct q_init_cmd - Queue init command + * struct ionic_q_init_cmd - Queue init command * @opcode: opcode * @type: Logical queue type * @ver: Queue version (defines opcode/descriptor scope) @@ -525,7 +525,7 @@ struct ionic_q_init_cmd { }; /** - * struct q_init_comp - Queue init command completion + * struct ionic_q_init_comp - Queue init command completion * @status: The status of the command (enum status_code) * @ver: Queue version (defines opcode/descriptor scope) * @comp_index: The index in the descriptor ring for which this @@ -556,7 +556,7 @@ enum ionic_txq_desc_opcode { }; /** - * struct txq_desc - Ethernet Tx queue descriptor format + * struct ionic_txq_desc - Ethernet Tx queue descriptor format * @opcode: Tx operation, see TXQ_DESC_OPCODE_*: * * IONIC_TXQ_DESC_OPCODE_CSUM_NONE: @@ -735,7 +735,7 @@ static inline void decode_txq_desc_cmd(u64 cmd, u8 *opcode, u8 *flags, #define IONIC_RX_MAX_SG_ELEMS 8 /** - * struct txq_sg_desc - Transmit scatter-gather (SG) list + * struct ionic_txq_sg_desc - Transmit scatter-gather (SG) list * @addr: DMA address of SG element data buffer * @len: Length of SG element data buffer, in bytes */ @@ -748,7 +748,7 @@ struct ionic_txq_sg_desc { }; /** - * struct txq_comp - Ethernet transmit queue completion descriptor + * struct ionic_txq_comp - Ethernet transmit queue completion descriptor * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -768,7 +768,7 @@ enum ionic_rxq_desc_opcode { }; /** - * struct rxq_desc - Ethernet Rx queue descriptor format + * struct ionic_rxq_desc - Ethernet Rx queue descriptor format * @opcode: Rx operation, see RXQ_DESC_OPCODE_*: * * RXQ_DESC_OPCODE_SIMPLE: @@ -789,7 +789,7 @@ struct ionic_rxq_desc { }; /** - * struct rxq_sg_desc - Receive scatter-gather (SG) list + * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) list * @addr: DMA address of SG element data buffer * @len: Length of SG element data buffer, in bytes */ @@ -802,7 +802,7 @@ struct ionic_rxq_sg_desc { }; /** - * struct rxq_comp - Ethernet receive queue completion descriptor + * struct ionic_rxq_comp - Ethernet receive queue completion descriptor * @status: The status of the command (enum status_code) * @num_sg_elems: Number of SG elements used by this descriptor * @comp_index: The index in the descriptor ring for which this @@ -896,7 +896,7 @@ enum ionic_eth_hw_features { }; /** - * struct q_control_cmd - Queue control command + * struct ionic_q_control_cmd - Queue control command * @opcode: opcode * @type: Queue type * @lif_index: LIF index @@ -1033,8 +1033,8 @@ enum ionic_port_loopback_mode { /** * Transceiver Status information - * @state: Transceiver status (enum xcvr_state) - * @phy: Physical connection type (enum phy_type) + * @state: Transceiver status (enum ionic_xcvr_state) + * @phy: Physical connection type (enum ionic_phy_type) * @pid: Transceiver link mode (enum pid) * @sprom: Transceiver sprom contents */ @@ -1051,9 +1051,9 @@ struct ionic_xcvr_status { * @mtu: mtu * @state: port admin state (enum port_admin_state) * @an_enable: autoneg enable - * @fec_type: fec type (enum port_fec_type) - * @pause_type: pause type (enum port_pause_type) - * @loopback_mode: loopback mode (enum port_loopback_mode) + * @fec_type: fec type (enum ionic_port_fec_type) + * @pause_type: pause type (enum ionic_port_pause_type) + * @loopback_mode: loopback mode (enum ionic_port_loopback_mode) */ union ionic_port_config { struct { @@ -1080,7 +1080,7 @@ union ionic_port_config { /** * Port Status information - * @status: link status (enum port_oper_status) + * @status: link status (enum ionic_port_oper_status) * @id: port id * @speed: link speed (in Mbps) * @xcvr: tranceiver status @@ -1094,7 +1094,7 @@ struct ionic_port_status { }; /** - * struct port_identify_cmd - Port identify command + * struct ionic_port_identify_cmd - Port identify command * @opcode: opcode * @index: port index * @ver: Highest version of identify supported by driver @@ -1107,7 +1107,7 @@ struct ionic_port_identify_cmd { }; /** - * struct port_identify_comp - Port identify command completion + * struct ionic_port_identify_comp - Port identify command completion * @status: The status of the command (enum status_code) * @ver: Version of identify returned by device */ @@ -1118,10 +1118,10 @@ struct ionic_port_identify_comp { }; /** - * struct port_init_cmd - Port initialization command + * struct ionic_port_init_cmd - Port initialization command * @opcode: opcode * @index: port index - * @info_pa: destination address for port info (struct port_info) + * @info_pa: destination address for port info (struct ionic_port_info) */ struct ionic_port_init_cmd { u8 opcode; @@ -1132,7 +1132,7 @@ struct ionic_port_init_cmd { }; /** - * struct port_init_comp - Port initialization command completion + * struct ionic_port_init_comp - Port initialization command completion * @status: The status of the command (enum status_code) */ struct ionic_port_init_comp { @@ -1141,7 +1141,7 @@ struct ionic_port_init_comp { }; /** - * struct port_reset_cmd - Port reset command + * struct ionic_port_reset_cmd - Port reset command * @opcode: opcode * @index: port index */ @@ -1152,7 +1152,7 @@ struct ionic_port_reset_cmd { }; /** - * struct port_reset_comp - Port reset command completion + * struct ionic_port_reset_comp - Port reset command completion * @status: The status of the command (enum status_code) */ struct ionic_port_reset_comp { @@ -1183,7 +1183,7 @@ enum ionic_port_attr { }; /** - * struct port_setattr_cmd - Set port attributes on the NIC + * struct ionic_port_setattr_cmd - Set port attributes on the NIC * @opcode: Opcode * @index: port index * @attr: Attribute type (enum ionic_port_attr) @@ -1207,7 +1207,7 @@ struct ionic_port_setattr_cmd { }; /** - * struct port_setattr_comp - Port set attr command completion + * struct ionic_port_setattr_comp - Port set attr command completion * @status: The status of the command (enum status_code) * @color: Color bit */ @@ -1218,7 +1218,7 @@ struct ionic_port_setattr_comp { }; /** - * struct port_getattr_cmd - Get port attributes from the NIC + * struct ionic_port_getattr_cmd - Get port attributes from the NIC * @opcode: Opcode * @index: port index * @attr: Attribute type (enum ionic_port_attr) @@ -1231,7 +1231,7 @@ struct ionic_port_getattr_cmd { }; /** - * struct port_getattr_comp - Port get attr command completion + * struct ionic_port_getattr_comp - Port get attr command completion * @status: The status of the command (enum status_code) * @color: Color bit */ @@ -1252,10 +1252,10 @@ struct ionic_port_getattr_comp { }; /** - * struct lif_status - Lif status register + * struct ionic_lif_status - Lif status register * @eid: most recent NotifyQ event id * @port_num: port the lif is connected to - * @link_status: port status (enum port_oper_status) + * @link_status: port status (enum ionic_port_oper_status) * @link_speed: speed of link in Mbps * @link_down_count: number of times link status changes */ @@ -1270,7 +1270,7 @@ struct ionic_lif_status { }; /** - * struct lif_reset_cmd - LIF reset command + * struct ionic_lif_reset_cmd - LIF reset command * @opcode: opcode * @index: LIF index */ @@ -1290,7 +1290,7 @@ enum ionic_dev_state { }; /** - * enum dev_attr - List of device attributes + * enum ionic_dev_attr - List of device attributes */ enum ionic_dev_attr { IONIC_DEV_ATTR_STATE = 0, @@ -1299,10 +1299,10 @@ enum ionic_dev_attr { }; /** - * struct dev_setattr_cmd - Set Device attributes on the NIC + * struct ionic_dev_setattr_cmd - Set Device attributes on the NIC * @opcode: Opcode - * @attr: Attribute type (enum dev_attr) - * @state: Device state (enum dev_state) + * @attr: Attribute type (enum ionic_dev_attr) + * @state: Device state (enum ionic_dev_state) * @name: The bus info, e.g. PCI slot-device-function, 0 terminated * @features: Device features */ @@ -1319,7 +1319,7 @@ struct ionic_dev_setattr_cmd { }; /** - * struct dev_setattr_comp - Device set attr command completion + * struct ionic_dev_setattr_comp - Device set attr command completion * @status: The status of the command (enum status_code) * @features: Device features * @color: Color bit @@ -1335,9 +1335,9 @@ struct ionic_dev_setattr_comp { }; /** - * struct dev_getattr_cmd - Get Device attributes from the NIC + * struct ionic_dev_getattr_cmd - Get Device attributes from the NIC * @opcode: opcode - * @attr: Attribute type (enum dev_attr) + * @attr: Attribute type (enum ionic_dev_attr) */ struct ionic_dev_getattr_cmd { u8 opcode; @@ -1346,7 +1346,7 @@ struct ionic_dev_getattr_cmd { }; /** - * struct dev_setattr_comp - Device set attr command completion + * struct ionic_dev_setattr_comp - Device set attr command completion * @status: The status of the command (enum status_code) * @features: Device features * @color: Color bit @@ -1376,7 +1376,7 @@ enum ionic_rss_hash_types { }; /** - * enum lif_attr - List of LIF attributes + * enum ionic_lif_attr - List of LIF attributes */ enum ionic_lif_attr { IONIC_LIF_ATTR_STATE = 0, @@ -1389,15 +1389,15 @@ enum ionic_lif_attr { }; /** - * struct lif_setattr_cmd - Set LIF attributes on the NIC + * struct ionic_lif_setattr_cmd - Set LIF attributes on the NIC * @opcode: Opcode - * @type: Attribute type (enum lif_attr) + * @type: Attribute type (enum ionic_lif_attr) * @index: LIF index * @state: lif state (enum lif_state) * @name: The netdev name string, 0 terminated * @mtu: Mtu * @mac: Station mac - * @features: Features (enum eth_hw_features) + * @features: Features (enum ionic_eth_hw_features) * @rss: RSS properties * @types: The hash types to enable (see rss_hash_types). * @key: The hash secret key. @@ -1426,11 +1426,11 @@ struct ionic_lif_setattr_cmd { }; /** - * struct lif_setattr_comp - LIF set attr command completion + * struct ionic_lif_setattr_comp - LIF set attr command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. - * @features: features (enum eth_hw_features) + * @features: features (enum ionic_eth_hw_features) * @color: Color bit */ struct ionic_lif_setattr_comp { @@ -1445,9 +1445,9 @@ struct ionic_lif_setattr_comp { }; /** - * struct lif_getattr_cmd - Get LIF attributes from the NIC + * struct ionic_lif_getattr_cmd - Get LIF attributes from the NIC * @opcode: Opcode - * @attr: Attribute type (enum lif_attr) + * @attr: Attribute type (enum ionic_lif_attr) * @index: LIF index */ struct ionic_lif_getattr_cmd { @@ -1458,7 +1458,7 @@ struct ionic_lif_getattr_cmd { }; /** - * struct lif_getattr_comp - LIF get attr command completion + * struct ionic_lif_getattr_comp - LIF get attr command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -1466,7 +1466,7 @@ struct ionic_lif_getattr_cmd { * @name: The netdev name string, 0 terminated * @mtu: Mtu * @mac: Station mac - * @features: Features (enum eth_hw_features) + * @features: Features (enum ionic_eth_hw_features) * @color: Color bit */ struct ionic_lif_getattr_comp { @@ -1492,7 +1492,7 @@ enum ionic_rx_mode { }; /** - * struct rx_mode_set_cmd - Set LIF's Rx mode command + * struct ionic_rx_mode_set_cmd - Set LIF's Rx mode command * @opcode: opcode * @lif_index: LIF index * @rx_mode: Rx mode flags: @@ -1519,7 +1519,7 @@ enum ionic_rx_filter_match_type { }; /** - * struct rx_filter_add_cmd - Add LIF Rx filter command + * struct ionic_rx_filter_add_cmd - Add LIF Rx filter command * @opcode: opcode * @qtype: Queue type * @lif_index: LIF index @@ -1550,7 +1550,7 @@ struct ionic_rx_filter_add_cmd { }; /** - * struct rx_filter_add_comp - Add LIF Rx filter command completion + * struct ionic_rx_filter_add_comp - Add LIF Rx filter command completion * @status: The status of the command (enum status_code) * @comp_index: The index in the descriptor ring for which this * is the completion. @@ -1567,7 +1567,7 @@ struct ionic_rx_filter_add_comp { }; /** - * struct rx_filter_del_cmd - Delete LIF Rx filter command + * struct ionic_rx_filter_del_cmd - Delete LIF Rx filter command * @opcode: opcode * @lif_index: LIF index * @filter_id: Filter ID @@ -1583,7 +1583,7 @@ struct ionic_rx_filter_del_cmd { typedef struct ionic_admin_comp ionic_rx_filter_del_comp; /** - * struct qos_identify_cmd - QoS identify command + * struct ionic_qos_identify_cmd - QoS identify command * @opcode: opcode * @ver: Highest version of identify supported by driver * @@ -1595,7 +1595,7 @@ struct ionic_qos_identify_cmd { }; /** - * struct qos_identify_comp - QoS identify command completion + * struct ionic_qos_identify_comp - QoS identify command completion * @status: The status of the command (enum status_code) * @ver: Version of identify returned by device */ @@ -1610,7 +1610,7 @@ struct ionic_qos_identify_comp { #define IONIC_QOS_DSCP_MAX_VALUES 64 /** - * enum qos_class + * enum ionic_qos_class */ enum ionic_qos_class { IONIC_QOS_CLASS_DEFAULT = 0, @@ -1623,7 +1623,7 @@ enum ionic_qos_class { }; /** - * enum qos_class_type - Traffic classification criteria + * enum ionic_qos_class_type - Traffic classification criteria */ enum ionic_qos_class_type { IONIC_QOS_CLASS_TYPE_NONE = 0, @@ -1632,7 +1632,7 @@ enum ionic_qos_class_type { }; /** - * enum qos_sched_type - Qos class scheduling type + * enum ionic_qos_sched_type - Qos class scheduling type */ enum ionic_qos_sched_type { IONIC_QOS_SCHED_TYPE_STRICT = 0, /* Strict priority */ @@ -1640,15 +1640,15 @@ enum ionic_qos_sched_type { }; /** - * union qos_config - Qos configuration structure + * union ionic_qos_config - Qos configuration structure * @flags: Configuration flags * IONIC_QOS_CONFIG_F_ENABLE enable * IONIC_QOS_CONFIG_F_DROP drop/nodrop * IONIC_QOS_CONFIG_F_RW_DOT1Q_PCP enable dot1q pcp rewrite * IONIC_QOS_CONFIG_F_RW_IP_DSCP enable ip dscp rewrite - * @sched_type: Qos class scheduling type (enum qos_sched_type) - * @class_type: Qos class type (enum qos_class_type) - * @pause_type: Qos pause type (enum qos_pause_type) + * @sched_type: Qos class scheduling type (enum ionic_qos_sched_type) + * @class_type: Qos class type (enum ionic_qos_class_type) + * @pause_type: Qos pause type (enum ionic_qos_pause_type) * @name: Qos class name * @mtu: MTU of the class * @pfc_dot1q_pcp: Pcp value for pause frames (valid iff F_NODROP) @@ -1697,7 +1697,7 @@ union ionic_qos_config { }; /** - * union qos_identity - QoS identity structure + * union ionic_qos_identity - QoS identity structure * @version: Version of the identify structure * @type: QoS system type * @nclasses: Number of usable QoS classes @@ -1730,7 +1730,7 @@ struct ionic_qos_init_cmd { typedef struct ionic_admin_comp ionic_qos_init_comp; /** - * struct qos_reset_cmd - Qos config reset command + * struct ionic_qos_reset_cmd - Qos config reset command * @opcode: Opcode */ struct ionic_qos_reset_cmd { @@ -1742,7 +1742,7 @@ struct ionic_qos_reset_cmd { typedef struct ionic_admin_comp ionic_qos_reset_comp; /** - * struct fw_download_cmd - Firmware download command + * struct ionic_fw_download_cmd - Firmware download command * @opcode: opcode * @addr: dma address of the firmware buffer * @offset: offset of the firmware buffer within the full image @@ -1765,9 +1765,9 @@ enum ionic_fw_control_oper { }; /** - * struct fw_control_cmd - Firmware control command + * struct ionic_fw_control_cmd - Firmware control command * @opcode: opcode - * @oper: firmware control operation (enum fw_control_oper) + * @oper: firmware control operation (enum ionic_fw_control_oper) * @slot: slot to activate */ struct ionic_fw_control_cmd { @@ -1779,7 +1779,7 @@ struct ionic_fw_control_cmd { }; /** - * struct fw_control_comp - Firmware control copletion + * struct ionic_fw_control_comp - Firmware control copletion * @opcode: opcode * @slot: slot where the firmware was installed */ @@ -1797,13 +1797,13 @@ struct ionic_fw_control_comp { ******************************************************************/ /** - * struct rdma_reset_cmd - Reset RDMA LIF cmd + * struct ionic_rdma_reset_cmd - Reset RDMA LIF cmd * @opcode: opcode * @lif_index: lif index * * There is no rdma specific dev command completion struct. Completion uses - * the common struct admin_comp. Only the status is indicated. Nonzero status - * means the LIF does not support rdma. + * the common struct ionic_admin_comp. Only the status is indicated. + * Nonzero status means the LIF does not support rdma. **/ struct ionic_rdma_reset_cmd { u8 opcode; @@ -1813,7 +1813,7 @@ struct ionic_rdma_reset_cmd { }; /** - * struct rdma_queue_cmd - Create RDMA Queue command + * struct ionic_rdma_queue_cmd - Create RDMA Queue command * @opcode: opcode, 52, 53 * @lif_index lif index * @qid_ver: (qid | (rdma version << 24)) @@ -1839,7 +1839,7 @@ struct ionic_rdma_reset_cmd { * memory registration. * * There is no rdma specific dev command completion struct. Completion uses - * the common struct admin_comp. Only the status is indicated. + * the common struct ionic_admin_comp. Only the status is indicated. **/ struct ionic_rdma_queue_cmd { u8 opcode; @@ -1860,7 +1860,7 @@ struct ionic_rdma_queue_cmd { ******************************************************************/ /** - * struct notifyq_event + * struct ionic_notifyq_event * @eid: event number * @ecode: event code * @data: unspecified data about the event @@ -1875,7 +1875,7 @@ struct ionic_notifyq_event { }; /** - * struct link_change_event + * struct ionic_link_change_event * @eid: event number * @ecode: event code = EVENT_OPCODE_LINK_CHANGE * @link_status: link up or down, with error bits (enum port_status) @@ -1892,7 +1892,7 @@ struct ionic_link_change_event { }; /** - * struct reset_event + * struct ionic_reset_event * @eid: event number * @ecode: event code = EVENT_OPCODE_RESET * @reset_code: reset type @@ -1910,7 +1910,7 @@ struct ionic_reset_event { }; /** - * struct heartbeat_event + * struct ionic_heartbeat_event * @eid: event number * @ecode: event code = EVENT_OPCODE_HEARTBEAT * @@ -1923,7 +1923,7 @@ struct ionic_heartbeat_event { }; /** - * struct log_event + * struct ionic_log_event * @eid: event number * @ecode: event code = EVENT_OPCODE_LOG * @data: log data @@ -1937,7 +1937,7 @@ struct ionic_log_event { }; /** - * struct port_stats + * struct ionic_port_stats */ struct ionic_port_stats { __le64 frames_rx_ok; @@ -2067,7 +2067,7 @@ struct ionic_mgmt_port_stats { }; /** - * struct port_identity - port identity structure + * struct ionic_port_identity - port identity structure * @version: identity structure version * @type: type of port (enum port_type) * @num_lanes: number of lanes for the port @@ -2099,7 +2099,7 @@ union ionic_port_identity { }; /** - * struct port_info - port info structure + * struct ionic_port_info - port info structure * @port_status: port status * @port_stats: port stats */ @@ -2110,7 +2110,7 @@ struct ionic_port_info { }; /** - * struct lif_stats + * struct ionic_lif_stats */ struct ionic_lif_stats { /* RX */ @@ -2264,7 +2264,7 @@ struct ionic_lif_stats { }; /** - * struct lif_info - lif info structure + * struct ionic_lif_info - lif info structure */ struct ionic_lif_info { union ionic_lif_config config; @@ -2357,7 +2357,7 @@ union ionic_dev_info_regs { }; /** - * union dev_cmd_regs - Device command register format (read-write) + * union ionic_dev_cmd_regs - Device command register format (read-write) * @doorbell: Device Cmd Doorbell, write-only. * Write a 1 to signal device to process cmd, * poll done for completion. @@ -2379,7 +2379,7 @@ union ionic_dev_cmd_regs { }; /** - * union dev_regs - Device register format in for bar 0 page 0 + * union ionic_dev_regs - Device register format in for bar 0 page 0 * @info: Device info registers * @devcmd: Device command registers */ @@ -2433,7 +2433,7 @@ union ionic_adminq_comp { #define IONIC_ASIC_TYPE_CAPRI 0 /** - * struct doorbell - Doorbell register layout + * struct ionic_doorbell - Doorbell register layout * @p_index: Producer index * @ring: Selects the specific ring of the queue to update. * Type-specific meaning: -- cgit v1.2.3-59-g8ed1b From ff7ebed94551bcb37bc344bba294ba58ead55db0 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:48:56 -0700 Subject: ionic: reverse an interrupt coalesce calculation Fix the initial interrupt coalesce usec-to-hw setting to actually be usec-to-hw. Fixes: 780eded34ccc ("ionic: report users coalesce request") Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_lif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 559b96ae48f5..cf64dea53f82 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1686,7 +1686,7 @@ static struct ionic_lif *ionic_lif_alloc(struct ionic *ionic, unsigned int index /* Convert the default coalesce value to actual hw resolution */ lif->rx_coalesce_usecs = IONIC_ITR_COAL_USEC_DEFAULT; - lif->rx_coalesce_hw = ionic_coal_hw_to_usec(lif->ionic, + lif->rx_coalesce_hw = ionic_coal_usec_to_hw(lif->ionic, lif->rx_coalesce_usecs); snprintf(lif->name, sizeof(lif->name), "lif%u", index); -- cgit v1.2.3-59-g8ed1b From 97ca486592c0e940a85a06b3ca37dcb6962b2a04 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:48:57 -0700 Subject: ionic: add heartbeat check Most of our firmware has a heartbeat feature that the driver can watch for to see if the FW is still alive and likely to answer a dev_cmd or AdminQ request. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_dev.c | 43 ++++++++++++++++++++++++ drivers/net/ethernet/pensando/ionic/ionic_dev.h | 4 +++ drivers/net/ethernet/pensando/ionic/ionic_main.c | 24 ++++++++++++- 3 files changed, 70 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index d168a6435322..544a9f799afc 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -84,6 +84,49 @@ void ionic_dev_teardown(struct ionic *ionic) } /* Devcmd Interface */ +int ionic_heartbeat_check(struct ionic *ionic) +{ + struct ionic_dev *idev = &ionic->idev; + unsigned long hb_time; + u32 fw_status; + u32 hb; + + /* wait a little more than one second before testing again */ + hb_time = jiffies; + if (time_before(hb_time, (idev->last_hb_time + (HZ * 2)))) + return 0; + + /* firmware is useful only if fw_status is non-zero */ + fw_status = ioread32(&idev->dev_info_regs->fw_status); + if (!fw_status) + return -ENXIO; + + /* early FW has no heartbeat, else FW will return non-zero */ + hb = ioread32(&idev->dev_info_regs->fw_heartbeat); + if (!hb) + return 0; + + /* are we stalled? */ + if (hb == idev->last_hb) { + /* only complain once for each stall seen */ + if (idev->last_hb_time != 1) { + dev_info(ionic->dev, "FW heartbeat stalled at %d\n", + idev->last_hb); + idev->last_hb_time = 1; + } + + return -ENXIO; + } + + if (idev->last_hb_time == 1) + dev_info(ionic->dev, "FW heartbeat restored at %d\n", hb); + + idev->last_hb = hb; + idev->last_hb_time = hb_time; + + return 0; +} + u8 ionic_dev_cmd_status(struct ionic_dev *idev) { return ioread8(&idev->dev_cmd_regs->comp.comp.status); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 9610aeb7d5f4..1ffb3e4dec5d 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -123,6 +123,9 @@ struct ionic_dev { union ionic_dev_info_regs __iomem *dev_info_regs; union ionic_dev_cmd_regs __iomem *dev_cmd_regs; + unsigned long last_hb_time; + u32 last_hb; + u64 __iomem *db_pages; dma_addr_t phy_db_pages; @@ -295,5 +298,6 @@ void ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb, void ionic_q_rewind(struct ionic_queue *q, struct ionic_desc_info *start); void ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info, unsigned int stop_index); +int ionic_heartbeat_check(struct ionic *ionic); #endif /* _IONIC_DEV_H_ */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c index 15e432386b35..52eb303e903f 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -245,6 +245,10 @@ static int ionic_adminq_post(struct ionic_lif *lif, struct ionic_admin_ctx *ctx) goto err_out; } + err = ionic_heartbeat_check(lif->ionic); + if (err) + goto err_out; + memcpy(adminq->head->desc, &ctx->cmd, sizeof(ctx->cmd)); dev_dbg(&lif->netdev->dev, "post admin queue command:\n"); @@ -305,6 +309,14 @@ int ionic_napi(struct napi_struct *napi, int budget, ionic_cq_cb cb, return work_done; } +static void ionic_dev_cmd_clean(struct ionic *ionic) +{ + union ionic_dev_cmd_regs *regs = ionic->idev.dev_cmd_regs; + + iowrite32(0, ®s->doorbell); + memset_io(®s->cmd, 0, sizeof(regs->cmd)); +} + int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) { struct ionic_dev *idev = &ionic->idev; @@ -314,6 +326,7 @@ int ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds) int opcode; int done; int err; + int hb; WARN_ON(in_interrupt()); @@ -328,7 +341,8 @@ try_again: if (done) break; msleep(20); - } while (!done && time_before(jiffies, max_wait)); + hb = ionic_heartbeat_check(ionic); + } while (!done && !hb && time_before(jiffies, max_wait)); duration = jiffies - start_time; opcode = idev->dev_cmd_regs->cmd.cmd.opcode; @@ -336,7 +350,15 @@ try_again: ionic_opcode_to_str(opcode), opcode, done, duration / HZ, duration); + if (!done && hb) { + ionic_dev_cmd_clean(ionic); + dev_warn(ionic->dev, "DEVCMD %s (%d) failed - FW halted\n", + ionic_opcode_to_str(opcode), opcode); + return -ENXIO; + } + if (!done && !time_before(jiffies, max_wait)) { + ionic_dev_cmd_clean(ionic); dev_warn(ionic->dev, "DEVCMD %s (%d) timeout after %ld secs\n", ionic_opcode_to_str(opcode), opcode, max_seconds); return -ETIMEDOUT; -- cgit v1.2.3-59-g8ed1b From 089406bc5ad639e4fcc9419f70f4d3d91d7370cb Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:48:58 -0700 Subject: ionic: add a watchdog timer to monitor heartbeat Add a watchdog to periodically monitor the NIC heartbeat. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic.h | 2 ++ drivers/net/ethernet/pensando/ionic/ionic_dev.c | 19 +++++++++++++++++-- drivers/net/ethernet/pensando/ionic/ionic_dev.h | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index 7a7060677f15..5b013250f8c3 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -46,6 +46,8 @@ struct ionic { DECLARE_BITMAP(intrs, IONIC_INTR_CTRL_REGS_MAX); struct work_struct nb_work; struct notifier_block nb; + struct timer_list watchdog_timer; + int watchdog_period; }; struct ionic_admin_ctx { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c index 544a9f799afc..5f9d2ec70446 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c @@ -11,6 +11,16 @@ #include "ionic_dev.h" #include "ionic_lif.h" +static void ionic_watchdog_cb(struct timer_list *t) +{ + struct ionic *ionic = from_timer(ionic, t, watchdog_timer); + + mod_timer(&ionic->watchdog_timer, + round_jiffies(jiffies + ionic->watchdog_period)); + + ionic_heartbeat_check(ionic); +} + void ionic_init_devinfo(struct ionic *ionic) { struct ionic_dev *idev = &ionic->idev; @@ -72,6 +82,11 @@ int ionic_dev_setup(struct ionic *ionic) return -EFAULT; } + timer_setup(&ionic->watchdog_timer, ionic_watchdog_cb, 0); + ionic->watchdog_period = IONIC_WATCHDOG_SECS * HZ; + mod_timer(&ionic->watchdog_timer, + round_jiffies(jiffies + ionic->watchdog_period)); + idev->db_pages = bar->vaddr; idev->phy_db_pages = bar->bus_addr; @@ -80,7 +95,7 @@ int ionic_dev_setup(struct ionic *ionic) void ionic_dev_teardown(struct ionic *ionic) { - /* place holder */ + del_timer_sync(&ionic->watchdog_timer); } /* Devcmd Interface */ @@ -93,7 +108,7 @@ int ionic_heartbeat_check(struct ionic *ionic) /* wait a little more than one second before testing again */ hb_time = jiffies; - if (time_before(hb_time, (idev->last_hb_time + (HZ * 2)))) + if (time_before(hb_time, (idev->last_hb_time + ionic->watchdog_period))) return 0; /* firmware is useful only if fw_status is non-zero */ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 1ffb3e4dec5d..78691c1ba20b 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -16,6 +16,7 @@ #define IONIC_MIN_TXRX_DESC 16 #define IONIC_DEF_TXRX_DESC 4096 #define IONIC_LIFS_MAX 1024 +#define IONIC_WATCHDOG_SECS 5 #define IONIC_ITR_COAL_USEC_DEFAULT 64 #define IONIC_DEV_CMD_REG_VERSION 1 -- cgit v1.2.3-59-g8ed1b From 08f2e4b2b2008ce461dd6958caa616a2e3a30ac8 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:48:59 -0700 Subject: ionic: implement support for rx sgl Even out Rx performance across MTU sizes by changing from full skb allocations to page-based frag allocations. The device supports a form of scatter-gather in the Rx path, so we can set up a number of pages for each descriptor, all of which are easier to alloc and pass around than the standard kzalloc'd buffer. An skb is wrapped around the pages while processing the received packets, and pages are recycled as needed, or left alone if they weren't used in the Rx. Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_dev.h | 7 + drivers/net/ethernet/pensando/ionic/ionic_lif.c | 9 +- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 292 ++++++++++++++++------- 3 files changed, 224 insertions(+), 84 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 78691c1ba20b..4665c5dc5324 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -155,12 +155,19 @@ typedef void (*ionic_desc_cb)(struct ionic_queue *q, struct ionic_desc_info *desc_info, struct ionic_cq_info *cq_info, void *cb_arg); +struct ionic_page_info { + struct page *page; + dma_addr_t dma_addr; +}; + struct ionic_desc_info { void *desc; void *sg_desc; struct ionic_desc_info *next; unsigned int index; unsigned int left; + unsigned int npages; + struct ionic_page_info pages[IONIC_RX_MAX_SG_ELEMS + 1]; ionic_desc_cb cb; void *cb_arg; }; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index cf64dea53f82..a9bb12ce5f13 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -622,12 +622,14 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq) .lif_index = cpu_to_le16(lif->index), .type = q->type, .index = cpu_to_le32(q->index), - .flags = cpu_to_le16(IONIC_QINIT_F_IRQ), + .flags = cpu_to_le16(IONIC_QINIT_F_IRQ | + IONIC_QINIT_F_SG), .intr_index = cpu_to_le16(cq->bound_intr->index), .pid = cpu_to_le16(q->pid), .ring_size = ilog2(q->num_descs), .ring_base = cpu_to_le64(q->base_pa), .cq_ring_base = cpu_to_le64(cq->base_pa), + .sg_ring_base = cpu_to_le64(q->sg_base_pa), }, }; int err; @@ -1460,13 +1462,14 @@ static int ionic_txrx_alloc(struct ionic_lif *lif) lif->txqcqs[i].qcq->stats = lif->txqcqs[i].stats; } - flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_INTR; + flags = IONIC_QCQ_F_RX_STATS | IONIC_QCQ_F_SG | IONIC_QCQ_F_INTR; for (i = 0; i < lif->nxqs; i++) { err = ionic_qcq_alloc(lif, IONIC_QTYPE_RXQ, i, "rx", flags, lif->nrxq_descs, sizeof(struct ionic_rxq_desc), sizeof(struct ionic_rxq_comp), - 0, lif->kern_pid, &lif->rxqcqs[i].qcq); + sizeof(struct ionic_rxq_sg_desc), + lif->kern_pid, &lif->rxqcqs[i].qcq); if (err) goto err_out; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index ab6663d94f42..0aeac3157160 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -34,52 +34,110 @@ static inline struct netdev_queue *q_to_ndq(struct ionic_queue *q) return netdev_get_tx_queue(q->lif->netdev, q->index); } -static void ionic_rx_recycle(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct sk_buff *skb) +static struct sk_buff *ionic_rx_skb_alloc(struct ionic_queue *q, + unsigned int len, bool frags) { - struct ionic_rxq_desc *old = desc_info->desc; - struct ionic_rxq_desc *new = q->head->desc; + struct ionic_lif *lif = q->lif; + struct ionic_rx_stats *stats; + struct net_device *netdev; + struct sk_buff *skb; + + netdev = lif->netdev; + stats = q_to_rx_stats(q); + + if (frags) + skb = napi_get_frags(&q_to_qcq(q)->napi); + else + skb = netdev_alloc_skb_ip_align(netdev, len); - new->addr = old->addr; - new->len = old->len; + if (unlikely(!skb)) { + net_warn_ratelimited("%s: SKB alloc failed on %s!\n", + netdev->name, q->name); + stats->alloc_err++; + return NULL; + } - ionic_rxq_post(q, true, ionic_rx_clean, skb); + return skb; } -static bool ionic_rx_copybreak(struct ionic_queue *q, struct ionic_desc_info *desc_info, - struct ionic_cq_info *cq_info, struct sk_buff **skb) +static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, + struct ionic_desc_info *desc_info, + struct ionic_cq_info *cq_info) { struct ionic_rxq_comp *comp = cq_info->cq_desc; - struct ionic_rxq_desc *desc = desc_info->desc; - struct net_device *netdev = q->lif->netdev; struct device *dev = q->lif->ionic->dev; - struct sk_buff *new_skb; - u16 clen, dlen; - - clen = le16_to_cpu(comp->len); - dlen = le16_to_cpu(desc->len); - if (clen > q->lif->rx_copybreak) { - dma_unmap_single(dev, (dma_addr_t)le64_to_cpu(desc->addr), - dlen, DMA_FROM_DEVICE); - return false; - } + struct ionic_page_info *page_info; + struct sk_buff *skb; + unsigned int i; + u16 frag_len; + u16 len; - new_skb = netdev_alloc_skb_ip_align(netdev, clen); - if (!new_skb) { - dma_unmap_single(dev, (dma_addr_t)le64_to_cpu(desc->addr), - dlen, DMA_FROM_DEVICE); - return false; - } + page_info = &desc_info->pages[0]; + len = le16_to_cpu(comp->len); - dma_sync_single_for_cpu(dev, (dma_addr_t)le64_to_cpu(desc->addr), - clen, DMA_FROM_DEVICE); + prefetch(page_address(page_info->page) + NET_IP_ALIGN); - memcpy(new_skb->data, (*skb)->data, clen); + skb = ionic_rx_skb_alloc(q, len, true); + if (unlikely(!skb)) + return NULL; - ionic_rx_recycle(q, desc_info, *skb); - *skb = new_skb; + i = comp->num_sg_elems + 1; + do { + if (unlikely(!page_info->page)) { + struct napi_struct *napi = &q_to_qcq(q)->napi; - return true; + napi->skb = NULL; + dev_kfree_skb(skb); + return NULL; + } + + frag_len = min(len, (u16)PAGE_SIZE); + len -= frag_len; + + dma_unmap_page(dev, dma_unmap_addr(page_info, dma_addr), + PAGE_SIZE, DMA_FROM_DEVICE); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + page_info->page, 0, frag_len, PAGE_SIZE); + page_info->page = NULL; + page_info++; + i--; + } while (i > 0); + + return skb; +} + +static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q, + struct ionic_desc_info *desc_info, + struct ionic_cq_info *cq_info) +{ + struct ionic_rxq_comp *comp = cq_info->cq_desc; + struct device *dev = q->lif->ionic->dev; + struct ionic_page_info *page_info; + struct sk_buff *skb; + u16 len; + + page_info = &desc_info->pages[0]; + len = le16_to_cpu(comp->len); + + skb = ionic_rx_skb_alloc(q, len, false); + if (unlikely(!skb)) + return NULL; + + if (unlikely(!page_info->page)) { + dev_kfree_skb(skb); + return NULL; + } + + dma_sync_single_for_cpu(dev, dma_unmap_addr(page_info, dma_addr), + len, DMA_FROM_DEVICE); + skb_copy_to_linear_data(skb, page_address(page_info->page), len); + dma_sync_single_for_device(dev, dma_unmap_addr(page_info, dma_addr), + len, DMA_FROM_DEVICE); + + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, q->lif->netdev); + + return skb; } static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info, @@ -87,35 +145,34 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i { struct ionic_rxq_comp *comp = cq_info->cq_desc; struct ionic_qcq *qcq = q_to_qcq(q); - struct sk_buff *skb = cb_arg; struct ionic_rx_stats *stats; struct net_device *netdev; + struct sk_buff *skb; stats = q_to_rx_stats(q); netdev = q->lif->netdev; - if (comp->status) { - ionic_rx_recycle(q, desc_info, skb); + if (comp->status) return; - } - if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) { - /* no packet processing while resetting */ - ionic_rx_recycle(q, desc_info, skb); + /* no packet processing while resetting */ + if (unlikely(test_bit(IONIC_LIF_QUEUE_RESET, q->lif->state))) return; - } stats->pkts++; stats->bytes += le16_to_cpu(comp->len); - ionic_rx_copybreak(q, desc_info, cq_info, &skb); + if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) + skb = ionic_rx_copybreak(q, desc_info, cq_info); + else + skb = ionic_rx_frags(q, desc_info, cq_info); - skb_put(skb, le16_to_cpu(comp->len)); - skb->protocol = eth_type_trans(skb, netdev); + if (unlikely(!skb)) + return; skb_record_rx_queue(skb, q->index); - if (netdev->features & NETIF_F_RXHASH) { + if (likely(netdev->features & NETIF_F_RXHASH)) { switch (comp->pkt_type_color & IONIC_RXQ_COMP_PKT_TYPE_MASK) { case IONIC_PKT_TYPE_IPV4: case IONIC_PKT_TYPE_IPV6: @@ -132,7 +189,7 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i } } - if (netdev->features & NETIF_F_RXCSUM) { + if (likely(netdev->features & NETIF_F_RXCSUM)) { if (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_CALC) { skb->ip_summed = CHECKSUM_COMPLETE; skb->csum = (__wsum)le16_to_cpu(comp->csum); @@ -142,18 +199,21 @@ static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_i stats->csum_none++; } - if ((comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_BAD) || - (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_BAD) || - (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD)) + if (unlikely((comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_TCP_BAD) || + (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_UDP_BAD) || + (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_IP_BAD))) stats->csum_error++; - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (likely(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) { if (comp->csum_flags & IONIC_RXQ_COMP_CSUM_F_VLAN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), le16_to_cpu(comp->vlan_tci)); } - napi_gro_receive(&qcq->napi, skb); + if (le16_to_cpu(comp->len) <= q->lif->rx_copybreak) + napi_gro_receive(&qcq->napi, skb); + else + napi_gro_frags(&qcq->napi); } static bool ionic_rx_service(struct ionic_cq *cq, struct ionic_cq_info *cq_info) @@ -213,66 +273,125 @@ void ionic_rx_flush(struct ionic_cq *cq) work_done, IONIC_INTR_CRED_RESET_COALESCE); } -static struct sk_buff *ionic_rx_skb_alloc(struct ionic_queue *q, unsigned int len, - dma_addr_t *dma_addr) +static struct page *ionic_rx_page_alloc(struct ionic_queue *q, + dma_addr_t *dma_addr) { struct ionic_lif *lif = q->lif; struct ionic_rx_stats *stats; struct net_device *netdev; - struct sk_buff *skb; struct device *dev; + struct page *page; netdev = lif->netdev; dev = lif->ionic->dev; stats = q_to_rx_stats(q); - skb = netdev_alloc_skb_ip_align(netdev, len); - if (!skb) { - net_warn_ratelimited("%s: SKB alloc failed on %s!\n", - netdev->name, q->name); + page = alloc_page(GFP_ATOMIC); + if (unlikely(!page)) { + net_err_ratelimited("%s: Page alloc failed on %s!\n", + netdev->name, q->name); stats->alloc_err++; return NULL; } - *dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, *dma_addr)) { - dev_kfree_skb(skb); - net_warn_ratelimited("%s: DMA single map failed on %s!\n", - netdev->name, q->name); + *dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(dev, *dma_addr))) { + __free_page(page); + net_err_ratelimited("%s: DMA single map failed on %s!\n", + netdev->name, q->name); stats->dma_map_err++; return NULL; } - return skb; + return page; +} + +static void ionic_rx_page_free(struct ionic_queue *q, struct page *page, + dma_addr_t dma_addr) +{ + struct ionic_lif *lif = q->lif; + struct net_device *netdev; + struct device *dev; + + netdev = lif->netdev; + dev = lif->ionic->dev; + + if (unlikely(!page)) { + net_err_ratelimited("%s: Trying to free unallocated buffer on %s!\n", + netdev->name, q->name); + return; + } + + dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE); + + __free_page(page); } -#define IONIC_RX_RING_DOORBELL_STRIDE ((1 << 2) - 1) +#define IONIC_RX_RING_DOORBELL_STRIDE ((1 << 5) - 1) +#define IONIC_RX_RING_HEAD_BUF_SZ 2048 void ionic_rx_fill(struct ionic_queue *q) { struct net_device *netdev = q->lif->netdev; + struct ionic_desc_info *desc_info; + struct ionic_page_info *page_info; + struct ionic_rxq_sg_desc *sg_desc; + struct ionic_rxq_sg_elem *sg_elem; struct ionic_rxq_desc *desc; - struct sk_buff *skb; - dma_addr_t dma_addr; + unsigned int nfrags; bool ring_doorbell; + unsigned int i, j; unsigned int len; - unsigned int i; len = netdev->mtu + ETH_HLEN; + nfrags = round_up(len, PAGE_SIZE) / PAGE_SIZE; for (i = ionic_q_space_avail(q); i; i--) { - skb = ionic_rx_skb_alloc(q, len, &dma_addr); - if (!skb) - return; + desc_info = q->head; + desc = desc_info->desc; + sg_desc = desc_info->sg_desc; + page_info = &desc_info->pages[0]; + + if (page_info->page) { /* recycle the buffer */ + ring_doorbell = ((q->head->index + 1) & + IONIC_RX_RING_DOORBELL_STRIDE) == 0; + ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL); + continue; + } - desc = q->head->desc; - desc->addr = cpu_to_le64(dma_addr); - desc->len = cpu_to_le16(len); - desc->opcode = IONIC_RXQ_DESC_OPCODE_SIMPLE; + /* fill main descriptor - pages[0] */ + desc->opcode = (nfrags > 1) ? IONIC_RXQ_DESC_OPCODE_SG : + IONIC_RXQ_DESC_OPCODE_SIMPLE; + desc_info->npages = nfrags; + page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); + if (unlikely(!page_info->page)) { + desc->addr = 0; + desc->len = 0; + return; + } + desc->addr = cpu_to_le64(page_info->dma_addr); + desc->len = cpu_to_le16(PAGE_SIZE); + page_info++; + + /* fill sg descriptors - pages[1..n] */ + for (j = 0; j < nfrags - 1; j++) { + if (page_info->page) /* recycle the sg buffer */ + continue; + + sg_elem = &sg_desc->elems[j]; + page_info->page = ionic_rx_page_alloc(q, &page_info->dma_addr); + if (unlikely(!page_info->page)) { + sg_elem->addr = 0; + sg_elem->len = 0; + return; + } + sg_elem->addr = cpu_to_le64(page_info->dma_addr); + sg_elem->len = cpu_to_le16(PAGE_SIZE); + page_info++; + } ring_doorbell = ((q->head->index + 1) & IONIC_RX_RING_DOORBELL_STRIDE) == 0; - - ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, skb); + ionic_rxq_post(q, ring_doorbell, ionic_rx_clean, NULL); } } @@ -283,15 +402,26 @@ static void ionic_rx_fill_cb(void *arg) void ionic_rx_empty(struct ionic_queue *q) { - struct device *dev = q->lif->ionic->dev; + struct ionic_rxq_sg_desc *sg_desc; struct ionic_desc_info *cur; struct ionic_rxq_desc *desc; + unsigned int i; for (cur = q->tail; cur != q->head; cur = cur->next) { desc = cur->desc; - dma_unmap_single(dev, le64_to_cpu(desc->addr), - le16_to_cpu(desc->len), DMA_FROM_DEVICE); - dev_kfree_skb(cur->cb_arg); + desc->addr = 0; + desc->len = 0; + + sg_desc = cur->sg_desc; + for (i = 0; i < cur->npages; i++) { + if (likely(cur->pages[i].page)) { + ionic_rx_page_free(q, cur->pages[i].page, + cur->pages[i].dma_addr); + cur->pages[i].page = NULL; + cur->pages[i].dma_addr = 0; + } + } + cur->cb_arg = NULL; } } -- cgit v1.2.3-59-g8ed1b From 63ad1cd68071d56d9ed99ed35f622513005f71dc Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Wed, 23 Oct 2019 17:49:00 -0700 Subject: ionic: update driver version Signed-off-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic.h b/drivers/net/ethernet/pensando/ionic/ionic.h index 5b013250f8c3..98e102af7756 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic.h +++ b/drivers/net/ethernet/pensando/ionic/ionic.h @@ -12,7 +12,7 @@ struct ionic_lif; #define IONIC_DRV_NAME "ionic" #define IONIC_DRV_DESCRIPTION "Pensando Ethernet NIC Driver" -#define IONIC_DRV_VERSION "0.15.0-k" +#define IONIC_DRV_VERSION "0.18.0-k" #define PCI_VENDOR_ID_PENSANDO 0x1dd8 -- cgit v1.2.3-59-g8ed1b From bb1eded18d139c815f39abb77390a7040fb24b04 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Sat, 26 Oct 2019 11:05:31 +0000 Subject: net: aquantia: fix var initialization warning found by sparse, simply useless local initialization with zero. Fixes: 94ad94558b0f ("net: aquantia: add PTP rings infrastructure") Reported-by: kbuild test robot Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 3ec08415e53e..bb6fbbadfd47 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -947,7 +947,7 @@ int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) { struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp; unsigned int tx_ring_idx, rx_ring_idx; - struct aq_ring_s *hwts = 0; + struct aq_ring_s *hwts; u32 tx_tc_mode, rx_tc_mode; struct aq_ring_s *ring; int err; -- cgit v1.2.3-59-g8ed1b From 5eeb6c3cf26eac522df07bee1a58573804179126 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Sat, 26 Oct 2019 11:05:33 +0000 Subject: net: aquantia: fix warnings on endianness fixes to remove sparse warnings: sparse: sparse: cast to restricted __be64 Fixes: 04a1839950d9 ("net: aquantia: implement data PTP datapath") Reported-by: kbuild test robot Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 9 ++++----- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 51ecf87e0198..abee561ea54e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1236,9 +1236,9 @@ static u16 hw_atl_b0_rx_extract_ts(struct aq_hw_s *self, u8 *p, { unsigned int offset = 14; struct ethhdr *eth; - u64 sec; + __be64 sec; + __be32 ns; u8 *ptr; - u32 ns; if (len <= offset || !timestamp) return 0; @@ -1256,9 +1256,8 @@ static u16 hw_atl_b0_rx_extract_ts(struct aq_hw_s *self, u8 *p, ptr += sizeof(sec); memcpy(&ns, ptr, sizeof(ns)); - sec = be64_to_cpu(sec) & 0xffffffffffffllu; - ns = be32_to_cpu(ns); - *timestamp = sec * NSEC_PER_SEC + ns + self->ptp_clk_offset; + *timestamp = (be64_to_cpu(sec) & 0xffffffffffffllu) * NSEC_PER_SEC + + be32_to_cpu(ns) + self->ptp_clk_offset; eth = (struct ethhdr *)p; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 37e6b696009d..ee11b107f0a5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -41,7 +41,7 @@ struct __packed hw_atl_rxd_wb_s { u16 status; u16 pkt_len; u16 next_desc_ptr; - u16 vlan; + __le16 vlan; }; /* Hardware rx HW TIMESTAMP writeback */ -- cgit v1.2.3-59-g8ed1b From 7873ee26b10bcb03553b6a26ec16b9a937a5b916 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Sat, 26 Oct 2019 11:05:34 +0000 Subject: net: aquantia: disable ptp object build if no config We do disable aq_ptp module build using inline stubs when CONFIG_PTP_1588_CLOCK is not declared. This reduces module size and removes unnecessary code. Reported-by: YueHaibing Signed-off-by: Igor Russkikh Acked-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/Makefile | 3 +- drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 84 +++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index 68c41141ede2..0020726db204 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -24,10 +24,11 @@ atlantic-objs := aq_main.o \ aq_ethtool.o \ aq_drvinfo.o \ aq_filters.o \ - aq_ptp.o \ aq_phy.o \ hw_atl/hw_atl_a0.o \ hw_atl/hw_atl_b0.o \ hw_atl/hw_atl_utils.o \ hw_atl/hw_atl_utils_fw2x.o \ hw_atl/hw_atl_llh.o + +atlantic-$(CONFIG_PTP_1588_CLOCK) += aq_ptp.o \ No newline at end of file diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index 3de4682f7c06..bf503a40b6a4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -11,6 +11,8 @@ #include #include +#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK) + /* Common functions */ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec); @@ -54,4 +56,86 @@ struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp); int aq_ptp_link_change(struct aq_nic_s *aq_nic); +#else + +static inline int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) +{ + return 0; +} + +static inline void aq_ptp_unregister(struct aq_nic_s *aq_nic) {} + +static inline void aq_ptp_free(struct aq_nic_s *aq_nic) +{ +} + +static inline int aq_ptp_irq_alloc(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_irq_free(struct aq_nic_s *aq_nic) +{ +} + +static inline int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_ring_free(struct aq_nic_s *aq_nic) {} + +static inline int aq_ptp_ring_init(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline int aq_ptp_ring_start(struct aq_nic_s *aq_nic) +{ + return 0; +} + +static inline void aq_ptp_ring_stop(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_service_task(struct aq_nic_s *aq_nic) {} +static inline void aq_ptp_tm_offset_set(struct aq_nic_s *aq_nic, + unsigned int mbps) {} +static inline void aq_ptp_clock_init(struct aq_nic_s *aq_nic) {} +static inline int aq_ptp_xmit(struct aq_nic_s *aq_nic, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static inline void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) {} +static inline void aq_ptp_hwtstamp_config_get(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) {} +static inline int aq_ptp_hwtstamp_config_set(struct aq_ptp_s *aq_ptp, + struct hwtstamp_config *config) +{ + return 0; +} + +static inline bool aq_ptp_ring(struct aq_nic_s *aq_nic, struct aq_ring_s *ring) +{ + return false; +} + +static inline u16 aq_ptp_extract_ts(struct aq_nic_s *aq_nic, + struct sk_buff *skb, u8 *p, + unsigned int len) +{ + return 0; +} + +static inline struct ptp_clock *aq_ptp_get_ptp_clock(struct aq_ptp_s *aq_ptp) +{ + return NULL; +} + +static inline int aq_ptp_link_change(struct aq_nic_s *aq_nic) +{ + return 0; +} +#endif + #endif /* AQ_PTP_H */ -- cgit v1.2.3-59-g8ed1b From 693463e8340d55af4baed3b0721f9d8f5350a18a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 23 Oct 2019 15:06:18 +0800 Subject: ieee802154: remove set but not used variable 'status' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ieee802154/cc2520.c:221:5: warning: variable status set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Signed-off-by: YueHaibing Signed-off-by: Stefan Schmidt --- drivers/net/ieee802154/cc2520.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 0c89d3edf901..bd0ec39d3fb0 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -223,7 +223,6 @@ static int cc2520_cmd_strobe(struct cc2520_private *priv, u8 cmd) { int ret; - u8 status = 0xff; struct spi_message msg; struct spi_transfer xfer = { .len = 0, @@ -241,8 +240,6 @@ cc2520_cmd_strobe(struct cc2520_private *priv, u8 cmd) priv->buf[0]); ret = spi_sync(priv->spi, &msg); - if (!ret) - status = priv->buf[0]; dev_vdbg(&priv->spi->dev, "buf[0] = %02x\n", priv->buf[0]); mutex_unlock(&priv->buffer_mutex); -- cgit v1.2.3-59-g8ed1b From f0d532c43073c8622f63872e3b8f188fec24ab75 Mon Sep 17 00:00:00 2001 From: Michal Vokáč Date: Thu, 24 Oct 2019 15:46:58 +0200 Subject: net: dsa: qca8k: Initialize the switch with correct number of ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 0394a63acfe2 ("net: dsa: enable and disable all ports") the dsa core disables all unused ports of a switch. In this case disabling ports with numbers higher than QCA8K_NUM_PORTS causes that some switch registers are overwritten with incorrect content. To fix this, initialize the dsa_switch->num_ports with correct number of ports. Fixes: 7e99e3470172 ("net: dsa: remove dsa_switch_alloc helper") Signed-off-by: Michal Vokáč Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/qca8k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 7e742cd491e8..36c6ed98f8e7 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -1083,7 +1083,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) return -ENOMEM; priv->ds->dev = &mdiodev->dev; - priv->ds->num_ports = DSA_MAX_PORTS; + priv->ds->num_ports = QCA8K_NUM_PORTS; priv->ds->priv = priv; priv->ops = qca8k_switch_ops; priv->ds->ops = &priv->ops; -- cgit v1.2.3-59-g8ed1b From c199ce4f9dd896c716aece33e6750be34aea1151 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:22:01 +0200 Subject: net: Fix misspellings of "configure" and "configuration" Fix various misspellings of "configuration" and "configure". Signed-off-by: Geert Uytterhoeven Acked-by: Kalle Valo Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_int.h | 4 ++-- drivers/net/ethernet/qlogic/qed/qed_sriov.h | 2 +- drivers/net/ethernet/qlogic/qede/qede_filter.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_hw.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 +- drivers/net/wireless/ti/wlcore/spi.c | 2 +- include/uapi/linux/dcbnl.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') 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 633b117eb13e..7b672ada63a3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c @@ -175,7 +175,7 @@ static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer, * @port_buffer: port receive buffer configuration * @change: * - * Update buffer configuration based on pfc configuraiton and + * Update buffer configuration based on pfc configuration and * priority to buffer mapping. * Buffer's lossy bit is changed to: * lossless if there is at least one PFC enabled priority diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h index d473b522afc5..9ad568d93ae6 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.h +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h @@ -37,14 +37,14 @@ #include #include "qed.h" -/* Fields of IGU PF CONFIGRATION REGISTER */ +/* Fields of IGU PF CONFIGURATION REGISTER */ #define IGU_PF_CONF_FUNC_EN (0x1 << 0) /* function enable */ #define IGU_PF_CONF_MSI_MSIX_EN (0x1 << 1) /* MSI/MSIX enable */ #define IGU_PF_CONF_INT_LINE_EN (0x1 << 2) /* INT enable */ #define IGU_PF_CONF_ATTN_BIT_EN (0x1 << 3) /* attention enable */ #define IGU_PF_CONF_SINGLE_ISR_EN (0x1 << 4) /* single ISR mode enable */ #define IGU_PF_CONF_SIMD_MODE (0x1 << 5) /* simd all ones mode */ -/* Fields of IGU VF CONFIGRATION REGISTER */ +/* Fields of IGU VF CONFIGURATION REGISTER */ #define IGU_VF_CONF_FUNC_EN (0x1 << 0) /* function enable */ #define IGU_VF_CONF_MSI_MSIX_EN (0x1 << 1) /* MSI/MSIX enable */ #define IGU_VF_CONF_SINGLE_ISR_EN (0x1 << 4) /* single ISR mode enable */ diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.h b/drivers/net/ethernet/qlogic/qed/qed_sriov.h index 9a8fd79611f2..368e88565783 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.h +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.h @@ -305,7 +305,7 @@ void qed_iov_bulletin_set_udp_ports(struct qed_hwfn *p_hwfn, /** * @brief Read sriov related information and allocated resources - * reads from configuraiton space, shmem, etc. + * reads from configuration space, shmem, etc. * * @param p_hwfn * diff --git a/drivers/net/ethernet/qlogic/qede/qede_filter.c b/drivers/net/ethernet/qlogic/qede/qede_filter.c index 9a6a9a008714..d6cfe4ffbaf3 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_filter.c +++ b/drivers/net/ethernet/qlogic/qede/qede_filter.c @@ -1298,7 +1298,7 @@ void qede_config_rx_mode(struct net_device *ndev) rx_mode.type = QED_FILTER_TYPE_RX_MODE; /* Remove all previous unicast secondary macs and multicast macs - * (configrue / leave the primary mac) + * (configure / leave the primary mac) */ rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_REPLACE, edev->ndev->dev_addr); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 2fe12b0de5b4..42f00a2a8c80 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -1037,7 +1037,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, } /* - * Configire PCIE after Ini init. SERDES values now come from ini file + * Configure PCIE after Ini init. SERDES values now come from ini file * This enables PCIe low power mode. */ array = power_off ? &ah->iniPcieSerdes : diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 0c12df558240..05c1c77c88a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -148,7 +148,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, * * Bits 3:0: * Define the maximum number of pending read requests. - * Maximum configration value allowed is 0xC + * Maximum configuration value allowed is 0xC * Bits 9:8: * Define the maximum transfer size. (64 / 128 / 256) * Bit 10: diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index d4c09e54fd63..18c4d998ce4b 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -186,7 +186,7 @@ static void wl12xx_spi_init(struct device *child) spi_sync(to_spi_device(glue->dev), &m); - /* Restore chip select configration to normal */ + /* Restore chip select configuration to normal */ spi->mode ^= SPI_CS_HIGH; kfree(cmd); } diff --git a/include/uapi/linux/dcbnl.h b/include/uapi/linux/dcbnl.h index 69df19aa8e72..a791a94013a6 100644 --- a/include/uapi/linux/dcbnl.h +++ b/include/uapi/linux/dcbnl.h @@ -286,7 +286,7 @@ struct dcbmsg { * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported * @DCB_CMD_SNUMTCS: set the number of traffic classes * @DCB_CMD_GBCN: set backward congestion notification configuration - * @DCB_CMD_SBCN: get backward congestion notification configration. + * @DCB_CMD_SBCN: get backward congestion notification configuration. * @DCB_CMD_GAPP: get application protocol configuration * @DCB_CMD_SAPP: set application protocol configuration * @DCB_CMD_IEEE_SET: set IEEE 802.1Qaz configuration -- cgit v1.2.3-59-g8ed1b From e1b185491f739983b596804953586346e50351c9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:23:23 +0200 Subject: net: Fix various misspellings of "connect" Fix misspellings of "disconnect", "disconnecting", "connections", and "disconnected". Signed-off-by: Geert Uytterhoeven Acked-by: Kalle Valo Acked-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/usb.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c | 4 ++-- include/net/cfg80211.h | 2 +- net/netfilter/ipvs/ip_vs_ovf.c | 2 +- net/wireless/reg.h | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 6953f904232f..9659f9e1aaa6 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -511,7 +511,7 @@ error_alloc_netdev: /* - * Disconect a i2400m from the system. + * Disconnect a i2400m from the system. * * i2400m_stop() has been called before, so al the rx and tx contexts * have been taken down already. Make sure the queue is stopped, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c index 6d6e8994460d..81313e0ca834 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/hw.c @@ -1352,9 +1352,9 @@ static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw) /* SW/HW radio off or halt adapter!! For example S3/S4 */ } else { /* LED function disable. Power range is about 8mA now. */ - /* if write 0xF1 disconnet_pci power + /* if write 0xF1 disconnect_pci power * ifconfig wlan0 down power are both high 35:70 */ - /* if write oxF9 disconnet_pci power + /* if write oxF9 disconnect_pci power * ifconfig wlan0 down power are both low 12:45*/ rtl_write_byte(rtlpriv, 0x03, 0xF9); } diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4ab2c49423dc..ab6850bbba99 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6593,7 +6593,7 @@ struct cfg80211_roam_info { * time it is accessed in __cfg80211_roamed() due to delay in scheduling * rdev->event_work. In case of any failures, the reference is released * either in cfg80211_roamed() or in __cfg80211_romed(), Otherwise, it will be - * released while diconneting from the current bss. + * released while disconnecting from the current bss. */ void cfg80211_roamed(struct net_device *dev, struct cfg80211_roam_info *info, gfp_t gfp); diff --git a/net/netfilter/ipvs/ip_vs_ovf.c b/net/netfilter/ipvs/ip_vs_ovf.c index 78b074cd5464..c03066fdd5ca 100644 --- a/net/netfilter/ipvs/ip_vs_ovf.c +++ b/net/netfilter/ipvs/ip_vs_ovf.c @@ -5,7 +5,7 @@ * Authors: Raducu Deaconu * * Scheduler implements "overflow" loadbalancing according to number of active - * connections , will keep all conections to the node with the highest weight + * connections , will keep all connections to the node with the highest weight * and overflow to the next node if the number of connections exceeds the node's * weight. * Note that this scheduler might not be suitable for UDP because it only uses diff --git a/net/wireless/reg.h b/net/wireless/reg.h index dc8f689bd469..f9e83031a40a 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -114,7 +114,7 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, u8 country_ie_len); /** - * regulatory_hint_disconnect - informs all devices have been disconneted + * regulatory_hint_disconnect - informs all devices have been disconnected * * Regulotory rules can be enhanced further upon scanning and upon * connection to an AP. These rules become stale if we disconnect -- cgit v1.2.3-59-g8ed1b From 7f7183af448ac55da9cc72bdbef6d140909fee83 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Thu, 24 Oct 2019 19:24:56 +0200 Subject: mvpp2: refactor frame drop routine Move some code down to remove a backward goto. Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 5fea65256b9d..b61e0ad0978a 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2956,14 +2956,8 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, * by the hardware, and the information about the buffer is * comprised by the RX descriptor. */ - if (rx_status & MVPP2_RXD_ERR_SUMMARY) { -err_drop_frame: - dev->stats.rx_errors++; - mvpp2_rx_error(port, rx_desc); - /* Return the buffer to the pool */ - mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); - continue; - } + if (rx_status & MVPP2_RXD_ERR_SUMMARY) + goto err_drop_frame; if (bm_pool->frag_size > PAGE_SIZE) frag_size = 0; @@ -2994,6 +2988,13 @@ err_drop_frame: mvpp2_rx_csum(port, rx_status, skb); napi_gro_receive(napi, skb); + continue; + +err_drop_frame: + dev->stats.rx_errors++; + mvpp2_rx_error(port, rx_desc); + /* Return the buffer to the pool */ + mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr); } if (rcvd_pkts) { -- cgit v1.2.3-59-g8ed1b From e1921168bbd4810de4197446e52f652cd0dd9541 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Thu, 24 Oct 2019 19:24:57 +0200 Subject: mvpp2: sync only the received frame In the RX path we always sync against the maximum frame size for that pool. Do the DMA sync and the unmap separately, so we can only sync by the size of the received frame. Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index b61e0ad0978a..c66943219e1b 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2959,6 +2959,10 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, if (rx_status & MVPP2_RXD_ERR_SUMMARY) goto err_drop_frame; + dma_sync_single_for_cpu(dev->dev.parent, dma_addr, + rx_bytes + MVPP2_MH_SIZE, + DMA_FROM_DEVICE); + if (bm_pool->frag_size > PAGE_SIZE) frag_size = 0; else @@ -2976,8 +2980,9 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, goto err_drop_frame; } - dma_unmap_single(dev->dev.parent, dma_addr, - bm_pool->buf_size, DMA_FROM_DEVICE); + dma_unmap_single_attrs(dev->dev.parent, dma_addr, + bm_pool->buf_size, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); rcvd_pkts++; rcvd_bytes += rx_bytes; -- cgit v1.2.3-59-g8ed1b From a0c78337dd3a4900bc8628a511131b5a0b1db42a Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Thu, 24 Oct 2019 19:24:58 +0200 Subject: mvpp2: prefetch frame header When receiving traffic, eth_type_trans() is high up on the perf top list, because it's the first function which access the packet data. Move the DMA unmap a bit higher, and put a prefetch just after it, so we have more time to load the data into the cache. The packet rate increase is about 14% with a tc drop test: 1620 => 1853 kpps Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index c66943219e1b..17e24c1e1c2b 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -2962,6 +2962,7 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi, dma_sync_single_for_cpu(dev->dev.parent, dma_addr, rx_bytes + MVPP2_MH_SIZE, DMA_FROM_DEVICE); + prefetch(data); if (bm_pool->frag_size > PAGE_SIZE) frag_size = 0; -- cgit v1.2.3-59-g8ed1b From 5d65b64a3d97011796b225ce315b3ce0011551e7 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 24 Oct 2019 12:45:07 -0700 Subject: net: dsa: b53: Add support for MDB In preparation for supporting IGMP snooping with or without the use of a bridge, add support within b53_common.c to program the ARL entries for multicast operations. The key difference is that a multicast ARL entry is comprised of a bitmask of enabled ports, instead of a port number. Signed-off-by: Florian Fainelli Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/b53/b53_common.c | 62 ++++++++++++++++++++++++++++++++++++++-- drivers/net/dsa/b53/b53_priv.h | 8 +++++- 2 files changed, 67 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index baadf622ac55..36828f210030 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1503,11 +1503,25 @@ static int b53_arl_op(struct b53_device *dev, int op, int port, idx = 1; } - memset(&ent, 0, sizeof(ent)); - ent.port = port; + /* For multicast address, the port is a bitmask and the validity + * is determined by having at least one port being still active + */ + if (!is_multicast_ether_addr(addr)) { + ent.port = port; + ent.is_valid = is_valid; + } else { + if (is_valid) + ent.port |= BIT(port); + else + ent.port &= ~BIT(port); + + ent.is_valid = !!(ent.port); + } + ent.is_valid = is_valid; ent.vid = vid; ent.is_static = true; + ent.is_age = false; memcpy(ent.mac, addr, ETH_ALEN); b53_arl_from_entry(&mac_vid, &fwd_entry, &ent); @@ -1626,6 +1640,47 @@ int b53_fdb_dump(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_fdb_dump); +int b53_mdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct b53_device *priv = ds->priv; + + /* 5325 and 5365 require some more massaging, but could + * be supported eventually + */ + if (is5325(priv) || is5365(priv)) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL(b53_mdb_prepare); + +void b53_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct b53_device *priv = ds->priv; + int ret; + + ret = b53_arl_op(priv, 0, port, mdb->addr, mdb->vid, true); + if (ret) + dev_err(ds->dev, "failed to add MDB entry\n"); +} +EXPORT_SYMBOL(b53_mdb_add); + +int b53_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb) +{ + struct b53_device *priv = ds->priv; + int ret; + + ret = b53_arl_op(priv, 0, port, mdb->addr, mdb->vid, false); + if (ret) + dev_err(ds->dev, "failed to delete MDB entry\n"); + + return ret; +} +EXPORT_SYMBOL(b53_mdb_del); + int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br) { struct b53_device *dev = ds->priv; @@ -1994,6 +2049,9 @@ static const struct dsa_switch_ops b53_switch_ops = { .port_fdb_del = b53_fdb_del, .port_mirror_add = b53_mirror_add, .port_mirror_del = b53_mirror_del, + .port_mdb_prepare = b53_mdb_prepare, + .port_mdb_add = b53_mdb_add, + .port_mdb_del = b53_mdb_del, }; struct b53_chip_data { diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index a7dd8acc281b..1877acf05081 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -250,7 +250,7 @@ b53_build_op(write48, u64); b53_build_op(write64, u64); struct b53_arl_entry { - u8 port; + u16 port; u8 mac[ETH_ALEN]; u16 vid; u8 is_valid:1; @@ -351,6 +351,12 @@ int b53_fdb_del(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); int b53_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, void *data); +int b53_mdb_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb); +void b53_mdb_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb); +int b53_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb); int b53_mirror_add(struct dsa_switch *ds, int port, struct dsa_mall_mirror_tc_entry *mirror, bool ingress); enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port); -- cgit v1.2.3-59-g8ed1b From 29bb5e8337caf2e3d9802ee6a6804561f125bfcf Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 24 Oct 2019 12:45:08 -0700 Subject: net: dsa: bcm_sf2: Wire up MDB operations Leverage the recently add b53_mdb_{add,del,prepare} functions since they work as-is for bcm_sf2. Signed-off-by: Florian Fainelli Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index c068a3b7207b..a4a46f8df352 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -968,6 +968,9 @@ static const struct dsa_switch_ops bcm_sf2_ops = { .set_rxnfc = bcm_sf2_set_rxnfc, .port_mirror_add = b53_mirror_add, .port_mirror_del = b53_mirror_del, + .port_mdb_prepare = b53_mdb_prepare, + .port_mdb_add = b53_mdb_add, + .port_mdb_del = b53_mdb_del, }; struct bcm_sf2_of_data { -- cgit v1.2.3-59-g8ed1b From ebdcebcb8b646cbca8b5b6f01f6416394a3c77a9 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 25 Oct 2019 00:30:38 +0200 Subject: r8169: use helper rtl_hw_aspm_clkreq_enable also in rtl_hw_start_8168g_2 One place in the driver was left where the open-coded functionality hasn't been replaced with helper rtl_hw_aspm_clkreq_enable yet. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 91978ce92e20..dfd92f61e9f6 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -4710,8 +4710,7 @@ static void rtl_hw_start_8168g_2(struct rtl8169_private *tp) rtl_hw_start_8168g(tp); /* disable aspm and clock request before access ephy */ - RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~ClkReqEn); - RTL_W8(tp, Config5, RTL_R8(tp, Config5) & ~ASPM_en); + rtl_hw_aspm_clkreq_enable(tp, false); rtl_ephy_init(tp, e_info_8168g_2); } -- cgit v1.2.3-59-g8ed1b From 23e8b470c7788da972d0be90d6ac20b4a2da2782 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Fri, 25 Oct 2019 01:03:52 +0200 Subject: net: dsa: mv88e6xxx: Add devlink param for ATU hash algorithm. Some of the marvell switches have bits controlling the hash algorithm the ATU uses for MAC addresses. In some industrial settings, where all the devices are from the same manufacture, and hence use the same OUI, the default hashing algorithm is not optimal. Allow the other algorithms to be selected via devlink. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- .../networking/devlink-params-mv88e6xxx.txt | 7 ++ MAINTAINERS | 1 + drivers/net/dsa/mv88e6xxx/chip.c | 131 ++++++++++++++++++++- drivers/net/dsa/mv88e6xxx/chip.h | 4 + drivers/net/dsa/mv88e6xxx/global1.h | 3 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 32 +++++ 6 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 Documentation/networking/devlink-params-mv88e6xxx.txt (limited to 'drivers/net') diff --git a/Documentation/networking/devlink-params-mv88e6xxx.txt b/Documentation/networking/devlink-params-mv88e6xxx.txt new file mode 100644 index 000000000000..21c4b3556ef2 --- /dev/null +++ b/Documentation/networking/devlink-params-mv88e6xxx.txt @@ -0,0 +1,7 @@ +ATU_hash [DEVICE, DRIVER-SPECIFIC] + Select one of four possible hashing algorithms for + MAC addresses in the Address Translation Unit. + A value of 3 seems to work better than the default of + 1 when many MAC addresses have the same OUI. + Configuration mode: runtime + Type: u8. 0-3 valid. diff --git a/MAINTAINERS b/MAINTAINERS index 7fc074632eac..c25441edb274 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9744,6 +9744,7 @@ S: Maintained F: drivers/net/dsa/mv88e6xxx/ F: include/linux/platform_data/mv88e6xxx.h F: Documentation/devicetree/bindings/net/dsa/marvell.txt +F: Documentation/networking/devlink-params-mv88e6xxx.txt MARVELL ARMADA DRM SUPPORT M: Russell King diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 5fdf6d6ebe27..619cd081339e 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1378,6 +1378,22 @@ static int mv88e6xxx_atu_new(struct mv88e6xxx_chip *chip, u16 *fid) return mv88e6xxx_g1_atu_flush(chip, *fid, true); } +static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) +{ + if (chip->info->ops->atu_get_hash) + return chip->info->ops->atu_get_hash(chip, hash); + + return -EOPNOTSUPP; +} + +static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) +{ + if (chip->info->ops->atu_set_hash) + return chip->info->ops->atu_set_hash(chip, hash); + + return -EOPNOTSUPP; +} + static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, u16 vid_begin, u16 vid_end) { @@ -2637,6 +2653,78 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) return mv88e6xxx_software_reset(chip); } +enum mv88e6xxx_devlink_param_id { + MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, +}; + +static int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err; + + mv88e6xxx_reg_lock(chip); + + switch (id) { + case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: + err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8); + break; + default: + err = -EOPNOTSUPP; + break; + } + + mv88e6xxx_reg_unlock(chip); + + return err; +} + +static int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err; + + mv88e6xxx_reg_lock(chip); + + switch (id) { + case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH: + err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8); + break; + default: + err = -EOPNOTSUPP; + break; + } + + mv88e6xxx_reg_unlock(chip); + + return err; +} + +static const struct devlink_param mv88e6xxx_devlink_params[] = { + DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH, + "ATU_hash", DEVLINK_PARAM_TYPE_U8, + BIT(DEVLINK_PARAM_CMODE_RUNTIME)), +}; + +static int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds) +{ + return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params, + ARRAY_SIZE(mv88e6xxx_devlink_params)); +} + +static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) +{ + dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params, + ARRAY_SIZE(mv88e6xxx_devlink_params)); +} + +static void mv88e6xxx_teardown(struct dsa_switch *ds) +{ + mv88e6xxx_teardown_devlink_params(ds); +} + static int mv88e6xxx_setup(struct dsa_switch *ds) { struct mv88e6xxx_chip *chip = ds->priv; @@ -2753,7 +2841,11 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) unlock: mv88e6xxx_reg_unlock(chip); - return err; + /* Has to be called without holding the register lock, since + * it takes the devlink lock, and we later take the locks in + * the reverse order when getting/setting parameters. + */ + return mv88e6xxx_setup_devlink_params(ds); } static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) @@ -3113,6 +3205,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .phylink_validate = mv88e6185_phylink_validate, @@ -3242,6 +3336,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6165_avb_ops, @@ -3276,6 +3372,8 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6165_avb_ops, @@ -3318,6 +3416,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .phylink_validate = mv88e6185_phylink_validate, @@ -3362,6 +3462,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, @@ -3405,6 +3507,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .phylink_validate = mv88e6185_phylink_validate, @@ -3449,6 +3553,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, @@ -3534,6 +3640,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -3583,6 +3691,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -3631,6 +3741,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -3682,6 +3794,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, @@ -3773,6 +3887,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -3959,6 +4075,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .phylink_validate = mv88e6185_phylink_validate, @@ -3999,6 +4117,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu, .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .avb_ops = &mv88e6352_avb_ops, @@ -4045,6 +4165,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6352_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, @@ -4101,6 +4223,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -4154,6 +4278,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .pot_clear = mv88e6xxx_g2_pot_clear, .reset = mv88e6352_g1_reset, .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, .vtu_getnext = mv88e6390_g1_vtu_getnext, .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, @@ -4929,6 +5055,7 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .get_tag_protocol = mv88e6xxx_get_tag_protocol, .setup = mv88e6xxx_setup, + .teardown = mv88e6xxx_teardown, .phylink_validate = mv88e6xxx_validate, .phylink_mac_link_state = mv88e6xxx_link_state, .phylink_mac_config = mv88e6xxx_mac_config, @@ -4971,6 +5098,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .port_txtstamp = mv88e6xxx_port_txtstamp, .port_rxtstamp = mv88e6xxx_port_rxtstamp, .get_ts_info = mv88e6xxx_get_ts_info, + .devlink_param_get = mv88e6xxx_devlink_param_get, + .devlink_param_set = mv88e6xxx_devlink_param_set, }; static int mv88e6xxx_register_switch(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index e9b1a1ac9a8e..52f7726cc099 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -497,6 +497,10 @@ struct mv88e6xxx_ops { int (*serdes_get_stats)(struct mv88e6xxx_chip *chip, int port, uint64_t *data); + /* Address Translation Unit operations */ + int (*atu_get_hash)(struct mv88e6xxx_chip *chip, u8 *hash); + int (*atu_set_hash)(struct mv88e6xxx_chip *chip, u8 hash); + /* VLAN Translation Unit operations */ int (*vtu_getnext)(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 0870fcc8bfc8..40fc0e13fc45 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -109,6 +109,7 @@ /* Offset 0x0A: ATU Control Register */ #define MV88E6XXX_G1_ATU_CTL 0x0a #define MV88E6XXX_G1_ATU_CTL_LEARN2ALL 0x0008 +#define MV88E6161_G1_ATU_CTL_HASH_MASK 0x0003 /* Offset 0x0B: ATU Operation Register */ #define MV88E6XXX_G1_ATU_OP 0x0b @@ -318,6 +319,8 @@ int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port, bool all); int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip); void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip); +int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash); +int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash); int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip, struct mv88e6xxx_vtu_entry *entry); diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index 792a96ef418f..d8a03bbba83c 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -73,6 +73,38 @@ int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip, return 0; } +int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash) +{ + int err; + u16 val; + + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); + if (err) + return err; + + *hash = val & MV88E6161_G1_ATU_CTL_HASH_MASK; + + return 0; +} + +int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash) +{ + int err; + u16 val; + + if (hash & ~MV88E6161_G1_ATU_CTL_HASH_MASK) + return -EINVAL; + + err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val); + if (err) + return err; + + val &= ~MV88E6161_G1_ATU_CTL_HASH_MASK; + val |= hash; + + return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val); +} + /* Offset 0x0B: ATU Operation Register */ static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip) -- cgit v1.2.3-59-g8ed1b From acf5133b1d27edca6aee2a82cb2ffb2bc7c58468 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:09:48 +0800 Subject: mlxsw: spectrum_buffers: remove unneeded semicolon Remove excess semicolon after closing parenthesis. Signed-off-by: YueHaibing Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 5fd9a72c8471..33a978af80d6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -1044,12 +1044,12 @@ int mlxsw_sp_sb_pool_set(struct mlxsw_core *mlxsw_core, if (pr->freeze_mode && pr->mode != mode) { NL_SET_ERR_MSG_MOD(extack, "Changing this pool's threshold type is forbidden"); return -EINVAL; - }; + } if (pr->freeze_size && pr->size != size) { NL_SET_ERR_MSG_MOD(extack, "Changing this pool's size is forbidden"); return -EINVAL; - }; + } return mlxsw_sp_sb_pr_write(mlxsw_sp, pool_index, mode, pool_size, false); -- cgit v1.2.3-59-g8ed1b From 11b3412cef89cb5c1937ddb744e84614a7b1f564 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:13:08 +0800 Subject: net: mediatek: remove unneeded semicolon remove unneeded semicolon. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_path.c | 6 +++--- drivers/net/ethernet/mediatek/mtk_sgmii.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_path.c b/drivers/net/ethernet/mediatek/mtk_eth_path.c index ef11cf3d1ccc..0fe97155dd8f 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_path.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c @@ -57,7 +57,7 @@ static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path) default: updated = false; break; - }; + } if (updated) { val = mtk_r32(eth, MTK_MAC_MISC); @@ -143,7 +143,7 @@ static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) default: updated = false; break; - }; + } if (updated) regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, @@ -174,7 +174,7 @@ static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) break; default: updated = false; - }; + } if (updated) regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, diff --git a/drivers/net/ethernet/mediatek/mtk_sgmii.c b/drivers/net/ethernet/mediatek/mtk_sgmii.c index 4db27dfc7ec1..32d83421226a 100644 --- a/drivers/net/ethernet/mediatek/mtk_sgmii.c +++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c @@ -93,7 +93,7 @@ int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, case SPEED_1000: val |= SGMII_SPEED_1000; break; - }; + } if (state->duplex == DUPLEX_FULL) val |= SGMII_DUPLEX_FULL; -- cgit v1.2.3-59-g8ed1b From 69977901867aefbdda5f5f75af067fff08650af2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 25 Oct 2019 12:38:28 +0100 Subject: net: aquantia: fix spelling mistake: tx_queus -> tx_queues There is a spelling mistake in a netdev_err error message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index bb6fbbadfd47..1b3be0553e31 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -533,7 +533,7 @@ void aq_ptp_tx_hwtstamp(struct aq_nic_s *aq_nic, u64 timestamp) struct skb_shared_hwtstamps hwtstamp; if (!skb) { - netdev_err(aq_nic->ndev, "have timestamp but tx_queus empty\n"); + netdev_err(aq_nic->ndev, "have timestamp but tx_queues empty\n"); return; } -- cgit v1.2.3-59-g8ed1b From 92d72f1b8bbbd87220daa49cd1253ce72bb7553c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 25 Oct 2019 12:58:11 +0100 Subject: net: aquantia: fix unintention integer overflow on left shift Shifting the integer value 1 is evaluated using 32-bit arithmetic and then used in an expression that expects a 64-bit value, so there is potentially an integer overflow. Fix this by using the BIT_ULL macro to perform the shift and avoid the overflow. Addresses-Coverity: ("Unintentional integer overflow") Fixes: 04a1839950d9 ("net: aquantia: implement data PTP datapath") Signed-off-by: Colin Ian King Reviewed-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 1b3be0553e31..dca092f454b4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -713,7 +713,7 @@ static int aq_ptp_poll(struct napi_struct *napi, int budget) if (work_done < budget) { napi_complete_done(napi, work_done); aq_nic->aq_hw_ops->hw_irq_enable(aq_nic->aq_hw, - 1 << aq_ptp->ptp_ring_param.vec_idx); + BIT_ULL(aq_ptp->ptp_ring_param.vec_idx)); } err_exit: -- cgit v1.2.3-59-g8ed1b From 352b1dee744090a4686bbf27b067f6cf87a40a35 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 25 Oct 2019 18:22:55 +0100 Subject: net: fec: remove redundant assignment to pointer bdp The pointer bdp is being assigned with a value that is never read, so the assignment is redundant and hence can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Acked-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d4d4c72adf49..608196bdd892 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2706,7 +2706,6 @@ static void fec_enet_free_buffers(struct net_device *ndev) for (q = 0; q < fep->num_tx_queues; q++) { txq = fep->tx_queue[q]; - bdp = txq->bd.base; for (i = 0; i < txq->bd.ring_size; i++) { kfree(txq->tx_bounce[i]); txq->tx_bounce[i] = NULL; -- cgit v1.2.3-59-g8ed1b From 11dbb632a45a120ceb64f9f2a733992f947278c8 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Sat, 26 Oct 2019 10:07:38 +0800 Subject: net: aquantia: make two symbols be static When using ARCH=mips CROSS_COMPILE=mips-linux-gnu- to build drivers/net/ethernet/aquantia/atlantic/aq_ptp.o and drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.o, below errors can be seen: drivers/net/ethernet/aquantia/atlantic/aq_ptp.c:1378:6: warning: symbol 'aq_ptp_poll_sync_work_cb' was not declared. Should it be static? drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c:1155:5: warning: symbol 'hw_atl_b0_ts_to_sys_clock' was not declared. Should it be static? This patch to make aq_ptp_poll_sync_work_cb and hw_atl_b0_ts_to_sys_clock be static to fix these warnings. Fixes: 9c477032f7d0 ("net: aquantia: add support for PIN funcs") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 +- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index dca092f454b4..4ca36003c6ca 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -1375,7 +1375,7 @@ static int aq_ptp_check_sync1588(struct aq_ptp_s *aq_ptp) return 0; } -void aq_ptp_poll_sync_work_cb(struct work_struct *w) +static void aq_ptp_poll_sync_work_cb(struct work_struct *w) { struct delayed_work *dw = to_delayed_work(w); struct aq_ptp_s *aq_ptp = container_of(dw, struct aq_ptp_s, poll_sync); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index abee561ea54e..c7297ca03624 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1152,7 +1152,7 @@ static int hw_atl_b0_set_sys_clock(struct aq_hw_s *self, u64 time, u64 ts) return hw_atl_b0_adj_sys_clock(self, delta); } -int hw_atl_b0_ts_to_sys_clock(struct aq_hw_s *self, u64 ts, u64 *time) +static int hw_atl_b0_ts_to_sys_clock(struct aq_hw_s *self, u64 ts, u64 *time) { *time = self->ptp_clk_offset + ts; return 0; -- cgit v1.2.3-59-g8ed1b From b6989d248a2d13f02895bae1a9321b3bbccc0283 Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Sat, 26 Oct 2019 10:21:39 +0800 Subject: net: dsa: LAN9303: select REGMAP when LAN9303 enable When NET_DSA_SMSC_LAN9303=y and NET_DSA_SMSC_LAN9303_MDIO=y, below errors can be seen: drivers/net/dsa/lan9303_mdio.c:87:23: error: REGMAP_ENDIAN_LITTLE undeclared here (not in a function) .reg_format_endian = REGMAP_ENDIAN_LITTLE, drivers/net/dsa/lan9303_mdio.c:93:3: error: const struct regmap_config has no member named reg_read .reg_read = lan9303_mdio_read, It should select REGMAP in config NET_DSA_SMSC_LAN9303. Fixes: dc7005831523 ("net: dsa: LAN9303: add MDIO managed mode support") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index f6232ce8481f..685e12b05a7c 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -77,6 +77,7 @@ config NET_DSA_REALTEK_SMI config NET_DSA_SMSC_LAN9303 tristate select NET_DSA_TAG_LAN9303 + select REGMAP ---help--- This enables support for the SMSC/Microchip LAN9303 3 port ethernet switch chips. -- cgit v1.2.3-59-g8ed1b From 207136dfeb3b2cde873b48d745100fa688c83f06 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 26 Oct 2019 02:51:09 +0000 Subject: net: aquantia: remove unused including Remove including that don't need it. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h index bf503a40b6a4..231906431a48 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.h @@ -9,7 +9,6 @@ #define AQ_PTP_H #include -#include #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK) -- cgit v1.2.3-59-g8ed1b From 76d7774e203d422edb6b8c6db800478ca029fde5 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 28 Oct 2019 02:04:47 -0500 Subject: net: aquantia: fix error handling in aq_ptp_poll Fix currenty ignored returned error by properly checking *err* after calling aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(). Addresses-Coverity-ID: 1487357 ("Unused value") Fixes: 04a1839950d9 ("net: aquantia: implement data PTP datapath") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 4ca36003c6ca..8175513e48c9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -678,6 +678,8 @@ static int aq_ptp_poll(struct napi_struct *napi, int budget) err = aq_nic->aq_hw_ops->hw_ring_hwts_rx_fill(aq_nic->aq_hw, &aq_ptp->hwts_rx); + if (err < 0) + goto err_exit; was_cleaned = true; } -- cgit v1.2.3-59-g8ed1b From caabee5b53f5eaa086170e4594f603965bd7d88c Mon Sep 17 00:00:00 2001 From: Thomas Haemmerle Date: Mon, 28 Oct 2019 08:08:14 +0000 Subject: net: phy: dp83867: support Wake on LAN This adds WoL support on TI DP83867 for magic, magic secure, unicast and broadcast. Signed-off-by: Thomas Haemmerle Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 131 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 5816a06a9439..0b95e7a2e273 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include @@ -21,8 +23,9 @@ #define MII_DP83867_PHYCTRL 0x10 #define MII_DP83867_MICR 0x12 #define MII_DP83867_ISR 0x13 -#define DP83867_CTRL 0x1f +#define DP83867_CFG2 0x14 #define DP83867_CFG3 0x1e +#define DP83867_CTRL 0x1f /* Extended Registers */ #define DP83867_CFG4 0x0031 @@ -36,6 +39,13 @@ #define DP83867_STRAP_STS1 0x006E #define DP83867_STRAP_STS2 0x006f #define DP83867_RGMIIDCTL 0x0086 +#define DP83867_RXFCFG 0x0134 +#define DP83867_RXFPMD1 0x0136 +#define DP83867_RXFPMD2 0x0137 +#define DP83867_RXFPMD3 0x0138 +#define DP83867_RXFSOP1 0x0139 +#define DP83867_RXFSOP2 0x013A +#define DP83867_RXFSOP3 0x013B #define DP83867_IO_MUX_CFG 0x0170 #define DP83867_SGMIICTL 0x00D3 #define DP83867_10M_SGMII_CFG 0x016F @@ -65,6 +75,13 @@ /* SGMIICTL bits */ #define DP83867_SGMII_TYPE BIT(14) +/* RXFCFG bits*/ +#define DP83867_WOL_MAGIC_EN BIT(0) +#define DP83867_WOL_BCAST_EN BIT(2) +#define DP83867_WOL_UCAST_EN BIT(4) +#define DP83867_WOL_SEC_EN BIT(5) +#define DP83867_WOL_ENH_MAC BIT(7) + /* STRAP_STS1 bits */ #define DP83867_STRAP_STS1_RESERVED BIT(11) @@ -130,6 +147,115 @@ static int dp83867_ack_interrupt(struct phy_device *phydev) return 0; } +static int dp83867_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct net_device *ndev = phydev->attached_dev; + u16 val_rxcfg, val_micr; + u8 *mac; + + val_rxcfg = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); + val_micr = phy_read(phydev, MII_DP83867_MICR); + + if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE | WAKE_UCAST | + WAKE_BCAST)) { + val_rxcfg |= DP83867_WOL_ENH_MAC; + val_micr |= MII_DP83867_MICR_WOL_INT_EN; + + if (wol->wolopts & WAKE_MAGIC) { + mac = (u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD1, + (mac[1] << 8 | mac[0])); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD2, + (mac[3] << 8 | mac[2])); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFPMD3, + (mac[5] << 8 | mac[4])); + + val_rxcfg |= DP83867_WOL_MAGIC_EN; + } else { + val_rxcfg &= ~DP83867_WOL_MAGIC_EN; + } + + if (wol->wolopts & WAKE_MAGICSECURE) { + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, + (wol->sopass[1] << 8) | wol->sopass[0]); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, + (wol->sopass[3] << 8) | wol->sopass[2]); + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFSOP1, + (wol->sopass[5] << 8) | wol->sopass[4]); + + val_rxcfg |= DP83867_WOL_SEC_EN; + } else { + val_rxcfg &= ~DP83867_WOL_SEC_EN; + } + + if (wol->wolopts & WAKE_UCAST) + val_rxcfg |= DP83867_WOL_UCAST_EN; + else + val_rxcfg &= ~DP83867_WOL_UCAST_EN; + + if (wol->wolopts & WAKE_BCAST) + val_rxcfg |= DP83867_WOL_BCAST_EN; + else + val_rxcfg &= ~DP83867_WOL_BCAST_EN; + } else { + val_rxcfg &= ~DP83867_WOL_ENH_MAC; + val_micr &= ~MII_DP83867_MICR_WOL_INT_EN; + } + + phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG, val_rxcfg); + phy_write(phydev, MII_DP83867_MICR, val_micr); + + return 0; +} + +static void dp83867_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + u16 value, sopass_val; + + wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC | + WAKE_MAGICSECURE); + wol->wolopts = 0; + + value = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RXFCFG); + + if (value & DP83867_WOL_UCAST_EN) + wol->wolopts |= WAKE_UCAST; + + if (value & DP83867_WOL_BCAST_EN) + wol->wolopts |= WAKE_BCAST; + + if (value & DP83867_WOL_MAGIC_EN) + wol->wolopts |= WAKE_MAGIC; + + if (value & DP83867_WOL_SEC_EN) { + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RXFSOP1); + wol->sopass[0] = (sopass_val & 0xff); + wol->sopass[1] = (sopass_val >> 8); + + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RXFSOP2); + wol->sopass[2] = (sopass_val & 0xff); + wol->sopass[3] = (sopass_val >> 8); + + sopass_val = phy_read_mmd(phydev, DP83867_DEVADDR, + DP83867_RXFSOP3); + wol->sopass[4] = (sopass_val & 0xff); + wol->sopass[5] = (sopass_val >> 8); + + wol->wolopts |= WAKE_MAGICSECURE; + } + + if (!(value & DP83867_WOL_ENH_MAC)) + wol->wolopts = 0; +} + static int dp83867_config_intr(struct phy_device *phydev) { int micr_status; @@ -464,6 +590,9 @@ static struct phy_driver dp83867_driver[] = { .config_init = dp83867_config_init, .soft_reset = dp83867_phy_reset, + .get_wol = dp83867_get_wol, + .set_wol = dp83867_set_wol, + /* IRQ related */ .ack_interrupt = dp83867_ack_interrupt, .config_intr = dp83867_config_intr, -- cgit v1.2.3-59-g8ed1b From 199f3ac319554f1ffddcc8e832448843f073d4c7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 28 Oct 2019 12:01:21 +0000 Subject: ionic: Remove set but not used variable 'sg_desc' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/ethernet/pensando/ionic/ionic_txrx.c: In function 'ionic_rx_empty': drivers/net/ethernet/pensando/ionic/ionic_txrx.c:405:28: warning: variable 'sg_desc' set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Signed-off-by: YueHaibing Acked-by: Shannon Nelson Signed-off-by: David S. Miller --- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 0aeac3157160..97e79949b359 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -402,7 +402,6 @@ static void ionic_rx_fill_cb(void *arg) void ionic_rx_empty(struct ionic_queue *q) { - struct ionic_rxq_sg_desc *sg_desc; struct ionic_desc_info *cur; struct ionic_rxq_desc *desc; unsigned int i; @@ -412,7 +411,6 @@ void ionic_rx_empty(struct ionic_queue *q) desc->addr = 0; desc->len = 0; - sg_desc = cur->sg_desc; for (i = 0; i < cur->npages; i++) { if (likely(cur->pages[i].page)) { ionic_rx_page_free(q, cur->pages[i].page, -- cgit v1.2.3-59-g8ed1b From f8d975be71143f00fea7a9ac0f57660e6a133dad Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 28 Oct 2019 20:52:22 +0100 Subject: net: phy: marvell: fix typo in constant MII_M1011_PHY_SRC_DOWNSHIFT_MASK Fix typo and use PHY_SCR for PHY-specific Control Register. Fixes: a3bdfce7bf9c ("net: phy: marvell: support downshift as PHY tunable") Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 0a814fde136a..e77fc25babe4 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -53,7 +53,7 @@ #define MII_M1011_PHY_SCR 0x10 #define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11) -#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12) +#define MII_M1011_PHY_SCR_DOWNSHIFT_MASK GENMASK(14, 12) #define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8 #define MII_M1011_PHY_SCR_MDI (0x0 << 5) #define MII_M1011_PHY_SCR_MDI_X (0x1 << 5) @@ -793,7 +793,7 @@ static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) return val; enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val); - cnt = FIELD_GET(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, val) + 1; + cnt = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val) + 1; *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; @@ -812,11 +812,11 @@ static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) MII_M1011_PHY_SCR_DOWNSHIFT_EN); val = MII_M1011_PHY_SCR_DOWNSHIFT_EN; - val |= FIELD_PREP(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, cnt - 1); + val |= FIELD_PREP(MII_M1011_PHY_SCR_DOWNSHIFT_MASK, cnt - 1); return phy_modify(phydev, MII_M1011_PHY_SCR, MII_M1011_PHY_SCR_DOWNSHIFT_EN | - MII_M1011_PHY_SRC_DOWNSHIFT_MASK, + MII_M1011_PHY_SCR_DOWNSHIFT_MASK, val); } -- cgit v1.2.3-59-g8ed1b From 911af5e149bb1116a2aebb5e7ae5f380caa2d7a1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 28 Oct 2019 20:52:55 +0100 Subject: net: phy: marvell: fix downshift function naming I got access to the M88E1111 datasheet, and this PHY version uses another register for downshift configuration. Therefore change prefix to m88e1011, aligned with constants like MII_M1011_PHY_SCR. Fixes: a3bdfce7bf9c ("net: phy: marvell: support downshift as PHY tunable") Reported-by: Chris Healy Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e77fc25babe4..68ef84c234a4 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -784,7 +784,7 @@ static int m88e1111_config_init(struct phy_device *phydev) return genphy_soft_reset(phydev); } -static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) +static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) { int val, cnt, enable; @@ -800,7 +800,7 @@ static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) return 0; } -static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) +static int m88e1011_set_downshift(struct phy_device *phydev, u8 cnt) { int val; @@ -820,29 +820,29 @@ static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) val); } -static int m88e1111_get_tunable(struct phy_device *phydev, +static int m88e1011_get_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, void *data) { switch (tuna->id) { case ETHTOOL_PHY_DOWNSHIFT: - return m88e1111_get_downshift(phydev, data); + return m88e1011_get_downshift(phydev, data); default: return -EOPNOTSUPP; } } -static int m88e1111_set_tunable(struct phy_device *phydev, +static int m88e1011_set_tunable(struct phy_device *phydev, struct ethtool_tunable *tuna, const void *data) { switch (tuna->id) { case ETHTOOL_PHY_DOWNSHIFT: - return m88e1111_set_downshift(phydev, *(const u8 *)data); + return m88e1011_set_downshift(phydev, *(const u8 *)data); default: return -EOPNOTSUPP; } } -static void m88e1111_link_change_notify(struct phy_device *phydev) +static void m88e1011_link_change_notify(struct phy_device *phydev) { int status; @@ -875,7 +875,7 @@ static int m88e1116r_config_init(struct phy_device *phydev) if (err < 0) return err; - err = m88e1111_set_downshift(phydev, 8); + err = m88e1011_set_downshift(phydev, 8); if (err < 0) return err; @@ -1177,7 +1177,7 @@ static int m88e1540_get_tunable(struct phy_device *phydev, case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_get_fld(phydev, data); case ETHTOOL_PHY_DOWNSHIFT: - return m88e1111_get_downshift(phydev, data); + return m88e1011_get_downshift(phydev, data); default: return -EOPNOTSUPP; } @@ -1190,7 +1190,7 @@ static int m88e1540_set_tunable(struct phy_device *phydev, case ETHTOOL_PHY_FAST_LINK_DOWN: return m88e1540_set_fld(phydev, data); case ETHTOOL_PHY_DOWNSHIFT: - return m88e1111_set_downshift(phydev, *(const u8 *)data); + return m88e1011_set_downshift(phydev, *(const u8 *)data); default: return -EOPNOTSUPP; } @@ -2283,9 +2283,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, - .get_tunable = m88e1111_get_tunable, - .set_tunable = m88e1111_set_tunable, - .link_change_notify = m88e1111_link_change_notify, + .get_tunable = m88e1011_get_tunable, + .set_tunable = m88e1011_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1318S, @@ -2425,7 +2425,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, - .link_change_notify = m88e1111_link_change_notify, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1545, @@ -2488,7 +2488,7 @@ static struct phy_driver marvell_drivers[] = { .get_stats = marvell_get_stats, .get_tunable = m88e1540_get_tunable, .set_tunable = m88e1540_set_tunable, - .link_change_notify = m88e1111_link_change_notify, + .link_change_notify = m88e1011_link_change_notify, }, }; -- cgit v1.2.3-59-g8ed1b From 5c6bc5199b5d142783b9f8ea662b54431b8e5509 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 28 Oct 2019 20:53:25 +0100 Subject: net: phy: marvell: add downshift support for M88E1111 This patch adds downshift support for M88E1111. This PHY version uses another register for downshift configuration, reading downshift status is possible via the same register as for other PHY versions. Signed-off-by: Heiner Kallweit Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 68ef84c234a4..aa4864c67f0c 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -66,6 +66,9 @@ #define MII_M1111_PHY_LED_DIRECT 0x4100 #define MII_M1111_PHY_LED_COMBINE 0x411c #define MII_M1111_PHY_EXT_CR 0x14 +#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK GENMASK(11, 9) +#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX 8 +#define MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN BIT(8) #define MII_M1111_RGMII_RX_DELAY BIT(7) #define MII_M1111_RGMII_TX_DELAY BIT(1) #define MII_M1111_PHY_EXT_SR 0x1b @@ -784,6 +787,64 @@ static int m88e1111_config_init(struct phy_device *phydev) return genphy_soft_reset(phydev); } +static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data) +{ + int val, cnt, enable; + + val = phy_read(phydev, MII_M1111_PHY_EXT_CR); + if (val < 0) + return val; + + enable = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN, val); + cnt = FIELD_GET(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, val) + 1; + + *data = enable ? cnt : DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt) +{ + int val; + + if (cnt > MII_M1111_PHY_EXT_CR_DOWNSHIFT_MAX) + return -E2BIG; + + if (!cnt) + return phy_clear_bits(phydev, MII_M1111_PHY_EXT_CR, + MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN); + + val = MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN; + val |= FIELD_PREP(MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, cnt - 1); + + return phy_modify(phydev, MII_M1111_PHY_EXT_CR, + MII_M1111_PHY_EXT_CR_DOWNSHIFT_EN | + MII_M1111_PHY_EXT_CR_DOWNSHIFT_MASK, + val); +} + +static int m88e1111_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} + +static int m88e1111_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return m88e1111_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} + static int m88e1011_get_downshift(struct phy_device *phydev, u8 *data) { int val, cnt, enable; @@ -2245,6 +2306,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1111_get_tunable, + .set_tunable = m88e1111_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1118, -- cgit v1.2.3-59-g8ed1b From 262caf47449d3ea6bf744397259fc61be3370077 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 28 Oct 2019 20:54:17 +0100 Subject: net: phy: marvell: add PHY tunable support for more PHY versions More PHY versions are compatible with the existing downshift implementation, so let's add downshift support for them. Signed-off-by: Heiner Kallweit Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index aa4864c67f0c..cb6570ac618a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -2287,6 +2287,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1011_get_tunable, + .set_tunable = m88e1011_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1111, @@ -2444,6 +2447,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1011_get_tunable, + .set_tunable = m88e1011_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1510, @@ -2467,6 +2473,9 @@ static struct phy_driver marvell_drivers[] = { .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, .set_loopback = genphy_loopback, + .get_tunable = m88e1011_get_tunable, + .set_tunable = m88e1011_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1540, @@ -2510,6 +2519,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1540_get_tunable, + .set_tunable = m88e1540_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E3016, -- cgit v1.2.3-59-g8ed1b From cb5ff33fbfee3438e4944550d55f1d83d2e365f6 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 01:39:50 +0530 Subject: cavium: thunder: Fix use true/false for bool type use true/false on bool type variables for assignment. Signed-off-by: Saurav Girepunje Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index acb016834f04..1e09fdb63c4f 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -1007,14 +1007,14 @@ static void bgx_poll_for_link(struct work_struct *work) if ((spu_link & SPU_STATUS1_RCV_LNK) && !(smu_link & SMU_RX_CTL_STATUS)) { - lmac->link_up = 1; + lmac->link_up = true; if (lmac->lmac_type == BGX_MODE_XLAUI) lmac->last_speed = SPEED_40000; else lmac->last_speed = SPEED_10000; lmac->last_duplex = DUPLEX_FULL; } else { - lmac->link_up = 0; + lmac->link_up = false; lmac->last_speed = SPEED_UNKNOWN; lmac->last_duplex = DUPLEX_UNKNOWN; } @@ -1023,7 +1023,7 @@ static void bgx_poll_for_link(struct work_struct *work) if (lmac->link_up) { if (bgx_xaui_check_link(lmac)) { /* Errors, clear link_up state */ - lmac->link_up = 0; + lmac->link_up = false; lmac->last_speed = SPEED_UNKNOWN; lmac->last_duplex = DUPLEX_UNKNOWN; } @@ -1055,11 +1055,11 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) if ((lmac->lmac_type == BGX_MODE_SGMII) || (lmac->lmac_type == BGX_MODE_QSGMII) || (lmac->lmac_type == BGX_MODE_RGMII)) { - lmac->is_sgmii = 1; + lmac->is_sgmii = true; if (bgx_lmac_sgmii_init(bgx, lmac)) return -1; } else { - lmac->is_sgmii = 0; + lmac->is_sgmii = false; if (bgx_lmac_xaui_init(bgx, lmac)) return -1; } @@ -1304,7 +1304,7 @@ static void lmac_set_training(struct bgx *bgx, struct lmac *lmac, int lmacid) { if ((lmac->lmac_type != BGX_MODE_10G_KR) && (lmac->lmac_type != BGX_MODE_40G_KR)) { - lmac->use_training = 0; + lmac->use_training = false; return; } -- cgit v1.2.3-59-g8ed1b From acda6180e86ba9e0026287d65f30d1e2b0c8882a Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 01:46:35 +0530 Subject: broadcom: bnxt: Fix use true/false for bool Use true/false for bool type in bnxt_timer function. Signed-off-by: Saurav Girepunje Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b4a8cf620a0c..8cdf71f8824d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10004,7 +10004,7 @@ static void bnxt_timer(struct timer_list *t) if (bp->link_info.phy_retry) { if (time_after(jiffies, bp->link_info.phy_retry_expires)) { - bp->link_info.phy_retry = 0; + bp->link_info.phy_retry = false; netdev_warn(bp->dev, "failed to update phy settings after maximum retries.\n"); } else { set_bit(BNXT_UPDATE_PHY_SP_EVENT, &bp->sp_event); -- cgit v1.2.3-59-g8ed1b From 914ee9c436cbe90c8ca8a46ec8433cb614a2ada5 Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Thu, 10 Oct 2019 13:15:39 +0300 Subject: e1000e: Add support for Comet Lake Add devices ID's for the next LOM generations that will be available on the next Intel Client platform (Comet Lake) This patch provides the initial support for these devices Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/hw.h | 6 ++++++ drivers/net/ethernet/intel/e1000e/netdev.c | 6 ++++++ 2 files changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index eff75bd8a8f0..11fdc27faa82 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -86,6 +86,12 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_ICP_I219_V8 0x15E0 #define E1000_DEV_ID_PCH_ICP_I219_LM9 0x15E1 #define E1000_DEV_ID_PCH_ICP_I219_V9 0x15E2 +#define E1000_DEV_ID_PCH_CMP_I219_LM10 0x0D4E +#define E1000_DEV_ID_PCH_CMP_I219_V10 0x0D4F +#define E1000_DEV_ID_PCH_CMP_I219_LM11 0x0D4C +#define E1000_DEV_ID_PCH_CMP_I219_V11 0x0D4D +#define E1000_DEV_ID_PCH_CMP_I219_LM12 0x0D53 +#define E1000_DEV_ID_PCH_CMP_I219_V12 0x0D55 #define E1000_REVISION_4 4 diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 42f57ab8fb8e..731e1b3e103a 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7749,6 +7749,12 @@ static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V8), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_LM9), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ICP_I219_V9), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM10), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V10), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM11), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V11), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM12), board_pch_spt }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V12), board_pch_spt }, { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; -- cgit v1.2.3-59-g8ed1b From a7023819404ac9bd2bb311a4fafd38515cfa71ec Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 11 Oct 2019 08:34:52 -0700 Subject: e1000e: Use rtnl_lock to prevent race conditions between net and pci/pm This patch is meant to address possible race conditions that can exist between network configuration and power management. A similar issue was fixed for igb in commit 9474933caf21 ("igb: close/suspend race in netif_device_detach"). In addition it consolidates the code so that the PCI error handling code will essentially perform the power management freeze on the device prior to attempting a reset, and will thaw the device afterwards if that is what it is planning to do. Otherwise when we call close on the interface it should see it is detached and not attempt to call the logic to down the interface and free the IRQs again. From what I can tell the check that was adding the check for __E1000_DOWN in e1000e_close was added when runtime power management was added. However it should not be relevant for us as we perform a call to pm_runtime_get_sync before we call e1000_down/free_irq so it should always be back up before we call into this anyway. Reported-by: Morumuri Srivalli Signed-off-by: Alexander Duyck Tested-by: David Dai Tested-by: Aaron Brown --- drivers/net/ethernet/intel/e1000e/netdev.c | 68 +++++++++++++++--------------- 1 file changed, 35 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 731e1b3e103a..b6b1cdf98096 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4715,12 +4715,12 @@ int e1000e_close(struct net_device *netdev) pm_runtime_get_sync(&pdev->dev); - if (!test_bit(__E1000_DOWN, &adapter->state)) { + if (netif_device_present(netdev)) { e1000e_down(adapter, true); e1000_free_irq(adapter); /* Link status message must follow this format */ - pr_info("%s NIC Link is Down\n", adapter->netdev->name); + pr_info("%s NIC Link is Down\n", netdev->name); } napi_disable(&adapter->napi); @@ -6466,10 +6466,14 @@ static int e1000e_pm_freeze(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); struct e1000_adapter *adapter = netdev_priv(netdev); + bool present; + rtnl_lock(); + + present = netif_device_present(netdev); netif_device_detach(netdev); - if (netif_running(netdev)) { + if (present && netif_running(netdev)) { int count = E1000_CHECK_RESET_COUNT; while (test_bit(__E1000_RESETTING, &adapter->state) && count--) @@ -6481,6 +6485,8 @@ static int e1000e_pm_freeze(struct device *dev) e1000e_down(adapter, false); e1000_free_irq(adapter); } + rtnl_unlock(); + e1000e_reset_interrupt_capability(adapter); /* Allow time for pending master requests to run */ @@ -6728,6 +6734,30 @@ static void e1000e_disable_aspm_locked(struct pci_dev *pdev, u16 state) __e1000e_disable_aspm(pdev, state, 1); } +static int e1000e_pm_thaw(struct device *dev) +{ + struct net_device *netdev = dev_get_drvdata(dev); + struct e1000_adapter *adapter = netdev_priv(netdev); + int rc = 0; + + e1000e_set_interrupt_capability(adapter); + + rtnl_lock(); + if (netif_running(netdev)) { + rc = e1000_request_irq(adapter); + if (rc) + goto err_irq; + + e1000e_up(adapter); + } + + netif_device_attach(netdev); +err_irq: + rtnl_unlock(); + + return rc; +} + #ifdef CONFIG_PM static int __e1000_resume(struct pci_dev *pdev) { @@ -6795,26 +6825,6 @@ static int __e1000_resume(struct pci_dev *pdev) } #ifdef CONFIG_PM_SLEEP -static int e1000e_pm_thaw(struct device *dev) -{ - struct net_device *netdev = dev_get_drvdata(dev); - struct e1000_adapter *adapter = netdev_priv(netdev); - - e1000e_set_interrupt_capability(adapter); - if (netif_running(netdev)) { - u32 err = e1000_request_irq(adapter); - - if (err) - return err; - - e1000e_up(adapter); - } - - netif_device_attach(netdev); - - return 0; -} - static int e1000e_pm_suspend(struct device *dev) { struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); @@ -7000,16 +7010,11 @@ static void e1000_netpoll(struct net_device *netdev) static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { - struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev_priv(netdev); - - netif_device_detach(netdev); + e1000e_pm_freeze(&pdev->dev); if (state == pci_channel_io_perm_failure) return PCI_ERS_RESULT_DISCONNECT; - if (netif_running(netdev)) - e1000e_down(adapter, true); pci_disable_device(pdev); /* Request a slot slot reset. */ @@ -7075,10 +7080,7 @@ static void e1000_io_resume(struct pci_dev *pdev) e1000_init_manageability_pt(adapter); - if (netif_running(netdev)) - e1000e_up(adapter); - - netif_device_attach(netdev); + e1000e_pm_thaw(&pdev->dev); /* If the controller has AMT, do not set DRV_LOAD until the interface * is up. For all other cases, let the f/w know that the h/w is now -- cgit v1.2.3-59-g8ed1b From daee5598e491d8d3979bd4ad6c447d89ce57b446 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 11 Oct 2019 08:34:59 -0700 Subject: e1000e: Drop unnecessary __E1000_DOWN bit twiddling Since we no longer check for __E1000_DOWN in e1000e_close we can drop the spot where we were restoring the bit. This saves us a bit of unnecessary complexity. Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index b6b1cdf98096..4aafa05287a4 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7591,15 +7591,13 @@ static void e1000_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - bool down = test_bit(__E1000_DOWN, &adapter->state); e1000e_ptp_remove(adapter); /* The timers may be rescheduled, so explicitly disable them * from being rescheduled. */ - if (!down) - set_bit(__E1000_DOWN, &adapter->state); + set_bit(__E1000_DOWN, &adapter->state); del_timer_sync(&adapter->phy_info_timer); cancel_work_sync(&adapter->reset_task); @@ -7619,9 +7617,6 @@ static void e1000_remove(struct pci_dev *pdev) } } - /* Don't lie to e1000_close() down the road. */ - if (!down) - clear_bit(__E1000_DOWN, &adapter->state); unregister_netdev(netdev); if (pci_dev_run_wake(pdev)) -- cgit v1.2.3-59-g8ed1b From 4085d06d2f225dc9b4827566f43b919e69f08bcb Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 11 Oct 2019 12:53:38 -0400 Subject: igb: Add UDP segmentation offload support Based on a series from Alexander Duyck this change adds UDP segmentation offload support to the igb driver. CC: Alexander Duyck CC: Willem de Bruijn Signed-off-by: Josh Hunt Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.h | 1 + drivers/net/ethernet/intel/igb/igb_main.c | 23 +++++++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index 6ad775b1a4c5..63ec253ac788 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -127,6 +127,7 @@ struct e1000_adv_tx_context_desc { }; #define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ #define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ #define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ #define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 packet TYPE of SCTP */ diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 105b0624081a..b65e8a063aef 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -2516,6 +2516,7 @@ igb_features_check(struct sk_buff *skb, struct net_device *dev, if (unlikely(mac_hdr_len > IGB_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_GSO_UDP_L4 | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_TSO | NETIF_F_TSO6); @@ -2524,6 +2525,7 @@ igb_features_check(struct sk_buff *skb, struct net_device *dev, if (unlikely(network_hdr_len > IGB_MAX_NETWORK_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_GSO_UDP_L4 | NETIF_F_TSO | NETIF_F_TSO6); @@ -3120,7 +3122,7 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) NETIF_F_HW_CSUM; if (hw->mac.type >= e1000_82576) - netdev->features |= NETIF_F_SCTP_CRC; + netdev->features |= NETIF_F_SCTP_CRC | NETIF_F_GSO_UDP_L4; if (hw->mac.type >= e1000_i350) netdev->features |= NETIF_F_HW_TC; @@ -5694,6 +5696,7 @@ static int igb_tso(struct igb_ring *tx_ring, } ip; union { struct tcphdr *tcp; + struct udphdr *udp; unsigned char *hdr; } l4; u32 paylen, l4_offset; @@ -5713,7 +5716,8 @@ static int igb_tso(struct igb_ring *tx_ring, l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ - type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP; + type_tucmd = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ? + E1000_ADVTXD_TUCMD_L4T_UDP : E1000_ADVTXD_TUCMD_L4T_TCP; /* initialize outer IP header fields */ if (ip.v4->version == 4) { @@ -5741,12 +5745,19 @@ static int igb_tso(struct igb_ring *tx_ring, /* determine offset of inner transport header */ l4_offset = l4.hdr - skb->data; - /* compute length of segmentation header */ - *hdr_len = (l4.tcp->doff * 4) + l4_offset; - /* remove payload length from inner checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.tcp->check, htonl(paylen)); + if (type_tucmd & E1000_ADVTXD_TUCMD_L4T_TCP) { + /* compute length of segmentation header */ + *hdr_len = (l4.tcp->doff * 4) + l4_offset; + csum_replace_by_diff(&l4.tcp->check, + (__force __wsum)htonl(paylen)); + } else { + /* compute length of segmentation header */ + *hdr_len = sizeof(*l4.udp) + l4_offset; + csum_replace_by_diff(&l4.udp->check, + (__force __wsum)htonl(paylen)); + } /* update gso size and bytecount with header size */ first->gso_segs = skb_shinfo(skb)->gso_segs; -- cgit v1.2.3-59-g8ed1b From c74d4bdbae4f00575362c2ba147ffcb31e724f04 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 11 Oct 2019 12:53:39 -0400 Subject: ixgbe: Add UDP segmentation offload support Repost from a series by Alexander Duyck to add UDP segmentation offload support to the igb driver: https://lore.kernel.org/netdev/20180504003916.4769.66271.stgit@localhost.localdomain/ CC: Alexander Duyck CC: Willem de Bruijn Suggested-by: Alexander Duyck Signed-off-by: Josh Hunt Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 1ce2397306b9..6c9edd272c7a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7946,6 +7946,7 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring, } ip; union { struct tcphdr *tcp; + struct udphdr *udp; unsigned char *hdr; } l4; u32 paylen, l4_offset; @@ -7969,7 +7970,8 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring, l4.hdr = skb_checksum_start(skb); /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ - type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP; + type_tucmd = (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) ? + IXGBE_ADVTXD_TUCMD_L4T_UDP : IXGBE_ADVTXD_TUCMD_L4T_TCP; /* initialize outer IP header fields */ if (ip.v4->version == 4) { @@ -7999,12 +8001,20 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring, /* determine offset of inner transport header */ l4_offset = l4.hdr - skb->data; - /* compute length of segmentation header */ - *hdr_len = (l4.tcp->doff * 4) + l4_offset; - /* remove payload length from inner checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); + + if (type_tucmd & IXGBE_ADVTXD_TUCMD_L4T_TCP) { + /* compute length of segmentation header */ + *hdr_len = (l4.tcp->doff * 4) + l4_offset; + csum_replace_by_diff(&l4.tcp->check, + (__force __wsum)htonl(paylen)); + } else { + /* compute length of segmentation header */ + *hdr_len = sizeof(*l4.udp) + l4_offset; + csum_replace_by_diff(&l4.udp->check, + (__force __wsum)htonl(paylen)); + } /* update gso size and bytecount with header size */ first->gso_segs = skb_shinfo(skb)->gso_segs; @@ -10190,6 +10200,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev, if (unlikely(mac_hdr_len > IXGBE_MAX_MAC_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_GSO_UDP_L4 | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_TSO | NETIF_F_TSO6); @@ -10198,6 +10209,7 @@ ixgbe_features_check(struct sk_buff *skb, struct net_device *dev, if (unlikely(network_hdr_len > IXGBE_MAX_NETWORK_HDR_LEN)) return features & ~(NETIF_F_HW_CSUM | NETIF_F_SCTP_CRC | + NETIF_F_GSO_UDP_L4 | NETIF_F_TSO | NETIF_F_TSO6); @@ -10907,7 +10919,7 @@ skip_sriov: IXGBE_GSO_PARTIAL_FEATURES; if (hw->mac.type >= ixgbe_mac_82599EB) - netdev->features |= NETIF_F_SCTP_CRC; + netdev->features |= NETIF_F_SCTP_CRC | NETIF_F_GSO_UDP_L4; #ifdef CONFIG_IXGBE_IPSEC #define IXGBE_ESP_FEATURES (NETIF_F_HW_ESP | \ -- cgit v1.2.3-59-g8ed1b From 3fd8ed5639589846baec0dc0ab312cdf709094f0 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 11 Oct 2019 12:53:40 -0400 Subject: i40e: Add UDP segmentation offload support Based on a series from Alexander Duyck this change adds UDP segmentation offload support to the i40e driver. CC: Alexander Duyck CC: Willem de Bruijn Signed-off-by: Josh Hunt Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 141575ada588..b3d7edbb1389 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -12931,6 +12931,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) NETIF_F_GSO_IPXIP6 | NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM | + NETIF_F_GSO_UDP_L4 | NETIF_F_SCTP_CRC | NETIF_F_RXHASH | NETIF_F_RXCSUM | diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index e3f29dc8b290..b8496037ef7f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2960,10 +2960,16 @@ static int i40e_tso(struct i40e_tx_buffer *first, u8 *hdr_len, /* remove payload length from inner checksum */ paylen = skb->len - l4_offset; - csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); - /* compute length of segmentation header */ - *hdr_len = (l4.tcp->doff * 4) + l4_offset; + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { + csum_replace_by_diff(&l4.udp->check, (__force __wsum)htonl(paylen)); + /* compute length of segmentation header */ + *hdr_len = sizeof(*l4.udp) + l4_offset; + } else { + csum_replace_by_diff(&l4.tcp->check, (__force __wsum)htonl(paylen)); + /* compute length of segmentation header */ + *hdr_len = (l4.tcp->doff * 4) + l4_offset; + } /* pull values out of skb_shinfo */ gso_size = skb_shinfo(skb)->gso_size; -- cgit v1.2.3-59-g8ed1b From fb776f5d57ee0f54924fec977657795cb82186dd Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 16 Oct 2019 11:08:38 +0300 Subject: e1000e: Add support for Tiger Lake Add devices ID's for the next LOM generations that will be available on the next Intel Client platform (Tiger Lake) This patch provides the initial support for these devices Signed-off-by: Sasha Neftin Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/ethtool.c | 4 +++- drivers/net/ethernet/intel/e1000e/hw.h | 6 ++++++ drivers/net/ethernet/intel/e1000e/ich8lan.c | 7 +++++++ drivers/net/ethernet/intel/e1000e/netdev.c | 8 ++++++++ drivers/net/ethernet/intel/e1000e/ptp.c | 2 ++ 5 files changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index de8c5818a305..adce7e319b9e 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -894,8 +894,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) case e1000_pch2lan: case e1000_pch_lpt: case e1000_pch_spt: - /* fall through */ case e1000_pch_cnp: + /* fall through */ + case e1000_pch_tgp: mask |= BIT(18); break; default: @@ -1559,6 +1560,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) switch (hw->mac.type) { case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: fext_nvm11 = er32(FEXTNVM11); fext_nvm11 &= ~E1000_FEXTNVM11_DISABLE_MULR_FIX; ew32(FEXTNVM11, fext_nvm11); diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index 11fdc27faa82..f556163481cb 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -92,6 +92,11 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_CMP_I219_V11 0x0D4D #define E1000_DEV_ID_PCH_CMP_I219_LM12 0x0D53 #define E1000_DEV_ID_PCH_CMP_I219_V12 0x0D55 +#define E1000_DEV_ID_PCH_TGP_I219_LM13 0x15FB +#define E1000_DEV_ID_PCH_TGP_I219_V13 0x15FC +#define E1000_DEV_ID_PCH_TGP_I219_LM14 0x15F9 +#define E1000_DEV_ID_PCH_TGP_I219_V14 0x15FA +#define E1000_DEV_ID_PCH_TGP_I219_LM15 0x15F4 #define E1000_REVISION_4 4 @@ -115,6 +120,7 @@ enum e1000_mac_type { e1000_pch_lpt, e1000_pch_spt, e1000_pch_cnp, + e1000_pch_tgp, }; enum e1000_media_type { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index a1fab77b2096..b4135c50e905 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -316,6 +316,7 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -458,6 +459,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: /* In case the PHY needs to be in mdio slow mode, * set slow mode and try to get the PHY id again. */ @@ -700,6 +702,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: case e1000_pchlan: /* check management mode */ mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; @@ -1638,6 +1641,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: rc = e1000_init_phy_params_pchlan(hw); break; default: @@ -2090,6 +2094,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; break; default: @@ -3127,6 +3132,7 @@ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) switch (hw->mac.type) { case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: bank1_offset = nvm->flash_bank_size; act_offset = E1000_ICH_NVM_SIG_WORD; @@ -4070,6 +4076,7 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + case e1000_pch_tgp: word = NVM_COMPAT; valid_csum_mask = NVM_COMPAT_VALID_CSUM; break; diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 4aafa05287a4..20965b5d9780 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3538,6 +3538,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) adapter->cc.shift = shift; break; case e1000_pch_cnp: + case e1000_pch_tgp: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 24MHz frequency */ incperiod = INCPERIOD_24MHZ; @@ -4049,6 +4050,8 @@ void e1000e_reset(struct e1000_adapter *adapter) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + /* fall-through */ + case e1000_pch_tgp: fc->refresh_time = 0xFFFF; fc->pause_time = 0xFFFF; @@ -7752,6 +7755,11 @@ static const struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V11), board_pch_cnp }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_LM12), board_pch_spt }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_CMP_I219_V12), board_pch_spt }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM13), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V13), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM14), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_V14), board_pch_cnp }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_TGP_I219_LM15), board_pch_cnp }, { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index 1a4c65d9feb4..eaa5a0fb99f0 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -295,6 +295,8 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: + /* fall-through */ + case e1000_pch_tgp: if ((hw->mac.type < e1000_pch_lpt) || (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) { adapter->ptp_clock_info.max_adj = 24000000 - 1; -- cgit v1.2.3-59-g8ed1b From 203bddfdfb6c2c542885b3da1a7d011fd54744db Mon Sep 17 00:00:00 2001 From: Sasha Neftin Date: Wed, 23 Oct 2019 18:09:17 +0300 Subject: e1000e: Fix compiler warning when CONFIG_PM_SLEEP is not set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM_SLEEP is not defined compiler complain as follow: CC [M] drivers/net/ethernet/intel/e1000e/netdev.o drivers/net/ethernet/intel/e1000e/netdev.c:6302:12: warning: ‘e1000e_s0ix_entry_flow’ defined but not used [-Wunused-function] static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) drivers/net/ethernet/intel/e1000e/netdev.c:6411:12: warning: ‘e1000e_s0ix_exit_flow’ defined but not used [-Wunused-function] static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) LD [M] drivers/net/ethernet/intel/e1000e/e1000e.o Add wrap to fix these warnings. Reported-by: kbuild test robot Signed-off-by: Sasha Neftin Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 20965b5d9780..032b88619054 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6297,6 +6297,7 @@ fl_out: pm_runtime_put_sync(netdev->dev.parent); } +#ifdef CONFIG_PM_SLEEP /* S0ix implementation */ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) { @@ -6464,6 +6465,7 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) mac_data &= ~E1000_CTRL_EXT_FORCE_SMBUS; ew32(CTRL_EXT, mac_data); } +#endif /* CONFIG_PM_SLEEP */ static int e1000e_pm_freeze(struct device *dev) { -- cgit v1.2.3-59-g8ed1b From 5075066a77822edf416fa3001df1144ac6b848be Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 30 Oct 2019 11:34:48 +0200 Subject: mlxsw: reg: Increase size of MPAR register In new firmware versions this register is extended with a sampling rate for Spectrum-2 and future ASICs. Increase the size of the register to ensure the field is initialized to 0 which means every packet is mirrored. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index adb63a266fc7..7f7f1b95290f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -8680,7 +8680,7 @@ mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(char *payload, u8 ttl, * properties. */ #define MLXSW_REG_MPAR_ID 0x901B -#define MLXSW_REG_MPAR_LEN 0x08 +#define MLXSW_REG_MPAR_LEN 0x0C MLXSW_REG_DEFINE(mpar, MLXSW_REG_MPAR_ID, MLXSW_REG_MPAR_LEN); -- cgit v1.2.3-59-g8ed1b From ff298839b6737ccb512d0fe8c6bc241ee5a94c49 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 30 Oct 2019 11:34:49 +0200 Subject: mlxsw: pci: Increase PCI reset timeout for SN3800 systems SN3800 Spectrum-2 based systems have gearboxes that need to be initialized by the firmware during its initialization flow. In certain cases, the firmware might need to flash these gearboxes, which is currently a time-consuming process. In newer firmware versions, the firmware will not signal to the driver that it is ready until the gearboxes are flashed. Increase the PCI reset timeout for these situations. In normal cases, the driver will need to wait no longer than 5 seconds. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci_hw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index 2b3aec482742..e0d7d2d9a0c8 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -27,7 +27,7 @@ #define MLXSW_PCI_SW_RESET 0xF0010 #define MLXSW_PCI_SW_RESET_RST_BIT BIT(0) -#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 20000 +#define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS 900000 #define MLXSW_PCI_SW_RESET_WAIT_MSECS 100 #define MLXSW_PCI_FW_READY 0xA1844 #define MLXSW_PCI_FW_READY_MASK 0xFFFF -- cgit v1.2.3-59-g8ed1b From 5fd2ef46890625f79fe4650a47c2e86473845a5b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 30 Oct 2019 11:34:50 +0200 Subject: mlxsw: Bump firmware version to 13.2000.2308 The version adds support for querying port module type. It will be used by a followup patch set from Jiri to make port split code more generic. Signed-off-by: Ido Schimmel Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 1275d21e8fbd..8a797fad2d56 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -48,7 +48,7 @@ #define MLXSW_SP1_FWREV_MAJOR 13 #define MLXSW_SP1_FWREV_MINOR 2000 -#define MLXSW_SP1_FWREV_SUBMINOR 1886 +#define MLXSW_SP1_FWREV_SUBMINOR 2308 #define MLXSW_SP1_FWREV_CAN_RESET_MINOR 1702 static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { -- cgit v1.2.3-59-g8ed1b From a72afb6879bb427143230bd0d892801c16b528ea Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 30 Oct 2019 11:34:51 +0200 Subject: mlxsw: Enforce firmware version for Spectrum-2 In a similar fashion to Spectrum-1, enforce a specific firmware version for Spectrum-2 so that the driver and firmware are always in sync with regards to new features. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 8a797fad2d56..97be4bc9a02f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -63,6 +63,21 @@ static const struct mlxsw_fw_rev mlxsw_sp1_fw_rev = { "." __stringify(MLXSW_SP1_FWREV_MINOR) \ "." __stringify(MLXSW_SP1_FWREV_SUBMINOR) ".mfa2" +#define MLXSW_SP2_FWREV_MAJOR 29 +#define MLXSW_SP2_FWREV_MINOR 2000 +#define MLXSW_SP2_FWREV_SUBMINOR 2308 + +static const struct mlxsw_fw_rev mlxsw_sp2_fw_rev = { + .major = MLXSW_SP2_FWREV_MAJOR, + .minor = MLXSW_SP2_FWREV_MINOR, + .subminor = MLXSW_SP2_FWREV_SUBMINOR, +}; + +#define MLXSW_SP2_FW_FILENAME \ + "mellanox/mlxsw_spectrum2-" __stringify(MLXSW_SP2_FWREV_MAJOR) \ + "." __stringify(MLXSW_SP2_FWREV_MINOR) \ + "." __stringify(MLXSW_SP2_FWREV_SUBMINOR) ".mfa2" + static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum"; static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2"; static const char mlxsw_sp3_driver_name[] = "mlxsw_spectrum3"; @@ -4988,6 +5003,8 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core, { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); + mlxsw_sp->req_rev = &mlxsw_sp2_fw_rev; + mlxsw_sp->fw_filename = MLXSW_SP2_FW_FILENAME; mlxsw_sp->kvdl_ops = &mlxsw_sp2_kvdl_ops; mlxsw_sp->afa_ops = &mlxsw_sp2_act_afa_ops; mlxsw_sp->afk_ops = &mlxsw_sp2_afk_ops; @@ -6649,3 +6666,4 @@ MODULE_DEVICE_TABLE(pci, mlxsw_sp1_pci_id_table); MODULE_DEVICE_TABLE(pci, mlxsw_sp2_pci_id_table); MODULE_DEVICE_TABLE(pci, mlxsw_sp3_pci_id_table); MODULE_FIRMWARE(MLXSW_SP1_FW_FILENAME); +MODULE_FIRMWARE(MLXSW_SP2_FW_FILENAME); -- cgit v1.2.3-59-g8ed1b From 58deb77cc52da9360d20676e68dd215742cbe473 Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Tue, 29 Oct 2019 14:50:53 +0100 Subject: bonding: balance ICMP echoes in layer3+4 mode The bonding uses the L4 ports to balance flows between slaves. As the ICMP protocol has no ports, those packets are sent all to the same device: # tcpdump -qltnni veth0 ip |sed 's/^/0: /' & # tcpdump -qltnni veth1 ip |sed 's/^/1: /' & # ping -qc1 192.168.0.2 1: IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 315, seq 1, length 64 1: IP 192.168.0.2 > 192.168.0.1: ICMP echo reply, id 315, seq 1, length 64 # ping -qc1 192.168.0.2 1: IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 316, seq 1, length 64 1: IP 192.168.0.2 > 192.168.0.1: ICMP echo reply, id 316, seq 1, length 64 # ping -qc1 192.168.0.2 1: IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 317, seq 1, length 64 1: IP 192.168.0.2 > 192.168.0.1: ICMP echo reply, id 317, seq 1, length 64 But some ICMP packets have an Identifier field which is used to match packets within sessions, let's use this value in the hash function to balance these packets between bond slaves: # ping -qc1 192.168.0.2 0: IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 303, seq 1, length 64 0: IP 192.168.0.2 > 192.168.0.1: ICMP echo reply, id 303, seq 1, length 64 # ping -qc1 192.168.0.2 1: IP 192.168.0.1 > 192.168.0.2: ICMP echo request, id 304, seq 1, length 64 1: IP 192.168.0.2 > 192.168.0.1: ICMP echo reply, id 304, seq 1, length 64 Aso, let's use a flow_dissector_key which defines FLOW_DISSECTOR_KEY_ICMP, so we can balance pings encapsulated in a tunnel when using mode encap3+4: # ping -q 192.168.1.2 -c1 0: IP 192.168.0.1 > 192.168.0.2: GREv0, length 102: IP 192.168.1.1 > 192.168.1.2: ICMP echo request, id 585, seq 1, length 64 0: IP 192.168.0.2 > 192.168.0.1: GREv0, length 102: IP 192.168.1.2 > 192.168.1.1: ICMP echo reply, id 585, seq 1, length 64 # ping -q 192.168.1.2 -c1 1: IP 192.168.0.1 > 192.168.0.2: GREv0, length 102: IP 192.168.1.1 > 192.168.1.2: ICMP echo request, id 586, seq 1, length 64 1: IP 192.168.0.2 > 192.168.0.1: GREv0, length 102: IP 192.168.1.2 > 192.168.1.1: ICMP echo reply, id 586, seq 1, length 64 Signed-off-by: Matteo Croce Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 77 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 21d8fcc83c9c..3e496e746cc6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -200,6 +200,51 @@ atomic_t netpoll_block_tx = ATOMIC_INIT(0); unsigned int bond_net_id __read_mostly; +static const struct flow_dissector_key flow_keys_bonding_keys[] = { + { + .key_id = FLOW_DISSECTOR_KEY_CONTROL, + .offset = offsetof(struct flow_keys, control), + }, + { + .key_id = FLOW_DISSECTOR_KEY_BASIC, + .offset = offsetof(struct flow_keys, basic), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, + .offset = offsetof(struct flow_keys, addrs.v4addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, + .offset = offsetof(struct flow_keys, addrs.v6addrs), + }, + { + .key_id = FLOW_DISSECTOR_KEY_TIPC, + .offset = offsetof(struct flow_keys, addrs.tipckey), + }, + { + .key_id = FLOW_DISSECTOR_KEY_PORTS, + .offset = offsetof(struct flow_keys, ports), + }, + { + .key_id = FLOW_DISSECTOR_KEY_ICMP, + .offset = offsetof(struct flow_keys, icmp), + }, + { + .key_id = FLOW_DISSECTOR_KEY_VLAN, + .offset = offsetof(struct flow_keys, vlan), + }, + { + .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL, + .offset = offsetof(struct flow_keys, tags), + }, + { + .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID, + .offset = offsetof(struct flow_keys, keyid), + }, +}; + +static struct flow_dissector flow_keys_bonding __read_mostly; + /*-------------------------- Forward declarations ---------------------------*/ static int bond_init(struct net_device *bond_dev); @@ -3263,10 +3308,14 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, const struct iphdr *iph; int noff, proto = -1; - if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) - return skb_flow_dissect_flow_keys(skb, fk, 0); + if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) { + memset(fk, 0, sizeof(*fk)); + return __skb_flow_dissect(NULL, skb, &flow_keys_bonding, + fk, NULL, 0, 0, 0, 0); + } fk->ports.ports = 0; + memset(&fk->icmp, 0, sizeof(fk->icmp)); noff = skb_network_offset(skb); if (skb->protocol == htons(ETH_P_IP)) { if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) @@ -3286,8 +3335,14 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, } else { return false; } - if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) - fk->ports.ports = skb_flow_get_ports(skb, noff, proto); + if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) { + if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) + skb_flow_get_icmp_tci(skb, &fk->icmp, skb->data, + skb_transport_offset(skb), + skb_headlen(skb)); + else + fk->ports.ports = skb_flow_get_ports(skb, noff, proto); + } return true; } @@ -3314,10 +3369,14 @@ u32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) return bond_eth_hash(skb); if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 || - bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) + bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) { hash = bond_eth_hash(skb); - else - hash = (__force u32)flow.ports.ports; + } else { + if (flow.icmp.id) + memcpy(&hash, &flow.icmp, sizeof(hash)); + else + memcpy(&hash, &flow.ports.ports, sizeof(hash)); + } hash ^= (__force u32)flow_get_u32_dst(&flow) ^ (__force u32)flow_get_u32_src(&flow); hash ^= (hash >> 16); @@ -4901,6 +4960,10 @@ static int __init bonding_init(void) goto err; } + skb_flow_dissector_init(&flow_keys_bonding, + flow_keys_bonding_keys, + ARRAY_SIZE(flow_keys_bonding_keys)); + register_netdevice_notifier(&bond_netdev_notifier); out: return res; -- cgit v1.2.3-59-g8ed1b From a319fb52e4b399927d4beb075d6112641ecedf16 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 29 Oct 2019 20:25:26 +0100 Subject: net: phy: marvell: add downshift support for 88E1145 Add downshift support for 88E1145, it uses the same downshift configuration registers as 88E1111. Signed-off-by: Heiner Kallweit Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index cb6570ac618a..b1fbd1937328 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -2394,6 +2394,9 @@ static struct phy_driver marvell_drivers[] = { .get_sset_count = marvell_get_sset_count, .get_strings = marvell_get_strings, .get_stats = marvell_get_stats, + .get_tunable = m88e1111_get_tunable, + .set_tunable = m88e1111_set_tunable, + .link_change_notify = m88e1011_link_change_notify, }, { .phy_id = MARVELL_PHY_ID_88E1149R, -- cgit v1.2.3-59-g8ed1b From 1d7a55267faebe3e16c0748b2beafe53cfab9f70 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Tue, 29 Oct 2019 21:57:10 +0100 Subject: vxlan: drop "vxlan" parameter in vxlan_fdb_alloc() This parameter has never been used. Signed-off-by: Guillaume Nault Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 3d9bcc957f7d..5ffea8e34771 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -793,8 +793,7 @@ static int vxlan_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff) return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr)); } -static struct vxlan_fdb *vxlan_fdb_alloc(struct vxlan_dev *vxlan, - const u8 *mac, __u16 state, +static struct vxlan_fdb *vxlan_fdb_alloc(const u8 *mac, __u16 state, __be32 src_vni, __u16 ndm_flags) { struct vxlan_fdb *f; @@ -835,7 +834,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, return -ENOSPC; netdev_dbg(vxlan->dev, "add %pM -> %pIS\n", mac, ip); - f = vxlan_fdb_alloc(vxlan, mac, state, src_vni, ndm_flags); + f = vxlan_fdb_alloc(mac, state, src_vni, ndm_flags); if (!f) return -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 84e93d999a677ee3229e244e9eb29209c3bb6677 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 30 Oct 2019 10:55:34 +0800 Subject: wimax: use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs fops It is more clear to use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs file operation rather than DEFINE_SIMPLE_ATTRIBUTE. It is detected with the help of coccinelle. Signed-off-by: zhong jiang Signed-off-by: David S. Miller --- drivers/net/wimax/i2400m/debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c index 73f5892ce6c1..1c640b41ea4c 100644 --- a/drivers/net/wimax/i2400m/debugfs.c +++ b/drivers/net/wimax/i2400m/debugfs.c @@ -26,7 +26,7 @@ int debugfs_netdev_queue_stopped_get(void *data, u64 *val) *val = netif_queue_stopped(i2400m->wimax_dev.net_dev); return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_netdev_queue_stopped, +DEFINE_DEBUGFS_ATTRIBUTE(fops_netdev_queue_stopped, debugfs_netdev_queue_stopped_get, NULL, "%llu\n"); @@ -154,7 +154,7 @@ int debugfs_i2400m_suspend_set(void *data, u64 val) result = 0; return result; } -DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_suspend, +DEFINE_DEBUGFS_ATTRIBUTE(fops_i2400m_suspend, NULL, debugfs_i2400m_suspend_set, "%llu\n"); @@ -183,7 +183,7 @@ int debugfs_i2400m_reset_set(void *data, u64 val) } return result; } -DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_reset, +DEFINE_DEBUGFS_ATTRIBUTE(fops_i2400m_reset, NULL, debugfs_i2400m_reset_set, "%llu\n"); -- cgit v1.2.3-59-g8ed1b From 1f592108bbd0c7eecfb0e60fd8f6690e134dc254 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 16:31:59 +0800 Subject: rtw88: fix sparse warnings for DPK sparse warnings: drivers/net/wireless/realtek/rtw88/rtw8822c.c:2871:6: sparse: sparse: symbol 'rtw8822c_dpk_cal_coef1' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/rtw8822c.c:3112:6: sparse: sparse: symbol 'rtw8822c_dpk_track' was not declared. Should it be static? Fixes: 5227c2ee453d ("rtw88: 8822c: add SW DPK support") Reported-by: kbuild test robot Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index b77905196ffb..97f4c4e1d7e9 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2970,7 +2970,7 @@ static void rtw8822c_dpk_cal_gs(struct rtw_dev *rtwdev, u8 path) dpk_info->dpk_gs[path] = tmp_gs; } -void rtw8822c_dpk_cal_coef1(struct rtw_dev *rtwdev) +static void rtw8822c_dpk_cal_coef1(struct rtw_dev *rtwdev) { struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; u32 offset[DPK_RF_PATH_NUM] = {0, 0x58}; @@ -3211,7 +3211,7 @@ static void rtw8822c_phy_calibration(struct rtw_dev *rtwdev) rtw8822c_do_dpk(rtwdev); } -void rtw8822c_dpk_track(struct rtw_dev *rtwdev) +static void rtw8822c_dpk_track(struct rtw_dev *rtwdev) { struct rtw_dpk_info *dpk_info = &rtwdev->dm_info.dpk_info; u8 path; -- cgit v1.2.3-59-g8ed1b From a969cf42e5fecbbcc04354dd22b851daa6ab5b30 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 16:32:00 +0800 Subject: rtw88: fix sparse warnings for power tracking sparse warnings: drivers/net/wireless/realtek/rtw88/rtw8822b.c:1440:6: sparse: sparse: symbol 'rtw8822b_pwr_track' was not declared. Should it be static? drivers/net/wireless/realtek/rtw88/rtw8822c.c:1008:6: sparse: sparse: symbol 'rtw8822c_pwrtrack_init' was not declared. Should it be static? Fixes: c97ee3e0bea2 ("rtw88: add power tracking support") Reported-by: kbuild test robot Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 2 +- drivers/net/wireless/realtek/rtw88/rtw8822c.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 6f4e7326068c..3ec3e8eb3ecd 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -1492,7 +1492,7 @@ iqk: rtw8822b_do_iqk(rtwdev); } -void rtw8822b_pwr_track(struct rtw_dev *rtwdev) +static void rtw8822b_pwr_track(struct rtw_dev *rtwdev) { struct rtw_efuse *efuse = &rtwdev->efuse; struct rtw_dm_info *dm_info = &rtwdev->dm_info; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 97f4c4e1d7e9..04ced3b2a247 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -1006,7 +1006,7 @@ static void rtw8822c_rf_init(struct rtw_dev *rtwdev) rtw8822c_rf_x2_check(rtwdev); } -void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev) +static void rtw8822c_pwrtrack_init(struct rtw_dev *rtwdev) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 path; -- cgit v1.2.3-59-g8ed1b From 7436a470b5835d4d06c9453736bc1d2e9b29a07e Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 17:33:40 +0800 Subject: rtw88: 8822b: add RFE type 3 support Some of the modules use RFE type 3, add corresponding tables for them. Tested-by: G.schlmm Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rtw8822b.c | 4 +- .../net/wireless/realtek/rtw88/rtw8822b_table.c | 642 +++++++++++++++++++++ .../net/wireless/realtek/rtw88/rtw8822b_table.h | 2 + 3 files changed, 647 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index 3ec3e8eb3ecd..4bc14b1a6340 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -391,6 +391,7 @@ struct rtw8822b_rfe_info { static const struct rtw8822b_rfe_info rtw8822b_rfe_info[] = { [2] = I2GE5G_CCUT(efem), + [3] = IFEM_EXT_CCUT(ifem), [5] = IFEM_EXT_CCUT(ifem), }; @@ -664,7 +665,7 @@ static void rtw8822b_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw, rtw_write32_mask(rtwdev, REG_ADC160, BIT(30), 0x1); - if (rfe_option == 2) { + if (rfe_option == 2 || rfe_option == 3) { rtw_write32_mask(rtwdev, REG_L1PKWT, 0x0000f000, 0x6); rtw_write32_mask(rtwdev, REG_ADC40, BIT(10), 0x1); } @@ -2041,6 +2042,7 @@ static struct rtw_intf_phy_para_table phy_para_table_8822b = { static const struct rtw_rfe_def rtw8822b_rfe_defs[] = { [2] = RTW_DEF_RFE(8822b, 2, 2), + [3] = RTW_DEF_RFE(8822b, 3, 0), [5] = RTW_DEF_RFE(8822b, 5, 5), }; diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c index 465f58411cab..25537d147e86 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c @@ -11694,6 +11694,58 @@ static const u32 rtw8822b_bb_pg_type2[] = { RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type2); +static const u32 rtw8822b_bb_pg_type3[] = { + 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, + 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, + 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, + 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, + 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, + 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, + 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, + 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, + 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, + 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, + 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, + 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, + 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, + 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, + 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, + 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, + 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, + 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, + 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, + 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, + 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, + 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, + 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, + 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, + 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, + 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, + 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, + 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, + 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, + 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, + 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, + 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, + 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, + 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, + 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, + 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, + 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, + 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, + 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, + 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, + 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, + 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, + 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, + 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, + 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426 + +}; + +RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type3); + static const u32 rtw8822b_bb_pg_type5[] = { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, @@ -20382,6 +20434,596 @@ static const u32 rtw8822b_rf_b[] = { RTW_DECL_TABLE_RF_RADIO(rtw8822b_rf_b, B); +static const struct rtw_txpwr_lmt_cfg_pair rtw8822b_txpwr_lmt_type0[] = { + { 0, 0, 0, 0, 1, 32, }, + { 2, 0, 0, 0, 1, 28, }, + { 1, 0, 0, 0, 1, 30, }, + { 0, 0, 0, 0, 2, 32, }, + { 2, 0, 0, 0, 2, 28, }, + { 1, 0, 0, 0, 2, 30, }, + { 0, 0, 0, 0, 3, 32, }, + { 2, 0, 0, 0, 3, 28, }, + { 1, 0, 0, 0, 3, 30, }, + { 0, 0, 0, 0, 4, 32, }, + { 2, 0, 0, 0, 4, 28, }, + { 1, 0, 0, 0, 4, 30, }, + { 0, 0, 0, 0, 5, 32, }, + { 2, 0, 0, 0, 5, 28, }, + { 1, 0, 0, 0, 5, 30, }, + { 0, 0, 0, 0, 6, 32, }, + { 2, 0, 0, 0, 6, 28, }, + { 1, 0, 0, 0, 6, 30, }, + { 0, 0, 0, 0, 7, 32, }, + { 2, 0, 0, 0, 7, 28, }, + { 1, 0, 0, 0, 7, 30, }, + { 0, 0, 0, 0, 8, 32, }, + { 2, 0, 0, 0, 8, 28, }, + { 1, 0, 0, 0, 8, 30, }, + { 0, 0, 0, 0, 9, 32, }, + { 2, 0, 0, 0, 9, 28, }, + { 1, 0, 0, 0, 9, 30, }, + { 0, 0, 0, 0, 10, 32, }, + { 2, 0, 0, 0, 10, 28, }, + { 1, 0, 0, 0, 10, 30, }, + { 0, 0, 0, 0, 11, 32, }, + { 2, 0, 0, 0, 11, 28, }, + { 1, 0, 0, 0, 11, 30, }, + { 0, 0, 0, 0, 12, 26, }, + { 2, 0, 0, 0, 12, 28, }, + { 1, 0, 0, 0, 12, 30, }, + { 0, 0, 0, 0, 13, 20, }, + { 2, 0, 0, 0, 13, 28, }, + { 1, 0, 0, 0, 13, 28, }, + { 0, 0, 0, 0, 14, 63, }, + { 2, 0, 0, 0, 14, 63, }, + { 1, 0, 0, 0, 14, 32, }, + { 0, 0, 0, 1, 1, 26, }, + { 2, 0, 0, 1, 1, 30, }, + { 1, 0, 0, 1, 1, 34, }, + { 0, 0, 0, 1, 2, 30, }, + { 2, 0, 0, 1, 2, 30, }, + { 1, 0, 0, 1, 2, 34, }, + { 0, 0, 0, 1, 3, 32, }, + { 2, 0, 0, 1, 3, 30, }, + { 1, 0, 0, 1, 3, 34, }, + { 0, 0, 0, 1, 4, 34, }, + { 2, 0, 0, 1, 4, 30, }, + { 1, 0, 0, 1, 4, 34, }, + { 0, 0, 0, 1, 5, 34, }, + { 2, 0, 0, 1, 5, 30, }, + { 1, 0, 0, 1, 5, 34, }, + { 0, 0, 0, 1, 6, 34, }, + { 2, 0, 0, 1, 6, 30, }, + { 1, 0, 0, 1, 6, 34, }, + { 0, 0, 0, 1, 7, 34, }, + { 2, 0, 0, 1, 7, 30, }, + { 1, 0, 0, 1, 7, 34, }, + { 0, 0, 0, 1, 8, 34, }, + { 2, 0, 0, 1, 8, 30, }, + { 1, 0, 0, 1, 8, 34, }, + { 0, 0, 0, 1, 9, 32, }, + { 2, 0, 0, 1, 9, 30, }, + { 1, 0, 0, 1, 9, 34, }, + { 0, 0, 0, 1, 10, 30, }, + { 2, 0, 0, 1, 10, 30, }, + { 1, 0, 0, 1, 10, 34, }, + { 0, 0, 0, 1, 11, 28, }, + { 2, 0, 0, 1, 11, 30, }, + { 1, 0, 0, 1, 11, 34, }, + { 0, 0, 0, 1, 12, 22, }, + { 2, 0, 0, 1, 12, 30, }, + { 1, 0, 0, 1, 12, 34, }, + { 0, 0, 0, 1, 13, 14, }, + { 2, 0, 0, 1, 13, 30, }, + { 1, 0, 0, 1, 13, 34, }, + { 0, 0, 0, 1, 14, 63, }, + { 2, 0, 0, 1, 14, 63, }, + { 1, 0, 0, 1, 14, 63, }, + { 0, 0, 0, 2, 1, 26, }, + { 2, 0, 0, 2, 1, 30, }, + { 1, 0, 0, 2, 1, 34, }, + { 0, 0, 0, 2, 2, 30, }, + { 2, 0, 0, 2, 2, 30, }, + { 1, 0, 0, 2, 2, 34, }, + { 0, 0, 0, 2, 3, 32, }, + { 2, 0, 0, 2, 3, 30, }, + { 1, 0, 0, 2, 3, 34, }, + { 0, 0, 0, 2, 4, 34, }, + { 2, 0, 0, 2, 4, 30, }, + { 1, 0, 0, 2, 4, 34, }, + { 0, 0, 0, 2, 5, 34, }, + { 2, 0, 0, 2, 5, 30, }, + { 1, 0, 0, 2, 5, 34, }, + { 0, 0, 0, 2, 6, 34, }, + { 2, 0, 0, 2, 6, 30, }, + { 1, 0, 0, 2, 6, 34, }, + { 0, 0, 0, 2, 7, 34, }, + { 2, 0, 0, 2, 7, 30, }, + { 1, 0, 0, 2, 7, 34, }, + { 0, 0, 0, 2, 8, 34, }, + { 2, 0, 0, 2, 8, 30, }, + { 1, 0, 0, 2, 8, 34, }, + { 0, 0, 0, 2, 9, 32, }, + { 2, 0, 0, 2, 9, 30, }, + { 1, 0, 0, 2, 9, 34, }, + { 0, 0, 0, 2, 10, 30, }, + { 2, 0, 0, 2, 10, 30, }, + { 1, 0, 0, 2, 10, 34, }, + { 0, 0, 0, 2, 11, 26, }, + { 2, 0, 0, 2, 11, 30, }, + { 1, 0, 0, 2, 11, 34, }, + { 0, 0, 0, 2, 12, 20, }, + { 2, 0, 0, 2, 12, 30, }, + { 1, 0, 0, 2, 12, 34, }, + { 0, 0, 0, 2, 13, 14, }, + { 2, 0, 0, 2, 13, 30, }, + { 1, 0, 0, 2, 13, 34, }, + { 0, 0, 0, 2, 14, 63, }, + { 2, 0, 0, 2, 14, 63, }, + { 1, 0, 0, 2, 14, 63, }, + { 0, 0, 0, 3, 1, 26, }, + { 2, 0, 0, 3, 1, 18, }, + { 1, 0, 0, 3, 1, 30, }, + { 0, 0, 0, 3, 2, 28, }, + { 2, 0, 0, 3, 2, 18, }, + { 1, 0, 0, 3, 2, 30, }, + { 0, 0, 0, 3, 3, 30, }, + { 2, 0, 0, 3, 3, 18, }, + { 1, 0, 0, 3, 3, 30, }, + { 0, 0, 0, 3, 4, 30, }, + { 2, 0, 0, 3, 4, 18, }, + { 1, 0, 0, 3, 4, 30, }, + { 0, 0, 0, 3, 5, 32, }, + { 2, 0, 0, 3, 5, 18, }, + { 1, 0, 0, 3, 5, 30, }, + { 0, 0, 0, 3, 6, 32, }, + { 2, 0, 0, 3, 6, 18, }, + { 1, 0, 0, 3, 6, 30, }, + { 0, 0, 0, 3, 7, 32, }, + { 2, 0, 0, 3, 7, 18, }, + { 1, 0, 0, 3, 7, 30, }, + { 0, 0, 0, 3, 8, 30, }, + { 2, 0, 0, 3, 8, 18, }, + { 1, 0, 0, 3, 8, 30, }, + { 0, 0, 0, 3, 9, 30, }, + { 2, 0, 0, 3, 9, 18, }, + { 1, 0, 0, 3, 9, 30, }, + { 0, 0, 0, 3, 10, 28, }, + { 2, 0, 0, 3, 10, 18, }, + { 1, 0, 0, 3, 10, 30, }, + { 0, 0, 0, 3, 11, 26, }, + { 2, 0, 0, 3, 11, 18, }, + { 1, 0, 0, 3, 11, 30, }, + { 0, 0, 0, 3, 12, 20, }, + { 2, 0, 0, 3, 12, 18, }, + { 1, 0, 0, 3, 12, 30, }, + { 0, 0, 0, 3, 13, 14, }, + { 2, 0, 0, 3, 13, 18, }, + { 1, 0, 0, 3, 13, 30, }, + { 0, 0, 0, 3, 14, 63, }, + { 2, 0, 0, 3, 14, 63, }, + { 1, 0, 0, 3, 14, 63, }, + { 0, 0, 1, 2, 1, 63, }, + { 2, 0, 1, 2, 1, 63, }, + { 1, 0, 1, 2, 1, 63, }, + { 0, 0, 1, 2, 2, 63, }, + { 2, 0, 1, 2, 2, 63, }, + { 1, 0, 1, 2, 2, 63, }, + { 0, 0, 1, 2, 3, 26, }, + { 2, 0, 1, 2, 3, 30, }, + { 1, 0, 1, 2, 3, 34, }, + { 0, 0, 1, 2, 4, 26, }, + { 2, 0, 1, 2, 4, 30, }, + { 1, 0, 1, 2, 4, 34, }, + { 0, 0, 1, 2, 5, 30, }, + { 2, 0, 1, 2, 5, 30, }, + { 1, 0, 1, 2, 5, 34, }, + { 0, 0, 1, 2, 6, 32, }, + { 2, 0, 1, 2, 6, 30, }, + { 1, 0, 1, 2, 6, 34, }, + { 0, 0, 1, 2, 7, 30, }, + { 2, 0, 1, 2, 7, 30, }, + { 1, 0, 1, 2, 7, 34, }, + { 0, 0, 1, 2, 8, 26, }, + { 2, 0, 1, 2, 8, 30, }, + { 1, 0, 1, 2, 8, 34, }, + { 0, 0, 1, 2, 9, 26, }, + { 2, 0, 1, 2, 9, 30, }, + { 1, 0, 1, 2, 9, 34, }, + { 0, 0, 1, 2, 10, 20, }, + { 2, 0, 1, 2, 10, 30, }, + { 1, 0, 1, 2, 10, 34, }, + { 0, 0, 1, 2, 11, 14, }, + { 2, 0, 1, 2, 11, 30, }, + { 1, 0, 1, 2, 11, 34, }, + { 0, 0, 1, 2, 12, 63, }, + { 2, 0, 1, 2, 12, 63, }, + { 1, 0, 1, 2, 12, 63, }, + { 0, 0, 1, 2, 13, 63, }, + { 2, 0, 1, 2, 13, 63, }, + { 1, 0, 1, 2, 13, 63, }, + { 0, 0, 1, 2, 14, 63, }, + { 2, 0, 1, 2, 14, 63, }, + { 1, 0, 1, 2, 14, 63, }, + { 0, 0, 1, 3, 1, 63, }, + { 2, 0, 1, 3, 1, 63, }, + { 1, 0, 1, 3, 1, 63, }, + { 0, 0, 1, 3, 2, 63, }, + { 2, 0, 1, 3, 2, 63, }, + { 1, 0, 1, 3, 2, 63, }, + { 0, 0, 1, 3, 3, 24, }, + { 2, 0, 1, 3, 3, 18, }, + { 1, 0, 1, 3, 3, 30, }, + { 0, 0, 1, 3, 4, 24, }, + { 2, 0, 1, 3, 4, 18, }, + { 1, 0, 1, 3, 4, 30, }, + { 0, 0, 1, 3, 5, 26, }, + { 2, 0, 1, 3, 5, 18, }, + { 1, 0, 1, 3, 5, 30, }, + { 0, 0, 1, 3, 6, 28, }, + { 2, 0, 1, 3, 6, 18, }, + { 1, 0, 1, 3, 6, 30, }, + { 0, 0, 1, 3, 7, 26, }, + { 2, 0, 1, 3, 7, 18, }, + { 1, 0, 1, 3, 7, 30, }, + { 0, 0, 1, 3, 8, 26, }, + { 2, 0, 1, 3, 8, 18, }, + { 1, 0, 1, 3, 8, 30, }, + { 0, 0, 1, 3, 9, 26, }, + { 2, 0, 1, 3, 9, 18, }, + { 1, 0, 1, 3, 9, 30, }, + { 0, 0, 1, 3, 10, 20, }, + { 2, 0, 1, 3, 10, 18, }, + { 1, 0, 1, 3, 10, 30, }, + { 0, 0, 1, 3, 11, 14, }, + { 2, 0, 1, 3, 11, 18, }, + { 1, 0, 1, 3, 11, 30, }, + { 0, 0, 1, 3, 12, 63, }, + { 2, 0, 1, 3, 12, 63, }, + { 1, 0, 1, 3, 12, 63, }, + { 0, 0, 1, 3, 13, 63, }, + { 2, 0, 1, 3, 13, 63, }, + { 1, 0, 1, 3, 13, 63, }, + { 0, 0, 1, 3, 14, 63, }, + { 2, 0, 1, 3, 14, 63, }, + { 1, 0, 1, 3, 14, 63, }, + { 0, 1, 0, 1, 36, 30, }, + { 2, 1, 0, 1, 36, 32, }, + { 1, 1, 0, 1, 36, 30, }, + { 0, 1, 0, 1, 40, 32, }, + { 2, 1, 0, 1, 40, 32, }, + { 1, 1, 0, 1, 40, 30, }, + { 0, 1, 0, 1, 44, 32, }, + { 2, 1, 0, 1, 44, 32, }, + { 1, 1, 0, 1, 44, 30, }, + { 0, 1, 0, 1, 48, 32, }, + { 2, 1, 0, 1, 48, 32, }, + { 1, 1, 0, 1, 48, 30, }, + { 0, 1, 0, 1, 52, 32, }, + { 2, 1, 0, 1, 52, 32, }, + { 1, 1, 0, 1, 52, 28, }, + { 0, 1, 0, 1, 56, 32, }, + { 2, 1, 0, 1, 56, 32, }, + { 1, 1, 0, 1, 56, 28, }, + { 0, 1, 0, 1, 60, 32, }, + { 2, 1, 0, 1, 60, 32, }, + { 1, 1, 0, 1, 60, 28, }, + { 0, 1, 0, 1, 64, 28, }, + { 2, 1, 0, 1, 64, 32, }, + { 1, 1, 0, 1, 64, 28, }, + { 0, 1, 0, 1, 100, 26, }, + { 2, 1, 0, 1, 100, 32, }, + { 1, 1, 0, 1, 100, 32, }, + { 0, 1, 0, 1, 104, 32, }, + { 2, 1, 0, 1, 104, 32, }, + { 1, 1, 0, 1, 104, 32, }, + { 0, 1, 0, 1, 108, 32, }, + { 2, 1, 0, 1, 108, 32, }, + { 1, 1, 0, 1, 108, 32, }, + { 0, 1, 0, 1, 112, 32, }, + { 2, 1, 0, 1, 112, 32, }, + { 1, 1, 0, 1, 112, 32, }, + { 0, 1, 0, 1, 116, 32, }, + { 2, 1, 0, 1, 116, 32, }, + { 1, 1, 0, 1, 116, 32, }, + { 0, 1, 0, 1, 120, 32, }, + { 2, 1, 0, 1, 120, 32, }, + { 1, 1, 0, 1, 120, 32, }, + { 0, 1, 0, 1, 124, 32, }, + { 2, 1, 0, 1, 124, 32, }, + { 1, 1, 0, 1, 124, 32, }, + { 0, 1, 0, 1, 128, 32, }, + { 2, 1, 0, 1, 128, 32, }, + { 1, 1, 0, 1, 128, 32, }, + { 0, 1, 0, 1, 132, 32, }, + { 2, 1, 0, 1, 132, 32, }, + { 1, 1, 0, 1, 132, 32, }, + { 0, 1, 0, 1, 136, 32, }, + { 2, 1, 0, 1, 136, 32, }, + { 1, 1, 0, 1, 136, 32, }, + { 0, 1, 0, 1, 140, 28, }, + { 2, 1, 0, 1, 140, 32, }, + { 1, 1, 0, 1, 140, 32, }, + { 0, 1, 0, 1, 144, 28, }, + { 2, 1, 0, 1, 144, 32, }, + { 1, 1, 0, 1, 144, 63, }, + { 0, 1, 0, 1, 149, 32, }, + { 2, 1, 0, 1, 149, 63, }, + { 1, 1, 0, 1, 149, 63, }, + { 0, 1, 0, 1, 153, 32, }, + { 2, 1, 0, 1, 153, 63, }, + { 1, 1, 0, 1, 153, 63, }, + { 0, 1, 0, 1, 157, 32, }, + { 2, 1, 0, 1, 157, 63, }, + { 1, 1, 0, 1, 157, 63, }, + { 0, 1, 0, 1, 161, 32, }, + { 2, 1, 0, 1, 161, 63, }, + { 1, 1, 0, 1, 161, 63, }, + { 0, 1, 0, 1, 165, 32, }, + { 2, 1, 0, 1, 165, 63, }, + { 1, 1, 0, 1, 165, 63, }, + { 0, 1, 0, 2, 36, 30, }, + { 2, 1, 0, 2, 36, 32, }, + { 1, 1, 0, 2, 36, 28, }, + { 0, 1, 0, 2, 40, 32, }, + { 2, 1, 0, 2, 40, 32, }, + { 1, 1, 0, 2, 40, 28, }, + { 0, 1, 0, 2, 44, 32, }, + { 2, 1, 0, 2, 44, 32, }, + { 1, 1, 0, 2, 44, 28, }, + { 0, 1, 0, 2, 48, 32, }, + { 2, 1, 0, 2, 48, 32, }, + { 1, 1, 0, 2, 48, 28, }, + { 0, 1, 0, 2, 52, 32, }, + { 2, 1, 0, 2, 52, 32, }, + { 1, 1, 0, 2, 52, 28, }, + { 0, 1, 0, 2, 56, 32, }, + { 2, 1, 0, 2, 56, 32, }, + { 1, 1, 0, 2, 56, 28, }, + { 0, 1, 0, 2, 60, 32, }, + { 2, 1, 0, 2, 60, 32, }, + { 1, 1, 0, 2, 60, 28, }, + { 0, 1, 0, 2, 64, 28, }, + { 2, 1, 0, 2, 64, 32, }, + { 1, 1, 0, 2, 64, 28, }, + { 0, 1, 0, 2, 100, 26, }, + { 2, 1, 0, 2, 100, 32, }, + { 1, 1, 0, 2, 100, 32, }, + { 0, 1, 0, 2, 104, 32, }, + { 2, 1, 0, 2, 104, 32, }, + { 1, 1, 0, 2, 104, 32, }, + { 0, 1, 0, 2, 108, 32, }, + { 2, 1, 0, 2, 108, 32, }, + { 1, 1, 0, 2, 108, 32, }, + { 0, 1, 0, 2, 112, 32, }, + { 2, 1, 0, 2, 112, 32, }, + { 1, 1, 0, 2, 112, 32, }, + { 0, 1, 0, 2, 116, 32, }, + { 2, 1, 0, 2, 116, 32, }, + { 1, 1, 0, 2, 116, 32, }, + { 0, 1, 0, 2, 120, 32, }, + { 2, 1, 0, 2, 120, 32, }, + { 1, 1, 0, 2, 120, 32, }, + { 0, 1, 0, 2, 124, 32, }, + { 2, 1, 0, 2, 124, 32, }, + { 1, 1, 0, 2, 124, 32, }, + { 0, 1, 0, 2, 128, 32, }, + { 2, 1, 0, 2, 128, 32, }, + { 1, 1, 0, 2, 128, 32, }, + { 0, 1, 0, 2, 132, 32, }, + { 2, 1, 0, 2, 132, 32, }, + { 1, 1, 0, 2, 132, 32, }, + { 0, 1, 0, 2, 136, 32, }, + { 2, 1, 0, 2, 136, 32, }, + { 1, 1, 0, 2, 136, 32, }, + { 0, 1, 0, 2, 140, 26, }, + { 2, 1, 0, 2, 140, 32, }, + { 1, 1, 0, 2, 140, 32, }, + { 0, 1, 0, 2, 144, 26, }, + { 2, 1, 0, 2, 144, 63, }, + { 1, 1, 0, 2, 144, 63, }, + { 0, 1, 0, 2, 149, 32, }, + { 2, 1, 0, 2, 149, 63, }, + { 1, 1, 0, 2, 149, 63, }, + { 0, 1, 0, 2, 153, 32, }, + { 2, 1, 0, 2, 153, 63, }, + { 1, 1, 0, 2, 153, 63, }, + { 0, 1, 0, 2, 157, 32, }, + { 2, 1, 0, 2, 157, 63, }, + { 1, 1, 0, 2, 157, 63, }, + { 0, 1, 0, 2, 161, 32, }, + { 2, 1, 0, 2, 161, 63, }, + { 1, 1, 0, 2, 161, 63, }, + { 0, 1, 0, 2, 165, 32, }, + { 2, 1, 0, 2, 165, 63, }, + { 1, 1, 0, 2, 165, 63, }, + { 0, 1, 0, 3, 36, 28, }, + { 2, 1, 0, 3, 36, 20, }, + { 1, 1, 0, 3, 36, 22, }, + { 0, 1, 0, 3, 40, 30, }, + { 2, 1, 0, 3, 40, 20, }, + { 1, 1, 0, 3, 40, 22, }, + { 0, 1, 0, 3, 44, 30, }, + { 2, 1, 0, 3, 44, 20, }, + { 1, 1, 0, 3, 44, 22, }, + { 0, 1, 0, 3, 48, 30, }, + { 2, 1, 0, 3, 48, 20, }, + { 1, 1, 0, 3, 48, 22, }, + { 0, 1, 0, 3, 52, 30, }, + { 2, 1, 0, 3, 52, 20, }, + { 1, 1, 0, 3, 52, 22, }, + { 0, 1, 0, 3, 56, 30, }, + { 2, 1, 0, 3, 56, 20, }, + { 1, 1, 0, 3, 56, 22, }, + { 0, 1, 0, 3, 60, 30, }, + { 2, 1, 0, 3, 60, 20, }, + { 1, 1, 0, 3, 60, 22, }, + { 0, 1, 0, 3, 64, 28, }, + { 2, 1, 0, 3, 64, 20, }, + { 1, 1, 0, 3, 64, 22, }, + { 0, 1, 0, 3, 100, 26, }, + { 2, 1, 0, 3, 100, 20, }, + { 1, 1, 0, 3, 100, 30, }, + { 0, 1, 0, 3, 104, 30, }, + { 2, 1, 0, 3, 104, 20, }, + { 1, 1, 0, 3, 104, 30, }, + { 0, 1, 0, 3, 108, 32, }, + { 2, 1, 0, 3, 108, 20, }, + { 1, 1, 0, 3, 108, 30, }, + { 0, 1, 0, 3, 112, 32, }, + { 2, 1, 0, 3, 112, 20, }, + { 1, 1, 0, 3, 112, 30, }, + { 0, 1, 0, 3, 116, 32, }, + { 2, 1, 0, 3, 116, 20, }, + { 1, 1, 0, 3, 116, 30, }, + { 0, 1, 0, 3, 120, 32, }, + { 2, 1, 0, 3, 120, 20, }, + { 1, 1, 0, 3, 120, 30, }, + { 0, 1, 0, 3, 124, 32, }, + { 2, 1, 0, 3, 124, 20, }, + { 1, 1, 0, 3, 124, 30, }, + { 0, 1, 0, 3, 128, 32, }, + { 2, 1, 0, 3, 128, 20, }, + { 1, 1, 0, 3, 128, 30, }, + { 0, 1, 0, 3, 132, 32, }, + { 2, 1, 0, 3, 132, 20, }, + { 1, 1, 0, 3, 132, 30, }, + { 0, 1, 0, 3, 136, 30, }, + { 2, 1, 0, 3, 136, 20, }, + { 1, 1, 0, 3, 136, 30, }, + { 0, 1, 0, 3, 140, 26, }, + { 2, 1, 0, 3, 140, 20, }, + { 1, 1, 0, 3, 140, 30, }, + { 0, 1, 0, 3, 144, 26, }, + { 2, 1, 0, 3, 144, 63, }, + { 1, 1, 0, 3, 144, 63, }, + { 0, 1, 0, 3, 149, 32, }, + { 2, 1, 0, 3, 149, 63, }, + { 1, 1, 0, 3, 149, 63, }, + { 0, 1, 0, 3, 153, 32, }, + { 2, 1, 0, 3, 153, 63, }, + { 1, 1, 0, 3, 153, 63, }, + { 0, 1, 0, 3, 157, 32, }, + { 2, 1, 0, 3, 157, 63, }, + { 1, 1, 0, 3, 157, 63, }, + { 0, 1, 0, 3, 161, 32, }, + { 2, 1, 0, 3, 161, 63, }, + { 1, 1, 0, 3, 161, 63, }, + { 0, 1, 0, 3, 165, 32, }, + { 2, 1, 0, 3, 165, 63, }, + { 1, 1, 0, 3, 165, 63, }, + { 0, 1, 1, 2, 38, 22, }, + { 2, 1, 1, 2, 38, 30, }, + { 1, 1, 1, 2, 38, 30, }, + { 0, 1, 1, 2, 46, 30, }, + { 2, 1, 1, 2, 46, 30, }, + { 1, 1, 1, 2, 46, 30, }, + { 0, 1, 1, 2, 54, 30, }, + { 2, 1, 1, 2, 54, 30, }, + { 1, 1, 1, 2, 54, 30, }, + { 0, 1, 1, 2, 62, 24, }, + { 2, 1, 1, 2, 62, 30, }, + { 1, 1, 1, 2, 62, 30, }, + { 0, 1, 1, 2, 102, 24, }, + { 2, 1, 1, 2, 102, 30, }, + { 1, 1, 1, 2, 102, 30, }, + { 0, 1, 1, 2, 110, 30, }, + { 2, 1, 1, 2, 110, 30, }, + { 1, 1, 1, 2, 110, 30, }, + { 0, 1, 1, 2, 118, 30, }, + { 2, 1, 1, 2, 118, 30, }, + { 1, 1, 1, 2, 118, 30, }, + { 0, 1, 1, 2, 126, 30, }, + { 2, 1, 1, 2, 126, 30, }, + { 1, 1, 1, 2, 126, 30, }, + { 0, 1, 1, 2, 134, 30, }, + { 2, 1, 1, 2, 134, 30, }, + { 1, 1, 1, 2, 134, 30, }, + { 0, 1, 1, 2, 142, 30, }, + { 2, 1, 1, 2, 142, 63, }, + { 1, 1, 1, 2, 142, 63, }, + { 0, 1, 1, 2, 151, 30, }, + { 2, 1, 1, 2, 151, 63, }, + { 1, 1, 1, 2, 151, 63, }, + { 0, 1, 1, 2, 159, 30, }, + { 2, 1, 1, 2, 159, 63, }, + { 1, 1, 1, 2, 159, 63, }, + { 0, 1, 1, 3, 38, 20, }, + { 2, 1, 1, 3, 38, 20, }, + { 1, 1, 1, 3, 38, 22, }, + { 0, 1, 1, 3, 46, 30, }, + { 2, 1, 1, 3, 46, 20, }, + { 1, 1, 1, 3, 46, 22, }, + { 0, 1, 1, 3, 54, 30, }, + { 2, 1, 1, 3, 54, 20, }, + { 1, 1, 1, 3, 54, 22, }, + { 0, 1, 1, 3, 62, 22, }, + { 2, 1, 1, 3, 62, 20, }, + { 1, 1, 1, 3, 62, 22, }, + { 0, 1, 1, 3, 102, 22, }, + { 2, 1, 1, 3, 102, 20, }, + { 1, 1, 1, 3, 102, 30, }, + { 0, 1, 1, 3, 110, 30, }, + { 2, 1, 1, 3, 110, 20, }, + { 1, 1, 1, 3, 110, 30, }, + { 0, 1, 1, 3, 118, 30, }, + { 2, 1, 1, 3, 118, 20, }, + { 1, 1, 1, 3, 118, 30, }, + { 0, 1, 1, 3, 126, 30, }, + { 2, 1, 1, 3, 126, 20, }, + { 1, 1, 1, 3, 126, 30, }, + { 0, 1, 1, 3, 134, 30, }, + { 2, 1, 1, 3, 134, 20, }, + { 1, 1, 1, 3, 134, 30, }, + { 0, 1, 1, 3, 142, 30, }, + { 2, 1, 1, 3, 142, 63, }, + { 1, 1, 1, 3, 142, 63, }, + { 0, 1, 1, 3, 151, 30, }, + { 2, 1, 1, 3, 151, 63, }, + { 1, 1, 1, 3, 151, 63, }, + { 0, 1, 1, 3, 159, 30, }, + { 2, 1, 1, 3, 159, 63, }, + { 1, 1, 1, 3, 159, 63, }, + { 0, 1, 2, 4, 42, 20, }, + { 2, 1, 2, 4, 42, 30, }, + { 1, 1, 2, 4, 42, 28, }, + { 0, 1, 2, 4, 58, 20, }, + { 2, 1, 2, 4, 58, 30, }, + { 1, 1, 2, 4, 58, 28, }, + { 0, 1, 2, 4, 106, 20, }, + { 2, 1, 2, 4, 106, 30, }, + { 1, 1, 2, 4, 106, 30, }, + { 0, 1, 2, 4, 122, 30, }, + { 2, 1, 2, 4, 122, 30, }, + { 1, 1, 2, 4, 122, 30, }, + { 0, 1, 2, 4, 138, 30, }, + { 2, 1, 2, 4, 138, 63, }, + { 1, 1, 2, 4, 138, 63, }, + { 0, 1, 2, 4, 155, 30, }, + { 2, 1, 2, 4, 155, 63, }, + { 1, 1, 2, 4, 155, 63, }, + { 0, 1, 2, 5, 42, 18, }, + { 2, 1, 2, 5, 42, 20, }, + { 1, 1, 2, 5, 42, 22, }, + { 0, 1, 2, 5, 58, 18, }, + { 2, 1, 2, 5, 58, 20, }, + { 1, 1, 2, 5, 58, 22, }, + { 0, 1, 2, 5, 106, 20, }, + { 2, 1, 2, 5, 106, 20, }, + { 1, 1, 2, 5, 106, 30, }, + { 0, 1, 2, 5, 122, 30, }, + { 2, 1, 2, 5, 122, 20, }, + { 1, 1, 2, 5, 122, 30, }, + { 0, 1, 2, 5, 138, 30, }, + { 2, 1, 2, 5, 138, 63, }, + { 1, 1, 2, 5, 138, 63, }, + { 0, 1, 2, 5, 155, 30, }, + { 2, 1, 2, 5, 155, 63, }, + { 1, 1, 2, 5, 155, 63, }, +}; + +RTW_DECL_TABLE_TXPWR_LMT(rtw8822b_txpwr_lmt_type0); + static const struct rtw_txpwr_lmt_cfg_pair rtw8822b_txpwr_lmt_type2[] = { { 0, 0, 0, 0, 1, 32, }, { 2, 0, 0, 0, 1, 28, }, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h index d4c268889368..4140e1ccb7b1 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.h @@ -9,9 +9,11 @@ extern const struct rtw_table rtw8822b_mac_tbl; extern const struct rtw_table rtw8822b_agc_tbl; extern const struct rtw_table rtw8822b_bb_tbl; extern const struct rtw_table rtw8822b_bb_pg_type2_tbl; +extern const struct rtw_table rtw8822b_bb_pg_type3_tbl; extern const struct rtw_table rtw8822b_bb_pg_type5_tbl; extern const struct rtw_table rtw8822b_rf_a_tbl; extern const struct rtw_table rtw8822b_rf_b_tbl; +extern const struct rtw_table rtw8822b_txpwr_lmt_type0_tbl; extern const struct rtw_table rtw8822b_txpwr_lmt_type2_tbl; extern const struct rtw_table rtw8822b_txpwr_lmt_type5_tbl; -- cgit v1.2.3-59-g8ed1b From 0b8db87da54178717d302ca5dc09285ad4922abc Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 17:33:41 +0800 Subject: rtw88: use rtw_phy_pg_cfg_pair struct, not arrays Use proper struct for BB PG tables. TODO: we need to find a way to store the tables that have condition values. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/phy.c | 15 +- drivers/net/wireless/realtek/rtw88/phy.h | 9 + .../net/wireless/realtek/rtw88/rtw8822b_table.c | 283 ++++++++++----------- .../net/wireless/realtek/rtw88/rtw8822c_table.c | 94 +++---- 4 files changed, 199 insertions(+), 202 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 69e7edb629f4..4a41134c420e 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -20,15 +20,6 @@ union phy_table_tile { struct phy_cfg_pair cfg; }; -struct phy_pg_cfg_pair { - u32 band; - u32 rf_path; - u32 tx_num; - u32 addr; - u32 bitmask; - u32 data; -}; - static const u32 db_invert_table[12][8] = { {10, 13, 16, 20, 25, 32, 40, 50}, @@ -1226,10 +1217,8 @@ static void rtw_phy_store_tx_power_by_rate(struct rtw_dev *rtwdev, void rtw_parse_tbl_bb_pg(struct rtw_dev *rtwdev, const struct rtw_table *tbl) { - const struct phy_pg_cfg_pair *p = tbl->data; - const struct phy_pg_cfg_pair *end = p + tbl->size / 6; - - BUILD_BUG_ON(sizeof(struct phy_pg_cfg_pair) != sizeof(u32) * 6); + const struct rtw_phy_pg_cfg_pair *p = tbl->data; + const struct rtw_phy_pg_cfg_pair *end = p + tbl->size; for (; p < end; p++) { if (p->addr == 0xfe || p->addr == 0xffe) { diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index 0dc7720aaad7..c389ef274ed8 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -66,6 +66,15 @@ struct rtw_txpwr_lmt_cfg_pair { s8 txpwr_lmt; }; +struct rtw_phy_pg_cfg_pair { + u32 band; + u32 rf_path; + u32 tx_num; + u32 addr; + u32 bitmask; + u32 data; +}; + #define RTW_DECL_TABLE_PHY_COND_CORE(name, cfg, path) \ const struct rtw_table name ## _tbl = { \ .data = name, \ diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c index 25537d147e86..b9010b111a13 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b_table.c @@ -11643,156 +11643,155 @@ static const u32 rtw8822b_bb[] = { RTW_DECL_TABLE_PHY_COND(rtw8822b_bb, rtw_phy_cfg_bb); -static const u32 rtw8822b_bb_pg_type2[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x40424446, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x38404244, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x30323436, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404244, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x30323436, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x38404244, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x30323436, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x42442628, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x34363840, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x26283032, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x40424446, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x38404244, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x30323436, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404244, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x30323436, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x38404244, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x30323436, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x42442628, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x34363840, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x26283032 +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type2[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x40424446, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x38404244, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x30323436, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x38404244, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x30323436, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x38404244, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x30323436, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x42442628, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x34363840, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x40424446, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x38404244, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x30323436, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x38404244, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x30323436, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x38404244, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x30323436, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x42442628, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x34363840, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x26283032, }, }; RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type2); -static const u32 rtw8822b_bb_pg_type3[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426 - +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type3[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426, }, }; RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type3); -static const u32 rtw8822b_bb_pg_type5[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426 +static const struct rtw_phy_pg_cfg_pair rtw8822b_bb_pg_type5[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x32343638, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x36384042, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x28303234, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x26283032, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x34363840, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x34363840, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x26283032, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x38402224, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x30323436, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x22242628, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x32343638, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x36384042, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x28303234, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x26283032, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x34363840, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x34363840, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x26283032, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x38402224, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x30323436, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x22242628, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x34363840, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x26283032, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x24262830, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x32343638, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x32343638, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x24262830, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x36382022, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x28303234, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x20222426, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x34363840, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x26283032, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x24262830, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x32343638, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x32343638, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x24262830, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x36382022, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x28303234, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x20222426, }, }; RTW_DECL_TABLE_BB_PG(rtw8822b_bb_pg_type5); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c index e2dd4c766077..d102a2c27757 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c_table.c @@ -1762,53 +1762,53 @@ static const u32 rtw8822c_bb[] = { RTW_DECL_TABLE_PHY_COND(rtw8822c_bb, rtw_phy_cfg_bb); -static const u32 rtw8822c_bb_pg_type0[] = { - 0, 0, 0, 0x00000c20, 0xffffffff, 0x484c5054, - 0, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, - 0, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, - 0, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, - 0, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, - 0, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, - 0, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, - 0, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, - 0, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, - 0, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, - 0, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, - 0, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, - 0, 1, 0, 0x00000e20, 0xffffffff, 0x484c5054, - 0, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, - 0, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, - 0, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, - 0, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, - 0, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, - 0, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, - 0, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, - 0, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, - 0, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, - 0, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, - 0, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, - 1, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, - 1, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, - 1, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, - 1, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, - 1, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, - 1, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, - 1, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, - 1, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, - 1, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, - 1, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, - 1, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, - 1, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, - 1, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, - 1, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, - 1, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, - 1, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, - 1, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, - 1, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, - 1, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, - 1, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, - 1, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, - 1, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044 +static const struct rtw_phy_pg_cfg_pair rtw8822c_bb_pg_type0[] = { + { 0, 0, 0, 0x00000c20, 0xffffffff, 0x484c5054, }, + { 0, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, }, + { 0, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, }, + { 0, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, }, + { 0, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, }, + { 0, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, }, + { 0, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, }, + { 0, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, }, + { 0, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, }, + { 0, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, }, + { 0, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, }, + { 0, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, }, + { 0, 1, 0, 0x00000e20, 0xffffffff, 0x484c5054, }, + { 0, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, }, + { 0, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, }, + { 0, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, }, + { 0, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, }, + { 0, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, }, + { 0, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, }, + { 0, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, }, + { 0, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, }, + { 0, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, }, + { 0, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, }, + { 0, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, }, + { 1, 0, 0, 0x00000c24, 0xffffffff, 0x54585c60, }, + { 1, 0, 0, 0x00000c28, 0xffffffff, 0x44484c50, }, + { 1, 0, 0, 0x00000c2c, 0xffffffff, 0x5054585c, }, + { 1, 0, 0, 0x00000c30, 0xffffffff, 0x4044484c, }, + { 1, 0, 1, 0x00000c34, 0xffffffff, 0x5054585c, }, + { 1, 0, 1, 0x00000c38, 0xffffffff, 0x4044484c, }, + { 1, 0, 0, 0x00000c3c, 0xffffffff, 0x5054585c, }, + { 1, 0, 0, 0x00000c40, 0xffffffff, 0x4044484c, }, + { 1, 0, 0, 0x00000c44, 0xffffffff, 0x585c383c, }, + { 1, 0, 1, 0x00000c48, 0xffffffff, 0x484c5054, }, + { 1, 0, 1, 0x00000c4c, 0xffffffff, 0x383c4044, }, + { 1, 1, 0, 0x00000e24, 0xffffffff, 0x54585c60, }, + { 1, 1, 0, 0x00000e28, 0xffffffff, 0x44484c50, }, + { 1, 1, 0, 0x00000e2c, 0xffffffff, 0x5054585c, }, + { 1, 1, 0, 0x00000e30, 0xffffffff, 0x4044484c, }, + { 1, 1, 1, 0x00000e34, 0xffffffff, 0x5054585c, }, + { 1, 1, 1, 0x00000e38, 0xffffffff, 0x4044484c, }, + { 1, 1, 0, 0x00000e3c, 0xffffffff, 0x5054585c, }, + { 1, 1, 0, 0x00000e40, 0xffffffff, 0x4044484c, }, + { 1, 1, 0, 0x00000e44, 0xffffffff, 0x585c383c, }, + { 1, 1, 1, 0x00000e48, 0xffffffff, 0x484c5054, }, + { 1, 1, 1, 0x00000e4c, 0xffffffff, 0x383c4044, }, }; RTW_DECL_TABLE_BB_PG(rtw8822c_bb_pg_type0); -- cgit v1.2.3-59-g8ed1b From ff0dfe5b0377c075986e8ac1c1516f5fbdb15b15 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 17:33:43 +0800 Subject: rtw88: rearrange if..else statements for rx rate indexes Driver just memset() rx_status to 0 before assigning rate indexes. And driver could never hit the 'else' because the driver checks if 'pkt_stat->rate >= DESC_RATEMCS0', so the 'else' statement can be removed. Also rearrange the if..else statements because DESC_RATEMCS0 is actually larger than DESC_RATE1M ~ DESC_RATE54M, move the check of 'pkt_stat->rate >= DESC_RATEMCS0' to the last to keep an increasing order. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/rx.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c index 36887f998090..9b90339ab697 100644 --- a/drivers/net/wireless/realtek/rtw88/rx.c +++ b/drivers/net/wireless/realtek/rtw88/rx.c @@ -160,19 +160,17 @@ void rtw_rx_fill_rx_status(struct rtw_dev *rtwdev, else if (pkt_stat->rate >= DESC_RATEMCS0) rx_status->encoding = RX_ENC_HT; - if (pkt_stat->rate >= DESC_RATEMCS0) { - rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx, - &rx_status->nss); - } else if (rx_status->band == NL80211_BAND_5GHZ && - pkt_stat->rate >= DESC_RATE6M && - pkt_stat->rate <= DESC_RATE54M) { + if (rx_status->band == NL80211_BAND_5GHZ && + pkt_stat->rate >= DESC_RATE6M && + pkt_stat->rate <= DESC_RATE54M) { rx_status->rate_idx = pkt_stat->rate - DESC_RATE6M; } else if (rx_status->band == NL80211_BAND_2GHZ && pkt_stat->rate >= DESC_RATE1M && pkt_stat->rate <= DESC_RATE54M) { rx_status->rate_idx = pkt_stat->rate - DESC_RATE1M; - } else { - rx_status->rate_idx = 0; + } else if (pkt_stat->rate >= DESC_RATEMCS0) { + rtw_desc_to_mcsrate(pkt_stat->rate, &rx_status->rate_idx, + &rx_status->nss); } rx_status->flag |= RX_FLAG_MACTIME_START; -- cgit v1.2.3-59-g8ed1b From 18a0696e85fde169e0109aa61d0505b2b935b59d Mon Sep 17 00:00:00 2001 From: Tzu-En Huang Date: Fri, 25 Oct 2019 17:33:44 +0800 Subject: rtw88: fix potential read outside array boundary The level of cckpd is from 0 to 4, and it is the index of array pd_lvl[] and cs_lvl[]. However, the length of both arrays are 4, which is smaller than the possible maximum input index. Enumerate cck level to make sure the max level will not be wrong if new level is added in future. Fixes: 479c4ee931a6 ("rtw88: add dynamic cck pd mechanism") Signed-off-by: Tzu-En Huang Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/phy.c | 17 ++++++++--------- drivers/net/wireless/realtek/rtw88/phy.h | 9 +++++++++ drivers/net/wireless/realtek/rtw88/rtw8822c.c | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 4a41134c420e..4adba44dbd74 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -109,7 +109,7 @@ static void rtw_phy_cck_pd_init(struct rtw_dev *rtwdev) for (i = 0; i <= RTW_CHANNEL_WIDTH_40; i++) { for (j = 0; j < RTW_RF_PATH_MAX; j++) - dm_info->cck_pd_lv[i][j] = 0; + dm_info->cck_pd_lv[i][j] = CCK_PD_LV0; } dm_info->cck_fa_avg = CCK_FA_AVG_RESET; @@ -461,7 +461,6 @@ static void rtw_phy_dpk_track(struct rtw_dev *rtwdev) chip->ops->dpk_track(rtwdev); } -#define CCK_PD_LV_MAX 5 #define CCK_PD_FA_LV1_MIN 1000 #define CCK_PD_FA_LV0_MAX 500 @@ -471,10 +470,10 @@ static u8 rtw_phy_cck_pd_lv_unlink(struct rtw_dev *rtwdev) u32 cck_fa_avg = dm_info->cck_fa_avg; if (cck_fa_avg > CCK_PD_FA_LV1_MIN) - return 1; + return CCK_PD_LV1; if (cck_fa_avg < CCK_PD_FA_LV0_MAX) - return 0; + return CCK_PD_LV0; return CCK_PD_LV_MAX; } @@ -494,15 +493,15 @@ static u8 rtw_phy_cck_pd_lv_link(struct rtw_dev *rtwdev) u32 cck_fa_avg = dm_info->cck_fa_avg; if (igi > CCK_PD_IGI_LV4_VAL && rssi > CCK_PD_RSSI_LV4_VAL) - return 4; + return CCK_PD_LV4; if (igi > CCK_PD_IGI_LV3_VAL && rssi > CCK_PD_RSSI_LV3_VAL) - return 3; + return CCK_PD_LV3; if (igi > CCK_PD_IGI_LV2_VAL || rssi > CCK_PD_RSSI_LV2_VAL) - return 2; + return CCK_PD_LV2; if (cck_fa_avg > CCK_PD_FA_LV1_MIN) - return 1; + return CCK_PD_LV1; if (cck_fa_avg < CCK_PD_FA_LV0_MAX) - return 0; + return CCK_PD_LV0; return CCK_PD_LV_MAX; } diff --git a/drivers/net/wireless/realtek/rtw88/phy.h b/drivers/net/wireless/realtek/rtw88/phy.h index c389ef274ed8..af916d8784cd 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.h +++ b/drivers/net/wireless/realtek/rtw88/phy.h @@ -146,6 +146,15 @@ rtw_get_tx_power_params(struct rtw_dev *rtwdev, u8 path, u8 rate, u8 bw, u8 ch, u8 regd, struct rtw_power_params *pwr_param); +enum rtw_phy_cck_pd_lv { + CCK_PD_LV0, + CCK_PD_LV1, + CCK_PD_LV2, + CCK_PD_LV3, + CCK_PD_LV4, + CCK_PD_LV_MAX, +}; + #define MASKBYTE0 0xff #define MASKBYTE1 0xff00 #define MASKBYTE2 0xff0000 diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 04ced3b2a247..174029836833 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -3295,8 +3295,8 @@ rtw8822c_phy_cck_pd_set_reg(struct rtw_dev *rtwdev, static void rtw8822c_phy_cck_pd_set(struct rtw_dev *rtwdev, u8 new_lvl) { struct rtw_dm_info *dm_info = &rtwdev->dm_info; - s8 pd_lvl[4] = {2, 4, 6, 8}; - s8 cs_lvl[4] = {2, 2, 2, 4}; + s8 pd_lvl[CCK_PD_LV_MAX] = {0, 2, 4, 6, 8}; + s8 cs_lvl[CCK_PD_LV_MAX] = {0, 2, 2, 2, 4}; u8 cur_lvl; u8 nrx, bw; -- cgit v1.2.3-59-g8ed1b From 5195b904264098839144d08d23c600811de2e2da Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 25 Oct 2019 17:33:45 +0800 Subject: rtw88: avoid FW info flood The FW info was printed everytime driver is powered on, such as leaving IDLE state. It will flood the kernel log. Move the FW info printing to callback when FW is loaded, so that will only be printed once when device is probed. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/mac.c | 17 ----------------- drivers/net/wireless/realtek/rtw88/main.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index c471117b1472..507970387b2a 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -567,21 +567,6 @@ download_firmware_to_mem(struct rtw_dev *rtwdev, const u8 *data, return 0; } -static void update_firmware_info(struct rtw_dev *rtwdev, - struct rtw_fw_state *fw) -{ - const struct rtw_fw_hdr *fw_hdr = - (const struct rtw_fw_hdr *)fw->firmware->data; - - fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); - fw->version = le16_to_cpu(fw_hdr->version); - fw->sub_version = fw_hdr->subversion; - fw->sub_index = fw_hdr->subindex; - - rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", - fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); -} - static int start_download_firmware(struct rtw_dev *rtwdev, const u8 *data, u32 size) { @@ -698,8 +683,6 @@ int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) if (ret) goto dlfw_fail; - update_firmware_info(rtwdev, fw); - /* reset desc and index */ rtw_hci_setup(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 7c1b89c4fb6c..021668f1b74f 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1022,12 +1022,22 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context) { struct rtw_dev *rtwdev = context; struct rtw_fw_state *fw = &rtwdev->fw; + const struct rtw_fw_hdr *fw_hdr; if (!firmware) rtw_err(rtwdev, "failed to request firmware\n"); + fw_hdr = (const struct rtw_fw_hdr *)firmware->data; + fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); + fw->version = le16_to_cpu(fw_hdr->version); + fw->sub_version = fw_hdr->subversion; + fw->sub_index = fw_hdr->subindex; + fw->firmware = firmware; complete_all(&fw->completion); + + rtw_info(rtwdev, "Firmware version %u.%u.%u, H2C version %u\n", + fw->version, fw->sub_version, fw->sub_index, fw->h2c_version); } static int rtw_load_firmware(struct rtw_dev *rtwdev, const char *fw_name) -- cgit v1.2.3-59-g8ed1b From baff8da6e1636420ce04cadd6df56e137fa6e005 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 25 Oct 2019 12:30:56 +0100 Subject: rtw88: remove redundant null pointer check on arrays The checks to see if swing_table->n or swing_table->p are null are redundant since n and p are arrays and can never be null if swing_table is non-null. I believe these are redundant checks and can be safely removed, especially the checks implies that these are not arrays which can lead to confusion. Addresses-Coverity: ("Array compared against 0") Fixes: c97ee3e0bea2 ("rtw88: add power tracking support") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/phy.c b/drivers/net/wireless/realtek/rtw88/phy.c index 4adba44dbd74..a3e1e9578b65 100644 --- a/drivers/net/wireless/realtek/rtw88/phy.c +++ b/drivers/net/wireless/realtek/rtw88/phy.c @@ -2059,7 +2059,7 @@ s8 rtw_phy_pwrtrack_get_pwridx(struct rtw_dev *rtwdev, return 0; } - if (!swing_table || !swing_table->n || !swing_table->p) { + if (!swing_table) { rtw_warn(rtwdev, "swing table not configured\n"); return 0; } -- cgit v1.2.3-59-g8ed1b From cbbd7f9a5e76e21a3d2ad8b0df030d1200a02110 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 00:21:30 +0530 Subject: rtlwifi: rtl8192c: Drop condition with no effect As the "else if" and "else" branch body are identical the condition has no effect. So drop the "else if" condition. Signed-off-by: Saurav Girepunje Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c index f2908ee5f860..4bef237f488d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/dm_common.c @@ -1649,8 +1649,6 @@ static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw, u8 tmp1byte) (rtlpriv->btcoexist.bt_rssi_state & BT_RSSI_STATE_SPECIAL_LOW)) { rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); - } else if (rtlpriv->btcoexist.bt_service == BT_PAN) { - rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte); } else { rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, tmp1byte); } -- cgit v1.2.3-59-g8ed1b From 6db774c1725059f98e4fce97f878688248584be5 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 00:32:04 +0530 Subject: b43: main: Fix use true/false for bool type use true/false on bool type variable assignment. Signed-off-by: Saurav Girepunje Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index b85603e91c7a..39da1a4c30ac 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3600,7 +3600,7 @@ static void b43_tx_work(struct work_struct *work) else err = b43_dma_tx(dev, skb); if (err == -ENOSPC) { - wl->tx_queue_stopped[queue_num] = 1; + wl->tx_queue_stopped[queue_num] = true; ieee80211_stop_queue(wl->hw, queue_num); skb_queue_head(&wl->tx_queue[queue_num], skb); break; @@ -3611,7 +3611,7 @@ static void b43_tx_work(struct work_struct *work) } if (!err) - wl->tx_queue_stopped[queue_num] = 0; + wl->tx_queue_stopped[queue_num] = false; } #if B43_DEBUG @@ -5603,7 +5603,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) /* Initialize queues and flags. */ for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) { skb_queue_head_init(&wl->tx_queue[queue_num]); - wl->tx_queue_stopped[queue_num] = 0; + wl->tx_queue_stopped[queue_num] = false; } snprintf(chip_name, ARRAY_SIZE(chip_name), -- cgit v1.2.3-59-g8ed1b From a9160bb35ad9ada8428a4d48426f7fc128db40cc Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 00:42:59 +0530 Subject: b43: dma: Fix use true/false for bool type variable use true/false for bool type variables assignment. Signed-off-by: Saurav Girepunje Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/b43/dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 31bf71a80c26..9733c64bf978 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1400,7 +1400,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) /* This TX ring is full. */ unsigned int skb_mapping = skb_get_queue_mapping(skb); ieee80211_stop_queue(dev->wl->hw, skb_mapping); - dev->wl->tx_queue_stopped[skb_mapping] = 1; + dev->wl->tx_queue_stopped[skb_mapping] = true; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); @@ -1566,7 +1566,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } if (dev->wl->tx_queue_stopped[ring->queue_prio]) { - dev->wl->tx_queue_stopped[ring->queue_prio] = 0; + dev->wl->tx_queue_stopped[ring->queue_prio] = false; } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ -- cgit v1.2.3-59-g8ed1b From 4b15f83adaf170ce55c8a572f66fe26342326983 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 18:46:24 +0530 Subject: rtlwifi: rtl8821ae: Drop condition with no effect As the "else if" and "else" branch body are identical the condition has no effect. So drop the "else if" condition. Signed-off-by: Saurav Girepunje Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index c54b80de25d3..c1a04efa69ea 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -3548,8 +3548,6 @@ void rtl8821ae_phy_sw_chnl_callback(struct ieee80211_hw *hw) if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { if (36 <= channel && channel <= 64) data = 0x114E9; - else if (100 <= channel && channel <= 140) - data = 0x110E9; else data = 0x110E9; rtl8821ae_phy_set_rf_reg(hw, path, RF_APK, -- cgit v1.2.3-59-g8ed1b From 086ddf860650cfa3065d6698fae81335b1846cdb Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 30 Oct 2019 16:08:44 +0800 Subject: mt7601u: use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs fops It is more clear to use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs file operation rather than DEFINE_SIMPLE_ATTRIBUTE. Signed-off-by: zhong jiang Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt7601u/debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index 5e549831370c..300242bce799 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -27,7 +27,7 @@ mt76_reg_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); static int mt7601u_ampdu_stat_read(struct seq_file *file, void *data) -- cgit v1.2.3-59-g8ed1b From 0dc269314a251816aeee3abe38184071cf96e733 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:10:41 +0800 Subject: ath10k: remove unneeded semicolon remove unneeded semicolon. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 9f0e7b4943ec..d95b63f133ab 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2073,7 +2073,7 @@ static void ath10k_htt_rx_mpdu_desc_pn_hl(struct htt_hl_rx_desc *rx_desc, case 24: pn->pn24 = __le32_to_cpu(rx_desc->pn_31_0); break; - }; + } } static bool ath10k_htt_rx_pn_cmp48(union htt_rx_pn_t *new_pn, -- cgit v1.2.3-59-g8ed1b From 85630469d268d3b7b4f79aa28948c1b7a2d6433b Mon Sep 17 00:00:00 2001 From: Lior David Date: Mon, 28 Oct 2019 19:24:37 +0200 Subject: wil6210: add SPDX license identifiers Change all files to add SPDX license identifiers and remove license text. This is only an administrative change, there is no change in actual license or copyright for any file. Signed-off-by: Lior David Signed-off-by: Maya Erez Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/boot_loader.h | 13 +------------ drivers/net/wireless/ath/wil6210/cfg80211.c | 13 +------------ drivers/net/wireless/ath/wil6210/debug.c | 13 +------------ drivers/net/wireless/ath/wil6210/debugfs.c | 13 +------------ drivers/net/wireless/ath/wil6210/ethtool.c | 13 +------------ drivers/net/wireless/ath/wil6210/fw.c | 13 +------------ drivers/net/wireless/ath/wil6210/fw.h | 13 +------------ drivers/net/wireless/ath/wil6210/fw_inc.c | 13 +------------ drivers/net/wireless/ath/wil6210/interrupt.c | 13 +------------ drivers/net/wireless/ath/wil6210/main.c | 13 +------------ drivers/net/wireless/ath/wil6210/netdev.c | 13 +------------ drivers/net/wireless/ath/wil6210/p2p.c | 13 +------------ drivers/net/wireless/ath/wil6210/pcie_bus.c | 13 +------------ drivers/net/wireless/ath/wil6210/pm.c | 13 +------------ drivers/net/wireless/ath/wil6210/pmc.c | 13 +------------ drivers/net/wireless/ath/wil6210/pmc.h | 17 ++--------------- drivers/net/wireless/ath/wil6210/rx_reorder.c | 13 +------------ drivers/net/wireless/ath/wil6210/trace.c | 13 +------------ drivers/net/wireless/ath/wil6210/trace.h | 13 +------------ drivers/net/wireless/ath/wil6210/txrx.c | 13 +------------ drivers/net/wireless/ath/wil6210/txrx.h | 13 +------------ drivers/net/wireless/ath/wil6210/txrx_edma.c | 13 +------------ drivers/net/wireless/ath/wil6210/txrx_edma.h | 13 +------------ drivers/net/wireless/ath/wil6210/wil6210.h | 13 +------------ drivers/net/wireless/ath/wil6210/wil_crash_dump.c | 13 +------------ drivers/net/wireless/ath/wil6210/wil_platform.c | 15 ++------------- drivers/net/wireless/ath/wil6210/wil_platform.h | 13 +------------ drivers/net/wireless/ath/wil6210/wmi.c | 13 +------------ drivers/net/wireless/ath/wil6210/wmi.h | 13 +------------ 29 files changed, 31 insertions(+), 352 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wil6210/boot_loader.h b/drivers/net/wireless/ath/wil6210/boot_loader.h index d32c1f4e533a..a8a43c25f843 100644 --- a/drivers/net/wireless/ath/wil6210/boot_loader.h +++ b/drivers/net/wireless/ath/wil6210/boot_loader.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* Copyright (c) 2015 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains the definitions for the boot loader diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c70854ea5634..7d6f14420855 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index a9befb971cc4..396c94c53702 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2013,2016 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 304b4d4e506a..11d0c79e9056 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index a04c87ffd37b..912c4eaf017b 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/fw.c b/drivers/net/wireless/ath/wil6210/fw.c index 3e2bbbceca06..6d3413a44b05 100644 --- a/drivers/net/wireless/ath/wil6210/fw.c +++ b/drivers/net/wireless/ath/wil6210/fw.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index fa3164765b20..540fa1607794 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2014,2016 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __WIL_FW_H__ #define __WIL_FW_H__ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 94ebfa338e3f..fbc84c03406b 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Algorithmic part of the firmware download. diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index b00a13d6d530..b1480b41cd3a 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 9b72202eeadc..06091d8a9e23 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index a87bb84a8286..07b4a252a23c 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index db087ea58ddf..f26bf046d889 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index f1a282364119..c174323c5c0b 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 56143e7670ed..ed4df561e5c5 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index 4b7ac14fc2a7..9b4ca6b256d2 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/pmc.h b/drivers/net/wireless/ath/wil6210/pmc.h index 92b8c4d84a6a..b3d79eb50a43 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.h +++ b/drivers/net/wireless/ath/wil6210/pmc.h @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2012-2015 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ +/* SPDX-License-Identifier: ISC */ +/* Copyright (c) 2012-2015 Qualcomm Atheros, Inc. */ #include diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index 13246d216803..d385bc03033a 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/trace.c b/drivers/net/wireless/ath/wil6210/trace.c index cd2534b9c5aa..6909e989baec 100644 --- a/drivers/net/wireless/ath/wil6210/trace.c +++ b/drivers/net/wireless/ath/wil6210/trace.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2013 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/trace.h b/drivers/net/wireless/ath/wil6210/trace.h index 36ebfcf9ef30..11c989e95880 100644 --- a/drivers/net/wireless/ath/wil6210/trace.h +++ b/drivers/net/wireless/ath/wil6210/trace.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2013-2016 Qualcomm Atheros, Inc. * Copyright (c) 2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #undef TRACE_SYSTEM diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 598c1fba9dac..8ebc6d59aa74 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index 5120475b0cd7..1f4c8ec75be8 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef WIL6210_TXRX_H diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 04d576deae72..778b63be6a9a 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index 136c51c338cf..c744c65225da 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2016,2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef WIL6210_TXRX_EDMA_H diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0783c7963621..97626bfd4dac 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __WIL6210_H__ diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index 772cb00c2002..1332eb8c831f 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "wil6210.h" diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c index 4eed05bddb60..10e10dc9fedf 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.c +++ b/drivers/net/wireless/ath/wil6210/wil_platform.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* - * Copyright (c) 2014 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2014-2016 Qualcomm Atheros, Inc. */ #include diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.h b/drivers/net/wireless/ath/wil6210/wil_platform.h index bca090611477..5ff66202238d 100644 --- a/drivers/net/wireless/ath/wil6210/wil_platform.h +++ b/drivers/net/wireless/ath/wil6210/wil_platform.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __WIL_PLATFORM_H__ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index f9a006d58a95..7a0d934eb271 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index a2f7034489ae..6bd4ccee28ab 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -1,19 +1,8 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2006-2012 Wilocity - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* -- cgit v1.2.3-59-g8ed1b From d77ef82c72edbbc3adcd33f0cf14fe1c51d6a27f Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 00:53:10 +0530 Subject: ath5k: eeprom: Remove unneeded variable Remove unneeded ret variable from ath5k_eeprom_read_spur_chans() Signed-off-by: Saurav Girepunje Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath5k/eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 94d34ee02265..307f1fea0a88 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1707,7 +1707,7 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u32 offset; u16 val; - int ret = 0, i; + int i; offset = AR5K_EEPROM_CTL(ee->ee_version) + AR5K_EEPROM_N_CTLS(ee->ee_version); @@ -1730,7 +1730,7 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) } } - return ret; + return 0; } -- cgit v1.2.3-59-g8ed1b From 6dea30b4fd548dd68e6a98da01ffeb50e7f99150 Mon Sep 17 00:00:00 2001 From: Eduardo Abinader Date: Wed, 30 Oct 2019 09:41:41 +0100 Subject: wcn36xx: remove unecessary return Signed-off-by: Eduardo Abinader Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 79998a3ddb7a..dcae79c576bf 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -935,8 +935,6 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, out: mutex_unlock(&wcn->conf_mutex); - - return; } /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */ -- cgit v1.2.3-59-g8ed1b From d74361dc58709fa200c2db86fa5cf086dc4acec8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 31 Oct 2019 06:53:45 +0100 Subject: cxgb4/l2t: Simplify 't4_l2e_free()' and '_t4_l2e_free()' Use '__skb_queue_purge()' instead of re-implementing it. Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 1a407d3c1d67..e9e45006632d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -351,15 +351,13 @@ exists: static void _t4_l2e_free(struct l2t_entry *e) { struct l2t_data *d; - struct sk_buff *skb; if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ if (e->neigh) { neigh_release(e->neigh); e->neigh = NULL; } - while ((skb = __skb_dequeue(&e->arpq)) != NULL) - kfree_skb(skb); + __skb_queue_purge(&e->arpq); } d = container_of(e, struct l2t_data, l2tab[e->idx]); @@ -370,7 +368,6 @@ static void _t4_l2e_free(struct l2t_entry *e) static void t4_l2e_free(struct l2t_entry *e) { struct l2t_data *d; - struct sk_buff *skb; spin_lock_bh(&e->lock); if (atomic_read(&e->refcnt) == 0) { /* hasn't been recycled */ @@ -378,8 +375,7 @@ static void t4_l2e_free(struct l2t_entry *e) neigh_release(e->neigh); e->neigh = NULL; } - while ((skb = __skb_dequeue(&e->arpq)) != NULL) - kfree_skb(skb); + __skb_queue_purge(&e->arpq); } spin_unlock_bh(&e->lock); -- cgit v1.2.3-59-g8ed1b From 94e768373ae10d72528307256a869c846dc4ba00 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:06 +0200 Subject: mlxsw: reg: Extend PMLP tx/rx lane value size to 4 bits The tx/rx lane fields got extended to 4 bits, update the reg field description accordingly. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 7f7f1b95290f..7fd6fd9c5244 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -3969,6 +3969,7 @@ MLXSW_ITEM32(reg, pmlp, local_port, 0x00, 16, 8); * 1 - Lane 0 is used. * 2 - Lanes 0 and 1 are used. * 4 - Lanes 0, 1, 2 and 3 are used. + * 8 - Lanes 0-7 are used. * Access: RW */ MLXSW_ITEM32(reg, pmlp, width, 0x00, 0, 8); @@ -3983,14 +3984,14 @@ MLXSW_ITEM32_INDEXED(reg, pmlp, module, 0x04, 0, 8, 0x04, 0x00, false); * Tx Lane. When rxtx field is cleared, this field is used for Rx as well. * Access: RW */ -MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 2, 0x04, 0x00, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, tx_lane, 0x04, 16, 4, 0x04, 0x00, false); /* reg_pmlp_rx_lane * Rx Lane. When rxtx field is cleared, this field is ignored and Rx lane is * equal to Tx lane. * Access: RW */ -MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 2, 0x04, 0x00, false); +MLXSW_ITEM32_INDEXED(reg, pmlp, rx_lane, 0x04, 24, 4, 0x04, 0x00, false); static inline void mlxsw_reg_pmlp_pack(char *payload, u8 local_port) { -- cgit v1.2.3-59-g8ed1b From a513b1a5910bfc15d5a42e969e66a7986fd32819 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:07 +0200 Subject: mlxsw: reg: Add Port Module Type Mapping Register The PMTM allows query or configuration of module types. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index 7fd6fd9c5244..bec035ee5349 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5375,6 +5375,55 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port, MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0); } +/* PMTM - Port Module Type Mapping Register + * ---------------------------------------- + * The PMTM allows query or configuration of module types. + */ +#define MLXSW_REG_PMTM_ID 0x5067 +#define MLXSW_REG_PMTM_LEN 0x10 + +MLXSW_REG_DEFINE(pmtm, MLXSW_REG_PMTM_ID, MLXSW_REG_PMTM_LEN); + +/* reg_pmtm_module + * Module number. + * Access: Index + */ +MLXSW_ITEM32(reg, pmtm, module, 0x00, 16, 8); + +enum mlxsw_reg_pmtm_module_type { + /* Backplane with 4 lanes */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_4X, + /* QSFP */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP, + /* SFP */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP, + /* Backplane with single lane */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_1X = 4, + /* Backplane with two lane */ + MLXSW_REG_PMTM_MODULE_TYPE_BP_2X = 8, + /* Chip2Chip */ + MLXSW_REG_PMTM_MODULE_TYPE_C2C = 10, +}; + +/* reg_pmtm_module_type + * Module type. + * Access: RW + */ +MLXSW_ITEM32(reg, pmtm, module_type, 0x04, 0, 4); + +static inline void mlxsw_reg_pmtm_pack(char *payload, u8 module) +{ + MLXSW_REG_ZERO(pmtm, payload); + mlxsw_reg_pmtm_module_set(payload, module); +} + +static inline void +mlxsw_reg_pmtm_unpack(char *payload, + enum mlxsw_reg_pmtm_module_type *module_type) +{ + *module_type = mlxsw_reg_pmtm_module_type_get(payload); +} + /* HTGT - Host Trap Group Table * ---------------------------- * Configures the properties for forwarding to CPU. @@ -10545,6 +10594,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { MLXSW_REG(pbmc), MLXSW_REG(pspa), MLXSW_REG(pplr), + MLXSW_REG(pmtm), MLXSW_REG(htgt), MLXSW_REG(hpkt), MLXSW_REG(rgcr), -- cgit v1.2.3-59-g8ed1b From 25911e1b97971a06b4c053f70c7c1eb0c33a607e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:08 +0200 Subject: mlxsw: spectrum: Use PMTM register to get max module width Currently the max module width is hard-coded according to ASIC type. That is not entirely correct, as the max module width might differ per-board. Use PMTM register to query FW for maximal width of a module. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 29 ++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/core.h | 1 + drivers/net/ethernet/mellanox/mlxsw/port.h | 2 - drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 54 ++++++++++++++++++-------- 4 files changed, 67 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 2b59f84b14f9..235d1990c127 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -2017,6 +2017,35 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get); +int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module) +{ + enum mlxsw_reg_pmtm_module_type module_type; + char pmtm_pl[MLXSW_REG_PMTM_LEN]; + int err; + + mlxsw_reg_pmtm_pack(pmtm_pl, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(pmtm), pmtm_pl); + if (err) + return err; + mlxsw_reg_pmtm_unpack(pmtm_pl, &module_type); + + /* Here we need to get the module width according to the module type. */ + + switch (module_type) { + case MLXSW_REG_PMTM_MODULE_TYPE_BP_4X: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_QSFP: + return 4; + case MLXSW_REG_PMTM_MODULE_TYPE_BP_2X: + return 2; + case MLXSW_REG_PMTM_MODULE_TYPE_BP_SFP: /* fall through */ + case MLXSW_REG_PMTM_MODULE_TYPE_BP_1X: + return 1; + default: + return -EINVAL; + } +} +EXPORT_SYMBOL(mlxsw_core_module_max_width); + static void mlxsw_core_buf_dump_dbg(struct mlxsw_core *mlxsw_core, const char *buf, size_t size) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index f25037074e2d..0d18bee6d140 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -200,6 +200,7 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, struct devlink_port * mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, u8 local_port); +int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module); int mlxsw_core_schedule_dw(struct delayed_work *dwork, unsigned long delay); bool mlxsw_core_schedule_work(struct work_struct *work); diff --git a/drivers/net/ethernet/mellanox/mlxsw/port.h b/drivers/net/ethernet/mellanox/mlxsw/port.h index a33eeef0b00c..741fd2989d12 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/port.h +++ b/drivers/net/ethernet/mellanox/mlxsw/port.h @@ -24,8 +24,6 @@ #define MLXSW_PORT_DONT_CARE 0xFF -#define MLXSW_PORT_MODULE_MAX_WIDTH 4 - enum mlxsw_port_admin_status { MLXSW_PORT_ADMIN_STATUS_UP = 1, MLXSW_PORT_ADMIN_STATUS_DOWN = 2, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 97be4bc9a02f..149b2cc2b4fd 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4038,17 +4038,18 @@ err_port_to_module_alloc: return err; } -static u8 mlxsw_sp_cluster_base_port_get(u8 local_port) +static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width) { - u8 offset = (local_port - 1) % MLXSW_SP_PORTS_PER_CLUSTER_MAX; + u8 offset = (local_port - 1) % max_width; return local_port - offset; } static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, - u8 module, unsigned int count, u8 offset) + u8 module, unsigned int count, u8 offset, + unsigned int max_width) { - u8 width = MLXSW_PORT_MODULE_MAX_WIDTH / count; + u8 width = max_width / count; int err, i; for (i = 0; i < count; i++) { @@ -4068,9 +4069,10 @@ err_port_create: } static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, - u8 base_port, unsigned int count) + u8 base_port, unsigned int count, + unsigned int max_width) { - u8 local_port, module, width = MLXSW_PORT_MODULE_MAX_WIDTH; + u8 local_port, module, width = max_width; int i; /* Split by four means we need to re-create two ports, otherwise @@ -4096,7 +4098,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); u8 local_ports_in_1x, local_ports_in_2x, offset; struct mlxsw_sp_port *mlxsw_sp_port; - u8 module, cur_width, base_port; + u8 module, base_port; + int max_width; int i; int err; @@ -4116,7 +4119,14 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, } module = mlxsw_sp_port->mapping.module; - cur_width = mlxsw_sp_port->mapping.width; + + max_width = mlxsw_core_module_max_width(mlxsw_core, + mlxsw_sp_port->mapping.module); + if (max_width < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); + return max_width; + } if (count != 2 && count != 4) { netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); @@ -4124,7 +4134,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - if (cur_width != MLXSW_PORT_MODULE_MAX_WIDTH) { + /* Split port with non-max module width cannot be split. */ + if (mlxsw_sp_port->mapping.width != max_width) { netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); return -EINVAL; @@ -4141,7 +4152,8 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, } } else { offset = local_ports_in_1x; - base_port = mlxsw_sp_cluster_base_port_get(local_port); + base_port = mlxsw_sp_cluster_base_port_get(local_port, + max_width); if (mlxsw_sp->ports[base_port + 1] || mlxsw_sp->ports[base_port + 3]) { netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); @@ -4155,7 +4167,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, module, count, - offset); + offset, max_width); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n"); goto err_port_split_create; @@ -4164,7 +4176,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return 0; err_port_split_create: - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width); return err; } @@ -4174,8 +4186,9 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); u8 local_ports_in_1x, local_ports_in_2x, offset; struct mlxsw_sp_port *mlxsw_sp_port; - u8 cur_width, base_port; unsigned int count; + int max_width; + u8 base_port; int i; if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) || @@ -4199,15 +4212,22 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - cur_width = mlxsw_sp_port->mapping.width; - count = cur_width == 1 ? 4 : 2; + max_width = mlxsw_core_module_max_width(mlxsw_core, + mlxsw_sp_port->mapping.module); + if (max_width < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot get max width of port module\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot get max width of port module"); + return max_width; + } + + count = max_width / mlxsw_sp_port->mapping.width; if (count == 2) offset = local_ports_in_2x; else offset = local_ports_in_1x; - base_port = mlxsw_sp_cluster_base_port_get(local_port); + base_port = mlxsw_sp_cluster_base_port_get(local_port, max_width); /* Determine which ports to remove. */ if (count == 2 && local_port >= base_port + 2) @@ -4217,7 +4237,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width); return 0; } -- cgit v1.2.3-59-g8ed1b From 2e6a2d7b4508ea01b276d8c7350582a07dca1c23 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:09 +0200 Subject: mlxsw: spectrum: Move max_width check up before count check The fact that the port cannot be split further should be checked before checking the count, so move it. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 149b2cc2b4fd..e0111e0a1a35 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4128,12 +4128,6 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return max_width; } - if (count != 2 && count != 4) { - netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); - NL_SET_ERR_MSG_MOD(extack, "Port can only be split into 2 or 4 ports"); - return -EINVAL; - } - /* Split port with non-max module width cannot be split. */ if (mlxsw_sp_port->mapping.width != max_width) { netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); @@ -4141,6 +4135,12 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } + if (count != 2 && count != 4) { + netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); + NL_SET_ERR_MSG_MOD(extack, "Port can only be split into 2 or 4 ports"); + return -EINVAL; + } + /* Make sure we have enough slave (even) ports for the split. */ if (count == 2) { offset = local_ports_in_2x; -- cgit v1.2.3-59-g8ed1b From 26a6befa5df79dddb1a1c464b5758de9d618ee23 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:10 +0200 Subject: mlxsw: spectrum: Distinguish between unsplittable and split port Currently when user does split, he is not able to distinguish if the port cannot be split because it is already split, or because it cannot be split at all. Add another check for split flag to distinguish this. Also add check forbidding split when maximal width is 1. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index e0111e0a1a35..3644fca096ac 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4118,6 +4118,13 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } + /* Split ports cannot be split. */ + if (mlxsw_sp_port->split) { + netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); + NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); + return -EINVAL; + } + module = mlxsw_sp_port->mapping.module; max_width = mlxsw_core_module_max_width(mlxsw_core, @@ -4128,10 +4135,10 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return max_width; } - /* Split port with non-max module width cannot be split. */ - if (mlxsw_sp_port->mapping.width != max_width) { - netdev_err(mlxsw_sp_port->dev, "Port cannot be split further\n"); - NL_SET_ERR_MSG_MOD(extack, "Port cannot be split further"); + /* Split port with non-max and 1 module width cannot be split. */ + if (mlxsw_sp_port->mapping.width != max_width || max_width == 1) { + netdev_err(mlxsw_sp_port->dev, "Port cannot be split\n"); + NL_SET_ERR_MSG_MOD(extack, "Port cannot be split"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 4a7f970f1240523b1bbabac88811e429de4697cb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:11 +0200 Subject: mlxsw: spectrum: Replace port_to_module array with array of structs Store the initial PMLP register configuration into array of structures instead of just simple array of module numbers. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 105 +++++++++++++++++-------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 18 +++-- 2 files changed, 84 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3644fca096ac..ee15428ca740 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -748,9 +748,9 @@ mlxsw_sp_port_system_port_mapping_set(struct mlxsw_sp_port *mlxsw_sp_port) return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sspr), sspr_pl); } -static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, - u8 local_port, u8 *p_module, - u8 *p_width, u8 *p_lane) +static int +mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, + struct mlxsw_sp_port_mapping *port_mapping) { char pmlp_pl[MLXSW_REG_PMLP_LEN]; int err; @@ -759,9 +759,9 @@ static int mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); if (err) return err; - *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); - *p_lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); + port_mapping->module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); + port_mapping->width = mlxsw_reg_pmlp_width_get(pmlp_pl); + port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); return 0; } @@ -3979,14 +3979,13 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) if (mlxsw_sp_port_created(mlxsw_sp, i)) mlxsw_sp_port_remove(mlxsw_sp, i); mlxsw_sp_cpu_port_remove(mlxsw_sp); - kfree(mlxsw_sp->port_to_module); kfree(mlxsw_sp->ports); } static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) { unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); - u8 module, width, lane; + struct mlxsw_sp_port_mapping *port_mapping; size_t alloc_size; int i; int err; @@ -3996,48 +3995,78 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) if (!mlxsw_sp->ports) return -ENOMEM; - mlxsw_sp->port_to_module = kmalloc_array(max_ports, sizeof(int), - GFP_KERNEL); - if (!mlxsw_sp->port_to_module) { - err = -ENOMEM; - goto err_port_to_module_alloc; - } - err = mlxsw_sp_cpu_port_create(mlxsw_sp); if (err) goto err_cpu_port_create; for (i = 1; i < max_ports; i++) { - /* Mark as invalid */ - mlxsw_sp->port_to_module[i] = -1; - - err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &module, - &width, &lane); - if (err) - goto err_port_module_info_get; - if (!width) + port_mapping = mlxsw_sp->port_mapping[i]; + if (!port_mapping) continue; - mlxsw_sp->port_to_module[i] = module; err = mlxsw_sp_port_create(mlxsw_sp, i, false, - module, width, lane); + port_mapping->module, + port_mapping->width, + port_mapping->lane); if (err) goto err_port_create; } return 0; err_port_create: -err_port_module_info_get: for (i--; i >= 1; i--) if (mlxsw_sp_port_created(mlxsw_sp, i)) mlxsw_sp_port_remove(mlxsw_sp, i); mlxsw_sp_cpu_port_remove(mlxsw_sp); err_cpu_port_create: - kfree(mlxsw_sp->port_to_module); -err_port_to_module_alloc: kfree(mlxsw_sp->ports); return err; } +static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + struct mlxsw_sp_port_mapping port_mapping; + int i; + int err; + + mlxsw_sp->port_mapping = kcalloc(max_ports, + sizeof(struct mlxsw_sp_port_mapping *), + GFP_KERNEL); + if (!mlxsw_sp->port_mapping) + return -ENOMEM; + + for (i = 1; i < max_ports; i++) { + err = mlxsw_sp_port_module_info_get(mlxsw_sp, i, &port_mapping); + if (err) + goto err_port_module_info_get; + if (!port_mapping.width) + continue; + + mlxsw_sp->port_mapping[i] = kmemdup(&port_mapping, + sizeof(port_mapping), + GFP_KERNEL); + if (!mlxsw_sp->port_mapping[i]) + goto err_port_module_info_dup; + } + return 0; + +err_port_module_info_get: +err_port_module_info_dup: + for (i--; i >= 1; i--) + kfree(mlxsw_sp->port_mapping[i]); + kfree(mlxsw_sp->port_mapping); + return err; +} + +static void mlxsw_sp_port_module_info_fini(struct mlxsw_sp *mlxsw_sp) +{ + int i; + + for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) + kfree(mlxsw_sp->port_mapping[i]); + kfree(mlxsw_sp->port_mapping); +} + static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width) { u8 offset = (local_port - 1) % max_width; @@ -4072,7 +4101,8 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, unsigned int count, unsigned int max_width) { - u8 local_port, module, width = max_width; + struct mlxsw_sp_port_mapping *port_mapping; + u8 local_port, width = max_width; int i; /* Split by four means we need to re-create two ports, otherwise @@ -4082,12 +4112,12 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, for (i = 0; i < count; i++) { local_port = base_port + i * 2; - if (mlxsw_sp->port_to_module[local_port] < 0) + port_mapping = mlxsw_sp->port_mapping[local_port]; + if (!port_mapping) continue; - module = mlxsw_sp->port_to_module[local_port]; - mlxsw_sp_port_create(mlxsw_sp, local_port, false, module, - width, 0); + mlxsw_sp_port_create(mlxsw_sp, local_port, false, + port_mapping->module, width, 0); } } @@ -4951,6 +4981,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_dpipe_init; } + err = mlxsw_sp_port_module_info_init(mlxsw_sp); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to init port module info\n"); + goto err_port_module_info_init; + } + err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -4960,6 +4996,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: + mlxsw_sp_port_module_info_fini(mlxsw_sp); +err_port_module_info_init: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), @@ -5052,6 +5090,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); + mlxsw_sp_port_module_info_fini(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); unregister_netdevice_notifier_net(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->netdevice_nb); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a5fdd84b4ca7..3a823911a9d9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -143,6 +143,12 @@ struct mlxsw_sp_port_type_speed_ops; struct mlxsw_sp_ptp_state; struct mlxsw_sp_ptp_ops; +struct mlxsw_sp_port_mapping { + u8 module; + u8 width; + u8 lane; +}; + struct mlxsw_sp { struct mlxsw_sp_port **ports; struct mlxsw_core *core; @@ -150,7 +156,7 @@ struct mlxsw_sp { unsigned char base_mac[ETH_ALEN]; const unsigned char *mac_mask; struct mlxsw_sp_upper *lags; - int *port_to_module; + struct mlxsw_sp_port_mapping **port_mapping; struct mlxsw_sp_sb *sb; struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_router *router; @@ -259,11 +265,11 @@ struct mlxsw_sp_port { struct ieee_pfc *pfc; enum mlxsw_reg_qpts_trust_state trust_state; } dcb; - struct { - u8 module; - u8 width; - u8 lane; - } mapping; + struct mlxsw_sp_port_mapping mapping; /* mapping is constant during the + * mlxsw_sp_port lifetime, however + * the same localport can have + * different mapping. + */ /* TC handles */ struct list_head mall_tc_list; struct { -- cgit v1.2.3-59-g8ed1b From 7b39fa5befbb531a91bbd91ecac516251063afe3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:12 +0200 Subject: mlxsw: spectrum: Use mapping of port being split for creating split ports Don't use constant max width value and instead of that, use the actual width of the port. Also don't pass module value and use the value stored in the same structure. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ee15428ca740..2145975af103 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4074,16 +4074,18 @@ static u8 mlxsw_sp_cluster_base_port_get(u8 local_port, unsigned int max_width) return local_port - offset; } -static int mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, - u8 module, unsigned int count, u8 offset, - unsigned int max_width) +static int +mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, + struct mlxsw_sp_port_mapping *port_mapping, + unsigned int count, u8 offset) { - u8 width = max_width / count; + u8 width = port_mapping->width / count; int err, i; for (i = 0; i < count; i++) { err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset, - true, module, width, i * width); + true, port_mapping->module, + width, i * width); if (err) goto err_port_create; } @@ -4127,9 +4129,10 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); u8 local_ports_in_1x, local_ports_in_2x, offset; + struct mlxsw_sp_port_mapping port_mapping; struct mlxsw_sp_port *mlxsw_sp_port; - u8 module, base_port; int max_width; + u8 base_port; int i; int err; @@ -4155,8 +4158,6 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - module = mlxsw_sp_port->mapping.module; - max_width = mlxsw_core_module_max_width(mlxsw_core, mlxsw_sp_port->mapping.module); if (max_width < 0) { @@ -4199,12 +4200,14 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, } } + port_mapping = mlxsw_sp_port->mapping; + for (i = 0; i < count; i++) if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, module, count, - offset, max_width); + err = mlxsw_sp_port_split_create(mlxsw_sp, base_port, &port_mapping, + count, offset); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create split ports\n"); goto err_port_split_create; -- cgit v1.2.3-59-g8ed1b From 35896d9641db1af0d6054b03ec3e13f6be83c6b8 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:13 +0200 Subject: mlxsw: spectrum: Pass mapping values in port mapping structure Pass the port mapping structure down to create, module_map and other function instead of individual values. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 56 ++++++++++++-------------- 1 file changed, 26 insertions(+), 30 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 2145975af103..68f1461d9919 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -765,18 +765,18 @@ mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, return 0; } -static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port, - u8 module, u8 width, u8 lane) +static int mlxsw_sp_port_module_map(struct mlxsw_sp_port *mlxsw_sp_port) { + struct mlxsw_sp_port_mapping *port_mapping = &mlxsw_sp_port->mapping; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char pmlp_pl[MLXSW_REG_PMLP_LEN]; int i; mlxsw_reg_pmlp_pack(pmlp_pl, mlxsw_sp_port->local_port); - mlxsw_reg_pmlp_width_set(pmlp_pl, width); - for (i = 0; i < width; i++) { - mlxsw_reg_pmlp_module_set(pmlp_pl, i, module); - mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, lane + i); /* Rx & Tx */ + mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width); + for (i = 0; i < port_mapping->width; i++) { + mlxsw_reg_pmlp_module_set(pmlp_pl, i, port_mapping->module); + mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */ } return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); @@ -3480,7 +3480,7 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = { }; static int -mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 width) +mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; const struct mlxsw_sp_port_type_speed_ops *ops; @@ -3496,7 +3496,7 @@ mlxsw_sp_port_speed_by_width_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 width) &base_speed); if (err) return err; - upper_speed = base_speed * width; + upper_speed = base_speed * mlxsw_sp_port->mapping.width; eth_proto_admin = ops->to_ptys_upper_speed(mlxsw_sp, upper_speed); ops->reg_ptys_eth_pack(mlxsw_sp, ptys_pl, mlxsw_sp_port->local_port, @@ -3657,7 +3657,8 @@ static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, } static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, - bool split, u8 module, u8 width, u8 lane) + bool split, + struct mlxsw_sp_port_mapping *port_mapping) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_port *mlxsw_sp_port; @@ -3665,7 +3666,8 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, int err; err = mlxsw_core_port_init(mlxsw_sp->core, local_port, - module + 1, split, lane / width, + port_mapping->module + 1, split, + port_mapping->lane / port_mapping->width, mlxsw_sp->base_mac, sizeof(mlxsw_sp->base_mac)); if (err) { @@ -3687,9 +3689,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_sp_port->local_port = local_port; mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID; mlxsw_sp_port->split = split; - mlxsw_sp_port->mapping.module = module; - mlxsw_sp_port->mapping.width = width; - mlxsw_sp_port->mapping.lane = lane; + mlxsw_sp_port->mapping = *port_mapping; mlxsw_sp_port->link.autoneg = 1; INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); INIT_LIST_HEAD(&mlxsw_sp_port->mall_tc_list); @@ -3714,7 +3714,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, dev->netdev_ops = &mlxsw_sp_port_netdev_ops; dev->ethtool_ops = &mlxsw_sp_port_ethtool_ops; - err = mlxsw_sp_port_module_map(mlxsw_sp_port, module, width, lane); + err = mlxsw_sp_port_module_map(mlxsw_sp_port); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to map module\n", mlxsw_sp_port->local_port); @@ -3756,7 +3756,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_system_port_mapping_set; } - err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port, width); + err = mlxsw_sp_port_speed_by_width_set(mlxsw_sp_port); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to enable speeds\n", mlxsw_sp_port->local_port); @@ -4003,10 +4003,7 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) port_mapping = mlxsw_sp->port_mapping[i]; if (!port_mapping) continue; - err = mlxsw_sp_port_create(mlxsw_sp, i, false, - port_mapping->module, - port_mapping->width, - port_mapping->lane); + err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping); if (err) goto err_port_create; } @@ -4079,15 +4076,17 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, struct mlxsw_sp_port_mapping *port_mapping, unsigned int count, u8 offset) { - u8 width = port_mapping->width / count; + struct mlxsw_sp_port_mapping split_port_mapping; int err, i; + split_port_mapping = *port_mapping; + split_port_mapping.width /= count; for (i = 0; i < count; i++) { err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset, - true, port_mapping->module, - width, i * width); + true, &split_port_mapping); if (err) goto err_port_create; + split_port_mapping.lane += split_port_mapping.width; } return 0; @@ -4100,11 +4099,10 @@ err_port_create: } static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, - u8 base_port, unsigned int count, - unsigned int max_width) + u8 base_port, unsigned int count) { struct mlxsw_sp_port_mapping *port_mapping; - u8 local_port, width = max_width; + u8 local_port; int i; /* Split by four means we need to re-create two ports, otherwise @@ -4117,9 +4115,7 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, port_mapping = mlxsw_sp->port_mapping[local_port]; if (!port_mapping) continue; - - mlxsw_sp_port_create(mlxsw_sp, local_port, false, - port_mapping->module, width, 0); + mlxsw_sp_port_create(mlxsw_sp, local_port, false, port_mapping); } } @@ -4216,7 +4212,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return 0; err_port_split_create: - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); return err; } @@ -4277,7 +4273,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, max_width); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); return 0; } -- cgit v1.2.3-59-g8ed1b From c8fc10dc17c2675212982934d6de7fb19aabe73c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:14 +0200 Subject: mlxsw: spectrum: Add sanity checks into module info get Driver assumes certain values in the PMLP register. Add checks that verify that PMLP register provides fitting values. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 39 ++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 68f1461d9919..938803cd29ca 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -753,14 +754,48 @@ mlxsw_sp_port_module_info_get(struct mlxsw_sp *mlxsw_sp, u8 local_port, struct mlxsw_sp_port_mapping *port_mapping) { char pmlp_pl[MLXSW_REG_PMLP_LEN]; + bool separate_rxtx; + u8 module; + u8 width; int err; + int i; mlxsw_reg_pmlp_pack(pmlp_pl, local_port); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl); if (err) return err; - port_mapping->module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); - port_mapping->width = mlxsw_reg_pmlp_width_get(pmlp_pl); + module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); + width = mlxsw_reg_pmlp_width_get(pmlp_pl); + separate_rxtx = mlxsw_reg_pmlp_rxtx_get(pmlp_pl); + + if (width && !is_power_of_2(width)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: width value is not power of 2\n", + local_port); + return -EINVAL; + } + + for (i = 0; i < width; i++) { + if (mlxsw_reg_pmlp_module_get(pmlp_pl, i) != module) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: contains multiple modules\n", + local_port); + return -EINVAL; + } + if (separate_rxtx && + mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != + mlxsw_reg_pmlp_rx_lane_get(pmlp_pl, i)) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are different\n", + local_port); + return -EINVAL; + } + if (mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, i) != i) { + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Unsupported module config: TX and RX lane numbers are not sequential\n", + local_port); + return -EINVAL; + } + } + + port_mapping->module = module; + port_mapping->width = width; port_mapping->lane = mlxsw_reg_pmlp_tx_lane_get(pmlp_pl, 0); return 0; } -- cgit v1.2.3-59-g8ed1b From d0846ce9aa9096e53e532a1c36c57efe63509b26 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:15 +0200 Subject: mlxsw: spectrum: Push getting offsets of split ports into a helper Get local port offsets of split port in a separate helper function and use it in both split and unsplit function. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 58 ++++++++++++++++---------- 1 file changed, 35 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 938803cd29ca..39ea408deec1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4154,26 +4154,38 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, } } +static int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core, + unsigned int count, + unsigned int max_width) +{ + enum mlxsw_res_id local_ports_in_x_res_id; + int split_width = max_width / count; + + if (split_width == 1) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X; + else if (split_width == 2) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X; + else + return -EINVAL; + + if (!mlxsw_core_res_valid(mlxsw_core, local_ports_in_x_res_id)) + return -EINVAL; + return mlxsw_core_res_get(mlxsw_core, local_ports_in_x_res_id); +} + static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, unsigned int count, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - u8 local_ports_in_1x, local_ports_in_2x, offset; struct mlxsw_sp_port_mapping port_mapping; struct mlxsw_sp_port *mlxsw_sp_port; int max_width; u8 base_port; + int offset; int i; int err; - if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) || - !MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_2X)) - return -EIO; - - local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X); - local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; if (!mlxsw_sp_port) { dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", @@ -4210,17 +4222,22 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } + offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); + if (offset < 0) { + netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); + return -EINVAL; + } + /* Make sure we have enough slave (even) ports for the split. */ if (count == 2) { - offset = local_ports_in_2x; base_port = local_port; - if (mlxsw_sp->ports[base_port + local_ports_in_2x]) { + if (mlxsw_sp->ports[base_port + offset]) { netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); return -EINVAL; } } else { - offset = local_ports_in_1x; base_port = mlxsw_sp_cluster_base_port_get(local_port, max_width); if (mlxsw_sp->ports[base_port + 1] || @@ -4255,20 +4272,13 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); - u8 local_ports_in_1x, local_ports_in_2x, offset; struct mlxsw_sp_port *mlxsw_sp_port; unsigned int count; int max_width; u8 base_port; + int offset; int i; - if (!MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_1X) || - !MLXSW_CORE_RES_VALID(mlxsw_core, LOCAL_PORTS_IN_2X)) - return -EIO; - - local_ports_in_1x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_1X); - local_ports_in_2x = MLXSW_CORE_RES_GET(mlxsw_core, LOCAL_PORTS_IN_2X); - mlxsw_sp_port = mlxsw_sp->ports[local_port]; if (!mlxsw_sp_port) { dev_err(mlxsw_sp->bus_info->dev, "Port number \"%d\" does not exist\n", @@ -4293,10 +4303,12 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, count = max_width / mlxsw_sp_port->mapping.width; - if (count == 2) - offset = local_ports_in_2x; - else - offset = local_ports_in_1x; + offset = mlxsw_sp_local_ports_offset(mlxsw_core, count, max_width); + if (WARN_ON(offset < 0)) { + netdev_err(mlxsw_sp_port->dev, "Cannot obtain local port offset\n"); + NL_SET_ERR_MSG_MOD(extack, "Cannot obtain local port offset"); + return -EINVAL; + } base_port = mlxsw_sp_cluster_base_port_get(local_port, max_width); -- cgit v1.2.3-59-g8ed1b From 038784a9dfc2180dde36d34a92cb4427eb1e928f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:16 +0200 Subject: mlxsw: spectrum: Introduce resource for getting offset of 4 lanes split port In Spectrum-3 the modules have 8 lanes, so split by count 2 results in two split ports each of 4 lanes. Add a resource that can be used to obtain local port offset in that case. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/resources.h | 2 ++ drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/resources.h b/drivers/net/ethernet/mellanox/mlxsw/resources.h index 85f919fe851b..6534184cb942 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/resources.h +++ b/drivers/net/ethernet/mellanox/mlxsw/resources.h @@ -26,6 +26,7 @@ enum mlxsw_res_id { MLXSW_RES_ID_MAX_LAG_MEMBERS, MLXSW_RES_ID_LOCAL_PORTS_IN_1X, MLXSW_RES_ID_LOCAL_PORTS_IN_2X, + MLXSW_RES_ID_LOCAL_PORTS_IN_4X, MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER, MLXSW_RES_ID_CELL_SIZE, MLXSW_RES_ID_MAX_HEADROOM_SIZE, @@ -82,6 +83,7 @@ static u16 mlxsw_res_ids[] = { [MLXSW_RES_ID_MAX_LAG_MEMBERS] = 0x2521, [MLXSW_RES_ID_LOCAL_PORTS_IN_1X] = 0x2610, [MLXSW_RES_ID_LOCAL_PORTS_IN_2X] = 0x2611, + [MLXSW_RES_ID_LOCAL_PORTS_IN_4X] = 0x2612, [MLXSW_RES_ID_GUARANTEED_SHARED_BUFFER] = 0x2805, /* Bytes */ [MLXSW_RES_ID_CELL_SIZE] = 0x2803, /* Bytes */ [MLXSW_RES_ID_MAX_HEADROOM_SIZE] = 0x2811, /* Bytes */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 39ea408deec1..d336e54d7a76 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4165,6 +4165,8 @@ static int mlxsw_sp_local_ports_offset(struct mlxsw_core *mlxsw_core, local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_1X; else if (split_width == 2) local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_2X; + else if (split_width == 4) + local_ports_in_x_res_id = MLXSW_RES_ID_LOCAL_PORTS_IN_4X; else return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 49185277cc451ebae894456384cc8996e8ec4fdc Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:17 +0200 Subject: mlxsw: spectrum: Remember split base local port and use it in unsplit Don't compute the original base local port during unsplit, rather remember it in mlxsw_sp_port structure during split port creation. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 16 +++++++--------- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 + 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d336e54d7a76..db05118adc44 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -3692,10 +3692,11 @@ static int mlxsw_sp_port_tc_mc_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, } static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, - bool split, + u8 split_base_local_port, struct mlxsw_sp_port_mapping *port_mapping) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + bool split = !!split_base_local_port; struct mlxsw_sp_port *mlxsw_sp_port; struct net_device *dev; int err; @@ -3724,6 +3725,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_sp_port->local_port = local_port; mlxsw_sp_port->pvid = MLXSW_SP_DEFAULT_VID; mlxsw_sp_port->split = split; + mlxsw_sp_port->split_base_local_port = split_base_local_port; mlxsw_sp_port->mapping = *port_mapping; mlxsw_sp_port->link.autoneg = 1; INIT_LIST_HEAD(&mlxsw_sp_port->vlans_list); @@ -4038,7 +4040,7 @@ static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) port_mapping = mlxsw_sp->port_mapping[i]; if (!port_mapping) continue; - err = mlxsw_sp_port_create(mlxsw_sp, i, false, port_mapping); + err = mlxsw_sp_port_create(mlxsw_sp, i, 0, port_mapping); if (err) goto err_port_create; } @@ -4118,7 +4120,7 @@ mlxsw_sp_port_split_create(struct mlxsw_sp *mlxsw_sp, u8 base_port, split_port_mapping.width /= count; for (i = 0; i < count; i++) { err = mlxsw_sp_port_create(mlxsw_sp, base_port + i * offset, - true, &split_port_mapping); + base_port, &split_port_mapping); if (err) goto err_port_create; split_port_mapping.lane += split_port_mapping.width; @@ -4150,7 +4152,7 @@ static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, port_mapping = mlxsw_sp->port_mapping[local_port]; if (!port_mapping) continue; - mlxsw_sp_port_create(mlxsw_sp, local_port, false, port_mapping); + mlxsw_sp_port_create(mlxsw_sp, local_port, 0, port_mapping); } } @@ -4312,11 +4314,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - base_port = mlxsw_sp_cluster_base_port_get(local_port, max_width); - - /* Determine which ports to remove. */ - if (count == 2 && local_port >= base_port + 2) - base_port = base_port + 2; + base_port = mlxsw_sp_port->split_base_local_port; for (i = 0; i < count; i++) if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 3a823911a9d9..ec6c9756791d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -293,6 +293,7 @@ struct mlxsw_sp_port { u16 egr_types; struct mlxsw_sp_ptp_port_stats stats; } ptp; + u8 split_base_local_port; }; struct mlxsw_sp_port_type_speed_ops { -- cgit v1.2.3-59-g8ed1b From 013da297911830882611c4ae4764117dacf6713f Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:18 +0200 Subject: mlxsw: spectrum: Use port_module_max_width to compute base port index Instead of using constant value, use port_module_max_width which is aligned with the cluster size. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index ec6c9756791d..347bec9d1ecf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -32,8 +32,6 @@ #define MLXSW_SP_MID_MAX 7000 -#define MLXSW_SP_PORTS_PER_CLUSTER_MAX 4 - #define MLXSW_SP_PORT_BASE_SPEED_25G 25000 /* Mb/s */ #define MLXSW_SP_PORT_BASE_SPEED_50G 50000 /* Mb/s */ -- cgit v1.2.3-59-g8ed1b From c3a64b5173e1416cf3d982b02e1c1b918382f701 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:19 +0200 Subject: mlxsw: spectrum: Fix base port get for split count 4 and 8 The current code considers only split by 2 or 4. Make the base port getting generic and allow split by 8 to be handled correctly. Generalize the used port checks as well. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index db05118adc44..0a5a4a252248 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4233,19 +4233,21 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - /* Make sure we have enough slave (even) ports for the split. */ - if (count == 2) { - base_port = local_port; - if (mlxsw_sp->ports[base_port + offset]) { - netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); - NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); - return -EINVAL; - } - } else { - base_port = mlxsw_sp_cluster_base_port_get(local_port, - max_width); - if (mlxsw_sp->ports[base_port + 1] || - mlxsw_sp->ports[base_port + 3]) { + /* Only in case max split is being done, the local port and + * base port may differ. + */ + base_port = count == max_width ? + mlxsw_sp_cluster_base_port_get(local_port, max_width) : + local_port; + + for (i = 0; i < count * offset; i++) { + /* Expect base port to exist and also the one in the middle in + * case of maximal split count. + */ + if (i == 0 || (count == max_width && i == count / 2)) + continue; + + if (mlxsw_sp_port_created(mlxsw_sp, base_port + i)) { netdev_err(mlxsw_sp_port->dev, "Invalid split configuration\n"); NL_SET_ERR_MSG_MOD(extack, "Invalid split configuration"); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From fbbeea31026767706f0644f14c3cf13cbc2fa3c8 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:20 +0200 Subject: mlxsw: spectrum: Iterate over all ports in gap during unsplit create During recreation of original unsplit ports, just simply iterate over the whole gap and recreate whatever originally existed. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 0a5a4a252248..3ce48d0df37f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4136,23 +4136,18 @@ err_port_create: } static void mlxsw_sp_port_unsplit_create(struct mlxsw_sp *mlxsw_sp, - u8 base_port, unsigned int count) + u8 base_port, + unsigned int count, u8 offset) { struct mlxsw_sp_port_mapping *port_mapping; - u8 local_port; int i; - /* Split by four means we need to re-create two ports, otherwise - * only one. - */ - count = count / 2; - - for (i = 0; i < count; i++) { - local_port = base_port + i * 2; - port_mapping = mlxsw_sp->port_mapping[local_port]; + /* Go over original unsplit ports in the gap and recreate them. */ + for (i = 0; i < count * offset; i++) { + port_mapping = mlxsw_sp->port_mapping[base_port + i]; if (!port_mapping) continue; - mlxsw_sp_port_create(mlxsw_sp, local_port, 0, port_mapping); + mlxsw_sp_port_create(mlxsw_sp, base_port + i, 0, port_mapping); } } @@ -4270,7 +4265,7 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return 0; err_port_split_create: - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); return err; } @@ -4322,7 +4317,7 @@ static int mlxsw_sp_port_unsplit(struct mlxsw_core *mlxsw_core, u8 local_port, if (mlxsw_sp_port_created(mlxsw_sp, base_port + i * offset)) mlxsw_sp_port_remove(mlxsw_sp, base_port + i * offset); - mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count); + mlxsw_sp_port_unsplit_create(mlxsw_sp, base_port, count, offset); return 0; } -- cgit v1.2.3-59-g8ed1b From 973b7fdb5ff17e5f19eba9103c3fcb77a01b93df Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 31 Oct 2019 11:42:21 +0200 Subject: mlxsw: spectrum: Generalize split count check Make the check generic for any possible value, not only 2 and 4. Signed-off-by: Jiri Pirko Reviewed-by: Shalom Toledo Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3ce48d0df37f..ea4cc2aa99e0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4215,9 +4215,9 @@ static int mlxsw_sp_port_split(struct mlxsw_core *mlxsw_core, u8 local_port, return -EINVAL; } - if (count != 2 && count != 4) { - netdev_err(mlxsw_sp_port->dev, "Port can only be split into 2 or 4 ports\n"); - NL_SET_ERR_MSG_MOD(extack, "Port can only be split into 2 or 4 ports"); + if (count == 1 || !is_power_of_2(count) || count > max_width) { + netdev_err(mlxsw_sp_port->dev, "Invalid split count\n"); + NL_SET_ERR_MSG_MOD(extack, "Invalid split count"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From e07ab2021eb6b7123ec66ae1dc019afae566a56c Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 31 Oct 2019 15:38:51 +0530 Subject: bnxt_en: Add support to invoke OP-TEE API to reset firmware In error recovery process when firmware indicates that it is completely down, initiate a firmware reset by calling OP-TEE API. Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: Sheetal Tigadoli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 +++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8cdf71f8824d..c24caaaf05ca 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10581,14 +10581,23 @@ static void bnxt_fw_reset_writel(struct bnxt *bp, int reg_idx) static void bnxt_reset_all(struct bnxt *bp) { struct bnxt_fw_health *fw_health = bp->fw_health; - int i; + int i, rc; + + if (bp->fw_cap & BNXT_FW_CAP_ERR_RECOVER_RELOAD) { +#ifdef CONFIG_TEE_BNXT_FW + rc = tee_bnxt_fw_load(); + if (rc) + netdev_err(bp->dev, "Unable to reset FW rc=%d\n", rc); + bp->fw_reset_timestamp = jiffies; +#endif + return; + } if (fw_health->flags & ERROR_RECOVERY_QCFG_RESP_FLAGS_HOST) { for (i = 0; i < fw_health->fw_reset_seq_cnt; i++) bnxt_fw_reset_writel(bp, i); } else if (fw_health->flags & ERROR_RECOVERY_QCFG_RESP_FLAGS_CO_CPU) { struct hwrm_fw_reset_input req = {0}; - int rc; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FW_RESET, -1, -1); req.resp_addr = cpu_to_le64(bp->hwrm_cmd_kong_resp_dma_addr); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d333589811a5..09437150f818 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -25,6 +25,9 @@ #include #include #include +#ifdef CONFIG_TEE_BNXT_FW +#include +#endif struct page_pool; -- cgit v1.2.3-59-g8ed1b From 0b0eacf3c83cb292c6eef55c76d5138c9302dc20 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 31 Oct 2019 15:38:52 +0530 Subject: bnxt_en: Add support to collect crash dump via ethtool Driver supports 2 types of core dumps. 1. Live dump - Firmware dump when system is up and running. 2. Crash dump - Dump which is collected during firmware crash that can be retrieved after recovery. Crash dump is currently supported only on specific 58800 chips which can be retrieved using OP-TEE API only, as firmware cannot access this region directly. User needs to set the dump flag using following command before initiating the dump collection: $ ethtool -W|--set-dump eth0 N Where N is "0" for live dump and "1" for crash dump Command to collect the dump after setting the flag: $ ethtool -w eth0 data Filename v3: Modify set_dump to support even when CONFIG_TEE_BNXT_FW=n. Also change log message to netdev_info(). Cc: Jakub Kicinski Cc: Michael Chan Signed-off-by: Vasundhara Volam Signed-off-by: Sheetal Tigadoli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 ++ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 37 +++++++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 09437150f818..3e7d1fb1b0b1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1807,6 +1807,9 @@ struct bnxt { u8 num_leds; struct bnxt_led_info leds[BNXT_MAX_LED]; + u16 dump_flag; +#define BNXT_DUMP_LIVE 0 +#define BNXT_DUMP_CRASH 1 struct bpf_prog *xdp_prog; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 51c140476717..f2220b826d61 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3311,6 +3311,24 @@ err: return rc; } +static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) +{ + struct bnxt *bp = netdev_priv(dev); + + if (dump->flag > BNXT_DUMP_CRASH) { + netdev_info(dev, "Supports only Live(0) and Crash(1) dumps.\n"); + return -EINVAL; + } + + if (!IS_ENABLED(CONFIG_TEE_BNXT_FW) && dump->flag == BNXT_DUMP_CRASH) { + netdev_info(dev, "Cannot collect crash dump as TEE_BNXT_FW config option is not enabled.\n"); + return -EOPNOTSUPP; + } + + bp->dump_flag = dump->flag; + return 0; +} + static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) { struct bnxt *bp = netdev_priv(dev); @@ -3323,7 +3341,12 @@ static int bnxt_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump) bp->ver_resp.hwrm_fw_bld_8b << 8 | bp->ver_resp.hwrm_fw_rsvd_8b; - return bnxt_get_coredump(bp, NULL, &dump->len); + dump->flag = bp->dump_flag; + if (bp->dump_flag == BNXT_DUMP_CRASH) + dump->len = BNXT_CRASH_DUMP_LEN; + else + bnxt_get_coredump(bp, NULL, &dump->len); + return 0; } static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, @@ -3336,7 +3359,16 @@ static int bnxt_get_dump_data(struct net_device *dev, struct ethtool_dump *dump, memset(buf, 0, dump->len); - return bnxt_get_coredump(bp, buf, &dump->len); + dump->flag = bp->dump_flag; + if (dump->flag == BNXT_DUMP_CRASH) { +#ifdef CONFIG_TEE_BNXT_FW + return tee_bnxt_copy_coredump(buf, 0, dump->len); +#endif + } else { + return bnxt_get_coredump(bp, buf, &dump->len); + } + + return 0; } void bnxt_ethtool_init(struct bnxt *bp) @@ -3446,6 +3478,7 @@ const struct ethtool_ops bnxt_ethtool_ops = { .set_phys_id = bnxt_set_phys_id, .self_test = bnxt_self_test, .reset = bnxt_reset, + .set_dump = bnxt_set_dump, .get_dump_flag = bnxt_get_dump_flag, .get_dump_data = bnxt_get_dump_data, }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index b5b65b3f8534..01de7e79d14f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -59,6 +59,8 @@ struct hwrm_dbg_cmn_output { #define HWRM_DBG_CMN_FLAGS_MORE 1 }; +#define BNXT_CRASH_DUMP_LEN (8 << 20) + #define BNXT_LED_DFLT_ENA \ (PORT_LED_CFG_REQ_ENABLES_LED0_ID | \ PORT_LED_CFG_REQ_ENABLES_LED0_STATE | \ -- cgit v1.2.3-59-g8ed1b From 3d77d0cb054cbc8d9171ebc7f6b0c33445b2a94d Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 31 Oct 2019 19:23:16 +0800 Subject: net: hns3: dump some debug information when reset fail When reset fails, there is some information that will help for finding out why does reset fail. and removes an unused core_rst_cnt field in struct hclge_rst_stats. Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 5 ++-- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 29 ++++++++++++++++++++++ 4 files changed, 35 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 0ccc8e7b19d0..122ad92e7e95 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -929,7 +929,7 @@ static void hclge_dbg_fd_tcam(struct hclge_dev *hdev) } } -static void hclge_dbg_dump_rst_info(struct hclge_dev *hdev) +void hclge_dbg_dump_rst_info(struct hclge_dev *hdev) { dev_info(&hdev->pdev->dev, "PF reset count: %u\n", hdev->rst_stats.pf_rst_cnt); @@ -945,8 +945,6 @@ static void hclge_dbg_dump_rst_info(struct hclge_dev *hdev) hdev->rst_stats.hw_reset_done_cnt); dev_info(&hdev->pdev->dev, "reset count: %u\n", hdev->rst_stats.reset_cnt); - dev_info(&hdev->pdev->dev, "reset count: %u\n", - hdev->rst_stats.reset_cnt); dev_info(&hdev->pdev->dev, "reset fail count: %u\n", hdev->rst_stats.reset_fail_cnt); dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n", @@ -961,6 +959,7 @@ static void hclge_dbg_dump_rst_info(struct hclge_dev *hdev) hclge_read_dev(&hdev->hw, HCLGE_NIC_CSQ_DEPTH_REG)); dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n", hclge_read_dev(&hdev->hw, HCLGE_FUN_RST_ING)); + dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state); } static void hclge_dbg_get_m7_stats_info(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index bf6bca26c337..19667c9b25cc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3669,6 +3669,9 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev) hclge_reset_handshake(hdev, true); dev_err(&hdev->pdev->dev, "Reset fail!\n"); + + hclge_dbg_dump_rst_info(hdev); + return false; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 9e59f0e074be..4386788dd204 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -656,7 +656,6 @@ struct hclge_rst_stats { u32 hw_reset_done_cnt; /* the number of HW reset has completed */ u32 pf_rst_cnt; /* the number of PF reset */ u32 flr_rst_cnt; /* the number of FLR */ - u32 core_rst_cnt; /* the number of CORE reset */ u32 global_rst_cnt; /* the number of GLOBAL */ u32 imp_rst_cnt; /* the number of IMP reset */ u32 reset_cnt; /* the number of reset */ @@ -1005,4 +1004,5 @@ int hclge_query_bd_num_cmd_send(struct hclge_dev *hdev, void hclge_report_hw_error(struct hclge_dev *hdev, enum hnae3_hw_error_type type); void hclge_inform_vf_promisc_info(struct hclge_vport *vport); +void hclge_dbg_dump_rst_info(struct hclge_dev *hdev); #endif diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 408e38644c60..c38eba899503 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1549,6 +1549,33 @@ static int hclgevf_reset_prepare_wait(struct hclgevf_dev *hdev) return ret; } +static void hclgevf_dump_rst_info(struct hclgevf_dev *hdev) +{ + dev_info(&hdev->pdev->dev, "VF function reset count: %u\n", + hdev->rst_stats.vf_func_rst_cnt); + dev_info(&hdev->pdev->dev, "FLR reset count: %u\n", + hdev->rst_stats.flr_rst_cnt); + dev_info(&hdev->pdev->dev, "VF reset count: %u\n", + hdev->rst_stats.vf_rst_cnt); + dev_info(&hdev->pdev->dev, "reset done count: %u\n", + hdev->rst_stats.rst_done_cnt); + dev_info(&hdev->pdev->dev, "HW reset done count: %u\n", + hdev->rst_stats.hw_rst_done_cnt); + dev_info(&hdev->pdev->dev, "reset count: %u\n", + hdev->rst_stats.rst_cnt); + dev_info(&hdev->pdev->dev, "reset fail count: %u\n", + hdev->rst_stats.rst_fail_cnt); + dev_info(&hdev->pdev->dev, "vector0 interrupt enable status: 0x%x\n", + hclgevf_read_dev(&hdev->hw, HCLGEVF_MISC_VECTOR_REG_BASE)); + dev_info(&hdev->pdev->dev, "vector0 interrupt status: 0x%x\n", + hclgevf_read_dev(&hdev->hw, HCLGEVF_VECTOR0_CMDQ_STAT_REG)); + dev_info(&hdev->pdev->dev, "handshake status: 0x%x\n", + hclgevf_read_dev(&hdev->hw, HCLGEVF_CMDQ_TX_DEPTH_REG)); + dev_info(&hdev->pdev->dev, "function reset status: 0x%x\n", + hclgevf_read_dev(&hdev->hw, HCLGEVF_RST_ING)); + dev_info(&hdev->pdev->dev, "hdev state: 0x%lx\n", hdev->state); +} + static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) { /* recover handshake status with IMP when reset fail */ @@ -1563,6 +1590,8 @@ static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) if (hclgevf_is_reset_pending(hdev)) { set_bit(HCLGEVF_RESET_PENDING, &hdev->reset_state); hclgevf_reset_task_schedule(hdev); + } else { + hclgevf_dump_rst_info(hdev); } } -- cgit v1.2.3-59-g8ed1b From 647522a5ef6401dcdb8ec417421e43fb21910167 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 31 Oct 2019 19:23:17 +0800 Subject: net: hns3: add struct netdev_queue debug info for TX timeout When there is a TX timeout, we can tell if the driver or stack has stopped the queue by looking at state field, and when has the last packet transmited by looking at trans_start field. So this patch prints these two field in the hns3_get_tx_timeo_queue_info(). Signed-off-by: Yunsheng Lin Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 0fdd684a8524..23bdfe8583da 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1792,6 +1792,9 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev) time_after(jiffies, (trans_start + ndev->watchdog_timeo))) { timeout_queue = i; + netdev_info(ndev, "queue state: 0x%lx, delta msecs: %u\n", + q->state, + jiffies_to_msecs(jiffies - trans_start)); break; } } -- cgit v1.2.3-59-g8ed1b From d6ad7c5306251f6e7f82e46118b8c13c08cebf7d Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Thu, 31 Oct 2019 19:23:18 +0800 Subject: net: hns3: cleanup some magic numbers To make the code more readable, this patch replaces some magic numbers with macro or sizeof operation. Also uses macro lower_32_bits and upper_32_bits to get bits 0-31 and 32-63 of a number, instead of using type conversion and '>>' operation. No functional change. Signed-off-by: Guojia Liao Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 29 ++++++++++++++++------ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 9 +++---- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 1 - .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 3 ++- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 8 +++--- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++- 6 files changed, 34 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 919911fe02ae..a4633d216997 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -8,6 +8,7 @@ #include #define HCLGE_CMDQ_TX_TIMEOUT 30000 +#define HCLGE_DESC_DATA_LEN 6 struct hclge_dev; struct hclge_desc { @@ -19,7 +20,7 @@ struct hclge_desc { __le16 flag; __le16 retval; __le16 rsv; - __le32 data[6]; + __le32 data[HCLGE_DESC_DATA_LEN]; }; struct hclge_cmq_ring { @@ -429,8 +430,10 @@ struct hclge_rx_pkt_buf_cmd { #define HCLGE_PF_MAC_NUM_MASK 0x3 #define HCLGE_PF_STATE_MAIN BIT(HCLGE_PF_STATE_MAIN_B) #define HCLGE_PF_STATE_DONE BIT(HCLGE_PF_STATE_DONE_B) +#define HCLGE_VF_RST_STATUS_CMD 4 + struct hclge_func_status_cmd { - __le32 vf_rst_state[4]; + __le32 vf_rst_state[HCLGE_VF_RST_STATUS_CMD]; u8 pf_state; u8 mac_id; u8 rsv1; @@ -486,10 +489,12 @@ struct hclge_pf_res_cmd { #define HCLGE_CFG_UMV_TBL_SPACE_S 16 #define HCLGE_CFG_UMV_TBL_SPACE_M GENMASK(31, 16) +#define HCLGE_CFG_CMD_CNT 4 + struct hclge_cfg_param_cmd { __le32 offset; __le32 rsv; - __le32 param[4]; + __le32 param[HCLGE_CFG_CMD_CNT]; }; #define HCLGE_MAC_MODE 0x0 @@ -758,20 +763,27 @@ struct hclge_vlan_filter_ctrl_cmd { u8 rsv2[19]; }; +#define HCLGE_VLAN_ID_OFFSET_STEP 160 +#define HCLGE_VLAN_BYTE_SIZE 8 +#define HCLGE_VLAN_OFFSET_BITMAP \ + (HCLGE_VLAN_ID_OFFSET_STEP / HCLGE_VLAN_BYTE_SIZE) + struct hclge_vlan_filter_pf_cfg_cmd { u8 vlan_offset; u8 vlan_cfg; u8 rsv[2]; - u8 vlan_offset_bitmap[20]; + u8 vlan_offset_bitmap[HCLGE_VLAN_OFFSET_BITMAP]; }; +#define HCLGE_MAX_VF_BYTES 16 + struct hclge_vlan_filter_vf_cfg_cmd { __le16 vlan_id; u8 resp_code; u8 rsv; u8 vlan_cfg; u8 rsv1[3]; - u8 vf_bitmap[16]; + u8 vf_bitmap[HCLGE_MAX_VF_BYTES]; }; #define HCLGE_SWITCH_ANTI_SPOOF_B 0U @@ -806,6 +818,7 @@ enum hclge_mac_vlan_cfg_sel { #define HCLGE_CFG_NIC_ROCE_SEL_B 4 #define HCLGE_ACCEPT_TAG2_B 5 #define HCLGE_ACCEPT_UNTAG2_B 6 +#define HCLGE_VF_NUM_PER_BYTE 8 struct hclge_vport_vtag_tx_cfg_cmd { u8 vport_vlan_cfg; @@ -813,7 +826,7 @@ struct hclge_vport_vtag_tx_cfg_cmd { u8 rsv1[2]; __le16 def_vlan_tag1; __le16 def_vlan_tag2; - u8 vf_bitmap[8]; + u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE]; u8 rsv2[8]; }; @@ -825,7 +838,7 @@ struct hclge_vport_vtag_rx_cfg_cmd { u8 vport_vlan_cfg; u8 vf_offset; u8 rsv1[6]; - u8 vf_bitmap[8]; + u8 vf_bitmap[HCLGE_VF_NUM_PER_BYTE]; u8 rsv2[8]; }; @@ -864,7 +877,7 @@ struct hclge_mac_ethertype_idx_rd_cmd { u8 flags; u8 resp_code; __le16 vlan_tag; - u8 mac_addr[6]; + u8 mac_addr[ETH_ALEN]; __le16 index; __le16 ethter_type; __le16 egress_port; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 19667c9b25cc..dbdc245803f1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7744,8 +7744,6 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, bool is_kill, u16 vlan, __be16 proto) { -#define HCLGE_MAX_VF_BYTES 16 - struct hclge_vport *vport = &hdev->vport[vfid]; struct hclge_vlan_filter_vf_cfg_cmd *req0; struct hclge_vlan_filter_vf_cfg_cmd *req1; @@ -7845,9 +7843,10 @@ static int hclge_set_port_vlan_filter(struct hclge_dev *hdev, __be16 proto, hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_PF_CFG, false); - vlan_offset_160 = vlan_id / 160; - vlan_offset_byte = (vlan_id % 160) / 8; - vlan_offset_byte_val = 1 << (vlan_id % 8); + vlan_offset_160 = vlan_id / HCLGE_VLAN_ID_OFFSET_STEP; + vlan_offset_byte = (vlan_id % HCLGE_VLAN_ID_OFFSET_STEP) / + HCLGE_VLAN_BYTE_SIZE; + vlan_offset_byte_val = 1 << (vlan_id % HCLGE_VLAN_BYTE_SIZE); req = (struct hclge_vlan_filter_pf_cfg_cmd *)desc.data; req->vlan_offset = vlan_offset_160; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 4386788dd204..599f76a05f41 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -141,7 +141,6 @@ /* Factor used to calculate offset and bitmap of VF num */ #define HCLGE_VF_NUM_PER_CMD 64 -#define HCLGE_VF_NUM_PER_BYTE 8 enum HLCGE_PORT_TYPE { HOST_PORT, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 97463e11aca7..088fc7c145e9 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -590,7 +590,8 @@ static int hclge_get_queue_id_in_pf(struct hclge_vport *vport, qid_in_pf = hclge_covert_handle_qid_global(&vport->nic, queue_id); memcpy(resp_data, &qid_in_pf, sizeof(qid_in_pf)); - return hclge_gen_resp_to_vf(vport, mbx_req, 0, resp_data, 2); + return hclge_gen_resp_to_vf(vport, mbx_req, 0, resp_data, + sizeof(resp_data)); } static int hclge_get_rss_key(struct hclge_vport *vport, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index d5d1cc5d1b6e..d261b5a9ef9f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -92,9 +92,9 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring) u32 reg_val; if (ring->flag == HCLGEVF_TYPE_CSQ) { - reg_val = (u32)ring->desc_dma_addr; + reg_val = lower_32_bits(ring->desc_dma_addr); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_L_REG, reg_val); - reg_val = (u32)((ring->desc_dma_addr >> 31) >> 1); + reg_val = upper_32_bits(ring->desc_dma_addr); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_BASEADDR_H_REG, reg_val); reg_val = hclgevf_read_dev(hw, HCLGEVF_NIC_CSQ_DEPTH_REG); @@ -105,9 +105,9 @@ static void hclgevf_cmd_config_regs(struct hclgevf_cmq_ring *ring) hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_HEAD_REG, 0); hclgevf_write_dev(hw, HCLGEVF_NIC_CSQ_TAIL_REG, 0); } else { - reg_val = (u32)ring->desc_dma_addr; + reg_val = lower_32_bits(ring->desc_dma_addr); hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_L_REG, reg_val); - reg_val = (u32)((ring->desc_dma_addr >> 31) >> 1); + reg_val = upper_32_bits(ring->desc_dma_addr); hclgevf_write_dev(hw, HCLGEVF_NIC_CRQ_BASEADDR_H_REG, reg_val); reg_val = (ring->desc_num >> HCLGEVF_NIC_CMQ_DESC_NUM_S); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index c38eba899503..2f3f63bd6a92 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1813,6 +1813,8 @@ static void hclgevf_service_timer(struct timer_list *t) static void hclgevf_reset_service_task(struct work_struct *work) { +#define HCLGEVF_MAX_RESET_ATTEMPTS_CNT 3 + struct hclgevf_dev *hdev = container_of(work, struct hclgevf_dev, rst_service_task); int ret; @@ -1865,7 +1867,7 @@ static void hclgevf_reset_service_task(struct work_struct *work) * We cannot do much for 2. but to check first we can try reset * our PCIe + stack and see if it alleviates the problem. */ - if (hdev->reset_attempts > 3) { + if (hdev->reset_attempts > HCLGEVF_MAX_RESET_ATTEMPTS_CNT) { /* prepare for full reset of stack + pcie interface */ set_bit(HNAE3_VF_FULL_RESET, &hdev->reset_pending); -- cgit v1.2.3-59-g8ed1b From db4d3d554eb53cacb3ce4defe294f19a548a1034 Mon Sep 17 00:00:00 2001 From: Guangbin Huang Date: Thu, 31 Oct 2019 19:23:19 +0800 Subject: net: hns3: cleanup some coding style issues To unify code style and make code simpler, this patch modifies some code, deletes unnecessary blank lines and {}, changes location of code, and so on. No functional change. Signed-off-by: Guangbin Huang Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 - drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 5 ++--- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 1 + drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 4 ++-- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 11 ++++++----- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 1 - 7 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index e48023643f4c..23478ee02a12 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -130,7 +130,6 @@ enum hnae3_module_type { HNAE3_MODULE_TYPE_CR = 0x04, HNAE3_MODULE_TYPE_KR = 0x05, HNAE3_MODULE_TYPE_TP = 0x06, - }; enum hnae3_fec_mode { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 0725dc52341e..345633f9dbf6 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -186,7 +186,7 @@ enum hns3_nic_state { #define HNS3_TXD_MSS_S 0 #define HNS3_TXD_MSS_M (0x3fff << HNS3_TXD_MSS_S) -#define HNS3_TX_LAST_SIZE_M 0xffff +#define HNS3_TX_LAST_SIZE_M 0xffff #define HNS3_VECTOR_TX_IRQ BIT_ULL(0) #define HNS3_VECTOR_RX_IRQ BIT_ULL(1) @@ -313,7 +313,7 @@ struct hns3_desc_cb { u16 reuse_flag; - /* desc type, used by the ring user to mark the type of the priv data */ + /* desc type, used by the ring user to mark the type of the priv data */ u16 type; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index ecf58cfd253d..c3311467fa9d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -314,11 +314,10 @@ int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num) } while (timeout < hw->cmq.tx_timeout); } - if (!complete) { + if (!complete) retval = -EBADE; - } else { + else retval = hclge_cmd_check_retval(hw, desc, num, ntc); - } /* Clean the command send queue */ handle = hclge_cmd_csq_clean(hw); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index a4633d216997..af96e7904925 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -261,6 +261,7 @@ enum hclge_opcode_type { /* NCL config command */ HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011, + /* M7 stats command */ HCLGE_OPC_M7_STATS_BD = 0x7012, HCLGE_OPC_M7_STATS_INFO = 0x7013, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index 122ad92e7e95..e65c8cf16a85 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -145,7 +145,7 @@ static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev, return; } - buf_len = sizeof(struct hclge_desc) * bd_num; + buf_len = sizeof(struct hclge_desc) * bd_num; desc_src = kzalloc(buf_len, GFP_KERNEL); if (!desc_src) { dev_err(&hdev->pdev->dev, "call kzalloc failed\n"); @@ -153,7 +153,7 @@ static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev, } desc = desc_src; - ret = hclge_dbg_cmd_send(hdev, desc, index, bd_num, reg_msg->cmd); + ret = hclge_dbg_cmd_send(hdev, desc, index, bd_num, reg_msg->cmd); if (ret) { kfree(desc_src); return; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index dbdc245803f1..69ab86a4b38d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -2777,7 +2777,7 @@ static void hclge_update_port_capability(struct hclge_mac *mac) else if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER) mac->module_type = HNAE3_MODULE_TYPE_TP; - if (mac->support_autoneg == true) { + if (mac->support_autoneg) { linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported); linkmode_copy(mac->advertising, mac->supported); } else { @@ -3855,12 +3855,13 @@ static void hclge_reset_event(struct pci_dev *pdev, struct hnae3_handle *handle) HCLGE_RESET_INTERVAL))) { mod_timer(&hdev->reset_timer, jiffies + HCLGE_RESET_INTERVAL); return; - } else if (hdev->default_reset_request) + } else if (hdev->default_reset_request) { hdev->reset_level = hclge_get_reset_level(ae_dev, &hdev->default_reset_request); - else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ))) + } else if (time_after(jiffies, (hdev->last_reset_time + 4 * 5 * HZ))) { hdev->reset_level = HNAE3_FUNC_RESET; + } dev_info(&hdev->pdev->dev, "received reset event, reset type is %d\n", hdev->reset_level); @@ -3985,6 +3986,7 @@ static void hclge_service_task(struct work_struct *work) hclge_update_link_status(hdev); hclge_update_vport_alive(hdev); hclge_sync_vlan_filter(hdev); + if (hdev->fd_arfs_expire_timer >= HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL) { hclge_rfs_filter_expire(hdev); hdev->fd_arfs_expire_timer = 0; @@ -7409,7 +7411,7 @@ void hclge_rm_vport_mac_table(struct hclge_vport *vport, const u8 *mac_addr, mc_flag = is_write_tbl && mac_type == HCLGE_MAC_ADDR_MC; list_for_each_entry_safe(mac_cfg, tmp, list, node) { - if (strncmp(mac_cfg->mac_addr, mac_addr, ETH_ALEN) == 0) { + if (ether_addr_equal(mac_cfg->mac_addr, mac_addr)) { if (uc_flag && mac_cfg->hd_tbl_status) hclge_rm_uc_addr_common(vport, mac_addr); @@ -9093,7 +9095,6 @@ static int hclge_init_client_instance(struct hnae3_client *client, switch (client->type) { case HNAE3_CLIENT_KNIC: - hdev->nic_client = client; vport->nic.client = client; ret = hclge_init_nic_client_instance(ae_dev, vport); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 2f3f63bd6a92..9506d7db04ae 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -2170,7 +2170,6 @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) ret = hclgevf_set_rss_input_tuple(hdev, rss_cfg); if (ret) return ret; - } /* Initialize RSS indirect table */ -- cgit v1.2.3-59-g8ed1b From e4b806edfabd43853d365a9fcaf238cf10c3c4ab Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Thu, 31 Oct 2019 19:23:20 +0800 Subject: net: hns3: cleanup a format-truncation warning In hns3_nic_init_irq(), when '*_int_idx' has more than 9 digits and the length of netdev's name is IFNAMSIZ, the total length of final name will be bigger the HNAE3_INT_NAME_LEN - 1, even though '*_int_idx' will never have such large value, but the compiler gives a format-truncation warning for this case. So this patch just enlarges the length to avoid this warning. Signed-off-by: Guojia Liao Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 23478ee02a12..45f59165bcd2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -575,7 +575,8 @@ struct hnae3_ae_algo { const struct pci_device_id *pdev_id_table; }; -#define HNAE3_INT_NAME_LEN (IFNAMSIZ + 16) +#define HNAE3_INT_NAME_EXT_LEN 32 /* Max extra information length */ +#define HNAE3_INT_NAME_LEN (IFNAMSIZ + HNAE3_INT_NAME_EXT_LEN) #define HNAE3_ITR_COUNTDOWN_START 100 struct hnae3_tc_info { -- cgit v1.2.3-59-g8ed1b From 0bfdf2868cd511e2ceff983fe66a508b0d03d8c5 Mon Sep 17 00:00:00 2001 From: Guangbin Huang Date: Thu, 31 Oct 2019 19:23:21 +0800 Subject: net: hns3: optimize local variable initialization The variable tx_ring is unnecessary to be initialized as it will be set before used, and the variable rst_cnt is better to be initialized when declaration for simplification. Signed-off-by: Guangbin Huang Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 23bdfe8583da..82ed9c4485fb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1771,7 +1771,7 @@ static bool hns3_get_tx_timeo_queue_info(struct net_device *ndev) { struct hns3_nic_priv *priv = netdev_priv(ndev); struct hnae3_handle *h = hns3_get_handle(ndev); - struct hns3_enet_ring *tx_ring = NULL; + struct hns3_enet_ring *tx_ring; struct napi_struct *napi; int timeout_queue = 0; int hw_head, hw_tail; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 69ab86a4b38d..300252785ad8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -8992,10 +8992,9 @@ static int hclge_init_nic_client_instance(struct hnae3_ae_dev *ae_dev, { struct hnae3_client *client = vport->nic.client; struct hclge_dev *hdev = ae_dev->priv; - int rst_cnt; + int rst_cnt = hdev->rst_stats.reset_cnt; int ret; - rst_cnt = hdev->rst_stats.reset_cnt; ret = client->ops->init_instance(&vport->nic); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 9e69045654ec12d11254ffc31860b3ced441ba65 Mon Sep 17 00:00:00 2001 From: Guangbin Huang Date: Thu, 31 Oct 2019 19:23:22 +0800 Subject: net: hns3: add or modify some comments This patch makes the comment for macro HCLGE_MBX_GET_VF_FLR_STATUS more correct, and adds comments in some place to make the code more readable. Signed-off-by: Guangbin Huang Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hnae3.c | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index 0059d440e1f9..cb45c7d0101b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -47,7 +47,7 @@ enum HCLGE_MBX_OPCODE { HCLGE_MBX_GET_MEDIA_TYPE, /* (VF -> PF) get media type */ HCLGE_MBX_PUSH_PROMISC_INFO, /* (PF -> VF) push vf promisc info */ - HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf reset status */ + HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */ HCLGE_MBX_PUSH_LINK_STATUS, /* (M7 -> PF) get port link status */ HCLGE_MBX_NCSI_ERROR, /* (M7 -> PF) receive a NCSI error */ }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.c b/drivers/net/ethernet/hisilicon/hns3/hnae3.c index 03ca7d925e8e..eef1b2764d34 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.c +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.c @@ -146,7 +146,7 @@ void hnae3_unregister_client(struct hnae3_client *client) return; mutex_lock(&hnae3_common_lock); - + /* one system should only have one client for every type */ list_for_each_entry(client_tmp, &hnae3_client_list, node) { if (client_tmp->type == client->type) { existed = true; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 300252785ad8..e578029e0616 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -8552,6 +8552,7 @@ int hclge_set_vport_mtu(struct hclge_vport *vport, int new_mtu) struct hclge_dev *hdev = vport->back; int i, max_frm_size, ret; + /* HW supprt 2 layer vlan */ max_frm_size = new_mtu + ETH_HLEN + ETH_FCS_LEN + 2 * VLAN_HLEN; if (max_frm_size < HCLGE_MAC_MIN_FRAME || max_frm_size > HCLGE_MAC_MAX_FRAME) @@ -9314,6 +9315,8 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) hdev->reset_type = HNAE3_NONE_RESET; hdev->reset_level = HNAE3_FUNC_RESET; ae_dev->priv = hdev; + + /* HW supprt 2 layer vlan */ hdev->mps = ETH_FRAME_LEN + ETH_FCS_LEN + 2 * VLAN_HLEN; mutex_init(&hdev->vport_lock); -- cgit v1.2.3-59-g8ed1b From adcf738b804b3cfd5a72d9975e92d84053fd394f Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Thu, 31 Oct 2019 19:23:23 +0800 Subject: net: hns3: cleanup some print format warning Using '%d' for printing type unsigned int or '%u' for type int would cause static tools to give false warnings, so this patch cleanups this warning by using the suitable format specifier of the type of variable. BTW, modifies the type of some variables and macro to synchronize with their usage. Signed-off-by: Guojia Liao Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 30 ++++----- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 20 +++--- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 12 ++-- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c | 2 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c | 2 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c | 2 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 78 +++++++++++----------- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 12 ++-- .../ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c | 2 +- .../net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 4 +- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c | 2 +- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 16 ++--- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c | 18 ++--- 14 files changed, 101 insertions(+), 101 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h index cb45c7d0101b..1b0313900f98 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h +++ b/drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h @@ -72,7 +72,7 @@ enum hclge_mbx_vlan_cfg_subcode { }; #define HCLGE_MBX_MAX_MSG_SIZE 16 -#define HCLGE_MBX_MAX_RESP_DATA_SIZE 8 +#define HCLGE_MBX_MAX_RESP_DATA_SIZE 8U #define HCLGE_MBX_RING_MAP_BASIC_MSG_NUM 3 #define HCLGE_MBX_RING_NODE_VARIABLE_NUM 3 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index fe5bc6fa8bcd..466a6e3c9cbf 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -57,68 +57,68 @@ static int hns3_dbg_queue_info(struct hnae3_handle *h, HNS3_RING_RX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_BASEADDR_L_REG); - dev_info(&h->pdev->dev, "RX(%d) BASE ADD: 0x%08x%08x\n", i, + dev_info(&h->pdev->dev, "RX(%u) BASE ADD: 0x%08x%08x\n", i, base_add_h, base_add_l); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_BD_NUM_REG); - dev_info(&h->pdev->dev, "RX(%d) RING BD NUM: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING BD NUM: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_BD_LEN_REG); - dev_info(&h->pdev->dev, "RX(%d) RING BD LEN: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING BD LEN: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG); - dev_info(&h->pdev->dev, "RX(%d) RING TAIL: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING TAIL: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_HEAD_REG); - dev_info(&h->pdev->dev, "RX(%d) RING HEAD: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING HEAD: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_FBDNUM_REG); - dev_info(&h->pdev->dev, "RX(%d) RING FBDNUM: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING FBDNUM: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_PKTNUM_RECORD_REG); - dev_info(&h->pdev->dev, "RX(%d) RING PKTNUM: %u\n", i, value); + dev_info(&h->pdev->dev, "RX(%u) RING PKTNUM: %u\n", i, value); ring = &priv->ring[i]; base_add_h = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_BASEADDR_H_REG); base_add_l = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_BASEADDR_L_REG); - dev_info(&h->pdev->dev, "TX(%d) BASE ADD: 0x%08x%08x\n", i, + dev_info(&h->pdev->dev, "TX(%u) BASE ADD: 0x%08x%08x\n", i, base_add_h, base_add_l); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_BD_NUM_REG); - dev_info(&h->pdev->dev, "TX(%d) RING BD NUM: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING BD NUM: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TC_REG); - dev_info(&h->pdev->dev, "TX(%d) RING TC: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING TC: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG); - dev_info(&h->pdev->dev, "TX(%d) RING TAIL: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING TAIL: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_HEAD_REG); - dev_info(&h->pdev->dev, "TX(%d) RING HEAD: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING HEAD: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_FBDNUM_REG); - dev_info(&h->pdev->dev, "TX(%d) RING FBDNUM: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING FBDNUM: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_OFFSET_REG); - dev_info(&h->pdev->dev, "TX(%d) RING OFFSET: %u\n", i, value); + dev_info(&h->pdev->dev, "TX(%u) RING OFFSET: %u\n", i, value); value = readl_relaxed(ring->tqp->io_base + HNS3_RING_TX_RING_PKTNUM_RECORD_REG); - dev_info(&h->pdev->dev, "TX(%d) RING PKTNUM: %u\n\n", i, + dev_info(&h->pdev->dev, "TX(%u) RING PKTNUM: %u\n\n", i, value); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 82ed9c4485fb..d5a121a44459 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2002,7 +2002,7 @@ bool hns3_is_phys_func(struct pci_dev *pdev) case HNAE3_DEV_ID_100G_RDMA_DCB_PFC_VF: return false; default: - dev_warn(&pdev->dev, "un-recognized pci device-id %d", + dev_warn(&pdev->dev, "un-recognized pci device-id %u", dev_id); } @@ -3939,14 +3939,14 @@ static void hns3_info_show(struct hns3_nic_priv *priv) struct hnae3_knic_private_info *kinfo = &priv->ae_handle->kinfo; dev_info(priv->dev, "MAC address: %pM\n", priv->netdev->dev_addr); - dev_info(priv->dev, "Task queue pairs numbers: %d\n", kinfo->num_tqps); - dev_info(priv->dev, "RSS size: %d\n", kinfo->rss_size); - dev_info(priv->dev, "Allocated RSS size: %d\n", kinfo->req_rss_size); - dev_info(priv->dev, "RX buffer length: %d\n", kinfo->rx_buf_len); - dev_info(priv->dev, "Desc num per TX queue: %d\n", kinfo->num_tx_desc); - dev_info(priv->dev, "Desc num per RX queue: %d\n", kinfo->num_rx_desc); - dev_info(priv->dev, "Total number of enabled TCs: %d\n", kinfo->num_tc); - dev_info(priv->dev, "Max mtu size: %d\n", priv->netdev->max_mtu); + dev_info(priv->dev, "Task queue pairs numbers: %u\n", kinfo->num_tqps); + dev_info(priv->dev, "RSS size: %u\n", kinfo->rss_size); + dev_info(priv->dev, "Allocated RSS size: %u\n", kinfo->req_rss_size); + dev_info(priv->dev, "RX buffer length: %u\n", kinfo->rx_buf_len); + dev_info(priv->dev, "Desc num per TX queue: %u\n", kinfo->num_tx_desc); + dev_info(priv->dev, "Desc num per RX queue: %u\n", kinfo->num_rx_desc); + dev_info(priv->dev, "Total number of enabled TCs: %u\n", kinfo->num_tc); + dev_info(priv->dev, "Max mtu size: %u\n", priv->netdev->max_mtu); } static int hns3_client_init(struct hnae3_handle *handle) @@ -4566,7 +4566,7 @@ int hns3_set_channels(struct net_device *netdev, if (new_tqp_num > hns3_get_max_available_channels(h) || new_tqp_num < 1) { dev_err(&netdev->dev, - "Change tqps fail, the tqp range is from 1 to %d", + "Change tqps fail, the tqp range is from 1 to %u", hns3_get_max_available_channels(h)); return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 50b07b9aafa5..b104d3c3b757 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -985,7 +985,7 @@ static int hns3_set_ringparam(struct net_device *ndev, } netdev_info(ndev, - "Changing Tx/Rx ring depth from %d/%d to %d/%d\n", + "Changing Tx/Rx ring depth from %u/%u to %u/%u\n", old_tx_desc_num, old_rx_desc_num, new_tx_desc_num, new_rx_desc_num); @@ -1097,7 +1097,7 @@ static int hns3_get_coalesce_per_queue(struct net_device *netdev, u32 queue, if (queue >= queue_num) { netdev_err(netdev, - "Invalid queue value %d! Queue max id=%d\n", + "Invalid queue value %u! Queue max id=%u\n", queue, queue_num - 1); return -EINVAL; } @@ -1147,14 +1147,14 @@ static int hns3_check_gl_coalesce_para(struct net_device *netdev, rx_gl = hns3_gl_round_down(cmd->rx_coalesce_usecs); if (rx_gl != cmd->rx_coalesce_usecs) { netdev_info(netdev, - "rx_usecs(%d) rounded down to %d, because it must be multiple of 2.\n", + "rx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n", cmd->rx_coalesce_usecs, rx_gl); } tx_gl = hns3_gl_round_down(cmd->tx_coalesce_usecs); if (tx_gl != cmd->tx_coalesce_usecs) { netdev_info(netdev, - "tx_usecs(%d) rounded down to %d, because it must be multiple of 2.\n", + "tx_usecs(%u) rounded down to %u, because it must be multiple of 2.\n", cmd->tx_coalesce_usecs, tx_gl); } @@ -1182,7 +1182,7 @@ static int hns3_check_rl_coalesce_para(struct net_device *netdev, rl = hns3_rl_round_down(cmd->rx_coalesce_usecs_high); if (rl != cmd->rx_coalesce_usecs_high) { netdev_info(netdev, - "usecs_high(%d) rounded down to %d, because it must be multiple of 4.\n", + "usecs_high(%u) rounded down to %u, because it must be multiple of 4.\n", cmd->rx_coalesce_usecs_high, rl); } @@ -1211,7 +1211,7 @@ static int hns3_check_coalesce_para(struct net_device *netdev, if (cmd->use_adaptive_tx_coalesce == 1 || cmd->use_adaptive_rx_coalesce == 1) { netdev_info(netdev, - "adaptive-tx=%d and adaptive-rx=%d, tx_usecs or rx_usecs will changed dynamically.\n", + "adaptive-tx=%u and adaptive-rx=%u, tx_usecs or rx_usecs will changed dynamically.\n", cmd->use_adaptive_tx_coalesce, cmd->use_adaptive_rx_coalesce); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index c3311467fa9d..940ead3970d1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -145,7 +145,7 @@ static int hclge_cmd_csq_clean(struct hclge_hw *hw) rmb(); /* Make sure head is ready before touch any data */ if (!is_valid_csq_clean_head(csq, head)) { - dev_warn(&hdev->pdev->dev, "wrong cmd head (%d, %d-%d)\n", head, + dev_warn(&hdev->pdev->dev, "wrong cmd head (%u, %d-%d)\n", head, csq->next_to_use, csq->next_to_clean); dev_warn(&hdev->pdev->dev, "Disabling any further commands to IMP firmware\n"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index c063301d6060..49ad8483723d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -87,7 +87,7 @@ static int hclge_dcb_common_validate(struct hclge_dev *hdev, u8 num_tc, for (i = 0; i < HNAE3_MAX_USER_PRIO; i++) { if (prio_tc[i] >= num_tc) { dev_err(&hdev->pdev->dev, - "prio_tc[%u] checking failed, %u >= num_tc(%u)\n", + "prio_tc[%d] checking failed, %u >= num_tc(%u)\n", i, prio_tc[i], num_tc); return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c index 87dece0e745d..dc66b4e13377 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_err.c @@ -1747,7 +1747,7 @@ static void hclge_handle_over_8bd_err(struct hclge_dev *hdev, if (vf_id) { if (vf_id >= hdev->num_alloc_vport) { - dev_err(dev, "invalid vf id(%d)\n", vf_id); + dev_err(dev, "invalid vf id(%u)\n", vf_id); return; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index e578029e0616..babec3b6ab16 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1398,7 +1398,7 @@ static int hclge_configure(struct hclge_dev *hdev) if ((hdev->tc_max > HNAE3_MAX_TC) || (hdev->tc_max < 1)) { - dev_warn(&hdev->pdev->dev, "TC num = %d.\n", + dev_warn(&hdev->pdev->dev, "TC num = %u.\n", hdev->tc_max); hdev->tc_max = 1; } @@ -1658,7 +1658,7 @@ static int hclge_alloc_vport(struct hclge_dev *hdev) num_vport = hdev->num_vmdq_vport + hdev->num_req_vfs + 1; if (hdev->num_tqps < num_vport) { - dev_err(&hdev->pdev->dev, "tqps(%d) is less than vports(%d)", + dev_err(&hdev->pdev->dev, "tqps(%u) is less than vports(%d)", hdev->num_tqps, num_vport); return -EINVAL; } @@ -2345,7 +2345,7 @@ static int hclge_init_msi(struct hclge_dev *hdev) } if (vectors < hdev->num_msi) dev_warn(&hdev->pdev->dev, - "requested %d MSI/MSI-X, but allocated %d MSI/MSI-X\n", + "requested %u MSI/MSI-X, but allocated %d MSI/MSI-X\n", hdev->num_msi, vectors); hdev->num_msi = vectors; @@ -3280,7 +3280,7 @@ static int hclge_reset_wait(struct hclge_dev *hdev) if (!test_bit(HNAE3_FLR_DONE, &hdev->flr_state)) { dev_err(&hdev->pdev->dev, - "flr wait timeout: %d\n", cnt); + "flr wait timeout: %u\n", cnt); return -EBUSY; } @@ -3330,7 +3330,7 @@ static int hclge_set_all_vf_rst(struct hclge_dev *hdev, bool reset) ret = hclge_set_vf_rst(hdev, vport->vport_id, reset); if (ret) { dev_err(&hdev->pdev->dev, - "set vf(%d) rst failed %d!\n", + "set vf(%u) rst failed %d!\n", vport->vport_id, ret); return ret; } @@ -3345,7 +3345,7 @@ static int hclge_set_all_vf_rst(struct hclge_dev *hdev, bool reset) ret = hclge_inform_reset_assert_to_vf(vport); if (ret) dev_warn(&hdev->pdev->dev, - "inform reset to vf(%d) failed %d!\n", + "inform reset to vf(%u) failed %d!\n", vport->vport_id, ret); } @@ -3658,7 +3658,7 @@ static bool hclge_reset_err_handle(struct hclge_dev *hdev) hdev->rst_stats.reset_fail_cnt++; set_bit(hdev->reset_type, &hdev->reset_pending); dev_info(&hdev->pdev->dev, - "re-schedule reset task(%d)\n", + "re-schedule reset task(%u)\n", hdev->rst_stats.reset_fail_cnt); return true; } @@ -4493,7 +4493,7 @@ int hclge_rss_init_hw(struct hclge_dev *hdev) */ if (rss_size > HCLGE_RSS_TC_SIZE_7 || rss_size == 0) { dev_err(&hdev->pdev->dev, - "Configure rss tc size failed, invalid TC_SIZE = %d\n", + "Configure rss tc size failed, invalid TC_SIZE = %u\n", rss_size); return -EINVAL; } @@ -4843,7 +4843,7 @@ static int hclge_init_fd_config(struct hclge_dev *hdev) break; default: dev_err(&hdev->pdev->dev, - "Unsupported flow director mode %d\n", + "Unsupported flow director mode %u\n", hdev->fd_cfg.fd_mode); return -EOPNOTSUPP; } @@ -5173,7 +5173,7 @@ static int hclge_config_key(struct hclge_dev *hdev, u8 stage, true); if (ret) { dev_err(&hdev->pdev->dev, - "fd key_y config fail, loc=%d, ret=%d\n", + "fd key_y config fail, loc=%u, ret=%d\n", rule->queue_id, ret); return ret; } @@ -5182,7 +5182,7 @@ static int hclge_config_key(struct hclge_dev *hdev, u8 stage, true); if (ret) dev_err(&hdev->pdev->dev, - "fd key_x config fail, loc=%d, ret=%d\n", + "fd key_x config fail, loc=%u, ret=%d\n", rule->queue_id, ret); return ret; } @@ -5431,7 +5431,7 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev, } } else if (!is_add) { dev_err(&hdev->pdev->dev, - "delete fail, rule %d is inexistent\n", + "delete fail, rule %u is inexistent\n", location); return -EINVAL; } @@ -5671,7 +5671,7 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, if (vf > hdev->num_req_vfs) { dev_err(&hdev->pdev->dev, - "Error: vf id (%d) > max vf num (%d)\n", + "Error: vf id (%u) > max vf num (%u)\n", vf, hdev->num_req_vfs); return -EINVAL; } @@ -5681,7 +5681,7 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, if (ring >= tqps) { dev_err(&hdev->pdev->dev, - "Error: queue id (%d) > max tqp num (%d)\n", + "Error: queue id (%u) > max tqp num (%u)\n", ring, tqps - 1); return -EINVAL; } @@ -5817,7 +5817,7 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle) if (ret) { dev_warn(&hdev->pdev->dev, - "Restore rule %d failed, remove it\n", + "Restore rule %u failed, remove it\n", rule->location); clear_bit(rule->location, hdev->fd_bmap); hlist_del(&rule->rule_node); @@ -6810,7 +6810,7 @@ static int hclge_get_mac_vlan_cmd_status(struct hclge_vport *vport, if (cmdq_resp) { dev_err(&hdev->pdev->dev, - "cmdq execute failed for get_mac_vlan_cmd_status,status=%d.\n", + "cmdq execute failed for get_mac_vlan_cmd_status,status=%u.\n", cmdq_resp); return -EIO; } @@ -7062,7 +7062,7 @@ static int hclge_init_umv_space(struct hclge_dev *hdev) if (allocated_size < hdev->wanted_umv_size) dev_warn(&hdev->pdev->dev, - "Alloc umv space failed, want %d, get %d\n", + "Alloc umv space failed, want %u, get %u\n", hdev->wanted_umv_size, allocated_size); mutex_init(&hdev->umv_mutex); @@ -7230,7 +7230,7 @@ int hclge_add_uc_addr_common(struct hclge_vport *vport, /* check if we just hit the duplicate */ if (!ret) { - dev_warn(&hdev->pdev->dev, "VF %d mac(%pM) exists\n", + dev_warn(&hdev->pdev->dev, "VF %u mac(%pM) exists\n", vport->vport_id, addr); return 0; } @@ -7483,7 +7483,7 @@ static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev, if (cmdq_resp) { dev_err(&hdev->pdev->dev, - "cmdq execute failed for get_mac_ethertype_cmd_status, status=%d.\n", + "cmdq execute failed for get_mac_ethertype_cmd_status, status=%u.\n", cmdq_resp); return -EIO; } @@ -7505,7 +7505,7 @@ static int hclge_get_mac_ethertype_cmd_status(struct hclge_dev *hdev, break; default: dev_err(&hdev->pdev->dev, - "add mac ethertype failed for undefined, code=%d.\n", + "add mac ethertype failed for undefined, code=%u.\n", resp_code); return_status = -EIO; } @@ -7810,7 +7810,7 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, } dev_err(&hdev->pdev->dev, - "Add vf vlan filter fail, ret =%d.\n", + "Add vf vlan filter fail, ret =%u.\n", req0->resp_code); } else { #define HCLGE_VF_VLAN_DEL_NO_FOUND 1 @@ -7826,7 +7826,7 @@ static int hclge_set_vf_vlan_common(struct hclge_dev *hdev, u16 vfid, return 0; dev_err(&hdev->pdev->dev, - "Kill vf vlan filter fail, ret =%d.\n", + "Kill vf vlan filter fail, ret =%u.\n", req0->resp_code); } @@ -7876,7 +7876,7 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, proto); if (ret) { dev_err(&hdev->pdev->dev, - "Set %d vport vlan filter config fail, ret =%d.\n", + "Set %u vport vlan filter config fail, ret =%d.\n", vport_id, ret); return ret; } @@ -7888,7 +7888,7 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, if (!is_kill && test_and_set_bit(vport_id, hdev->vlan_table[vlan_id])) { dev_err(&hdev->pdev->dev, - "Add port vlan failed, vport %d is already in vlan %d\n", + "Add port vlan failed, vport %u is already in vlan %u\n", vport_id, vlan_id); return -EINVAL; } @@ -7896,7 +7896,7 @@ static int hclge_set_vlan_filter_hw(struct hclge_dev *hdev, __be16 proto, if (is_kill && !test_and_clear_bit(vport_id, hdev->vlan_table[vlan_id])) { dev_err(&hdev->pdev->dev, - "Delete port vlan failed, vport %d is not in vlan %d\n", + "Delete port vlan failed, vport %u is not in vlan %u\n", vport_id, vlan_id); return -EINVAL; } @@ -8968,16 +8968,16 @@ static void hclge_info_show(struct hclge_dev *hdev) dev_info(dev, "PF info begin:\n"); - dev_info(dev, "Task queue pairs numbers: %d\n", hdev->num_tqps); - dev_info(dev, "Desc num per TX queue: %d\n", hdev->num_tx_desc); - dev_info(dev, "Desc num per RX queue: %d\n", hdev->num_rx_desc); - dev_info(dev, "Numbers of vports: %d\n", hdev->num_alloc_vport); - dev_info(dev, "Numbers of vmdp vports: %d\n", hdev->num_vmdq_vport); - dev_info(dev, "Numbers of VF for this PF: %d\n", hdev->num_req_vfs); - dev_info(dev, "HW tc map: %d\n", hdev->hw_tc_map); - dev_info(dev, "Total buffer size for TX/RX: %d\n", hdev->pkt_buf_size); - dev_info(dev, "TX buffer size for each TC: %d\n", hdev->tx_buf_size); - dev_info(dev, "DV buffer size for each TC: %d\n", hdev->dv_buf_size); + dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps); + dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc); + dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc); + dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport); + dev_info(dev, "Numbers of vmdp vports: %u\n", hdev->num_vmdq_vport); + dev_info(dev, "Numbers of VF for this PF: %u\n", hdev->num_req_vfs); + dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map); + dev_info(dev, "Total buffer size for TX/RX: %u\n", hdev->pkt_buf_size); + dev_info(dev, "TX buffer size for each TC: %u\n", hdev->tx_buf_size); + dev_info(dev, "DV buffer size for each TC: %u\n", hdev->dv_buf_size); dev_info(dev, "This is %s PF\n", hdev->flag & HCLGE_FLAG_MAIN ? "main" : "not main"); dev_info(dev, "DCB %s\n", @@ -9293,7 +9293,7 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev) ret = hclge_set_vf_rst(hdev, vport->vport_id, false); if (ret) dev_warn(&hdev->pdev->dev, - "clear vf(%d) rst failed %d!\n", + "clear vf(%u) rst failed %d!\n", vport->vport_id, ret); } } @@ -9914,8 +9914,8 @@ static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, u16 tc_offset[HCLGE_MAX_TC_NUM] = {0}; struct hclge_dev *hdev = vport->back; u16 tc_size[HCLGE_MAX_TC_NUM] = {0}; - int cur_rss_size = kinfo->rss_size; - int cur_tqps = kinfo->num_tqps; + u16 cur_rss_size = kinfo->rss_size; + u16 cur_tqps = kinfo->num_tqps; u16 tc_valid[HCLGE_MAX_TC_NUM]; u16 roundup_size; u32 *rss_indir; @@ -9969,7 +9969,7 @@ static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num, out: if (!ret) dev_info(&hdev->pdev->dev, - "Channels changed, rss_size from %d to %d, tqps from %d to %d", + "Channels changed, rss_size from %u to %u, tqps from %u to %u", cur_rss_size, kinfo->rss_size, cur_tqps, kinfo->rss_size * kinfo->num_tc); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c index 088fc7c145e9..0b433ebe6a2d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c @@ -26,7 +26,7 @@ static int hclge_gen_resp_to_vf(struct hclge_vport *vport, if (resp_data_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) { dev_err(&hdev->pdev->dev, - "PF fail to gen resp to VF len %d exceeds max len %d\n", + "PF fail to gen resp to VF len %u exceeds max len %u\n", resp_data_len, HCLGE_MBX_MAX_RESP_DATA_SIZE); /* If resp_data_len is too long, set the value to max length @@ -285,7 +285,7 @@ static int hclge_set_vf_uc_mac_addr(struct hclge_vport *vport, false, HCLGE_MAC_ADDR_UC); } else { dev_err(&hdev->pdev->dev, - "failed to set unicast mac addr, unknown subcode %d\n", + "failed to set unicast mac addr, unknown subcode %u\n", mbx_req->msg[1]); return -EIO; } @@ -319,7 +319,7 @@ static int hclge_set_vf_mc_mac_addr(struct hclge_vport *vport, false, HCLGE_MAC_ADDR_MC); } else { dev_err(&hdev->pdev->dev, - "failed to set mcast mac addr, unknown subcode %d\n", + "failed to set mcast mac addr, unknown subcode %u\n", mbx_req->msg[1]); return -EIO; } @@ -555,7 +555,7 @@ static void hclge_reset_vf(struct hclge_vport *vport, struct hclge_dev *hdev = vport->back; int ret; - dev_warn(&hdev->pdev->dev, "PF received VF reset request from VF %d!", + dev_warn(&hdev->pdev->dev, "PF received VF reset request from VF %u!", vport->vport_id); ret = hclge_func_reset_cmd(hdev, vport->vport_id); @@ -681,7 +681,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev) flag = le16_to_cpu(crq->desc[crq->next_to_use].flag); if (unlikely(!hnae3_get_bit(flag, HCLGE_CMDQ_RX_OUTVLD_B))) { dev_warn(&hdev->pdev->dev, - "dropped invalid mailbox message, code = %d\n", + "dropped invalid mailbox message, code = %u\n", req->msg[0]); /* dropping/not processing this invalid message */ @@ -828,7 +828,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev) break; default: dev_err(&hdev->pdev->dev, - "un-supported mailbox message, code = %d\n", + "un-supported mailbox message, code = %u\n", req->msg[0]); break; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c index dc4dfd4602ab..696c5ae922e3 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mdio.c @@ -134,7 +134,7 @@ int hclge_mac_mdio_config(struct hclge_dev *hdev) "no phy device is connected to mdio bus\n"); return 0; } else if (hdev->hw.mac.phy_addr >= PHY_MAX_ADDR) { - dev_err(&hdev->pdev->dev, "phy_addr(%d) is too large.\n", + dev_err(&hdev->pdev->dev, "phy_addr(%u) is too large.\n", hdev->hw.mac.phy_addr); return -EINVAL; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c index b3c30e5f9aa5..fbc39a2480d0 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c @@ -544,7 +544,7 @@ int hclge_tm_qs_shaper_cfg(struct hclge_vport *vport, int max_tx_rate) ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) { dev_err(&hdev->pdev->dev, - "vf%d, qs%u failed to set tx_rate:%d, ret=%d\n", + "vf%u, qs%u failed to set tx_rate:%d, ret=%d\n", vport->vport_id, shap_cfg_cmd->qs_id, max_tx_rate, ret); return ret; @@ -575,7 +575,7 @@ static void hclge_tm_vport_tc_info_update(struct hclge_vport *vport) /* Set to user value, no larger than max_rss_size. */ if (kinfo->req_rss_size != kinfo->rss_size && kinfo->req_rss_size && kinfo->req_rss_size <= max_rss_size) { - dev_info(&hdev->pdev->dev, "rss changes from %d to %d\n", + dev_info(&hdev->pdev->dev, "rss changes from %u to %u\n", kinfo->rss_size, kinfo->req_rss_size); kinfo->rss_size = kinfo->req_rss_size; } else if (kinfo->rss_size > max_rss_size || diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index d261b5a9ef9f..af2245e3bb95 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -50,7 +50,7 @@ static int hclgevf_cmd_csq_clean(struct hclgevf_hw *hw) rmb(); /* Make sure head is ready before touch any data */ if (!hclgevf_is_valid_csq_clean_head(csq, head)) { - dev_warn(&hdev->pdev->dev, "wrong cmd head (%d, %d-%d)\n", head, + dev_warn(&hdev->pdev->dev, "wrong cmd head (%u, %d-%d)\n", head, csq->next_to_use, csq->next_to_clean); dev_warn(&hdev->pdev->dev, "Disabling any further commands to IMP firmware\n"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 9506d7db04ae..25d78a5aaa34 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1581,7 +1581,7 @@ static void hclgevf_reset_err_handle(struct hclgevf_dev *hdev) /* recover handshake status with IMP when reset fail */ hclgevf_reset_handshake(hdev, true); hdev->rst_stats.rst_fail_cnt++; - dev_err(&hdev->pdev->dev, "failed to reset VF(%d)\n", + dev_err(&hdev->pdev->dev, "failed to reset VF(%u)\n", hdev->rst_stats.rst_fail_cnt); if (hdev->rst_stats.rst_fail_cnt < HCLGEVF_RESET_MAX_FAIL_CNT) @@ -2338,7 +2338,7 @@ static int hclgevf_init_msi(struct hclgevf_dev *hdev) } if (vectors < hdev->num_msi) dev_warn(&hdev->pdev->dev, - "requested %d MSI/MSI-X, but allocated %d MSI/MSI-X\n", + "requested %u MSI/MSI-X, but allocated %d MSI/MSI-X\n", hdev->num_msi, vectors); hdev->num_msi = vectors; @@ -2414,12 +2414,12 @@ static void hclgevf_info_show(struct hclgevf_dev *hdev) dev_info(dev, "VF info begin:\n"); - dev_info(dev, "Task queue pairs numbers: %d\n", hdev->num_tqps); - dev_info(dev, "Desc num per TX queue: %d\n", hdev->num_tx_desc); - dev_info(dev, "Desc num per RX queue: %d\n", hdev->num_rx_desc); - dev_info(dev, "Numbers of vports: %d\n", hdev->num_alloc_vport); - dev_info(dev, "HW tc map: %d\n", hdev->hw_tc_map); - dev_info(dev, "PF media type of this VF: %d\n", + dev_info(dev, "Task queue pairs numbers: %u\n", hdev->num_tqps); + dev_info(dev, "Desc num per TX queue: %u\n", hdev->num_tx_desc); + dev_info(dev, "Desc num per RX queue: %u\n", hdev->num_rx_desc); + dev_info(dev, "Numbers of vports: %u\n", hdev->num_alloc_vport); + dev_info(dev, "HW tc map: 0x%x\n", hdev->hw_tc_map); + dev_info(dev, "PF media type of this VF: %u\n", hdev->hw.mac.media_type); dev_info(dev, "VF info end.\n"); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 72bacf89f09c..7cbd715d5e7a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -33,7 +33,7 @@ static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, if (resp_len > HCLGE_MBX_MAX_RESP_DATA_SIZE) { dev_err(&hdev->pdev->dev, - "VF mbx response len(=%d) exceeds maximum(=%d)\n", + "VF mbx response len(=%u) exceeds maximum(=%u)\n", resp_len, HCLGE_MBX_MAX_RESP_DATA_SIZE); return -EINVAL; @@ -49,7 +49,7 @@ static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, if (i >= HCLGEVF_MAX_TRY_TIMES) { dev_err(&hdev->pdev->dev, - "VF could not get mbx(%d,%d) resp(=%d) from PF in %d tries\n", + "VF could not get mbx(%u,%u) resp(=%d) from PF in %d tries\n", code0, code1, hdev->mbx_resp.received_resp, i); return -EIO; } @@ -68,10 +68,10 @@ static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, if (!(r_code0 == code0 && r_code1 == code1 && !mbx_resp->resp_status)) { dev_err(&hdev->pdev->dev, - "VF could not match resp code(code0=%d,code1=%d), %d\n", + "VF could not match resp code(code0=%u,code1=%u), %d\n", code0, code1, mbx_resp->resp_status); dev_err(&hdev->pdev->dev, - "VF could not match resp r_code(r_code0=%d,r_code1=%d)\n", + "VF could not match resp r_code(r_code0=%u,r_code1=%u)\n", r_code0, r_code1); return -EIO; } @@ -168,7 +168,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) flag = le16_to_cpu(crq->desc[crq->next_to_use].flag); if (unlikely(!hnae3_get_bit(flag, HCLGEVF_CMDQ_RX_OUTVLD_B))) { dev_warn(&hdev->pdev->dev, - "dropped invalid mailbox message, code = %d\n", + "dropped invalid mailbox message, code = %u\n", req->msg[0]); /* dropping/not processing this invalid message */ @@ -187,7 +187,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) case HCLGE_MBX_PF_VF_RESP: if (resp->received_resp) dev_warn(&hdev->pdev->dev, - "VF mbx resp flag not clear(%d)\n", + "VF mbx resp flag not clear(%u)\n", req->msg[1]); resp->received_resp = true; @@ -219,7 +219,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) if (atomic_read(&hdev->arq.count) >= HCLGE_MBX_MAX_ARQ_MSG_NUM) { dev_warn(&hdev->pdev->dev, - "Async Q full, dropping msg(%d)\n", + "Async Q full, dropping msg(%u)\n", req->msg[1]); break; } @@ -236,7 +236,7 @@ void hclgevf_mbx_handler(struct hclgevf_dev *hdev) break; default: dev_err(&hdev->pdev->dev, - "VF received unsupported(%d) mbx msg from PF\n", + "VF received unsupported(%u) mbx msg from PF\n", req->msg[0]); break; } @@ -327,7 +327,7 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) break; default: dev_err(&hdev->pdev->dev, - "fetched unsupported(%d) message from arq\n", + "fetched unsupported(%u) message from arq\n", msg_q[0]); break; } -- cgit v1.2.3-59-g8ed1b From 39edaf24f8195e94a07b6fc95a7337f12522e8e9 Mon Sep 17 00:00:00 2001 From: Guojia Liao Date: Thu, 31 Oct 2019 19:23:24 +0800 Subject: net: hns3: cleanup byte order issues when printed Though the hip08 and the IMP(Intelligent Management Processor) have the same byte order right now, it is better to convert __be or __le variable into the CPU's byte order before print. Signed-off-by: Guojia Liao Signed-off-by: Huazhong Tan Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c | 39 ++++---- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 +- .../ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c | 100 ++++++++++++--------- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 4 files changed, 83 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 466a6e3c9cbf..6b328a259efc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -190,21 +190,24 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) addr = le64_to_cpu(tx_desc->addr); dev_info(dev, "TX Queue Num: %u, BD Index: %u\n", q_num, tx_index); dev_info(dev, "(TX)addr: %pad\n", &addr); - dev_info(dev, "(TX)vlan_tag: %u\n", tx_desc->tx.vlan_tag); - dev_info(dev, "(TX)send_size: %u\n", tx_desc->tx.send_size); + dev_info(dev, "(TX)vlan_tag: %u\n", le16_to_cpu(tx_desc->tx.vlan_tag)); + dev_info(dev, "(TX)send_size: %u\n", + le16_to_cpu(tx_desc->tx.send_size)); dev_info(dev, "(TX)vlan_tso: %u\n", tx_desc->tx.type_cs_vlan_tso); dev_info(dev, "(TX)l2_len: %u\n", tx_desc->tx.l2_len); dev_info(dev, "(TX)l3_len: %u\n", tx_desc->tx.l3_len); dev_info(dev, "(TX)l4_len: %u\n", tx_desc->tx.l4_len); - dev_info(dev, "(TX)vlan_tag: %u\n", tx_desc->tx.outer_vlan_tag); - dev_info(dev, "(TX)tv: %u\n", tx_desc->tx.tv); + dev_info(dev, "(TX)vlan_tag: %u\n", + le16_to_cpu(tx_desc->tx.outer_vlan_tag)); + dev_info(dev, "(TX)tv: %u\n", le16_to_cpu(tx_desc->tx.tv)); dev_info(dev, "(TX)vlan_msec: %u\n", tx_desc->tx.ol_type_vlan_msec); dev_info(dev, "(TX)ol2_len: %u\n", tx_desc->tx.ol2_len); dev_info(dev, "(TX)ol3_len: %u\n", tx_desc->tx.ol3_len); dev_info(dev, "(TX)ol4_len: %u\n", tx_desc->tx.ol4_len); - dev_info(dev, "(TX)paylen: %u\n", tx_desc->tx.paylen); - dev_info(dev, "(TX)vld_ra_ri: %u\n", tx_desc->tx.bdtp_fe_sc_vld_ra_ri); - dev_info(dev, "(TX)mss: %u\n", tx_desc->tx.mss); + dev_info(dev, "(TX)paylen: %u\n", le32_to_cpu(tx_desc->tx.paylen)); + dev_info(dev, "(TX)vld_ra_ri: %u\n", + le16_to_cpu(tx_desc->tx.bdtp_fe_sc_vld_ra_ri)); + dev_info(dev, "(TX)mss: %u\n", le16_to_cpu(tx_desc->tx.mss)); ring = &priv->ring[q_num + h->kinfo.num_tqps]; value = readl_relaxed(ring->tqp->io_base + HNS3_RING_RX_RING_TAIL_REG); @@ -214,15 +217,19 @@ static int hns3_dbg_bd_info(struct hnae3_handle *h, const char *cmd_buf) addr = le64_to_cpu(rx_desc->addr); dev_info(dev, "RX Queue Num: %u, BD Index: %u\n", q_num, rx_index); dev_info(dev, "(RX)addr: %pad\n", &addr); - dev_info(dev, "(RX)l234_info: %u\n", rx_desc->rx.l234_info); - dev_info(dev, "(RX)pkt_len: %u\n", rx_desc->rx.pkt_len); - dev_info(dev, "(RX)size: %u\n", rx_desc->rx.size); - dev_info(dev, "(RX)rss_hash: %u\n", rx_desc->rx.rss_hash); - dev_info(dev, "(RX)fd_id: %u\n", rx_desc->rx.fd_id); - dev_info(dev, "(RX)vlan_tag: %u\n", rx_desc->rx.vlan_tag); - dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n", rx_desc->rx.o_dm_vlan_id_fb); - dev_info(dev, "(RX)ot_vlan_tag: %u\n", rx_desc->rx.ot_vlan_tag); - dev_info(dev, "(RX)bd_base_info: %u\n", rx_desc->rx.bd_base_info); + dev_info(dev, "(RX)l234_info: %u\n", + le32_to_cpu(rx_desc->rx.l234_info)); + dev_info(dev, "(RX)pkt_len: %u\n", le16_to_cpu(rx_desc->rx.pkt_len)); + dev_info(dev, "(RX)size: %u\n", le16_to_cpu(rx_desc->rx.size)); + dev_info(dev, "(RX)rss_hash: %u\n", le32_to_cpu(rx_desc->rx.rss_hash)); + dev_info(dev, "(RX)fd_id: %u\n", le16_to_cpu(rx_desc->rx.fd_id)); + dev_info(dev, "(RX)vlan_tag: %u\n", le16_to_cpu(rx_desc->rx.vlan_tag)); + dev_info(dev, "(RX)o_dm_vlan_id_fb: %u\n", + le16_to_cpu(rx_desc->rx.o_dm_vlan_id_fb)); + dev_info(dev, "(RX)ot_vlan_tag: %u\n", + le16_to_cpu(rx_desc->rx.ot_vlan_tag)); + dev_info(dev, "(RX)bd_base_info: %u\n", + le32_to_cpu(rx_desc->rx.bd_base_info)); return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index d5a121a44459..ba0536802b13 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -1710,8 +1710,8 @@ static int hns3_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, int ret = -EIO; netif_dbg(h, drv, netdev, - "set vf vlan: vf=%d, vlan=%u, qos=%u, vlan_proto=%u\n", - vf, vlan, qos, vlan_proto); + "set vf vlan: vf=%d, vlan=%u, qos=%u, vlan_proto=0x%x\n", + vf, vlan, qos, ntohs(vlan_proto)); if (h->ae_algo->ops->set_vf_vlan_filter) ret = h->ae_algo->ops->set_vf_vlan_filter(h, vf, vlan, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c index e65c8cf16a85..112df34b3869 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c @@ -169,7 +169,7 @@ static void hclge_dbg_dump_reg_common(struct hclge_dev *hdev, if (dfx_message->flag) dev_info(&hdev->pdev->dev, "%s: 0x%x\n", dfx_message->message, - desc->data[i % entries_per_desc]); + le32_to_cpu(desc->data[i % entries_per_desc])); dfx_message++; } @@ -237,44 +237,48 @@ static void hclge_dbg_dump_dcb(struct hclge_dev *hdev, const char *cmd_buf) if (ret) return; - dev_info(dev, "sch_nq_cnt: 0x%x\n", desc[0].data[1]); + dev_info(dev, "sch_nq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1])); ret = hclge_dbg_cmd_send(hdev, desc, nq_id, 1, HCLGE_OPC_SCH_RQ_CNT); if (ret) return; - dev_info(dev, "sch_rq_cnt: 0x%x\n", desc[0].data[1]); + dev_info(dev, "sch_rq_cnt: 0x%x\n", le32_to_cpu(desc[0].data[1])); ret = hclge_dbg_cmd_send(hdev, desc, 0, 2, HCLGE_OPC_TM_INTERNAL_STS); if (ret) return; - dev_info(dev, "pri_bp: 0x%x\n", desc[0].data[1]); - dev_info(dev, "fifo_dfx_info: 0x%x\n", desc[0].data[2]); - dev_info(dev, "sch_roce_fifo_afull_gap: 0x%x\n", desc[0].data[3]); - dev_info(dev, "tx_private_waterline: 0x%x\n", desc[0].data[4]); - dev_info(dev, "tm_bypass_en: 0x%x\n", desc[0].data[5]); - dev_info(dev, "SSU_TM_BYPASS_EN: 0x%x\n", desc[1].data[0]); - dev_info(dev, "SSU_RESERVE_CFG: 0x%x\n", desc[1].data[1]); + dev_info(dev, "pri_bp: 0x%x\n", le32_to_cpu(desc[0].data[1])); + dev_info(dev, "fifo_dfx_info: 0x%x\n", le32_to_cpu(desc[0].data[2])); + dev_info(dev, "sch_roce_fifo_afull_gap: 0x%x\n", + le32_to_cpu(desc[0].data[3])); + dev_info(dev, "tx_private_waterline: 0x%x\n", + le32_to_cpu(desc[0].data[4])); + dev_info(dev, "tm_bypass_en: 0x%x\n", le32_to_cpu(desc[0].data[5])); + dev_info(dev, "SSU_TM_BYPASS_EN: 0x%x\n", le32_to_cpu(desc[1].data[0])); + dev_info(dev, "SSU_RESERVE_CFG: 0x%x\n", le32_to_cpu(desc[1].data[1])); ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, HCLGE_OPC_TM_INTERNAL_CNT); if (ret) return; - dev_info(dev, "SCH_NIC_NUM: 0x%x\n", desc[0].data[1]); - dev_info(dev, "SCH_ROCE_NUM: 0x%x\n", desc[0].data[2]); + dev_info(dev, "SCH_NIC_NUM: 0x%x\n", le32_to_cpu(desc[0].data[1])); + dev_info(dev, "SCH_ROCE_NUM: 0x%x\n", le32_to_cpu(desc[0].data[2])); ret = hclge_dbg_cmd_send(hdev, desc, port_id, 1, HCLGE_OPC_TM_INTERNAL_STS_1); if (ret) return; - dev_info(dev, "TC_MAP_SEL: 0x%x\n", desc[0].data[1]); - dev_info(dev, "IGU_PFC_PRI_EN: 0x%x\n", desc[0].data[2]); - dev_info(dev, "MAC_PFC_PRI_EN: 0x%x\n", desc[0].data[3]); - dev_info(dev, "IGU_PRI_MAP_TC_CFG: 0x%x\n", desc[0].data[4]); - dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n", desc[0].data[5]); + dev_info(dev, "TC_MAP_SEL: 0x%x\n", le32_to_cpu(desc[0].data[1])); + dev_info(dev, "IGU_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[2])); + dev_info(dev, "MAC_PFC_PRI_EN: 0x%x\n", le32_to_cpu(desc[0].data[3])); + dev_info(dev, "IGU_PRI_MAP_TC_CFG: 0x%x\n", + le32_to_cpu(desc[0].data[4])); + dev_info(dev, "IGU_TX_PRI_MAP_TC_CFG: 0x%x\n", + le32_to_cpu(desc[0].data[5])); } static void hclge_dbg_dump_reg_cmd(struct hclge_dev *hdev, const char *cmd_buf) @@ -364,7 +368,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data; dev_info(&hdev->pdev->dev, "PG_C pg_id: %u\n", pg_shap_cfg_cmd->pg_id); dev_info(&hdev->pdev->dev, "PG_C pg_shapping: 0x%x\n", - pg_shap_cfg_cmd->pg_shapping_para); + le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para)); cmd = HCLGE_OPC_TM_PG_P_SHAPPING; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -375,7 +379,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) pg_shap_cfg_cmd = (struct hclge_pg_shapping_cmd *)desc.data; dev_info(&hdev->pdev->dev, "PG_P pg_id: %u\n", pg_shap_cfg_cmd->pg_id); dev_info(&hdev->pdev->dev, "PG_P pg_shapping: 0x%x\n", - pg_shap_cfg_cmd->pg_shapping_para); + le32_to_cpu(pg_shap_cfg_cmd->pg_shapping_para)); cmd = HCLGE_OPC_TM_PORT_SHAPPING; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -385,7 +389,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) port_shap_cfg_cmd = (struct hclge_port_shapping_cmd *)desc.data; dev_info(&hdev->pdev->dev, "PORT port_shapping: 0x%x\n", - port_shap_cfg_cmd->port_shapping_para); + le32_to_cpu(port_shap_cfg_cmd->port_shapping_para)); cmd = HCLGE_OPC_TM_PG_SCH_MODE_CFG; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -393,7 +397,8 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) if (ret) goto err_tm_pg_cmd_send; - dev_info(&hdev->pdev->dev, "PG_SCH pg_id: %u\n", desc.data[0]); + dev_info(&hdev->pdev->dev, "PG_SCH pg_id: %u\n", + le32_to_cpu(desc.data[0])); cmd = HCLGE_OPC_TM_PRI_SCH_MODE_CFG; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -401,7 +406,8 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) if (ret) goto err_tm_pg_cmd_send; - dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n", desc.data[0]); + dev_info(&hdev->pdev->dev, "PRI_SCH pri_id: %u\n", + le32_to_cpu(desc.data[0])); cmd = HCLGE_OPC_TM_QS_SCH_MODE_CFG; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -409,7 +415,8 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) if (ret) goto err_tm_pg_cmd_send; - dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n", desc.data[0]); + dev_info(&hdev->pdev->dev, "QS_SCH qs_id: %u\n", + le32_to_cpu(desc.data[0])); if (!hnae3_dev_dcb_supported(hdev)) { dev_info(&hdev->pdev->dev, @@ -429,7 +436,7 @@ static void hclge_dbg_dump_tm_pg(struct hclge_dev *hdev) dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_group_id: 0x%x\n", bp_to_qs_map_cmd->qs_group_id); dev_info(&hdev->pdev->dev, "BP_TO_QSET qs_bit_map: 0x%x\n", - bp_to_qs_map_cmd->qs_bit_map); + le32_to_cpu(bp_to_qs_map_cmd->qs_bit_map)); return; err_tm_pg_cmd_send: @@ -471,7 +478,7 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev) qs_to_pri_map = (struct hclge_qs_to_pri_link_cmd *)desc.data; dev_info(&hdev->pdev->dev, "QS_TO_PRI qs_id: %u\n", - qs_to_pri_map->qs_id); + le16_to_cpu(qs_to_pri_map->qs_id)); dev_info(&hdev->pdev->dev, "QS_TO_PRI priority: %u\n", qs_to_pri_map->priority); dev_info(&hdev->pdev->dev, "QS_TO_PRI link_vld: %u\n", @@ -484,9 +491,10 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev) goto err_tm_cmd_send; nq_to_qs_map = (struct hclge_nq_to_qs_link_cmd *)desc.data; - dev_info(&hdev->pdev->dev, "NQ_TO_QS nq_id: %u\n", nq_to_qs_map->nq_id); + dev_info(&hdev->pdev->dev, "NQ_TO_QS nq_id: %u\n", + le16_to_cpu(nq_to_qs_map->nq_id)); dev_info(&hdev->pdev->dev, "NQ_TO_QS qset_id: 0x%x\n", - nq_to_qs_map->qset_id); + le16_to_cpu(nq_to_qs_map->qset_id)); cmd = HCLGE_OPC_TM_PG_WEIGHT; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -505,7 +513,8 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev) goto err_tm_cmd_send; qs_weight = (struct hclge_qs_weight_cmd *)desc.data; - dev_info(&hdev->pdev->dev, "QS qs_id: %u\n", qs_weight->qs_id); + dev_info(&hdev->pdev->dev, "QS qs_id: %u\n", + le16_to_cpu(qs_weight->qs_id)); dev_info(&hdev->pdev->dev, "QS dwrr: %u\n", qs_weight->dwrr); cmd = HCLGE_OPC_TM_PRI_WEIGHT; @@ -527,7 +536,7 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev) shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data; dev_info(&hdev->pdev->dev, "PRI_C pri_id: %u\n", shap_cfg_cmd->pri_id); dev_info(&hdev->pdev->dev, "PRI_C pri_shapping: 0x%x\n", - shap_cfg_cmd->pri_shapping_para); + le32_to_cpu(shap_cfg_cmd->pri_shapping_para)); cmd = HCLGE_OPC_TM_PRI_P_SHAPPING; hclge_cmd_setup_basic_desc(&desc, cmd, true); @@ -538,7 +547,7 @@ static void hclge_dbg_dump_tm(struct hclge_dev *hdev) shap_cfg_cmd = (struct hclge_pri_shapping_cmd *)desc.data; dev_info(&hdev->pdev->dev, "PRI_P pri_id: %u\n", shap_cfg_cmd->pri_id); dev_info(&hdev->pdev->dev, "PRI_P pri_shapping: 0x%x\n", - shap_cfg_cmd->pri_shapping_para); + le32_to_cpu(shap_cfg_cmd->pri_shapping_para)); hclge_dbg_dump_tm_pg(hdev); @@ -658,7 +667,7 @@ static void hclge_dbg_dump_qos_pause_cfg(struct hclge_dev *hdev) dev_info(&hdev->pdev->dev, "pause_trans_gap: 0x%x\n", pause_param->pause_trans_gap); dev_info(&hdev->pdev->dev, "pause_trans_time: 0x%x\n", - pause_param->pause_trans_time); + le16_to_cpu(pause_param->pause_trans_time)); } static void hclge_dbg_dump_qos_pri_map(struct hclge_dev *hdev) @@ -712,7 +721,7 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) tx_buf_cmd = (struct hclge_tx_buff_alloc_cmd *)desc[0].data; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) dev_info(&hdev->pdev->dev, "tx_packet_buf_tc_%d: 0x%x\n", i, - tx_buf_cmd->tx_pkt_buff[i]); + le16_to_cpu(tx_buf_cmd->tx_pkt_buff[i])); cmd = HCLGE_OPC_RX_PRIV_BUFF_ALLOC; hclge_cmd_setup_basic_desc(desc, cmd, true); @@ -724,10 +733,10 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) rx_buf_cmd = (struct hclge_rx_priv_buff_cmd *)desc[0].data; for (i = 0; i < HCLGE_MAX_TC_NUM; i++) dev_info(&hdev->pdev->dev, "rx_packet_buf_tc_%d: 0x%x\n", i, - rx_buf_cmd->buf_num[i]); + le16_to_cpu(rx_buf_cmd->buf_num[i])); dev_info(&hdev->pdev->dev, "rx_share_buf: 0x%x\n", - rx_buf_cmd->shared_buf); + le16_to_cpu(rx_buf_cmd->shared_buf)); cmd = HCLGE_OPC_RX_COM_WL_ALLOC; hclge_cmd_setup_basic_desc(desc, cmd, true); @@ -738,7 +747,8 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) rx_com_wl = (struct hclge_rx_com_wl *)desc[0].data; dev_info(&hdev->pdev->dev, "\n"); dev_info(&hdev->pdev->dev, "rx_com_wl: high: 0x%x, low: 0x%x\n", - rx_com_wl->com_wl.high, rx_com_wl->com_wl.low); + le16_to_cpu(rx_com_wl->com_wl.high), + le16_to_cpu(rx_com_wl->com_wl.low)); cmd = HCLGE_OPC_RX_GBL_PKT_CNT; hclge_cmd_setup_basic_desc(desc, cmd, true); @@ -749,7 +759,8 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) rx_packet_cnt = (struct hclge_rx_com_wl *)desc[0].data; dev_info(&hdev->pdev->dev, "rx_global_packet_cnt: high: 0x%x, low: 0x%x\n", - rx_packet_cnt->com_wl.high, rx_packet_cnt->com_wl.low); + le16_to_cpu(rx_packet_cnt->com_wl.high), + le16_to_cpu(rx_packet_cnt->com_wl.low)); dev_info(&hdev->pdev->dev, "\n"); if (!hnae3_dev_dcb_supported(hdev)) { @@ -769,14 +780,16 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++) dev_info(&hdev->pdev->dev, "rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n", i, - rx_priv_wl->tc_wl[i].high, rx_priv_wl->tc_wl[i].low); + le16_to_cpu(rx_priv_wl->tc_wl[i].high), + le16_to_cpu(rx_priv_wl->tc_wl[i].low)); rx_priv_wl = (struct hclge_rx_priv_wl_buf *)desc[1].data; for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++) dev_info(&hdev->pdev->dev, "rx_priv_wl_tc_%d: high: 0x%x, low: 0x%x\n", i + HCLGE_TC_NUM_ONE_DESC, - rx_priv_wl->tc_wl[i].high, rx_priv_wl->tc_wl[i].low); + le16_to_cpu(rx_priv_wl->tc_wl[i].high), + le16_to_cpu(rx_priv_wl->tc_wl[i].low)); cmd = HCLGE_OPC_RX_COM_THRD_ALLOC; hclge_cmd_setup_basic_desc(&desc[0], cmd, true); @@ -791,16 +804,16 @@ static void hclge_dbg_dump_qos_buf_cfg(struct hclge_dev *hdev) for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++) dev_info(&hdev->pdev->dev, "rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n", i, - rx_com_thrd->com_thrd[i].high, - rx_com_thrd->com_thrd[i].low); + le16_to_cpu(rx_com_thrd->com_thrd[i].high), + le16_to_cpu(rx_com_thrd->com_thrd[i].low)); rx_com_thrd = (struct hclge_rx_com_thrd *)desc[1].data; for (i = 0; i < HCLGE_TC_NUM_ONE_DESC; i++) dev_info(&hdev->pdev->dev, "rx_com_thrd_tc_%d: high: 0x%x, low: 0x%x\n", i + HCLGE_TC_NUM_ONE_DESC, - rx_com_thrd->com_thrd[i].high, - rx_com_thrd->com_thrd[i].low); + le16_to_cpu(rx_com_thrd->com_thrd[i].high), + le16_to_cpu(rx_com_thrd->com_thrd[i].low)); return; err_qos_cmd_send: @@ -845,7 +858,8 @@ static void hclge_dbg_dump_mng_table(struct hclge_dev *hdev) memset(printf_buf, 0, HCLGE_DBG_BUF_LEN); snprintf(printf_buf, HCLGE_DBG_BUF_LEN, "%02u |%02x:%02x:%02x:%02x:%02x:%02x|", - req0->index, req0->mac_addr[0], req0->mac_addr[1], + le16_to_cpu(req0->index), + req0->mac_addr[0], req0->mac_addr[1], req0->mac_addr[2], req0->mac_addr[3], req0->mac_addr[4], req0->mac_addr[5]); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index babec3b6ab16..4f8f0684beb2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5740,7 +5740,7 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle, if (!hclge_fd_rule_exist(hdev, fs->location)) { dev_err(&hdev->pdev->dev, - "Delete fail, rule %d is inexistent\n", fs->location); + "Delete fail, rule %u is inexistent\n", fs->location); return -ENOENT; } -- cgit v1.2.3-59-g8ed1b From f07f30042f8e0f7e67c5bf573e764a846ca9e8b5 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:47 +0200 Subject: dpaa_eth: use only one buffer pool per interface Currently the DPAA Ethernet driver is using three buffer pools for each interface, with three different sizes for the buffers provided for the FMan reception path. This patch reduces the number of buffer pools to one per interface. This change is in preparation of another, that will be switching from netdev_frags to page backed buffers for the receive path. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 95 ++++++++-------------- drivers/net/ethernet/freescale/dpaa/dpaa_eth.h | 4 +- .../net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c | 6 +- drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c | 44 +++++----- 4 files changed, 57 insertions(+), 92 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index d3214541c7c5..9af6fdbeb9af 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -178,23 +178,7 @@ struct fm_port_fqs { /* All the dpa bps in use at any moment */ static struct dpaa_bp *dpaa_bp_array[BM_MAX_NUM_OF_POOLS]; -/* The raw buffer size must be cacheline aligned */ #define DPAA_BP_RAW_SIZE 4096 -/* When using more than one buffer pool, the raw sizes are as follows: - * 1 bp: 4KB - * 2 bp: 2KB, 4KB - * 3 bp: 1KB, 2KB, 4KB - * 4 bp: 1KB, 2KB, 4KB, 8KB - */ -static inline size_t bpool_buffer_raw_size(u8 index, u8 cnt) -{ - size_t res = DPAA_BP_RAW_SIZE / 4; - u8 i; - - for (i = (cnt < 3) ? cnt : 3; i < 3 + index; i++) - res *= 2; - return res; -} /* FMan-DMA requires 16-byte alignment for Rx buffers, but SKB_DATA_ALIGN is * even stronger (SMP_CACHE_BYTES-aligned), so we just get away with that, @@ -596,10 +580,7 @@ static void dpaa_bp_free(struct dpaa_bp *dpaa_bp) static void dpaa_bps_free(struct dpaa_priv *priv) { - int i; - - for (i = 0; i < DPAA_BPS_NUM; i++) - dpaa_bp_free(priv->dpaa_bps[i]); + dpaa_bp_free(priv->dpaa_bp); } /* Use multiple WQs for FQ assignment: @@ -1197,15 +1178,15 @@ static int dpaa_eth_init_tx_port(struct fman_port *port, struct dpaa_fq *errq, return err; } -static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps, - size_t count, struct dpaa_fq *errq, +static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp *bp, + struct dpaa_fq *errq, struct dpaa_fq *defq, struct dpaa_fq *pcdq, struct dpaa_buffer_layout *buf_layout) { struct fman_buffer_prefix_content buf_prefix_content; struct fman_port_rx_params *rx_p; struct fman_port_params params; - int i, err; + int err; memset(¶ms, 0, sizeof(params)); memset(&buf_prefix_content, 0, sizeof(buf_prefix_content)); @@ -1224,12 +1205,9 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps, rx_p->pcd_fqs_count = DPAA_ETH_PCD_RXQ_NUM; } - count = min(ARRAY_SIZE(rx_p->ext_buf_pools.ext_buf_pool), count); - rx_p->ext_buf_pools.num_of_pools_used = (u8)count; - for (i = 0; i < count; i++) { - rx_p->ext_buf_pools.ext_buf_pool[i].id = bps[i]->bpid; - rx_p->ext_buf_pools.ext_buf_pool[i].size = (u16)bps[i]->size; - } + rx_p->ext_buf_pools.num_of_pools_used = 1; + rx_p->ext_buf_pools.ext_buf_pool[0].id = bp->bpid; + rx_p->ext_buf_pools.ext_buf_pool[0].size = (u16)bp->size; err = fman_port_config(port, ¶ms); if (err) { @@ -1252,7 +1230,7 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp **bps, } static int dpaa_eth_init_ports(struct mac_device *mac_dev, - struct dpaa_bp **bps, size_t count, + struct dpaa_bp *bp, struct fm_port_fqs *port_fqs, struct dpaa_buffer_layout *buf_layout, struct device *dev) @@ -1266,7 +1244,7 @@ static int dpaa_eth_init_ports(struct mac_device *mac_dev, if (err) return err; - err = dpaa_eth_init_rx_port(rxport, bps, count, port_fqs->rx_errq, + err = dpaa_eth_init_rx_port(rxport, bp, port_fqs->rx_errq, port_fqs->rx_defq, port_fqs->rx_pcdq, &buf_layout[RX]); @@ -1583,17 +1561,16 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv) { struct dpaa_bp *dpaa_bp; int *countptr; - int res, i; + int res; + + dpaa_bp = priv->dpaa_bp; + if (!dpaa_bp) + return -EINVAL; + countptr = this_cpu_ptr(dpaa_bp->percpu_count); + res = dpaa_eth_refill_bpool(dpaa_bp, countptr); + if (res) + return res; - for (i = 0; i < DPAA_BPS_NUM; i++) { - dpaa_bp = priv->dpaa_bps[i]; - if (!dpaa_bp) - return -EINVAL; - countptr = this_cpu_ptr(dpaa_bp->percpu_count); - res = dpaa_eth_refill_bpool(dpaa_bp, countptr); - if (res) - return res; - } return 0; } @@ -2761,13 +2738,13 @@ static inline u16 dpaa_get_headroom(struct dpaa_buffer_layout *bl) static int dpaa_eth_probe(struct platform_device *pdev) { - struct dpaa_bp *dpaa_bps[DPAA_BPS_NUM] = {NULL}; struct net_device *net_dev = NULL; + struct dpaa_bp *dpaa_bp = NULL; struct dpaa_fq *dpaa_fq, *tmp; struct dpaa_priv *priv = NULL; struct fm_port_fqs port_fqs; struct mac_device *mac_dev; - int err = 0, i, channel; + int err = 0, channel; struct device *dev; dev = &pdev->dev; @@ -2856,23 +2833,21 @@ static int dpaa_eth_probe(struct platform_device *pdev) priv->buf_layout[TX].priv_data_size = DPAA_TX_PRIV_DATA_SIZE; /* Tx */ /* bp init */ - for (i = 0; i < DPAA_BPS_NUM; i++) { - dpaa_bps[i] = dpaa_bp_alloc(dev); - if (IS_ERR(dpaa_bps[i])) { - err = PTR_ERR(dpaa_bps[i]); - goto free_dpaa_bps; - } - /* the raw size of the buffers used for reception */ - dpaa_bps[i]->raw_size = bpool_buffer_raw_size(i, DPAA_BPS_NUM); - /* avoid runtime computations by keeping the usable size here */ - dpaa_bps[i]->size = dpaa_bp_size(dpaa_bps[i]->raw_size); - dpaa_bps[i]->priv = priv; - - err = dpaa_bp_alloc_pool(dpaa_bps[i]); - if (err < 0) - goto free_dpaa_bps; - priv->dpaa_bps[i] = dpaa_bps[i]; + dpaa_bp = dpaa_bp_alloc(dev); + if (IS_ERR(dpaa_bp)) { + err = PTR_ERR(dpaa_bp); + goto free_dpaa_bps; } + /* the raw size of the buffers used for reception */ + dpaa_bp->raw_size = DPAA_BP_RAW_SIZE; + /* avoid runtime computations by keeping the usable size here */ + dpaa_bp->size = dpaa_bp_size(dpaa_bp->raw_size); + dpaa_bp->priv = priv; + + err = dpaa_bp_alloc_pool(dpaa_bp); + if (err < 0) + goto free_dpaa_bps; + priv->dpaa_bp = dpaa_bp; INIT_LIST_HEAD(&priv->dpaa_fq_list); @@ -2930,7 +2905,7 @@ static int dpaa_eth_probe(struct platform_device *pdev) priv->rx_headroom = dpaa_get_headroom(&priv->buf_layout[RX]); /* All real interfaces need their ports initialized */ - err = dpaa_eth_init_ports(mac_dev, dpaa_bps, DPAA_BPS_NUM, &port_fqs, + err = dpaa_eth_init_ports(mac_dev, dpaa_bp, &port_fqs, &priv->buf_layout[0], dev); if (err) goto free_dpaa_fqs; diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h index 1bdfead1d334..fc2cc4c48e06 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h @@ -47,8 +47,6 @@ /* Total number of Tx queues */ #define DPAA_ETH_TXQ_NUM (DPAA_TC_NUM * DPAA_TC_TXQ_NUM) -#define DPAA_BPS_NUM 3 /* number of bpools per interface */ - /* More detailed FQ types - used for fine-grained WQ assignments */ enum dpaa_fq_type { FQ_TYPE_RX_DEFAULT = 1, /* Rx Default FQs */ @@ -148,7 +146,7 @@ struct dpaa_buffer_layout { struct dpaa_priv { struct dpaa_percpu_priv __percpu *percpu_priv; - struct dpaa_bp *dpaa_bps[DPAA_BPS_NUM]; + struct dpaa_bp *dpaa_bp; /* Store here the needed Tx headroom for convenience and speed * (even though it can be computed based on the fields of buf_layout) */ diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c index 0d9b185e317f..ee62d25cac81 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth_sysfs.c @@ -131,11 +131,9 @@ static ssize_t dpaa_eth_show_bpids(struct device *dev, { struct dpaa_priv *priv = netdev_priv(to_net_dev(dev)); ssize_t bytes = 0; - int i = 0; - for (i = 0; i < DPAA_BPS_NUM; i++) - bytes += snprintf(buf + bytes, PAGE_SIZE - bytes, "%u\n", - priv->dpaa_bps[i]->bpid); + bytes += snprintf(buf + bytes, PAGE_SIZE - bytes, "%u\n", + priv->dpaa_bp->bpid); return bytes; } diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 7ce2e99b594d..bc6ed1df53ca 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -223,7 +223,7 @@ static int dpaa_get_sset_count(struct net_device *net_dev, int type) unsigned int total_stats, num_stats; num_stats = num_online_cpus() + 1; - total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM) + + total_stats = num_stats * (DPAA_STATS_PERCPU_LEN + 1) + DPAA_STATS_GLOBAL_LEN; switch (type) { @@ -235,10 +235,10 @@ static int dpaa_get_sset_count(struct net_device *net_dev, int type) } static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus, - int crr_cpu, u64 *bp_count, u64 *data) + int crr_cpu, u64 bp_count, u64 *data) { int num_values = num_cpus + 1; - int crr = 0, j; + int crr = 0; /* update current CPU's stats and also add them to the total values */ data[crr * num_values + crr_cpu] = percpu_priv->in_interrupt; @@ -262,23 +262,21 @@ static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus, data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors; data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors; - for (j = 0; j < DPAA_BPS_NUM; j++) { - data[crr * num_values + crr_cpu] = bp_count[j]; - data[crr++ * num_values + num_cpus] += bp_count[j]; - } + data[crr * num_values + crr_cpu] = bp_count; + data[crr++ * num_values + num_cpus] += bp_count; } static void dpaa_get_ethtool_stats(struct net_device *net_dev, struct ethtool_stats *stats, u64 *data) { - u64 bp_count[DPAA_BPS_NUM], cg_time, cg_num; struct dpaa_percpu_priv *percpu_priv; struct dpaa_rx_errors rx_errors; unsigned int num_cpus, offset; + u64 bp_count, cg_time, cg_num; struct dpaa_ern_cnt ern_cnt; struct dpaa_bp *dpaa_bp; struct dpaa_priv *priv; - int total_stats, i, j; + int total_stats, i; bool cg_status; total_stats = dpaa_get_sset_count(net_dev, ETH_SS_STATS); @@ -292,12 +290,10 @@ static void dpaa_get_ethtool_stats(struct net_device *net_dev, for_each_online_cpu(i) { percpu_priv = per_cpu_ptr(priv->percpu_priv, i); - for (j = 0; j < DPAA_BPS_NUM; j++) { - dpaa_bp = priv->dpaa_bps[j]; - if (!dpaa_bp->percpu_count) - continue; - bp_count[j] = *(per_cpu_ptr(dpaa_bp->percpu_count, i)); - } + dpaa_bp = priv->dpaa_bp; + if (!dpaa_bp->percpu_count) + continue; + bp_count = *(per_cpu_ptr(dpaa_bp->percpu_count, i)); rx_errors.dme += percpu_priv->rx_errors.dme; rx_errors.fpe += percpu_priv->rx_errors.fpe; rx_errors.fse += percpu_priv->rx_errors.fse; @@ -315,7 +311,7 @@ static void dpaa_get_ethtool_stats(struct net_device *net_dev, copy_stats(percpu_priv, num_cpus, i, bp_count, data); } - offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + DPAA_BPS_NUM); + offset = (num_cpus + 1) * (DPAA_STATS_PERCPU_LEN + 1); memcpy(data + offset, &rx_errors, sizeof(struct dpaa_rx_errors)); offset += sizeof(struct dpaa_rx_errors) / sizeof(u64); @@ -363,18 +359,16 @@ static void dpaa_get_strings(struct net_device *net_dev, u32 stringset, memcpy(strings, string_cpu, ETH_GSTRING_LEN); strings += ETH_GSTRING_LEN; } - for (i = 0; i < DPAA_BPS_NUM; i++) { - for (j = 0; j < num_cpus; j++) { - snprintf(string_cpu, ETH_GSTRING_LEN, - "bpool %c [CPU %d]", 'a' + i, j); - memcpy(strings, string_cpu, ETH_GSTRING_LEN); - strings += ETH_GSTRING_LEN; - } - snprintf(string_cpu, ETH_GSTRING_LEN, "bpool %c [TOTAL]", - 'a' + i); + for (j = 0; j < num_cpus; j++) { + snprintf(string_cpu, ETH_GSTRING_LEN, + "bpool [CPU %d]", j); memcpy(strings, string_cpu, ETH_GSTRING_LEN); strings += ETH_GSTRING_LEN; } + snprintf(string_cpu, ETH_GSTRING_LEN, "bpool [TOTAL]"); + memcpy(strings, string_cpu, ETH_GSTRING_LEN); + strings += ETH_GSTRING_LEN; + memcpy(strings, dpaa_stats_global, size); } -- cgit v1.2.3-59-g8ed1b From 8151ee88bad568f0c8284d913310473f3b95945d Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:48 +0200 Subject: dpaa_eth: use page backed rx buffers Change the buffers used for reception from netdev_frags to pages. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 51 +++++++++++--------------- 1 file changed, 22 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 9af6fdbeb9af..9979cd09214c 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -180,13 +180,7 @@ static struct dpaa_bp *dpaa_bp_array[BM_MAX_NUM_OF_POOLS]; #define DPAA_BP_RAW_SIZE 4096 -/* FMan-DMA requires 16-byte alignment for Rx buffers, but SKB_DATA_ALIGN is - * even stronger (SMP_CACHE_BYTES-aligned), so we just get away with that, - * via SKB_WITH_OVERHEAD(). We can't rely on netdev_alloc_frag() giving us - * half-page-aligned buffers, so we reserve some more space for start-of-buffer - * alignment. - */ -#define dpaa_bp_size(raw_size) SKB_WITH_OVERHEAD((raw_size) - SMP_CACHE_BYTES) +#define dpaa_bp_size(raw_size) SKB_WITH_OVERHEAD(raw_size) static int dpaa_max_frm; @@ -1313,13 +1307,14 @@ static void dpaa_fd_release(const struct net_device *net_dev, vaddr = phys_to_virt(qm_fd_addr(fd)); sgt = vaddr + qm_fd_get_offset(fd); - dma_unmap_single(dpaa_bp->priv->rx_dma_dev, qm_fd_addr(fd), - dpaa_bp->size, DMA_FROM_DEVICE); + dma_unmap_page(dpaa_bp->priv->rx_dma_dev, qm_fd_addr(fd), + DPAA_BP_RAW_SIZE, DMA_FROM_DEVICE); dpaa_release_sgt_members(sgt); - addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, vaddr, - dpaa_bp->size, DMA_FROM_DEVICE); + addr = dma_map_page(dpaa_bp->priv->rx_dma_dev, + virt_to_page(vaddr), 0, DPAA_BP_RAW_SIZE, + DMA_FROM_DEVICE); if (dma_mapping_error(dpaa_bp->priv->rx_dma_dev, addr)) { netdev_err(net_dev, "DMA mapping failed\n"); return; @@ -1469,21 +1464,18 @@ static int dpaa_bp_add_8_bufs(const struct dpaa_bp *dpaa_bp) struct net_device *net_dev = dpaa_bp->priv->net_dev; struct bm_buffer bmb[8]; dma_addr_t addr; - void *new_buf; + struct page *p; u8 i; for (i = 0; i < 8; i++) { - new_buf = netdev_alloc_frag(dpaa_bp->raw_size); - if (unlikely(!new_buf)) { - netdev_err(net_dev, - "netdev_alloc_frag() failed, size %zu\n", - dpaa_bp->raw_size); + p = dev_alloc_pages(0); + if (unlikely(!p)) { + netdev_err(net_dev, "dev_alloc_pages() failed\n"); goto release_previous_buffs; } - new_buf = PTR_ALIGN(new_buf, SMP_CACHE_BYTES); - addr = dma_map_single(dpaa_bp->priv->rx_dma_dev, new_buf, - dpaa_bp->size, DMA_FROM_DEVICE); + addr = dma_map_page(dpaa_bp->priv->rx_dma_dev, p, 0, + DPAA_BP_RAW_SIZE, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(dpaa_bp->priv->rx_dma_dev, addr))) { netdev_err(net_dev, "DMA map failed\n"); @@ -1694,7 +1686,7 @@ static struct sk_buff *contig_fd_to_skb(const struct dpaa_priv *priv, return skb; free_buffer: - skb_free_frag(vaddr); + free_pages((unsigned long)vaddr, 0); return NULL; } @@ -1741,8 +1733,8 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, goto free_buffers; count_ptr = this_cpu_ptr(dpaa_bp->percpu_count); - dma_unmap_single(dpaa_bp->priv->rx_dma_dev, sg_addr, - dpaa_bp->size, DMA_FROM_DEVICE); + dma_unmap_page(priv->rx_dma_dev, sg_addr, + DPAA_BP_RAW_SIZE, DMA_FROM_DEVICE); if (!skb) { sz = dpaa_bp->size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); @@ -1794,7 +1786,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, WARN_ONCE(i == DPAA_SGT_MAX_ENTRIES, "No final bit on SGT\n"); /* free the SG table buffer */ - skb_free_frag(vaddr); + free_pages((unsigned long)vaddr, 0); return skb; @@ -1811,7 +1803,7 @@ free_buffers: for (i = 0; i < DPAA_SGT_MAX_ENTRIES ; i++) { sg_addr = qm_sg_addr(&sgt[i]); sg_vaddr = phys_to_virt(sg_addr); - skb_free_frag(sg_vaddr); + free_pages((unsigned long)sg_vaddr, 0); dpaa_bp = dpaa_bpid2pool(sgt[i].bpid); if (dpaa_bp) { count_ptr = this_cpu_ptr(dpaa_bp->percpu_count); @@ -1822,7 +1814,7 @@ free_buffers: break; } /* free the SGT fragment */ - skb_free_frag(vaddr); + free_pages((unsigned long)vaddr, 0); return NULL; } @@ -2281,8 +2273,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, return qman_cb_dqrr_consume; } - dma_unmap_single(dpaa_bp->priv->rx_dma_dev, addr, dpaa_bp->size, - DMA_FROM_DEVICE); + dma_unmap_page(dpaa_bp->priv->rx_dma_dev, addr, DPAA_BP_RAW_SIZE, + DMA_FROM_DEVICE); /* prefetch the first 64 bytes of the frame or the SGT start */ vaddr = phys_to_virt(addr); @@ -2637,7 +2629,8 @@ static inline void dpaa_bp_free_pf(const struct dpaa_bp *bp, { dma_addr_t addr = bm_buf_addr(bmb); - dma_unmap_single(bp->priv->rx_dma_dev, addr, bp->size, DMA_FROM_DEVICE); + dma_unmap_page(bp->priv->rx_dma_dev, addr, DPAA_BP_RAW_SIZE, + DMA_FROM_DEVICE); skb_free_frag(phys_to_virt(addr)); } -- cgit v1.2.3-59-g8ed1b From c70fd3182caef014e6c628b412f81aa57a3ef9e4 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:49 +0200 Subject: dpaa_eth: perform DMA unmapping before read DMA unmapping is required before accessing the HW provided timestamping information. Fixes: 4664856e9ca2 ("dpaa_eth: add support for hardware timestamping") Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 9979cd09214c..4b0a1b0f9888 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1591,18 +1591,6 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, skbh = (struct sk_buff **)phys_to_virt(addr); skb = *skbh; - if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { - memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - - if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh, - &ns)) { - shhwtstamps.hwtstamp = ns_to_ktime(ns); - skb_tstamp_tx(skb, &shhwtstamps); - } else { - dev_warn(dev, "fman_port_get_tstamp failed!\n"); - } - } - if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { nr_frags = skb_shinfo(skb)->nr_frags; dma_unmap_single(priv->tx_dma_dev, addr, @@ -1625,14 +1613,28 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[i]), qm_sg_entry_get_len(&sgt[i]), dma_dir); } - - /* Free the page frag that we allocated on Tx */ - skb_free_frag(phys_to_virt(addr)); } else { dma_unmap_single(priv->tx_dma_dev, addr, skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); } + /* DMA unmapping is required before accessing the HW provided info */ + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + + if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh, + &ns)) { + shhwtstamps.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(skb, &shhwtstamps); + } else { + dev_warn(dev, "fman_port_get_tstamp failed!\n"); + } + } + + if (qm_fd_get_format(fd) == qm_fd_sg) + /* Free the page frag that we allocated on Tx */ + skb_free_frag(phys_to_virt(addr)); + return skb; } -- cgit v1.2.3-59-g8ed1b From 9a4f4f3a894ff4487f5597b7aabba9432b238292 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:50 +0200 Subject: dpaa_eth: avoid timestamp read on error paths The dpaa_cleanup_tx_fd() function is called by the frame transmit confirmation callback but also on several error paths. This function is reading the transmit timestamp value. Avoid reading an invalid timestamp value on the error paths. Fixes: 4664856e9ca2 ("dpaa_eth: add support for hardware timestamping") Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 4b0a1b0f9888..085cf0636a8d 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1571,13 +1571,15 @@ static int dpaa_eth_refill_bpools(struct dpaa_priv *priv) * Skb freeing is not handled here. * * This function may be called on error paths in the Tx function, so guard - * against cases when not all fd relevant fields were filled in. + * against cases when not all fd relevant fields were filled in. To avoid + * reading the invalid transmission timestamp for the error paths set ts to + * false. * * Return the skb backpointer, since for S/G frames the buffer containing it * gets freed here. */ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, - const struct qm_fd *fd) + const struct qm_fd *fd, bool ts) { const enum dma_data_direction dma_dir = DMA_TO_DEVICE; struct device *dev = priv->net_dev->dev.parent; @@ -1619,7 +1621,8 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, } /* DMA unmapping is required before accessing the HW provided info */ - if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + if (ts && priv->tx_tstamp && + skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { memset(&shhwtstamps, 0, sizeof(shhwtstamps)); if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh, @@ -2085,7 +2088,7 @@ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev) if (likely(dpaa_xmit(priv, percpu_stats, queue_mapping, &fd) == 0)) return NETDEV_TX_OK; - dpaa_cleanup_tx_fd(priv, &fd); + dpaa_cleanup_tx_fd(priv, &fd, false); skb_to_fd_failed: enomem: percpu_stats->tx_errors++; @@ -2131,7 +2134,7 @@ static void dpaa_tx_error(struct net_device *net_dev, percpu_priv->stats.tx_errors++; - skb = dpaa_cleanup_tx_fd(priv, fd); + skb = dpaa_cleanup_tx_fd(priv, fd, false); dev_kfree_skb(skb); } @@ -2171,7 +2174,7 @@ static void dpaa_tx_conf(struct net_device *net_dev, percpu_priv->tx_confirm++; - skb = dpaa_cleanup_tx_fd(priv, fd); + skb = dpaa_cleanup_tx_fd(priv, fd, true); consume_skb(skb); } @@ -2398,7 +2401,7 @@ static void egress_ern(struct qman_portal *portal, percpu_priv->stats.tx_fifo_errors++; count_ern(percpu_priv, msg); - skb = dpaa_cleanup_tx_fd(priv, fd); + skb = dpaa_cleanup_tx_fd(priv, fd, false); dev_kfree_skb_any(skb); } -- cgit v1.2.3-59-g8ed1b From ae1512fb745f60d35de4e2140df7b4b2e3497abb Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:51 +0200 Subject: dpaa_eth: simplify variables used in dpaa_cleanup_tx_fd() Avoid casts and repeated conversions. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 085cf0636a8d..f0b5da50a4a5 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1585,13 +1585,13 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, struct device *dev = priv->net_dev->dev.parent; struct skb_shared_hwtstamps shhwtstamps; dma_addr_t addr = qm_fd_addr(fd); + void *vaddr = phys_to_virt(addr); const struct qm_sg_entry *sgt; - struct sk_buff **skbh, *skb; + struct sk_buff *skb; int nr_frags, i; u64 ns; - skbh = (struct sk_buff **)phys_to_virt(addr); - skb = *skbh; + skb = *(struct sk_buff **)vaddr; if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { nr_frags = skb_shinfo(skb)->nr_frags; @@ -1602,7 +1602,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, /* The sgt buffer has been allocated with netdev_alloc_frag(), * it's from lowmem. */ - sgt = phys_to_virt(addr + qm_fd_get_offset(fd)); + sgt = vaddr + qm_fd_get_offset(fd); /* sgt[0] is from lowmem, was dma_map_single()-ed */ dma_unmap_single(priv->tx_dma_dev, qm_sg_addr(&sgt[0]), @@ -1617,7 +1617,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, } } else { dma_unmap_single(priv->tx_dma_dev, addr, - skb_tail_pointer(skb) - (u8 *)skbh, dma_dir); + skb_tail_pointer(skb) - (u8 *)vaddr, dma_dir); } /* DMA unmapping is required before accessing the HW provided info */ @@ -1625,7 +1625,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - if (!fman_port_get_tstamp(priv->mac_dev->port[TX], (void *)skbh, + if (!fman_port_get_tstamp(priv->mac_dev->port[TX], vaddr, &ns)) { shhwtstamps.hwtstamp = ns_to_ktime(ns); skb_tstamp_tx(skb, &shhwtstamps); @@ -1636,7 +1636,7 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, if (qm_fd_get_format(fd) == qm_fd_sg) /* Free the page frag that we allocated on Tx */ - skb_free_frag(phys_to_virt(addr)); + skb_free_frag(vaddr); return skb; } -- cgit v1.2.3-59-g8ed1b From 7689d82c4585cf2047801b36f9a78410c8237a25 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:52 +0200 Subject: dpaa_eth: use fd information in dpaa_cleanup_tx_fd() Instead of reading skb fields, use information from the DPAA frame descriptor. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index f0b5da50a4a5..a278651c81f6 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1588,13 +1588,10 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, void *vaddr = phys_to_virt(addr); const struct qm_sg_entry *sgt; struct sk_buff *skb; - int nr_frags, i; u64 ns; - - skb = *(struct sk_buff **)vaddr; + int i; if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { - nr_frags = skb_shinfo(skb)->nr_frags; dma_unmap_single(priv->tx_dma_dev, addr, qm_fd_get_offset(fd) + DPAA_SGT_SIZE, dma_dir); @@ -1609,7 +1606,8 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, qm_sg_entry_get_len(&sgt[0]), dma_dir); /* remaining pages were mapped with skb_frag_dma_map() */ - for (i = 1; i <= nr_frags; i++) { + for (i = 1; (i < DPAA_SGT_MAX_ENTRIES) && + !qm_sg_entry_is_final(&sgt[i - 1]); i++) { WARN_ON(qm_sg_entry_is_ext(&sgt[i])); dma_unmap_page(priv->tx_dma_dev, qm_sg_addr(&sgt[i]), @@ -1617,9 +1615,12 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, } } else { dma_unmap_single(priv->tx_dma_dev, addr, - skb_tail_pointer(skb) - (u8 *)vaddr, dma_dir); + priv->tx_headroom + qm_fd_get_length(fd), + dma_dir); } + skb = *(struct sk_buff **)vaddr; + /* DMA unmapping is required before accessing the HW provided info */ if (ts && priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { -- cgit v1.2.3-59-g8ed1b From 2388ba36e94594406a755aceafc5983c289e68bf Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:53 +0200 Subject: dpaa_eth: cleanup skb_to_contig_fd() Remove cast, align variable name, simplify DMA map size computation. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index a278651c81f6..f3aa154172c3 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1369,7 +1369,7 @@ static void count_ern(struct dpaa_percpu_priv *percpu_priv, static int dpaa_enable_tx_csum(struct dpaa_priv *priv, struct sk_buff *skb, struct qm_fd *fd, - char *parse_results) + void *parse_results) { struct fman_prs_result *parse_result; u16 ethertype = ntohs(skb->protocol); @@ -1831,7 +1831,7 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, { struct net_device *net_dev = priv->net_dev; enum dma_data_direction dma_dir; - unsigned char *buffer_start; + unsigned char *buff_start; struct sk_buff **skbh; dma_addr_t addr; int err; @@ -1840,10 +1840,10 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, * available, so just use that for offset. */ fd->bpid = FSL_DPAA_BPID_INV; - buffer_start = skb->data - priv->tx_headroom; + buff_start = skb->data - priv->tx_headroom; dma_dir = DMA_TO_DEVICE; - skbh = (struct sk_buff **)buffer_start; + skbh = (struct sk_buff **)buff_start; *skbh = skb; /* Enable L3/L4 hardware checksum computation. @@ -1852,7 +1852,7 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, * need to write into the skb. */ err = dpaa_enable_tx_csum(priv, skb, fd, - ((char *)skbh) + DPAA_TX_PRIV_DATA_SIZE); + buff_start + DPAA_TX_PRIV_DATA_SIZE); if (unlikely(err < 0)) { if (net_ratelimit()) netif_err(priv, tx_err, net_dev, "HW csum error: %d\n", @@ -1865,8 +1865,8 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO); /* Map the entire buffer size that may be seen by FMan, but no more */ - addr = dma_map_single(priv->tx_dma_dev, skbh, - skb_tail_pointer(skb) - buffer_start, dma_dir); + addr = dma_map_single(priv->tx_dma_dev, buff_start, + priv->tx_headroom + skb->len, dma_dir); if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { if (net_ratelimit()) netif_err(priv, tx_err, net_dev, "dma_map_single() failed\n"); -- cgit v1.2.3-59-g8ed1b From 84d06c606ca4726d0c1e8f2eecacfafed8aec3c5 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:54 +0200 Subject: dpaa_eth: use a page to store the SGT Use a page to store the scatter gather table on the transmit path. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 43 +++++++++++++------------- 1 file changed, 21 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index f3aa154172c3..ef81ec32ef57 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -1592,9 +1592,9 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, int i; if (unlikely(qm_fd_get_format(fd) == qm_fd_sg)) { - dma_unmap_single(priv->tx_dma_dev, addr, - qm_fd_get_offset(fd) + DPAA_SGT_SIZE, - dma_dir); + dma_unmap_page(priv->tx_dma_dev, addr, + qm_fd_get_offset(fd) + DPAA_SGT_SIZE, + dma_dir); /* The sgt buffer has been allocated with netdev_alloc_frag(), * it's from lowmem. @@ -1636,8 +1636,8 @@ static struct sk_buff *dpaa_cleanup_tx_fd(const struct dpaa_priv *priv, } if (qm_fd_get_format(fd) == qm_fd_sg) - /* Free the page frag that we allocated on Tx */ - skb_free_frag(vaddr); + /* Free the page that we allocated on Tx for the SGT */ + free_pages((unsigned long)vaddr, 0); return skb; } @@ -1885,21 +1885,20 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, struct net_device *net_dev = priv->net_dev; struct qm_sg_entry *sgt; struct sk_buff **skbh; - int i, j, err, sz; - void *buffer_start; + void *buff_start; skb_frag_t *frag; dma_addr_t addr; size_t frag_len; - void *sgt_buf; - - /* get a page frag to store the SGTable */ - sz = SKB_DATA_ALIGN(priv->tx_headroom + DPAA_SGT_SIZE); - sgt_buf = netdev_alloc_frag(sz); - if (unlikely(!sgt_buf)) { - netdev_err(net_dev, "netdev_alloc_frag() failed for size %d\n", - sz); + struct page *p; + int i, j, err; + + /* get a page to store the SGTable */ + p = dev_alloc_pages(0); + if (unlikely(!p)) { + netdev_err(net_dev, "dev_alloc_pages() failed\n"); return -ENOMEM; } + buff_start = page_address(p); /* Enable L3/L4 hardware checksum computation. * @@ -1907,7 +1906,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, * need to write into the skb. */ err = dpaa_enable_tx_csum(priv, skb, fd, - sgt_buf + DPAA_TX_PRIV_DATA_SIZE); + buff_start + DPAA_TX_PRIV_DATA_SIZE); if (unlikely(err < 0)) { if (net_ratelimit()) netif_err(priv, tx_err, net_dev, "HW csum error: %d\n", @@ -1916,7 +1915,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, } /* SGT[0] is used by the linear part */ - sgt = (struct qm_sg_entry *)(sgt_buf + priv->tx_headroom); + sgt = (struct qm_sg_entry *)(buff_start + priv->tx_headroom); frag_len = skb_headlen(skb); qm_sg_entry_set_len(&sgt[0], frag_len); sgt[0].bpid = FSL_DPAA_BPID_INV; @@ -1954,15 +1953,15 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, /* Set the final bit in the last used entry of the SGT */ qm_sg_entry_set_f(&sgt[nr_frags], frag_len); + /* set fd offset to priv->tx_headroom */ qm_fd_set_sg(fd, priv->tx_headroom, skb->len); /* DMA map the SGT page */ - buffer_start = (void *)sgt - priv->tx_headroom; - skbh = (struct sk_buff **)buffer_start; + skbh = (struct sk_buff **)buff_start; *skbh = skb; - addr = dma_map_single(priv->tx_dma_dev, buffer_start, - priv->tx_headroom + DPAA_SGT_SIZE, dma_dir); + addr = dma_map_page(priv->tx_dma_dev, p, 0, + priv->tx_headroom + DPAA_SGT_SIZE, dma_dir); if (unlikely(dma_mapping_error(priv->tx_dma_dev, addr))) { netdev_err(priv->net_dev, "DMA mapping failed\n"); err = -EINVAL; @@ -1982,7 +1981,7 @@ sg_map_failed: qm_sg_entry_get_len(&sgt[j]), dma_dir); sg0_map_failed: csum_failed: - skb_free_frag(sgt_buf); + free_pages((unsigned long)buff_start, 0); return err; } -- cgit v1.2.3-59-g8ed1b From 46e93e5443a7adb66d7503f3e32a0cc3bf5b4d3e Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:55 +0200 Subject: dpaa_eth: add dropped frames to percpu ethtool stats Prior to this change, the frames dropped on receive or transmit were not displayed in the ethtool statistics, leaving the dropped frames unaccounted for. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index bc6ed1df53ca..1c689e11c61f 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -47,6 +47,8 @@ static const char dpaa_stats_percpu[][ETH_GSTRING_LEN] = { "tx S/G", "tx error", "rx error", + "rx dropped", + "tx dropped", }; static char dpaa_stats_global[][ETH_GSTRING_LEN] = { @@ -262,6 +264,12 @@ static void copy_stats(struct dpaa_percpu_priv *percpu_priv, int num_cpus, data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_errors; data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_errors; + data[crr * num_values + crr_cpu] = percpu_priv->stats.rx_dropped; + data[crr++ * num_values + num_cpus] += percpu_priv->stats.rx_dropped; + + data[crr * num_values + crr_cpu] = percpu_priv->stats.tx_dropped; + data[crr++ * num_values + num_cpus] += percpu_priv->stats.tx_dropped; + data[crr * num_values + crr_cpu] = bp_count; data[crr++ * num_values + num_cpus] += bp_count; } -- cgit v1.2.3-59-g8ed1b From 1f722e19a2648c4310d6f3443558549edaca4081 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:56 +0200 Subject: dpaa_eth: remove netdev_err() for user errors User reports that an application making an (incorrect) call to restart AN on a fixed link DPAA interface triggers an error in the kernel log while the returned EINVAL should be enough. Reported-by: Joakim Tjernlund Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c index 1c689e11c61f..66d150872d48 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_ethtool.c @@ -80,10 +80,8 @@ static char dpaa_stats_global[][ETH_GSTRING_LEN] = { static int dpaa_get_link_ksettings(struct net_device *net_dev, struct ethtool_link_ksettings *cmd) { - if (!net_dev->phydev) { - netdev_dbg(net_dev, "phy device not initialized\n"); + if (!net_dev->phydev) return 0; - } phy_ethtool_ksettings_get(net_dev->phydev, cmd); @@ -95,10 +93,8 @@ static int dpaa_set_link_ksettings(struct net_device *net_dev, { int err; - if (!net_dev->phydev) { - netdev_err(net_dev, "phy device not initialized\n"); + if (!net_dev->phydev) return -ENODEV; - } err = phy_ethtool_ksettings_set(net_dev->phydev, cmd); if (err < 0) @@ -142,10 +138,8 @@ static int dpaa_nway_reset(struct net_device *net_dev) { int err; - if (!net_dev->phydev) { - netdev_err(net_dev, "phy device not initialized\n"); + if (!net_dev->phydev) return -ENODEV; - } err = 0; if (net_dev->phydev->autoneg) { @@ -167,10 +161,8 @@ static void dpaa_get_pauseparam(struct net_device *net_dev, priv = netdev_priv(net_dev); mac_dev = priv->mac_dev; - if (!net_dev->phydev) { - netdev_err(net_dev, "phy device not initialized\n"); + if (!net_dev->phydev) return; - } epause->autoneg = mac_dev->autoneg_pause; epause->rx_pause = mac_dev->rx_pause_active; -- cgit v1.2.3-59-g8ed1b From e414696d49521b9ceb7734e037d5aa18ef92d8a3 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:57 +0200 Subject: dpaa_eth: extend delays in ndo_stop Make sure all the frames that are in flight have time to be processed before the interface is completely brought down. Add a missing delay for the Rx path. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index ef81ec32ef57..d8b41a0a7e3c 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -266,7 +266,7 @@ static int dpaa_stop(struct net_device *net_dev) /* Allow the Fman (Tx) port to process in-flight frames before we * try switching it off. */ - usleep_range(5000, 10000); + msleep(200); err = mac_dev->stop(mac_dev); if (err < 0) @@ -283,6 +283,8 @@ static int dpaa_stop(struct net_device *net_dev) phy_disconnect(net_dev->phydev); net_dev->phydev = NULL; + msleep(200); + return err; } -- cgit v1.2.3-59-g8ed1b From e06eea555b878f2c95b498aa1c485250ad30c960 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 31 Oct 2019 16:37:59 +0200 Subject: dpaa_eth: register a device link for the qman portal used Before this change, unbinding the QMan portals did not trigger a corresponding unbinding of the dpaa_eth making use of it; the first QMan portal related operation issued afterwards crashed the kernel. The device link ensures the dpaa_eth dependency upon the qman portal used is honoured at the QMan portal removal. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 5 +++-- drivers/soc/fsl/qbman/qman.c | 6 ------ include/soc/fsl/qman.h | 7 ------- 3 files changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index d8b41a0a7e3c..6a9d12dad5d9 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -750,7 +750,7 @@ static void dpaa_release_channel(void) qman_release_pool(rx_pool_channel); } -static void dpaa_eth_add_channel(u16 channel) +static void dpaa_eth_add_channel(u16 channel, struct device *dev) { u32 pool = QM_SDQCR_CHANNELS_POOL_CONV(channel); const cpumask_t *cpus = qman_affine_cpus(); @@ -760,6 +760,7 @@ static void dpaa_eth_add_channel(u16 channel) for_each_cpu_and(cpu, cpus, cpu_online_mask) { portal = qman_get_affine_portal(cpu); qman_p_static_dequeue_add(portal, pool); + qman_start_using_portal(portal, dev); } } @@ -2873,7 +2874,7 @@ static int dpaa_eth_probe(struct platform_device *pdev) /* Walk the CPUs with affine portals * and add this pool channel to each's dequeue mask. */ - dpaa_eth_add_channel(priv->channel); + dpaa_eth_add_channel(priv->channel, &pdev->dev); dpaa_fq_setup(priv, &dpaa_fq_cbs, priv->mac_dev->port[TX]); diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index bc75a5882b9e..1e164e03410a 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -1756,12 +1756,6 @@ int qman_start_using_portal(struct qman_portal *p, struct device *dev) } EXPORT_SYMBOL(qman_start_using_portal); -void qman_stop_using_portal(struct qman_portal *p, struct device *dev) -{ - device_link_remove(dev, p->config->dev); -} -EXPORT_SYMBOL(qman_stop_using_portal); - int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit) { return __poll_portal_fast(p, limit); diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index c499c5cfa7c9..cfe00e08e85b 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -925,13 +925,6 @@ struct qman_portal *qman_get_affine_portal(int cpu); */ int qman_start_using_portal(struct qman_portal *p, struct device *dev); -/** - * qman_stop_using_portal - deregister a device link for the portal user - * @p: the portal that will no longer be in use - * @dev: the device that uses the portal - */ -void qman_stop_using_portal(struct qman_portal *p, struct device *dev); - /** * qman_p_poll_dqrr - process DQRR (fast-path) entries * @limit: the maximum number of DQRR entries to process -- cgit v1.2.3-59-g8ed1b From d170eb69d40e9e5fccb8d57edbbacb97427dcf1c Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 30 Oct 2019 09:01:52 -0700 Subject: mlxsw: Fix 64-bit division in mlxsw_sp_sb_prs_init When building for 32-bit ARM, there is a link time error because of a 64-bit division: ld.lld: error: undefined symbol: __aeabi_uldivmod >>> referenced by spectrum_buffers.c >>> net/ethernet/mellanox/mlxsw/spectrum_buffers.o:(mlxsw_sp_buffers_init) in archive drivers/built-in.a >>> did you mean: __aeabi_uidivmod >>> defined in: arch/arm/lib/lib.a(lib1funcs.o Avoid this by using div_u64, which is designed to avoid this problem. Fixes: bc9f6e94bcb5 ("mlxsw: spectrum_buffers: Calculate the size of the main pool") Signed-off-by: Nathan Chancellor Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c index 33a978af80d6..968f0902e4fe 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c @@ -470,7 +470,7 @@ static int mlxsw_sp_sb_prs_init(struct mlxsw_sp *mlxsw_sp, size_t prs_len) { /* Round down, unlike mlxsw_sp_bytes_cells(). */ - u32 sb_cells = mlxsw_sp->sb->sb_size / mlxsw_sp->sb->cell_size; + u32 sb_cells = div_u64(mlxsw_sp->sb->sb_size, mlxsw_sp->sb->cell_size); u32 rest_cells[2] = {sb_cells, sb_cells}; int i; int err; -- cgit v1.2.3-59-g8ed1b From 8c42350116fe4ad23a5a813eba367355cfe7cff5 Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:23:10 +0000 Subject: sfc: support encapsulation of xdp_frames in efx_tx_buffer Add a field to efx_tx_buffer so that we can track xdp_frames. Add a flag so that buffers that contain xdp_frames can be identified and passed to xdp_return_frame. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/net_driver.h | 10 ++++++++-- drivers/net/ethernet/sfc/tx.c | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 284a1b047ac2..7394d901e021 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" @@ -136,7 +137,8 @@ struct efx_special_buffer { * struct efx_tx_buffer - buffer state for a TX descriptor * @skb: When @flags & %EFX_TX_BUF_SKB, the associated socket buffer to be * freed when descriptor completes - * @option: When @flags & %EFX_TX_BUF_OPTION, a NIC-specific option descriptor. + * @xdpf: When @flags & %EFX_TX_BUF_XDP, the XDP frame information; its @data + * member is the associated buffer to drop a page reference on. * @dma_addr: DMA address of the fragment. * @flags: Flags for allocation and DMA mapping type * @len: Length of this fragment. @@ -146,7 +148,10 @@ struct efx_special_buffer { * Only valid if @unmap_len != 0. */ struct efx_tx_buffer { - const struct sk_buff *skb; + union { + const struct sk_buff *skb; + struct xdp_frame *xdpf; + }; union { efx_qword_t option; dma_addr_t dma_addr; @@ -160,6 +165,7 @@ struct efx_tx_buffer { #define EFX_TX_BUF_SKB 2 /* buffer is last part of skb */ #define EFX_TX_BUF_MAP_SINGLE 8 /* buffer was mapped with dma_map_single() */ #define EFX_TX_BUF_OPTION 0x10 /* empty buffer for option descriptor */ +#define EFX_TX_BUF_XDP 0x20 /* buffer was sent with XDP */ /** * struct efx_tx_queue - An Efx TX queue diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 65e81ec1b314..204aafb3d96a 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -95,6 +95,8 @@ static void efx_dequeue_buffer(struct efx_tx_queue *tx_queue, netif_vdbg(tx_queue->efx, tx_done, tx_queue->efx->net_dev, "TX queue %d transmission id %x complete\n", tx_queue->queue, tx_queue->read_count); + } else if (buffer->flags & EFX_TX_BUF_XDP) { + xdp_return_frame_rx_napi(buffer->xdpf); } buffer->len = 0; -- cgit v1.2.3-59-g8ed1b From eb9a36be7f3ec414700af9a616f035eda1f1e63e Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:23:23 +0000 Subject: sfc: perform XDP processing on received packets Adds a field to hold an attached xdp_prog, but never populates it (see following patch). Also, XDP_TX support is deferred to a later patch in the series. Track failures of xdp_rxq_info_reg() via per-queue xdp_rxq_info_valid flags and a per-nic xdp_rxq_info_failed flag. The per-queue flags are needed to prevent attempts to xdp_rxq_info_unreg() structs that failed to register. Possibly the API could be changed in the future to avoid the need for these flags. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 5 +- drivers/net/ethernet/sfc/net_driver.h | 12 ++++ drivers/net/ethernet/sfc/rx.c | 130 +++++++++++++++++++++++++++++++++- 3 files changed, 145 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 2fef7402233e..bd0424414781 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -340,6 +340,8 @@ static int efx_poll(struct napi_struct *napi, int budget) spent = efx_process_channel(channel, budget); + xdp_do_flush_map(); + if (spent < budget) { if (efx_channel_has_rx_queue(channel) && efx->irq_rx_adaptive && @@ -651,7 +653,7 @@ static void efx_start_datapath(struct efx_nic *efx) efx->rx_dma_len = (efx->rx_prefix_size + EFX_MAX_FRAME_LEN(efx->net_dev->mtu) + efx->type->rx_buffer_padding); - rx_buf_len = (sizeof(struct efx_rx_page_state) + + rx_buf_len = (sizeof(struct efx_rx_page_state) + XDP_PACKET_HEADROOM + efx->rx_ip_align + efx->rx_dma_len); if (rx_buf_len <= PAGE_SIZE) { efx->rx_scatter = efx->type->always_rx_scatter; @@ -774,6 +776,7 @@ static void efx_stop_datapath(struct efx_nic *efx) efx_for_each_possible_channel_tx_queue(tx_queue, channel) efx_fini_tx_queue(tx_queue); } + efx->xdp_rxq_info_failed = false; } static void efx_remove_channel(struct efx_channel *channel) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 7394d901e021..a5a5055969fb 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -369,6 +369,8 @@ struct efx_rx_page_state { * refill was triggered. * @recycle_count: RX buffer recycle counter. * @slow_fill: Timer used to defer efx_nic_generate_fill_event(). + * @xdp_rxq_info: XDP specific RX queue information. + * @xdp_rxq_info_valid: Is xdp_rxq_info valid data?. */ struct efx_rx_queue { struct efx_nic *efx; @@ -400,6 +402,8 @@ struct efx_rx_queue { unsigned int slow_fill_count; /* Statistics to supplement MAC stats */ unsigned long rx_packets; + struct xdp_rxq_info xdp_rxq_info; + bool xdp_rxq_info_valid; }; enum efx_sync_events_state { @@ -900,6 +904,7 @@ struct efx_async_filter_insertion { * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask * @loopback_selftest: Offline self-test private state + * @xdp_prog: Current XDP programme for this interface * @filter_sem: Filter table rw_semaphore, protects existence of @filter_state * @filter_state: Architecture-dependent filter table state * @rps_mutex: Protects RPS state of all channels @@ -925,6 +930,8 @@ struct efx_async_filter_insertion { * @ptp_data: PTP state data * @ptp_warned: has this NIC seen and warned about unexpected PTP events? * @vpd_sn: Serial number read from VPD + * @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their + * xdp_rxq_info structures? * @monitor_work: Hardware monitor workitem * @biu_lock: BIU (bus interface unit) lock * @last_irq_cpu: Last CPU to handle a possible test interrupt. This @@ -1059,6 +1066,10 @@ struct efx_nic { u64 loopback_modes; void *loopback_selftest; + /* We access loopback_selftest immediately before running XDP, + * so we want them next to each other. + */ + struct bpf_prog __rcu *xdp_prog; struct rw_semaphore filter_sem; void *filter_state; @@ -1088,6 +1099,7 @@ struct efx_nic { bool ptp_warned; char *vpd_sn; + bool xdp_rxq_info_failed; /* The following fields may be written more often */ diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 85ec07f5a674..644d157843c6 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "net_driver.h" #include "efx.h" #include "filter.h" @@ -27,6 +29,9 @@ /* Preferred number of descriptors to fill at once */ #define EFX_RX_PREFERRED_BATCH 8U +/* Maximum rx prefix used by any architecture. */ +#define EFX_MAX_RX_PREFIX_SIZE 16 + /* Number of RX buffers to recycle pages for. When creating the RX page recycle * ring, this number is divided by the number of buffers per page to calculate * the number of pages to store in the RX page recycle ring. @@ -95,7 +100,7 @@ void efx_rx_config_page_split(struct efx_nic *efx) EFX_RX_BUF_ALIGNMENT); efx->rx_bufs_per_page = efx->rx_buffer_order ? 1 : ((PAGE_SIZE - sizeof(struct efx_rx_page_state)) / - efx->rx_page_buf_step); + (efx->rx_page_buf_step + XDP_PACKET_HEADROOM)); efx->rx_buffer_truesize = (PAGE_SIZE << efx->rx_buffer_order) / efx->rx_bufs_per_page; efx->rx_pages_per_batch = DIV_ROUND_UP(EFX_RX_PREFERRED_BATCH, @@ -185,6 +190,9 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue, bool atomic) page_offset = sizeof(struct efx_rx_page_state); do { + page_offset += XDP_PACKET_HEADROOM; + dma_addr += XDP_PACKET_HEADROOM; + index = rx_queue->added_count & rx_queue->ptr_mask; rx_buf = efx_rx_buffer(rx_queue, index); rx_buf->dma_addr = dma_addr + efx->rx_ip_align; @@ -635,6 +643,104 @@ static void efx_rx_deliver(struct efx_channel *channel, u8 *eh, netif_receive_skb(skb); } +/** efx_do_xdp: perform XDP processing on a received packet + * + * Returns true if packet should still be delivered. + */ +static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, + struct efx_rx_buffer *rx_buf, u8 **ehp) +{ + u8 rx_prefix[EFX_MAX_RX_PREFIX_SIZE]; + struct efx_rx_queue *rx_queue; + struct bpf_prog *xdp_prog; + struct xdp_buff xdp; + u32 xdp_act; + s16 offset; + int err; + + rcu_read_lock(); + xdp_prog = rcu_dereference(efx->xdp_prog); + if (!xdp_prog) { + rcu_read_unlock(); + return true; + } + + rx_queue = efx_channel_get_rx_queue(channel); + + if (unlikely(channel->rx_pkt_n_frags > 1)) { + /* We can't do XDP on fragmented packets - drop. */ + rcu_read_unlock(); + efx_free_rx_buffers(rx_queue, rx_buf, + channel->rx_pkt_n_frags); + if (net_ratelimit()) + netif_err(efx, rx_err, efx->net_dev, + "XDP is not possible with multiple receive fragments (%d)\n", + channel->rx_pkt_n_frags); + return false; + } + + dma_sync_single_for_cpu(&efx->pci_dev->dev, rx_buf->dma_addr, + rx_buf->len, DMA_FROM_DEVICE); + + /* Save the rx prefix. */ + EFX_WARN_ON_PARANOID(efx->rx_prefix_size > EFX_MAX_RX_PREFIX_SIZE); + memcpy(rx_prefix, *ehp - efx->rx_prefix_size, + efx->rx_prefix_size); + + xdp.data = *ehp; + xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM; + + /* No support yet for XDP metadata */ + xdp_set_data_meta_invalid(&xdp); + xdp.data_end = xdp.data + rx_buf->len; + xdp.rxq = &rx_queue->xdp_rxq_info; + + xdp_act = bpf_prog_run_xdp(xdp_prog, &xdp); + rcu_read_unlock(); + + offset = (u8 *)xdp.data - *ehp; + + switch (xdp_act) { + case XDP_PASS: + /* Fix up rx prefix. */ + if (offset) { + *ehp += offset; + rx_buf->page_offset += offset; + rx_buf->len -= offset; + memcpy(*ehp - efx->rx_prefix_size, rx_prefix, + efx->rx_prefix_size); + } + break; + + case XDP_TX: + return -EOPNOTSUPP; + + case XDP_REDIRECT: + err = xdp_do_redirect(efx->net_dev, &xdp, xdp_prog); + if (unlikely(err)) { + efx_free_rx_buffers(rx_queue, rx_buf, 1); + if (net_ratelimit()) + netif_err(efx, rx_err, efx->net_dev, + "XDP redirect failed (%d)\n", err); + } + break; + + default: + bpf_warn_invalid_xdp_action(xdp_act); + efx_free_rx_buffers(rx_queue, rx_buf, 1); + break; + + case XDP_ABORTED: + trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act); + /* Fall through */ + case XDP_DROP: + efx_free_rx_buffers(rx_queue, rx_buf, 1); + break; + } + + return xdp_act == XDP_PASS; +} + /* Handle a received packet. Second half: Touches packet payload. */ void __efx_rx_packet(struct efx_channel *channel) { @@ -663,6 +769,9 @@ void __efx_rx_packet(struct efx_channel *channel) goto out; } + if (!efx_do_xdp(efx, channel, rx_buf, &eh)) + goto out; + if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM))) rx_buf->flags &= ~EFX_RX_PKT_CSUMMED; @@ -731,6 +840,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) { struct efx_nic *efx = rx_queue->efx; unsigned int max_fill, trigger, max_trigger; + int rc = 0; netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev, "initialising RX queue %d\n", efx_rx_queue_index(rx_queue)); @@ -764,6 +874,19 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->fast_fill_trigger = trigger; rx_queue->refill_enabled = true; + /* Initialise XDP queue information */ + rc = xdp_rxq_info_reg(&rx_queue->xdp_rxq_info, efx->net_dev, + rx_queue->core_index); + + if (rc) { + netif_err(efx, rx_err, efx->net_dev, + "Failure to initialise XDP queue information rc=%d\n", + rc); + efx->xdp_rxq_info_failed = true; + } else { + rx_queue->xdp_rxq_info_valid = true; + } + /* Set up RX descriptor ring */ efx_nic_init_rx(rx_queue); } @@ -805,6 +928,11 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) } kfree(rx_queue->page_ring); rx_queue->page_ring = NULL; + + if (rx_queue->xdp_rxq_info_valid) + xdp_rxq_info_unreg(&rx_queue->xdp_rxq_info); + + rx_queue->xdp_rxq_info_valid = false; } void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) -- cgit v1.2.3-59-g8ed1b From e45a4fed9d006480a5cc2312d5d4f7988a3a655e Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:23:37 +0000 Subject: sfc: Enable setting of xdp_prog Provide an ndo_bpf function to efx_netdev_ops that allows setting and querying of xdp programs on an interface. Also check that the MTU size isn't too big when setting a program or when the MTU is explicitly set. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index bd0424414781..429fb268b0da 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -226,6 +226,8 @@ static void efx_fini_napi_channel(struct efx_channel *channel); static void efx_fini_struct(struct efx_nic *efx); static void efx_start_all(struct efx_nic *efx); static void efx_stop_all(struct efx_nic *efx); +static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog); +static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ @@ -2025,6 +2027,10 @@ static void efx_stop_all(struct efx_nic *efx) static void efx_remove_all(struct efx_nic *efx) { + rtnl_lock(); + efx_xdp_setup_prog(efx, NULL); + rtnl_unlock(); + efx_remove_channels(efx); efx_remove_filters(efx); #ifdef CONFIG_SFC_SRIOV @@ -2280,6 +2286,17 @@ static void efx_watchdog(struct net_device *net_dev) efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); } +static unsigned int efx_xdp_max_mtu(struct efx_nic *efx) +{ + /* The maximum MTU that we can fit in a single page, allowing for + * framing, overhead and XDP headroom. + */ + int overhead = EFX_MAX_FRAME_LEN(0) + sizeof(struct efx_rx_page_state) + + efx->rx_prefix_size + efx->type->rx_buffer_padding + + efx->rx_ip_align + XDP_PACKET_HEADROOM; + + return PAGE_SIZE - overhead; +} /* Context: process, rtnl_lock() held. */ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) @@ -2291,6 +2308,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) if (rc) return rc; + if (rtnl_dereference(efx->xdp_prog) && + new_mtu > efx_xdp_max_mtu(efx)) { + netif_err(efx, drv, efx->net_dev, + "Requested MTU of %d too big for XDP (max: %d)\n", + new_mtu, efx_xdp_max_mtu(efx)); + return -EINVAL; + } + netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu); efx_device_detach_sync(efx); @@ -2492,8 +2517,53 @@ static const struct net_device_ops efx_netdev_ops = { #endif .ndo_udp_tunnel_add = efx_udp_tunnel_add, .ndo_udp_tunnel_del = efx_udp_tunnel_del, + .ndo_bpf = efx_xdp }; +static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog) +{ + struct bpf_prog *old_prog; + + if (efx->xdp_rxq_info_failed) { + netif_err(efx, drv, efx->net_dev, + "Unable to bind XDP program due to previous failure of rxq_info\n"); + return -EINVAL; + } + + if (prog && efx->net_dev->mtu > efx_xdp_max_mtu(efx)) { + netif_err(efx, drv, efx->net_dev, + "Unable to configure XDP with MTU of %d (max: %d)\n", + efx->net_dev->mtu, efx_xdp_max_mtu(efx)); + return -EINVAL; + } + + old_prog = rtnl_dereference(efx->xdp_prog); + rcu_assign_pointer(efx->xdp_prog, prog); + /* Release the reference that was originally passed by the caller. */ + if (old_prog) + bpf_prog_put(old_prog); + + return 0; +} + +/* Context: process, rtnl_lock() held. */ +static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + struct efx_nic *efx = netdev_priv(dev); + struct bpf_prog *xdp_prog; + + switch (xdp->command) { + case XDP_SETUP_PROG: + return efx_xdp_setup_prog(efx, xdp->prog); + case XDP_QUERY_PROG: + xdp_prog = rtnl_dereference(efx->xdp_prog); + xdp->prog_id = xdp_prog ? xdp_prog->aux->id : 0; + return 0; + default: + return -EINVAL; + } +} + static void efx_update_name(struct efx_nic *efx) { strcpy(efx->name, efx->net_dev->name); -- cgit v1.2.3-59-g8ed1b From 3990a8fffbdad5765f47ea593f9de66c91762059 Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:23:49 +0000 Subject: sfc: allocate channels for XDP tx queues Each CPU needs access to its own queue to allow uncontested transmission of XDP_TX packets. This means we need to allocate (up front) enough channels ("xdp transmit channels") to provide at least one extra tx queue per CPU. These tx queues should not do TSO. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 14 ++- drivers/net/ethernet/sfc/efx.c | 180 ++++++++++++++++++++++++++++------ drivers/net/ethernet/sfc/net_driver.h | 34 ++++++- drivers/net/ethernet/sfc/tx.c | 2 + 4 files changed, 190 insertions(+), 40 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 0ec13f520e90..ad68eb0cb8fd 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -946,8 +946,10 @@ static int efx_ef10_link_piobufs(struct efx_nic *efx) /* Extra channels, even those with TXQs (PTP), do not require * PIO resources. */ - if (!channel->type->want_pio) + if (!channel->type->want_pio || + channel->channel >= efx->xdp_channel_offset) continue; + efx_for_each_channel_tx_queue(tx_queue, channel) { /* We assign the PIO buffers to queues in * reverse order to allow for the following @@ -1296,8 +1298,9 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) int rc; channel_vis = max(efx->n_channels, - (efx->n_tx_channels + efx->n_extra_tx_channels) * - EFX_TXQ_TYPES); + ((efx->n_tx_channels + efx->n_extra_tx_channels) * + EFX_TXQ_TYPES) + + efx->n_xdp_channels * efx->xdp_tx_per_channel); #ifdef EFX_USE_PIO /* Try to allocate PIO buffers if wanted and if the full @@ -2434,11 +2437,12 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue) /* TSOv2 is a limited resource that can only be configured on a limited * number of queues. TSO without checksum offload is not really a thing, * so we only enable it for those queues. - * TSOv2 cannot be used with Hardware timestamping. + * TSOv2 cannot be used with Hardware timestamping, and is never needed + * for XDP tx. */ if (csum_offload && (nic_data->datapath_caps2 & (1 << MC_CMD_GET_CAPABILITIES_V2_OUT_TX_TSO_V2_LBN)) && - !tx_queue->timestamping) { + !tx_queue->timestamping && !tx_queue->xdp_tx) { tso_v2 = true; netif_dbg(efx, hw, efx->net_dev, "Using TSOv2 for channel %u\n", channel->channel); diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 429fb268b0da..10c9b1ede799 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -583,9 +583,14 @@ efx_get_channel_name(struct efx_channel *channel, char *buf, size_t len) int number; number = channel->channel; - if (efx->tx_channel_offset == 0) { + + if (number >= efx->xdp_channel_offset && + !WARN_ON_ONCE(!efx->n_xdp_channels)) { + type = "-xdp"; + number -= efx->xdp_channel_offset; + } else if (efx->tx_channel_offset == 0) { type = ""; - } else if (channel->channel < efx->tx_channel_offset) { + } else if (number < efx->tx_channel_offset) { type = "-rx"; } else { type = "-tx"; @@ -803,6 +808,8 @@ static void efx_remove_channels(struct efx_nic *efx) efx_for_each_channel(channel, efx) efx_remove_channel(channel); + + kfree(efx->xdp_tx_queues); } int @@ -1440,6 +1447,101 @@ static unsigned int efx_wanted_parallelism(struct efx_nic *efx) return count; } +static int efx_allocate_msix_channels(struct efx_nic *efx, + unsigned int max_channels, + unsigned int extra_channels, + unsigned int parallelism) +{ + unsigned int n_channels = parallelism; + int vec_count; + int n_xdp_tx; + int n_xdp_ev; + + if (efx_separate_tx_channels) + n_channels *= 2; + n_channels += extra_channels; + + /* To allow XDP transmit to happen from arbitrary NAPI contexts + * we allocate a TX queue per CPU. We share event queues across + * multiple tx queues, assuming tx and ev queues are both + * maximum size. + */ + + n_xdp_tx = num_possible_cpus(); + n_xdp_ev = DIV_ROUND_UP(n_xdp_tx, EFX_TXQ_TYPES); + + /* Check resources. + * We need a channel per event queue, plus a VI per tx queue. + * This may be more pessimistic than it needs to be. + */ + if (n_channels + n_xdp_ev > max_channels) { + netif_err(efx, drv, efx->net_dev, + "Insufficient resources for %d XDP event queues (%d other channels, max %d)\n", + n_xdp_ev, n_channels, max_channels); + efx->n_xdp_channels = 0; + efx->xdp_tx_per_channel = 0; + efx->xdp_tx_queue_count = 0; + } else { + efx->n_xdp_channels = n_xdp_ev; + efx->xdp_tx_per_channel = EFX_TXQ_TYPES; + efx->xdp_tx_queue_count = n_xdp_tx; + n_channels += n_xdp_ev; + netif_dbg(efx, drv, efx->net_dev, + "Allocating %d TX and %d event queues for XDP\n", + n_xdp_tx, n_xdp_ev); + } + + n_channels = min(n_channels, max_channels); + + vec_count = pci_msix_vec_count(efx->pci_dev); + if (vec_count < 0) + return vec_count; + if (vec_count < n_channels) { + netif_err(efx, drv, efx->net_dev, + "WARNING: Insufficient MSI-X vectors available (%d < %u).\n", + vec_count, n_channels); + netif_err(efx, drv, efx->net_dev, + "WARNING: Performance may be reduced.\n"); + n_channels = vec_count; + } + + efx->n_channels = n_channels; + + /* Do not create the PTP TX queue(s) if PTP uses the MC directly. */ + if (extra_channels && !efx_ptp_use_mac_tx_timestamps(efx)) + n_channels--; + + /* Ignore XDP tx channels when creating rx channels. */ + n_channels -= efx->n_xdp_channels; + + if (efx_separate_tx_channels) { + efx->n_tx_channels = + min(max(n_channels / 2, 1U), + efx->max_tx_channels); + efx->tx_channel_offset = + n_channels - efx->n_tx_channels; + efx->n_rx_channels = + max(n_channels - + efx->n_tx_channels, 1U); + } else { + efx->n_tx_channels = min(n_channels, efx->max_tx_channels); + efx->tx_channel_offset = 0; + efx->n_rx_channels = n_channels; + } + + if (efx->n_xdp_channels) + efx->xdp_channel_offset = efx->tx_channel_offset + + efx->n_tx_channels; + else + efx->xdp_channel_offset = efx->n_channels; + + netif_dbg(efx, drv, efx->net_dev, + "Allocating %u RX channels\n", + efx->n_rx_channels); + + return efx->n_channels; +} + /* Probe the number and type of interrupts we are able to obtain, and * the resulting numbers of channels and RX queues. */ @@ -1454,19 +1556,19 @@ static int efx_probe_interrupts(struct efx_nic *efx) ++extra_channels; if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { + unsigned int parallelism = efx_wanted_parallelism(efx); struct msix_entry xentries[EFX_MAX_CHANNELS]; unsigned int n_channels; - n_channels = efx_wanted_parallelism(efx); - if (efx_separate_tx_channels) - n_channels *= 2; - n_channels += extra_channels; - n_channels = min(n_channels, efx->max_channels); - - for (i = 0; i < n_channels; i++) - xentries[i].entry = i; - rc = pci_enable_msix_range(efx->pci_dev, - xentries, 1, n_channels); + rc = efx_allocate_msix_channels(efx, efx->max_channels, + extra_channels, parallelism); + if (rc >= 0) { + n_channels = rc; + for (i = 0; i < n_channels; i++) + xentries[i].entry = i; + rc = pci_enable_msix_range(efx->pci_dev, xentries, 1, + n_channels); + } if (rc < 0) { /* Fall back to single channel MSI */ netif_err(efx, drv, efx->net_dev, @@ -1485,21 +1587,6 @@ static int efx_probe_interrupts(struct efx_nic *efx) } if (rc > 0) { - efx->n_channels = n_channels; - if (n_channels > extra_channels) - n_channels -= extra_channels; - if (efx_separate_tx_channels) { - efx->n_tx_channels = min(max(n_channels / 2, - 1U), - efx->max_tx_channels); - efx->n_rx_channels = max(n_channels - - efx->n_tx_channels, - 1U); - } else { - efx->n_tx_channels = min(n_channels, - efx->max_tx_channels); - efx->n_rx_channels = n_channels; - } for (i = 0; i < efx->n_channels; i++) efx_get_channel(efx, i)->irq = xentries[i].vector; @@ -1511,6 +1598,8 @@ static int efx_probe_interrupts(struct efx_nic *efx) efx->n_channels = 1; efx->n_rx_channels = 1; efx->n_tx_channels = 1; + efx->n_xdp_channels = 0; + efx->xdp_channel_offset = efx->n_channels; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { efx_get_channel(efx, 0)->irq = efx->pci_dev->irq; @@ -1529,12 +1618,14 @@ static int efx_probe_interrupts(struct efx_nic *efx) efx->n_channels = 1 + (efx_separate_tx_channels ? 1 : 0); efx->n_rx_channels = 1; efx->n_tx_channels = 1; + efx->n_xdp_channels = 0; + efx->xdp_channel_offset = efx->n_channels; efx->legacy_irq = efx->pci_dev->irq; } - /* Assign extra channels if possible */ + /* Assign extra channels if possible, before XDP channels */ efx->n_extra_tx_channels = 0; - j = efx->n_channels; + j = efx->xdp_channel_offset; for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) { if (!efx->extra_channel_type[i]) continue; @@ -1729,29 +1820,50 @@ static void efx_remove_interrupts(struct efx_nic *efx) efx->legacy_irq = 0; } -static void efx_set_channels(struct efx_nic *efx) +static int efx_set_channels(struct efx_nic *efx) { struct efx_channel *channel; struct efx_tx_queue *tx_queue; + int xdp_queue_number; efx->tx_channel_offset = efx_separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + if (efx->xdp_tx_queue_count) { + EFX_WARN_ON_PARANOID(efx->xdp_tx_queues); + + /* Allocate array for XDP TX queue lookup. */ + efx->xdp_tx_queues = kcalloc(efx->xdp_tx_queue_count, + sizeof(*efx->xdp_tx_queues), + GFP_KERNEL); + if (!efx->xdp_tx_queues) + return -ENOMEM; + } + /* We need to mark which channels really have RX and TX * queues, and adjust the TX queue numbers if we have separate * RX-only and TX-only channels. */ + xdp_queue_number = 0; efx_for_each_channel(channel, efx) { if (channel->channel < efx->n_rx_channels) channel->rx_queue.core_index = channel->channel; else channel->rx_queue.core_index = -1; - efx_for_each_channel_tx_queue(tx_queue, channel) + efx_for_each_channel_tx_queue(tx_queue, channel) { tx_queue->queue -= (efx->tx_channel_offset * EFX_TXQ_TYPES); + + if (efx_channel_is_xdp_tx(channel) && + xdp_queue_number < efx->xdp_tx_queue_count) { + efx->xdp_tx_queues[xdp_queue_number] = tx_queue; + xdp_queue_number++; + } + } } + return 0; } static int efx_probe_nic(struct efx_nic *efx) @@ -1781,7 +1893,9 @@ static int efx_probe_nic(struct efx_nic *efx) if (rc) goto fail1; - efx_set_channels(efx); + rc = efx_set_channels(efx); + if (rc) + goto fail1; /* dimension_resources can fail with EAGAIN */ rc = efx->type->dimension_resources(efx); @@ -2091,6 +2205,8 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, channel->irq_moderation_us = rx_usecs; else if (efx_channel_has_tx_queues(channel)) channel->irq_moderation_us = tx_usecs; + else if (efx_channel_is_xdp_tx(channel)) + channel->irq_moderation_us = tx_usecs; } return 0; diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index a5a5055969fb..505ddc060e64 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -195,6 +195,7 @@ struct efx_tx_buffer { * @piobuf_offset: Buffer offset to be specified in PIO descriptors * @initialised: Has hardware queue been initialised? * @timestamping: Is timestamping enabled for this channel? + * @xdp_tx: Is this an XDP tx queue? * @handle_tso: TSO xmit preparation handler. Sets up the TSO metadata and * may also map tx data, depending on the nature of the TSO implementation. * @read_count: Current read pointer. @@ -256,6 +257,7 @@ struct efx_tx_queue { unsigned int piobuf_offset; bool initialised; bool timestamping; + bool xdp_tx; /* Function pointers used in the fast path. */ int (*handle_tso)(struct efx_tx_queue*, struct sk_buff*, bool *); @@ -828,6 +830,8 @@ struct efx_async_filter_insertion { * @msi_context: Context for each MSI * @extra_channel_types: Types of extra (non-traffic) channels that * should be allocated for this NIC + * @xdp_tx_queue_count: Number of entries in %xdp_tx_queues. + * @xdp_tx_queues: Array of pointers to tx queues used for XDP transmit. * @rxq_entries: Size of receive queues requested by user. * @txq_entries: Size of transmit queues requested by user. * @txq_stop_thresh: TX queue fill level at or above which we stop it. @@ -840,6 +844,9 @@ struct efx_async_filter_insertion { * @n_rx_channels: Number of channels used for RX (= number of RX queues) * @n_tx_channels: Number of channels used for TX * @n_extra_tx_channels: Number of extra channels with TX queues + * @n_xdp_channels: Number of channels used for XDP TX + * @xdp_channel_offset: Offset of zeroth channel used for XPD TX. + * @xdp_tx_per_channel: Max number of TX queues on an XDP TX channel. * @rx_ip_align: RX DMA address offset to have IP header aligned in * in accordance with NET_IP_ALIGN * @rx_dma_len: Current maximum RX DMA length @@ -979,6 +986,9 @@ struct efx_nic { const struct efx_channel_type * extra_channel_type[EFX_MAX_EXTRA_CHANNELS]; + unsigned int xdp_tx_queue_count; + struct efx_tx_queue **xdp_tx_queues; + unsigned rxq_entries; unsigned txq_entries; unsigned int txq_stop_thresh; @@ -997,6 +1007,9 @@ struct efx_nic { unsigned tx_channel_offset; unsigned n_tx_channels; unsigned n_extra_tx_channels; + unsigned int n_xdp_channels; + unsigned int xdp_channel_offset; + unsigned int xdp_tx_per_channel; unsigned int rx_ip_align; unsigned int rx_dma_len; unsigned int rx_buffer_order; @@ -1491,10 +1504,24 @@ efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) return &efx->channel[efx->tx_channel_offset + index]->tx_queue[type]; } +static inline struct efx_channel * +efx_get_xdp_channel(struct efx_nic *efx, unsigned int index) +{ + EFX_WARN_ON_ONCE_PARANOID(index >= efx->n_xdp_channels); + return efx->channel[efx->xdp_channel_offset + index]; +} + +static inline bool efx_channel_is_xdp_tx(struct efx_channel *channel) +{ + return channel->channel - channel->efx->xdp_channel_offset < + channel->efx->n_xdp_channels; +} + static inline bool efx_channel_has_tx_queues(struct efx_channel *channel) { - return channel->type && channel->type->want_txqs && - channel->type->want_txqs(channel); + return efx_channel_is_xdp_tx(channel) || + (channel->type && channel->type->want_txqs && + channel->type->want_txqs(channel)); } static inline struct efx_tx_queue * @@ -1518,7 +1545,8 @@ static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue) else \ for (_tx_queue = (_channel)->tx_queue; \ _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES && \ - efx_tx_queue_used(_tx_queue); \ + (efx_tx_queue_used(_tx_queue) || \ + efx_channel_is_xdp_tx(_channel)); \ _tx_queue++) /* Iterate over all possible TX queues belonging to a channel */ diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 204aafb3d96a..8a5bc500d2a1 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -859,6 +859,8 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) tx_queue->completed_timestamp_major = 0; tx_queue->completed_timestamp_minor = 0; + tx_queue->xdp_tx = efx_channel_is_xdp_tx(tx_queue->channel); + /* Set up default function pointers. These may get replaced by * efx_nic_init_tx() based off NIC/queue capabilities. */ -- cgit v1.2.3-59-g8ed1b From dfe44c1f52eed6020df74e83d21d617308164a68 Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:24:12 +0000 Subject: sfc: handle XDP_TX outcomes of XDP eBPF programs Provide an ndo_xdp_xmit function that uses the XDP tx queue for this CPU to send the packet. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/efx.c | 14 +++++++ drivers/net/ethernet/sfc/efx.h | 3 ++ drivers/net/ethernet/sfc/rx.c | 12 +++++- drivers/net/ethernet/sfc/tx.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 10c9b1ede799..0fa9972027db 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -228,6 +228,8 @@ static void efx_start_all(struct efx_nic *efx); static void efx_stop_all(struct efx_nic *efx); static int efx_xdp_setup_prog(struct efx_nic *efx, struct bpf_prog *prog); static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp); +static int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs, + u32 flags); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ @@ -2633,6 +2635,7 @@ static const struct net_device_ops efx_netdev_ops = { #endif .ndo_udp_tunnel_add = efx_udp_tunnel_add, .ndo_udp_tunnel_del = efx_udp_tunnel_del, + .ndo_xdp_xmit = efx_xdp_xmit, .ndo_bpf = efx_xdp }; @@ -2680,6 +2683,17 @@ static int efx_xdp(struct net_device *dev, struct netdev_bpf *xdp) } } +static int efx_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **xdpfs, + u32 flags) +{ + struct efx_nic *efx = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return efx_xdp_tx_buffers(efx, n, xdpfs, flags & XDP_XMIT_FLUSH); +} + static void efx_update_name(struct efx_nic *efx) { strcpy(efx->name, efx->net_dev->name); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 04fed7c06618..45c7ae4114ec 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -322,4 +322,7 @@ static inline bool efx_rwsem_assert_write_locked(struct rw_semaphore *sem) return true; } +int efx_xdp_tx_buffers(struct efx_nic *efx, int n, struct xdp_frame **xdpfs, + bool flush); + #endif /* EFX_EFX_H */ diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 644d157843c6..91f6d5b9ceac 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -653,6 +653,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, u8 rx_prefix[EFX_MAX_RX_PREFIX_SIZE]; struct efx_rx_queue *rx_queue; struct bpf_prog *xdp_prog; + struct xdp_frame *xdpf; struct xdp_buff xdp; u32 xdp_act; s16 offset; @@ -713,7 +714,16 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, break; case XDP_TX: - return -EOPNOTSUPP; + /* Buffer ownership passes to tx on success. */ + xdpf = convert_to_xdp_frame(&xdp); + err = efx_xdp_tx_buffers(efx, 1, &xdpf, true); + if (unlikely(err != 1)) { + efx_free_rx_buffers(rx_queue, rx_buf, 1); + if (net_ratelimit()) + netif_err(efx, rx_err, efx->net_dev, + "XDP TX failed (%d)\n", err); + } + break; case XDP_REDIRECT: err = xdp_do_redirect(efx->net_dev, &xdp, xdp_prog); diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index 8a5bc500d2a1..00c1c4402451 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -599,6 +599,94 @@ err: return NETDEV_TX_OK; } +static void efx_xdp_return_frames(int n, struct xdp_frame **xdpfs) +{ + int i; + + for (i = 0; i < n; i++) + xdp_return_frame_rx_napi(xdpfs[i]); +} + +/* Transmit a packet from an XDP buffer + * + * Returns number of packets sent on success, error code otherwise. + * Runs in NAPI context, either in our poll (for XDP TX) or a different NIC + * (for XDP redirect). + */ +int efx_xdp_tx_buffers(struct efx_nic *efx, int n, struct xdp_frame **xdpfs, + bool flush) +{ + struct efx_tx_buffer *tx_buffer; + struct efx_tx_queue *tx_queue; + struct xdp_frame *xdpf; + dma_addr_t dma_addr; + unsigned int len; + int space; + int cpu; + int i; + + cpu = raw_smp_processor_id(); + + if (!efx->xdp_tx_queue_count || + unlikely(cpu >= efx->xdp_tx_queue_count)) + return -EINVAL; + + tx_queue = efx->xdp_tx_queues[cpu]; + if (unlikely(!tx_queue)) + return -EINVAL; + + if (unlikely(n && !xdpfs)) + return -EINVAL; + + if (!n) + return 0; + + /* Check for available space. We should never need multiple + * descriptors per frame. + */ + space = efx->txq_entries + + tx_queue->read_count - tx_queue->insert_count; + + for (i = 0; i < n; i++) { + xdpf = xdpfs[i]; + + if (i >= space) + break; + + /* We'll want a descriptor for this tx. */ + prefetchw(__efx_tx_queue_get_insert_buffer(tx_queue)); + + len = xdpf->len; + + /* Map for DMA. */ + dma_addr = dma_map_single(&efx->pci_dev->dev, + xdpf->data, len, + DMA_TO_DEVICE); + if (dma_mapping_error(&efx->pci_dev->dev, dma_addr)) + break; + + /* Create descriptor and set up for unmapping DMA. */ + tx_buffer = efx_tx_map_chunk(tx_queue, dma_addr, len); + tx_buffer->xdpf = xdpf; + tx_buffer->flags = EFX_TX_BUF_XDP | + EFX_TX_BUF_MAP_SINGLE; + tx_buffer->dma_offset = 0; + tx_buffer->unmap_len = len; + tx_queue->tx_packets++; + } + + /* Pass mapped frames to hardware. */ + if (flush && i > 0) + efx_nic_push_buffers(tx_queue); + + if (i == 0) + return -EIO; + + efx_xdp_return_frames(n - i, xdpfs + i); + + return i; +} + /* Remove packets from the TX queue * * This removes packets from the TX queue, up to and including the -- cgit v1.2.3-59-g8ed1b From cd846bef2d7464b58db01ecd2c6cb20652c5a7a8 Mon Sep 17 00:00:00 2001 From: Charles McLachlan Date: Thu, 31 Oct 2019 10:24:23 +0000 Subject: sfc: add XDP counters to ethtool stats Count XDP packet drops, error drops, transmissions and redirects and expose these counters via the ethtool stats command. Signed-off-by: Charles McLachlan Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ethtool.c | 25 +++++++++++++++++++++++++ drivers/net/ethernet/sfc/net_driver.h | 8 ++++++++ drivers/net/ethernet/sfc/rx.c | 9 +++++++++ 3 files changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 86b965875540..8db593fb9699 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -83,6 +83,10 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_events), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_merge_packets), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_drops), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect), }; #define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) @@ -399,6 +403,19 @@ static size_t efx_describe_per_queue_stats(struct efx_nic *efx, u8 *strings) } } } + if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) { + unsigned short xdp; + + for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) { + n_stats++; + if (strings) { + snprintf(strings, ETH_GSTRING_LEN, + "tx-xdp-cpu-%hu.tx_packets", xdp); + strings += ETH_GSTRING_LEN; + } + } + } + return n_stats; } @@ -509,6 +526,14 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, data++; } } + if (efx->xdp_tx_queue_count && efx->xdp_tx_queues) { + int xdp; + + for (xdp = 0; xdp < efx->xdp_tx_queue_count; xdp++) { + data[0] = efx->xdp_tx_queues[xdp]->tx_packets; + data++; + } + } efx_ptp_update_stats(efx, data); } diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 505ddc060e64..04e49eac7327 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -453,6 +453,10 @@ enum efx_sync_events_state { * lack of descriptors * @n_rx_merge_events: Number of RX merged completion events * @n_rx_merge_packets: Number of RX packets completed by merged events + * @n_rx_xdp_drops: Count of RX packets intentionally dropped due to XDP + * @n_rx_xdp_bad_drops: Count of RX packets dropped due to XDP errors + * @n_rx_xdp_tx: Count of RX packets retransmitted due to XDP + * @n_rx_xdp_redirect: Count of RX packets redirected to a different NIC by XDP * @rx_pkt_n_frags: Number of fragments in next packet to be delivered by * __efx_rx_packet(), or zero if there is none * @rx_pkt_index: Ring index of first buffer for next packet to be delivered @@ -506,6 +510,10 @@ struct efx_channel { unsigned int n_rx_nodesc_trunc; unsigned int n_rx_merge_events; unsigned int n_rx_merge_packets; + unsigned int n_rx_xdp_drops; + unsigned int n_rx_xdp_bad_drops; + unsigned int n_rx_xdp_tx; + unsigned int n_rx_xdp_redirect; unsigned int rx_pkt_n_frags; unsigned int rx_pkt_index; diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 91f6d5b9ceac..a7d9841105d8 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -677,6 +677,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, netif_err(efx, rx_err, efx->net_dev, "XDP is not possible with multiple receive fragments (%d)\n", channel->rx_pkt_n_frags); + channel->n_rx_xdp_bad_drops++; return false; } @@ -722,6 +723,9 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, if (net_ratelimit()) netif_err(efx, rx_err, efx->net_dev, "XDP TX failed (%d)\n", err); + channel->n_rx_xdp_bad_drops++; + } else { + channel->n_rx_xdp_tx++; } break; @@ -732,12 +736,16 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, if (net_ratelimit()) netif_err(efx, rx_err, efx->net_dev, "XDP redirect failed (%d)\n", err); + channel->n_rx_xdp_bad_drops++; + } else { + channel->n_rx_xdp_redirect++; } break; default: bpf_warn_invalid_xdp_action(xdp_act); efx_free_rx_buffers(rx_queue, rx_buf, 1); + channel->n_rx_xdp_bad_drops++; break; case XDP_ABORTED: @@ -745,6 +753,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, /* Fall through */ case XDP_DROP: efx_free_rx_buffers(rx_queue, rx_buf, 1); + channel->n_rx_xdp_drops++; break; } -- cgit v1.2.3-59-g8ed1b From f5c3fffa4c18783edc3954b7b4c6e0893345c478 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Thu, 31 Oct 2019 01:18:30 +0200 Subject: dpaa2-eth: update the TX frame queues on DPNI_IRQ_EVENT_ENDPOINT_CHANGED Currently the function is called at every link up event, although the FQID values will only change when the DPNI is disconnected from the current object and reconnected to a different one. The patch also avoids the forward declaration of update_tx_fqids. Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 90fc79b3fd0a..602d5118e928 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1255,8 +1255,6 @@ static void dpaa2_eth_set_rx_taildrop(struct dpaa2_eth_priv *priv, bool enable) priv->rx_td_enabled = enable; } -static void update_tx_fqids(struct dpaa2_eth_priv *priv); - static int link_state_update(struct dpaa2_eth_priv *priv) { struct dpni_link_state state = {0}; @@ -1283,7 +1281,6 @@ static int link_state_update(struct dpaa2_eth_priv *priv) goto out; if (state.up) { - update_tx_fqids(priv); netif_carrier_on(priv->net_dev); netif_tx_start_all_queues(priv->net_dev); } else { @@ -3363,8 +3360,10 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) if (status & DPNI_IRQ_EVENT_LINK_CHANGED) link_state_update(netdev_priv(net_dev)); - if (status & DPNI_IRQ_EVENT_ENDPOINT_CHANGED) + if (status & DPNI_IRQ_EVENT_ENDPOINT_CHANGED) { set_mac_addr(netdev_priv(net_dev)); + update_tx_fqids(priv); + } return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 71947923089353f23f4f210864903c4dcf2c1696 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Thu, 31 Oct 2019 01:18:31 +0200 Subject: dpaa2-eth: add MAC/PHY support through phylink The dpaa2-eth driver now has support for connecting to its associated PHY device found through standard OF bindings. This happens when the DPNI object (that the driver probes on) gets connected to a DPMAC. When that happens, the device tree is looked up by the DPMAC ID, and the associated PHY bindings are found. The old logic of handling the net device's link state by hand still needs to be kept, as the DPNI can be connected to other devices on the bus than a DPMAC: other DPNI, DPSW ports, etc. This logic is only engaged when there is no DPMAC (and therefore no phylink instance) attached. The MC firmware support multiple type of DPMAC links: TYPE_FIXED, TYPE_PHY. The TYPE_FIXED mode does not require any DPMAC management from Linux side, and as such, the driver will not handle such a DPMAC. Although PHYLINK typically handles SFP cages and in-band AN modes, for the moment the driver only supports the RGMII interfaces found on the LX2160A. Support for other modes will come later. Signed-off-by: Ioana Ciornei Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- MAINTAINERS | 2 + drivers/net/ethernet/freescale/dpaa2/Makefile | 2 +- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 119 ++++++-- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h | 3 + .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c | 25 ++ drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 301 +++++++++++++++++++++ drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h | 32 +++ drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h | 62 +++++ drivers/net/ethernet/freescale/dpaa2/dpmac.c | 149 ++++++++++ drivers/net/ethernet/freescale/dpaa2/dpmac.h | 144 ++++++++++ 10 files changed, 818 insertions(+), 21 deletions(-) create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac.c create mode 100644 drivers/net/ethernet/freescale/dpaa2/dpmac.h (limited to 'drivers/net') diff --git a/MAINTAINERS b/MAINTAINERS index c25441edb274..541c9e04ded1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5053,7 +5053,9 @@ M: Ioana Radulescu L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/freescale/dpaa2/dpaa2-eth* +F: drivers/net/ethernet/freescale/dpaa2/dpaa2-mac* F: drivers/net/ethernet/freescale/dpaa2/dpni* +F: drivers/net/ethernet/freescale/dpaa2/dpmac* F: drivers/net/ethernet/freescale/dpaa2/dpkg.h F: drivers/net/ethernet/freescale/dpaa2/Makefile F: drivers/net/ethernet/freescale/dpaa2/Kconfig diff --git a/drivers/net/ethernet/freescale/dpaa2/Makefile b/drivers/net/ethernet/freescale/dpaa2/Makefile index d1e78cdd512f..69184ca3b7b9 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Makefile +++ b/drivers/net/ethernet/freescale/dpaa2/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_FSL_DPAA2_ETH) += fsl-dpaa2-eth.o obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += fsl-dpaa2-ptp.o -fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o +fsl-dpaa2-eth-objs := dpaa2-eth.o dpaa2-ethtool.o dpni.o dpaa2-mac.o dpmac.o fsl-dpaa2-eth-${CONFIG_DEBUG_FS} += dpaa2-eth-debugfs.o fsl-dpaa2-ptp-objs := dpaa2-ptp.o dprtc.o diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 602d5118e928..c26c0a7cbb6b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016-2017 NXP + * Copyright 2016-2019 NXP */ #include #include @@ -1276,6 +1276,12 @@ static int link_state_update(struct dpaa2_eth_priv *priv) !!(state.options & DPNI_LINK_OPT_ASYM_PAUSE); dpaa2_eth_set_rx_taildrop(priv, !tx_pause); + /* When we manage the MAC/PHY using phylink there is no need + * to manually update the netif_carrier. + */ + if (priv->mac) + goto out; + /* Chech link state; speed / duplex changes are not treated yet */ if (priv->link_state.up == state.up) goto out; @@ -1312,17 +1318,21 @@ static int dpaa2_eth_open(struct net_device *net_dev) priv->dpbp_dev->obj_desc.id, priv->bpid); } - /* We'll only start the txqs when the link is actually ready; make sure - * we don't race against the link up notification, which may come - * immediately after dpni_enable(); - */ - netif_tx_stop_all_queues(net_dev); + if (!priv->mac) { + /* We'll only start the txqs when the link is actually ready; + * make sure we don't race against the link up notification, + * which may come immediately after dpni_enable(); + */ + netif_tx_stop_all_queues(net_dev); + + /* Also, explicitly set carrier off, otherwise + * netif_carrier_ok() will return true and cause 'ip link show' + * to report the LOWER_UP flag, even though the link + * notification wasn't even received. + */ + netif_carrier_off(net_dev); + } enable_ch_napi(priv); - /* Also, explicitly set carrier off, otherwise netif_carrier_ok() will - * return true and cause 'ip link show' to report the LOWER_UP flag, - * even though the link notification wasn't even received. - */ - netif_carrier_off(net_dev); err = dpni_enable(priv->mc_io, 0, priv->mc_token); if (err < 0) { @@ -1330,13 +1340,17 @@ static int dpaa2_eth_open(struct net_device *net_dev) goto enable_err; } - /* If the DPMAC object has already processed the link up interrupt, - * we have to learn the link state ourselves. - */ - err = link_state_update(priv); - if (err < 0) { - netdev_err(net_dev, "Can't update link state\n"); - goto link_state_err; + if (!priv->mac) { + /* If the DPMAC object has already processed the link up + * interrupt, we have to learn the link state ourselves. + */ + err = link_state_update(priv); + if (err < 0) { + netdev_err(net_dev, "Can't update link state\n"); + goto link_state_err; + } + } else { + phylink_start(priv->mac->phylink); } return 0; @@ -1411,8 +1425,12 @@ static int dpaa2_eth_stop(struct net_device *net_dev) int dpni_enabled = 0; int retries = 10; - netif_tx_stop_all_queues(net_dev); - netif_carrier_off(net_dev); + if (!priv->mac) { + netif_tx_stop_all_queues(net_dev); + netif_carrier_off(net_dev); + } else { + phylink_stop(priv->mac->phylink); + } /* On dpni_disable(), the MC firmware will: * - stop MAC Rx and wait for all Rx frames to be enqueued to software @@ -3342,12 +3360,56 @@ static int poll_link_state(void *arg) return 0; } +static int dpaa2_eth_connect_mac(struct dpaa2_eth_priv *priv) +{ + struct fsl_mc_device *dpni_dev, *dpmac_dev; + struct dpaa2_mac *mac; + int err; + + dpni_dev = to_fsl_mc_device(priv->net_dev->dev.parent); + dpmac_dev = fsl_mc_get_endpoint(dpni_dev); + if (IS_ERR(dpmac_dev) || dpmac_dev->dev.type != &fsl_mc_bus_dpmac_type) + return 0; + + if (dpaa2_mac_is_type_fixed(dpmac_dev, priv->mc_io)) + return 0; + + mac = kzalloc(sizeof(struct dpaa2_mac), GFP_KERNEL); + if (!mac) + return -ENOMEM; + + mac->mc_dev = dpmac_dev; + mac->mc_io = priv->mc_io; + mac->net_dev = priv->net_dev; + + err = dpaa2_mac_connect(mac); + if (err) { + netdev_err(priv->net_dev, "Error connecting to the MAC endpoint\n"); + kfree(mac); + return err; + } + priv->mac = mac; + + return 0; +} + +static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv) +{ + if (!priv->mac) + return; + + dpaa2_mac_disconnect(priv->mac); + kfree(priv->mac); + priv->mac = NULL; +} + static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) { u32 status = ~0; struct device *dev = (struct device *)arg; struct fsl_mc_device *dpni_dev = to_fsl_mc_device(dev); struct net_device *net_dev = dev_get_drvdata(dev); + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); int err; err = dpni_get_irq_status(dpni_dev->mc_io, 0, dpni_dev->mc_handle, @@ -3363,6 +3425,13 @@ static irqreturn_t dpni_irq0_handler_thread(int irq_num, void *arg) if (status & DPNI_IRQ_EVENT_ENDPOINT_CHANGED) { set_mac_addr(netdev_priv(net_dev)); update_tx_fqids(priv); + + rtnl_lock(); + if (priv->mac) + dpaa2_eth_disconnect_mac(priv); + else + dpaa2_eth_connect_mac(priv); + rtnl_unlock(); } return IRQ_HANDLED; @@ -3539,6 +3608,10 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) priv->do_link_poll = true; } + err = dpaa2_eth_connect_mac(priv); + if (err) + goto err_connect_mac; + err = register_netdev(net_dev); if (err < 0) { dev_err(dev, "register_netdev() failed\n"); @@ -3553,6 +3626,8 @@ static int dpaa2_eth_probe(struct fsl_mc_device *dpni_dev) return 0; err_netdev_reg: + dpaa2_eth_disconnect_mac(priv); +err_connect_mac: if (priv->do_link_poll) kthread_stop(priv->poll_thread); else @@ -3595,6 +3670,10 @@ static int dpaa2_eth_remove(struct fsl_mc_device *ls_dev) #ifdef CONFIG_DEBUG_FS dpaa2_dbg_remove(priv); #endif + rtnl_lock(); + dpaa2_eth_disconnect_mac(priv); + rtnl_unlock(); + unregister_netdev(net_dev); if (priv->do_link_poll) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h index 686b651edcb2..7635db3ef903 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.h @@ -17,6 +17,7 @@ #include "dpaa2-eth-trace.h" #include "dpaa2-eth-debugfs.h" +#include "dpaa2-mac.h" #define DPAA2_WRIOP_VERSION(x, y, z) ((x) << 10 | (y) << 5 | (z) << 0) @@ -415,6 +416,8 @@ struct dpaa2_eth_priv { #ifdef CONFIG_DEBUG_FS struct dpaa2_debugfs dbg; #endif + + struct dpaa2_mac *mac; }; #define DPAA2_RXH_SUPPORTED (RXH_L2DA | RXH_VLAN | RXH_L3_PROTO \ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index dc9a6c36cac0..0883620631b8 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -85,6 +85,10 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev, { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + if (priv->mac) + return phylink_ethtool_ksettings_get(priv->mac->phylink, + link_settings); + link_settings->base.autoneg = AUTONEG_DISABLE; if (!(priv->link_state.options & DPNI_LINK_OPT_HALF_DUPLEX)) link_settings->base.duplex = DUPLEX_FULL; @@ -93,12 +97,29 @@ dpaa2_eth_get_link_ksettings(struct net_device *net_dev, return 0; } +static int +dpaa2_eth_set_link_ksettings(struct net_device *net_dev, + const struct ethtool_link_ksettings *link_settings) +{ + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + + if (!priv->mac) + return -ENOTSUPP; + + return phylink_ethtool_ksettings_set(priv->mac->phylink, link_settings); +} + static void dpaa2_eth_get_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct dpaa2_eth_priv *priv = netdev_priv(net_dev); u64 link_options = priv->link_state.options; + if (priv->mac) { + phylink_ethtool_get_pauseparam(priv->mac->phylink, pause); + return; + } + pause->rx_pause = !!(link_options & DPNI_LINK_OPT_PAUSE); pause->tx_pause = pause->rx_pause ^ !!(link_options & DPNI_LINK_OPT_ASYM_PAUSE); @@ -118,6 +139,9 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, return -EOPNOTSUPP; } + if (priv->mac) + return phylink_ethtool_set_pauseparam(priv->mac->phylink, + pause); if (pause->autoneg) return -EOPNOTSUPP; @@ -728,6 +752,7 @@ const struct ethtool_ops dpaa2_ethtool_ops = { .get_drvinfo = dpaa2_eth_get_drvinfo, .get_link = ethtool_op_get_link, .get_link_ksettings = dpaa2_eth_get_link_ksettings, + .set_link_ksettings = dpaa2_eth_set_link_ksettings, .get_pauseparam = dpaa2_eth_get_pauseparam, .set_pauseparam = dpaa2_eth_set_pauseparam, .get_sset_count = dpaa2_eth_get_sset_count, diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c new file mode 100644 index 000000000000..fea388d86f20 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2019 NXP */ + +#include "dpaa2-eth.h" +#include "dpaa2-mac.h" + +#define phylink_to_dpaa2_mac(config) \ + container_of((config), struct dpaa2_mac, phylink_config) + +static phy_interface_t phy_mode(enum dpmac_eth_if eth_if) +{ + switch (eth_if) { + case DPMAC_ETH_IF_RGMII: + return PHY_INTERFACE_MODE_RGMII; + default: + return -EINVAL; + } +} + +/* Caller must call of_node_put on the returned value */ +static struct device_node *dpaa2_mac_get_node(u16 dpmac_id) +{ + struct device_node *dpmacs, *dpmac = NULL; + u32 id; + int err; + + dpmacs = of_find_node_by_name(NULL, "dpmacs"); + if (!dpmacs) + return NULL; + + while ((dpmac = of_get_next_child(dpmacs, dpmac)) != NULL) { + err = of_property_read_u32(dpmac, "reg", &id); + if (err) + continue; + if (id == dpmac_id) + break; + } + + of_node_put(dpmacs); + + return dpmac; +} + +static int dpaa2_mac_get_if_mode(struct device_node *node, + struct dpmac_attr attr) +{ + int if_mode; + + if_mode = of_get_phy_mode(node); + if (if_mode >= 0) + return if_mode; + + if_mode = phy_mode(attr.eth_if); + if (if_mode >= 0) + return if_mode; + + return -ENODEV; +} + +static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac, + phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + return (interface != mac->if_mode); + default: + return true; + } +} + +static void dpaa2_mac_validate(struct phylink_config *config, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config); + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + if (state->interface != PHY_INTERFACE_MODE_NA && + dpaa2_mac_phy_mode_mismatch(mac, state->interface)) { + goto empty_set; + } + + phylink_set_port_modes(mask); + phylink_set(mask, Autoneg); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + + switch (state->interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, 1000baseT_Full); + break; + default: + goto empty_set; + } + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); + + return; + +empty_set: + linkmode_zero(supported); +} + +static void dpaa2_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config); + struct dpmac_link_state *dpmac_state = &mac->state; + int err; + + if (state->speed != SPEED_UNKNOWN) + dpmac_state->rate = state->speed; + + if (state->duplex != DUPLEX_UNKNOWN) { + if (!state->duplex) + dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX; + } + + if (state->an_enabled) + dpmac_state->options |= DPMAC_LINK_OPT_AUTONEG; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_AUTONEG; + + if (state->pause & MLO_PAUSE_RX) + dpmac_state->options |= DPMAC_LINK_OPT_PAUSE; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE; + + if (!!(state->pause & MLO_PAUSE_RX) ^ !!(state->pause & MLO_PAUSE_TX)) + dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE; + else + dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE; + + err = dpmac_set_link_state(mac->mc_io, 0, + mac->mc_dev->mc_handle, dpmac_state); + if (err) + netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err); +} + +static void dpaa2_mac_link_up(struct phylink_config *config, unsigned int mode, + phy_interface_t interface, struct phy_device *phy) +{ + struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config); + struct dpmac_link_state *dpmac_state = &mac->state; + int err; + + dpmac_state->up = 1; + err = dpmac_set_link_state(mac->mc_io, 0, + mac->mc_dev->mc_handle, dpmac_state); + if (err) + netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err); +} + +static void dpaa2_mac_link_down(struct phylink_config *config, + unsigned int mode, + phy_interface_t interface) +{ + struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config); + struct dpmac_link_state *dpmac_state = &mac->state; + int err; + + dpmac_state->up = 0; + err = dpmac_set_link_state(mac->mc_io, 0, + mac->mc_dev->mc_handle, dpmac_state); + if (err) + netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err); +} + +static const struct phylink_mac_ops dpaa2_mac_phylink_ops = { + .validate = dpaa2_mac_validate, + .mac_config = dpaa2_mac_config, + .mac_link_up = dpaa2_mac_link_up, + .mac_link_down = dpaa2_mac_link_down, +}; + +bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, + struct fsl_mc_io *mc_io) +{ + struct dpmac_attr attr; + bool fixed = false; + u16 mc_handle = 0; + int err; + + err = dpmac_open(mc_io, 0, dpmac_dev->obj_desc.id, + &mc_handle); + if (err || !mc_handle) + return false; + + err = dpmac_get_attributes(mc_io, 0, mc_handle, &attr); + if (err) + goto out; + + if (attr.link_type == DPMAC_LINK_TYPE_FIXED) + fixed = true; + +out: + dpmac_close(mc_io, 0, mc_handle); + + return fixed; +} + +int dpaa2_mac_connect(struct dpaa2_mac *mac) +{ + struct fsl_mc_device *dpmac_dev = mac->mc_dev; + struct net_device *net_dev = mac->net_dev; + struct device_node *dpmac_node; + struct phylink *phylink; + struct dpmac_attr attr; + int err; + + err = dpmac_open(mac->mc_io, 0, dpmac_dev->obj_desc.id, + &dpmac_dev->mc_handle); + if (err || !dpmac_dev->mc_handle) { + netdev_err(net_dev, "dpmac_open() = %d\n", err); + return -ENODEV; + } + + err = dpmac_get_attributes(mac->mc_io, 0, dpmac_dev->mc_handle, &attr); + if (err) { + netdev_err(net_dev, "dpmac_get_attributes() = %d\n", err); + goto err_close_dpmac; + } + + dpmac_node = dpaa2_mac_get_node(attr.id); + if (!dpmac_node) { + netdev_err(net_dev, "No dpmac@%d node found.\n", attr.id); + err = -ENODEV; + goto err_close_dpmac; + } + + err = dpaa2_mac_get_if_mode(dpmac_node, attr); + if (err < 0) { + err = -EINVAL; + goto err_put_node; + } + mac->if_mode = err; + + /* The MAC does not have the capability to add RGMII delays so + * error out if the interface mode requests them and there is no PHY + * to act upon them + */ + if (of_phy_is_fixed_link(dpmac_node) && + (mac->if_mode == PHY_INTERFACE_MODE_RGMII_ID || + mac->if_mode == PHY_INTERFACE_MODE_RGMII_RXID || + mac->if_mode == PHY_INTERFACE_MODE_RGMII_TXID)) { + netdev_err(net_dev, "RGMII delay not supported\n"); + err = -EINVAL; + goto err_put_node; + } + + mac->phylink_config.dev = &net_dev->dev; + mac->phylink_config.type = PHYLINK_NETDEV; + + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(dpmac_node), mac->if_mode, + &dpaa2_mac_phylink_ops); + if (IS_ERR(phylink)) { + err = PTR_ERR(phylink); + goto err_put_node; + } + mac->phylink = phylink; + + err = phylink_of_phy_connect(mac->phylink, dpmac_node, 0); + if (err) { + netdev_err(net_dev, "phylink_of_phy_connect() = %d\n", err); + goto err_phylink_destroy; + } + + of_node_put(dpmac_node); + + return 0; + +err_phylink_destroy: + phylink_destroy(mac->phylink); +err_put_node: + of_node_put(dpmac_node); +err_close_dpmac: + dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle); + return err; +} + +void dpaa2_mac_disconnect(struct dpaa2_mac *mac) +{ + if (!mac->phylink) + return; + + phylink_disconnect_phy(mac->phylink); + phylink_destroy(mac->phylink); + dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle); +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h new file mode 100644 index 000000000000..8634d0de7ef3 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2019 NXP */ +#ifndef DPAA2_MAC_H +#define DPAA2_MAC_H + +#include +#include +#include +#include + +#include "dpmac.h" +#include "dpmac-cmd.h" + +struct dpaa2_mac { + struct fsl_mc_device *mc_dev; + struct dpmac_link_state state; + struct net_device *net_dev; + struct fsl_mc_io *mc_io; + + struct phylink_config phylink_config; + struct phylink *phylink; + phy_interface_t if_mode; +}; + +bool dpaa2_mac_is_type_fixed(struct fsl_mc_device *dpmac_dev, + struct fsl_mc_io *mc_io); + +int dpaa2_mac_connect(struct dpaa2_mac *mac); + +void dpaa2_mac_disconnect(struct dpaa2_mac *mac); + +#endif /* DPAA2_MAC_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h new file mode 100644 index 000000000000..96a9b0d0992e --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2019 NXP + */ +#ifndef _FSL_DPMAC_CMD_H +#define _FSL_DPMAC_CMD_H + +/* DPMAC Version */ +#define DPMAC_VER_MAJOR 4 +#define DPMAC_VER_MINOR 4 +#define DPMAC_CMD_BASE_VERSION 1 +#define DPMAC_CMD_2ND_VERSION 2 +#define DPMAC_CMD_ID_OFFSET 4 + +#define DPMAC_CMD(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_BASE_VERSION) +#define DPMAC_CMD_V2(id) (((id) << DPMAC_CMD_ID_OFFSET) | DPMAC_CMD_2ND_VERSION) + +/* Command IDs */ +#define DPMAC_CMDID_CLOSE DPMAC_CMD(0x800) +#define DPMAC_CMDID_OPEN DPMAC_CMD(0x80c) + +#define DPMAC_CMDID_GET_ATTR DPMAC_CMD(0x004) +#define DPMAC_CMDID_SET_LINK_STATE DPMAC_CMD_V2(0x0c3) + +/* Macros for accessing command fields smaller than 1byte */ +#define DPMAC_MASK(field) \ + GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \ + DPMAC_##field##_SHIFT) + +#define dpmac_set_field(var, field, val) \ + ((var) |= (((val) << DPMAC_##field##_SHIFT) & DPMAC_MASK(field))) +#define dpmac_get_field(var, field) \ + (((var) & DPMAC_MASK(field)) >> DPMAC_##field##_SHIFT) + +struct dpmac_cmd_open { + __le32 dpmac_id; +}; + +struct dpmac_rsp_get_attributes { + u8 eth_if; + u8 link_type; + __le16 id; + __le32 max_rate; +}; + +#define DPMAC_STATE_SIZE 1 +#define DPMAC_STATE_SHIFT 0 +#define DPMAC_STATE_VALID_SIZE 1 +#define DPMAC_STATE_VALID_SHIFT 1 + +struct dpmac_cmd_set_link_state { + __le64 options; + __le32 rate; + __le32 pad0; + /* from lsb: up:1, state_valid:1 */ + u8 state; + u8 pad1[7]; + __le64 supported; + __le64 advertising; +}; + +#endif /* _FSL_DPMAC_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.c b/drivers/net/ethernet/freescale/dpaa2/dpmac.c new file mode 100644 index 000000000000..b75189deffb1 --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2019 NXP + */ +#include +#include "dpmac.h" +#include "dpmac-cmd.h" + +/** + * dpmac_open() - Open a control session for the specified object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dpmac_id: DPMAC unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dpmac_create function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpmac_id, + u16 *token) +{ + struct dpmac_cmd_open *cmd_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_OPEN, + cmd_flags, + 0); + cmd_params = (struct dpmac_cmd_open *)cmd.params; + cmd_params->dpmac_id = cpu_to_le32(dpmac_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + *token = mc_cmd_hdr_read_token(&cmd); + + return err; +} + +/** + * dpmac_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_CLOSE, cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +/** + * dpmac_get_attributes - Retrieve DPMAC attributes. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * @attr: Returned object's attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpmac_attr *attr) +{ + struct dpmac_rsp_get_attributes *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_ATTR, + cmd_flags, + token); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpmac_rsp_get_attributes *)cmd.params; + attr->eth_if = rsp_params->eth_if; + attr->link_type = rsp_params->link_type; + attr->id = le16_to_cpu(rsp_params->id); + attr->max_rate = le32_to_cpu(rsp_params->max_rate); + + return 0; +} + +/** + * dpmac_set_link_state() - Set the Ethernet link status + * @mc_io: Pointer to opaque I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * @link_state: Link state configuration + * + * Return: '0' on Success; Error code otherwise. + */ +int dpmac_set_link_state(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpmac_link_state *link_state) +{ + struct dpmac_cmd_set_link_state *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_SET_LINK_STATE, + cmd_flags, + token); + cmd_params = (struct dpmac_cmd_set_link_state *)cmd.params; + cmd_params->options = cpu_to_le64(link_state->options); + cmd_params->rate = cpu_to_le32(link_state->rate); + dpmac_set_field(cmd_params->state, STATE, link_state->up); + dpmac_set_field(cmd_params->state, STATE_VALID, + link_state->state_valid); + cmd_params->supported = cpu_to_le64(link_state->supported); + cmd_params->advertising = cpu_to_le64(link_state->advertising); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.h b/drivers/net/ethernet/freescale/dpaa2/dpmac.h new file mode 100644 index 000000000000..4efc410a479e --- /dev/null +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2019 NXP + */ +#ifndef __FSL_DPMAC_H +#define __FSL_DPMAC_H + +/* Data Path MAC API + * Contains initialization APIs and runtime control APIs for DPMAC + */ + +struct fsl_mc_io; + +int dpmac_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dpmac_id, + u16 *token); + +int dpmac_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * enum dpmac_link_type - DPMAC link type + * @DPMAC_LINK_TYPE_NONE: No link + * @DPMAC_LINK_TYPE_FIXED: Link is fixed type + * @DPMAC_LINK_TYPE_PHY: Link by PHY ID + * @DPMAC_LINK_TYPE_BACKPLANE: Backplane link type + */ +enum dpmac_link_type { + DPMAC_LINK_TYPE_NONE, + DPMAC_LINK_TYPE_FIXED, + DPMAC_LINK_TYPE_PHY, + DPMAC_LINK_TYPE_BACKPLANE +}; + +/** + * enum dpmac_eth_if - DPMAC Ethrnet interface + * @DPMAC_ETH_IF_MII: MII interface + * @DPMAC_ETH_IF_RMII: RMII interface + * @DPMAC_ETH_IF_SMII: SMII interface + * @DPMAC_ETH_IF_GMII: GMII interface + * @DPMAC_ETH_IF_RGMII: RGMII interface + * @DPMAC_ETH_IF_SGMII: SGMII interface + * @DPMAC_ETH_IF_QSGMII: QSGMII interface + * @DPMAC_ETH_IF_XAUI: XAUI interface + * @DPMAC_ETH_IF_XFI: XFI interface + * @DPMAC_ETH_IF_CAUI: CAUI interface + * @DPMAC_ETH_IF_1000BASEX: 1000BASEX interface + * @DPMAC_ETH_IF_USXGMII: USXGMII interface + */ +enum dpmac_eth_if { + DPMAC_ETH_IF_MII, + DPMAC_ETH_IF_RMII, + DPMAC_ETH_IF_SMII, + DPMAC_ETH_IF_GMII, + DPMAC_ETH_IF_RGMII, + DPMAC_ETH_IF_SGMII, + DPMAC_ETH_IF_QSGMII, + DPMAC_ETH_IF_XAUI, + DPMAC_ETH_IF_XFI, + DPMAC_ETH_IF_CAUI, + DPMAC_ETH_IF_1000BASEX, + DPMAC_ETH_IF_USXGMII, +}; + +/** + * struct dpmac_attr - Structure representing DPMAC attributes + * @id: DPMAC object ID + * @max_rate: Maximum supported rate - in Mbps + * @eth_if: Ethernet interface + * @link_type: link type + */ +struct dpmac_attr { + u16 id; + u32 max_rate; + enum dpmac_eth_if eth_if; + enum dpmac_link_type link_type; +}; + +int dpmac_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpmac_attr *attr); + +/** + * DPMAC link configuration/state options + */ + +/** + * Enable auto-negotiation + */ +#define DPMAC_LINK_OPT_AUTONEG BIT_ULL(0) +/** + * Enable half-duplex mode + */ +#define DPMAC_LINK_OPT_HALF_DUPLEX BIT_ULL(1) +/** + * Enable pause frames + */ +#define DPMAC_LINK_OPT_PAUSE BIT_ULL(2) +/** + * Enable a-symmetric pause frames + */ +#define DPMAC_LINK_OPT_ASYM_PAUSE BIT_ULL(3) + +/** + * Advertised link speeds + */ +#define DPMAC_ADVERTISED_10BASET_FULL BIT_ULL(0) +#define DPMAC_ADVERTISED_100BASET_FULL BIT_ULL(1) +#define DPMAC_ADVERTISED_1000BASET_FULL BIT_ULL(2) +#define DPMAC_ADVERTISED_10000BASET_FULL BIT_ULL(4) +#define DPMAC_ADVERTISED_2500BASEX_FULL BIT_ULL(5) + +/** + * Advertise auto-negotiation enable + */ +#define DPMAC_ADVERTISED_AUTONEG BIT_ULL(3) + +/** + * struct dpmac_link_state - DPMAC link configuration request + * @rate: Rate in Mbps + * @options: Enable/Disable DPMAC link cfg features (bitmap) + * @up: Link state + * @state_valid: Ignore/Update the state of the link + * @supported: Speeds capability of the phy (bitmap) + * @advertising: Speeds that are advertised for autoneg (bitmap) + */ +struct dpmac_link_state { + u32 rate; + u64 options; + int up; + int state_valid; + u64 supported; + u64 advertising; +}; + +int dpmac_set_link_state(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dpmac_link_state *link_state); + +#endif /* __FSL_DPMAC_H */ -- cgit v1.2.3-59-g8ed1b From c5f51765a1f60b701840544faf3ca63204b8dc3c Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 30 Oct 2019 22:09:13 -0400 Subject: net: dsa: list DSA links in the fabric Implement a new list of DSA links in the switch fabric itself, to provide an alterative to the ds->rtable static arrays. At the same time, provide a new dsa_routing_port() helper to abstract the usage of ds->rtable in drivers. If there's no port to reach a given device, return the first invalid port, ds->num_ports. This avoids potential signedness errors or the need to define special values. Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++---- include/net/dsa.h | 29 +++++++++++++++++++++++++++- net/dsa/dsa2.c | 41 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 619cd081339e..66de492117ad 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1143,6 +1143,7 @@ static int mv88e6xxx_pri_setup(struct mv88e6xxx_chip *chip) static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) { + struct dsa_switch *ds = chip->ds; int target, port; int err; @@ -1151,10 +1152,9 @@ static int mv88e6xxx_devmap_setup(struct mv88e6xxx_chip *chip) /* Initialize the routing port to the 32 possible target devices */ for (target = 0; target < 32; target++) { - port = 0x1f; - if (target < DSA_MAX_SWITCHES) - if (chip->ds->rtable[target] != DSA_RTABLE_NONE) - port = chip->ds->rtable[target]; + port = dsa_routing_port(ds, target); + if (port == ds->num_ports) + port = 0x1f; err = mv88e6xxx_g2_device_mapping_write(chip, target, port); if (err) diff --git a/include/net/dsa.h b/include/net/dsa.h index 9aba326abb64..3d7366d634d8 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -123,6 +123,9 @@ struct dsa_switch_tree { /* List of switch ports */ struct list_head ports; + /* List of DSA links composing the routing table */ + struct list_head rtable; + /* * Data for the individual switch chips. */ @@ -214,6 +217,17 @@ struct dsa_port { bool setup; }; +/* TODO: ideally DSA ports would have a single dp->link_dp member, + * and no dst->rtable nor this struct dsa_link would be needed, + * but this would require some more complex tree walking, + * so keep it stupid at the moment and list them all. + */ +struct dsa_link { + struct dsa_port *dp; + struct dsa_port *link_dp; + struct list_head list; +}; + struct dsa_switch { bool setup; @@ -324,6 +338,19 @@ static inline u32 dsa_user_ports(struct dsa_switch *ds) return mask; } +/* Return the local port used to reach an arbitrary switch device */ +static inline unsigned int dsa_routing_port(struct dsa_switch *ds, int device) +{ + struct dsa_switch_tree *dst = ds->dst; + struct dsa_link *dl; + + list_for_each_entry(dl, &dst->rtable, list) + if (dl->dp->ds == ds && dl->link_dp->ds->index == device) + return dl->dp->index; + + return ds->num_ports; +} + /* Return the local port used to reach an arbitrary switch port */ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, int port) @@ -331,7 +358,7 @@ static inline unsigned int dsa_towards_port(struct dsa_switch *ds, int device, if (device == ds->index) return port; else - return ds->rtable[device]; + return dsa_routing_port(ds, device); } /* Return the local port used to reach the dedicated CPU port */ diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c index e7aae96b54bb..222d7dbfcfea 100644 --- a/net/dsa/dsa2.c +++ b/net/dsa/dsa2.c @@ -45,6 +45,8 @@ static struct dsa_switch_tree *dsa_tree_alloc(int index) dst->index = index; + INIT_LIST_HEAD(&dst->rtable); + INIT_LIST_HEAD(&dst->ports); INIT_LIST_HEAD(&dst->list); @@ -122,6 +124,31 @@ static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst, return NULL; } +struct dsa_link *dsa_link_touch(struct dsa_port *dp, struct dsa_port *link_dp) +{ + struct dsa_switch *ds = dp->ds; + struct dsa_switch_tree *dst; + struct dsa_link *dl; + + dst = ds->dst; + + list_for_each_entry(dl, &dst->rtable, list) + if (dl->dp == dp && dl->link_dp == link_dp) + return dl; + + dl = kzalloc(sizeof(*dl), GFP_KERNEL); + if (!dl) + return NULL; + + dl->dp = dp; + dl->link_dp = link_dp; + + INIT_LIST_HEAD(&dl->list); + list_add_tail(&dl->list, &dst->rtable); + + return dl; +} + static bool dsa_port_setup_routing_table(struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; @@ -129,6 +156,7 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) struct device_node *dn = dp->dn; struct of_phandle_iterator it; struct dsa_port *link_dp; + struct dsa_link *dl; int err; of_for_each_phandle(&it, err, dn, "link", NULL, 0) { @@ -138,7 +166,11 @@ static bool dsa_port_setup_routing_table(struct dsa_port *dp) return false; } - ds->rtable[link_dp->ds->index] = dp->index; + dl = dsa_link_touch(dp, link_dp); + if (!dl) { + of_node_put(it.node); + return false; + } } return true; @@ -544,6 +576,8 @@ teardown_default_cpu: static void dsa_tree_teardown(struct dsa_switch_tree *dst) { + struct dsa_link *dl, *next; + if (!dst->setup) return; @@ -553,6 +587,11 @@ static void dsa_tree_teardown(struct dsa_switch_tree *dst) dsa_tree_teardown_default_cpu(dst); + list_for_each_entry_safe(dl, next, &dst->rtable, list) { + list_del(&dl->list); + kfree(dl); + } + pr_info("DSA: tree %d torn down\n", dst->index); dst->setup = false; -- cgit v1.2.3-59-g8ed1b From 90f906243bf633f07757467506dfab3422b43ca2 Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Thu, 31 Oct 2019 01:07:45 -0400 Subject: bnxt_en: Add support for L2 rewrite This patch adds support for packet edit offload of L2 fields (src mac & dst mac, also referred as L2 rewrite). Only when the mask is fully exact match for a field, the command is sent down to the adapter to offload such a flow. Otherwise, an error is returned. v2: Fix pointer alignment issue in bnxt_fill_l2_rewrite_fields() [MChan] Signed-off-by: Venkat Duvvuru Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 132 +++++++++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h | 11 +++ 2 files changed, 143 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index c8062d020d1e..80b39ffa4ca2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "bnxt_hsi.h" @@ -36,6 +37,8 @@ #define is_vid_exactmatch(vlan_tci_mask) \ ((ntohs(vlan_tci_mask) & VLAN_VID_MASK) == VLAN_VID_MASK) +static bool is_wildcard(void *mask, int len); +static bool is_exactmatch(void *mask, int len); /* Return the dst fid of the func for flow forwarding * For PFs: src_fid is the fid of the PF * For VF-reps: src_fid the fid of the VF @@ -111,10 +114,115 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp, return 0; } +/* Key & Mask from the stack comes unaligned in multiple iterations. + * This routine consolidates such multiple unaligned values into one + * field each for Key & Mask (for src and dst macs separately) + * For example, + * Mask/Key Offset Iteration + * ========== ====== ========= + * dst mac 0xffffffff 0 1 + * dst mac 0x0000ffff 4 2 + * + * src mac 0xffff0000 4 1 + * src mac 0xffffffff 8 2 + * + * The above combination coming from the stack will be consolidated as + * Mask/Key + * ============== + * src mac: 0xffffffffffff + * dst mac: 0xffffffffffff + */ +static void bnxt_set_l2_key_mask(u32 part_key, u32 part_mask, + u8 *actual_key, u8 *actual_mask) +{ + u32 key = get_unaligned((u32 *)actual_key); + u32 mask = get_unaligned((u32 *)actual_mask); + + part_key &= part_mask; + part_key |= key & ~part_mask; + + put_unaligned(mask | part_mask, (u32 *)actual_mask); + put_unaligned(part_key, (u32 *)actual_key); +} + +static int +bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions, + u16 *eth_addr, u16 *eth_addr_mask) +{ + u16 *p; + int j; + + if (unlikely(bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask))) + return -EINVAL; + + if (!is_wildcard(ð_addr_mask[0], ETH_ALEN)) { + if (!is_exactmatch(ð_addr_mask[0], ETH_ALEN)) + return -EINVAL; + /* FW expects dmac to be in u16 array format */ + p = eth_addr; + for (j = 0; j < 3; j++) + actions->l2_rewrite_dmac[j] = cpu_to_be16(*(p + j)); + } + + if (!is_wildcard(ð_addr_mask[ETH_ALEN], ETH_ALEN)) { + if (!is_exactmatch(ð_addr_mask[ETH_ALEN], ETH_ALEN)) + return -EINVAL; + /* FW expects smac to be in u16 array format */ + p = ð_addr[ETH_ALEN / 2]; + for (j = 0; j < 3; j++) + actions->l2_rewrite_smac[j] = cpu_to_be16(*(p + j)); + } + + return 0; +} + +static int +bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, + struct flow_action_entry *act, u8 *eth_addr, + u8 *eth_addr_mask) +{ + u32 mask, val, offset; + u8 htype; + + offset = act->mangle.offset; + htype = act->mangle.htype; + switch (htype) { + case FLOW_ACT_MANGLE_HDR_TYPE_ETH: + if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) { + netdev_err(bp->dev, + "%s: eth_hdr: Invalid pedit field\n", + __func__); + return -EINVAL; + } + actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE; + mask = ~act->mangle.mask; + val = act->mangle.val; + + bnxt_set_l2_key_mask(val, mask, ð_addr[offset], + ð_addr_mask[offset]); + break; + default: + netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n", + __func__); + return -EINVAL; + } + return 0; +} + static int bnxt_tc_parse_actions(struct bnxt *bp, struct bnxt_tc_actions *actions, struct flow_action *flow_action) { + /* Used to store the L2 rewrite mask for dmac (6 bytes) followed by + * smac (6 bytes) if rewrite of both is specified, otherwise either + * dmac or smac + */ + u16 eth_addr_mask[ETH_ALEN] = { 0 }; + /* Used to store the L2 rewrite key for dmac (6 bytes) followed by + * smac (6 bytes) if rewrite of both is specified, otherwise either + * dmac or smac + */ + u16 eth_addr[ETH_ALEN] = { 0 }; struct flow_action_entry *act; int i, rc; @@ -148,11 +256,26 @@ static int bnxt_tc_parse_actions(struct bnxt *bp, case FLOW_ACTION_TUNNEL_DECAP: actions->flags |= BNXT_TC_ACTION_FLAG_TUNNEL_DECAP; break; + /* Packet edit: L2 rewrite, NAT, NAPT */ + case FLOW_ACTION_MANGLE: + rc = bnxt_tc_parse_pedit(bp, actions, act, + (u8 *)eth_addr, + (u8 *)eth_addr_mask); + if (rc) + return rc; + break; default: break; } } + if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) { + rc = bnxt_fill_l2_rewrite_fields(actions, eth_addr, + eth_addr_mask); + if (rc) + return rc; + } + if (actions->flags & BNXT_TC_ACTION_FLAG_FWD) { if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { /* dst_fid is PF's fid */ @@ -401,6 +524,15 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow, req.src_fid = cpu_to_le16(flow->src_fid); req.ref_flow_handle = ref_flow_handle; + if (actions->flags & BNXT_TC_ACTION_FLAG_L2_REWRITE) { + memcpy(req.l2_rewrite_dmac, actions->l2_rewrite_dmac, + ETH_ALEN); + memcpy(req.l2_rewrite_smac, actions->l2_rewrite_smac, + ETH_ALEN); + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE; + } + if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP || actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { req.tunnel_handle = tunnel_handle; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h index 4f05305052f2..6d0d4857992b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h @@ -62,6 +62,12 @@ struct bnxt_tc_tunnel_key { __be32 id; }; +#define bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask) \ + ((is_wildcard(&(eth_addr)[0], ETH_ALEN) && \ + is_wildcard(&(eth_addr)[ETH_ALEN], ETH_ALEN)) || \ + (is_wildcard(&(eth_addr_mask)[0], ETH_ALEN) && \ + is_wildcard(&(eth_addr_mask)[ETH_ALEN], ETH_ALEN))) + struct bnxt_tc_actions { u32 flags; #define BNXT_TC_ACTION_FLAG_FWD BIT(0) @@ -71,6 +77,7 @@ struct bnxt_tc_actions { #define BNXT_TC_ACTION_FLAG_DROP BIT(5) #define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6) #define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7) +#define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8) u16 dst_fid; struct net_device *dst_dev; @@ -79,6 +86,10 @@ struct bnxt_tc_actions { /* tunnel encap */ struct ip_tunnel_key tun_encap_key; +#define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8 + __be16 l2_rewrite_dmac[3]; + __be16 l2_rewrite_smac[3]; + }; struct bnxt_tc_flow { -- cgit v1.2.3-59-g8ed1b From 08f8280e8788202a67a359952cd436707f8789bd Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Thu, 31 Oct 2019 01:07:46 -0400 Subject: bnxt: Avoid logging an unnecessary message when a flow can't be offloaded For every single case where bnxt_tc_can_offload() can fail, we are logging a user friendly descriptive message anyway, but because of the path it would take in case of failure, another redundant error message would get logged. Just freeing the node and returning from the point of failure should suffice. Signed-off-by: Somnath Kotur Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index 80b39ffa4ca2..c35cde8a5b29 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -1406,7 +1406,8 @@ static int bnxt_tc_add_flow(struct bnxt *bp, u16 src_fid, if (!bnxt_tc_can_offload(bp, flow)) { rc = -EOPNOTSUPP; - goto free_node; + kfree_rcu(new_node, rcu); + return rc; } /* If a flow exists with the same cookie, delete it */ -- cgit v1.2.3-59-g8ed1b From 9b9eb518e3383d94c8b81ff403d524f2cee5b6b9 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Thu, 31 Oct 2019 01:07:47 -0400 Subject: bnxt_en: Add support for NAT(L3/L4 rewrite) Provides support for modifying L3/L4 Header parameters to support NAT. Sets the appropriate fields/bits in cfa_flow_alloc cmd. Sample cmd for offloading an IPv4 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144,output:p7p1" Replace 'nw_src' with 'nw_dst' in above cmd for DNAT with IPv4 Sample cmd for offloading an IPv4 flow with SNAPT: ovs-ofctl add-flow ovsbr0 "ip,nw_src=192.168.201.44 \ actions=mod_nw_src:203.31.220.144, mod_tp_src:6789,output:p7p1" Similar to DNAT, replace 'tp_src' with 'tp_dst' for offloading flow with DNAPT Sample cmd for offloading an IPv6 flow with SNAT: ovs-ofctl add-flow ovsbr0 "ipv6, ipv6_src=2001:5c0:9168::2/64 \ actions=load:0x1->NXM_NX_IPV6_SRC[0..63], \ load:0x20010db801920000->NXM_NX_IPV6_SRC[64..127],output:p7p1" Replace 'SRC' with DST' above for IPv6 DNAT Signed-off-by: Somnath Kotur Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 140 +++++++++++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h | 11 ++- 2 files changed, 144 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index c35cde8a5b29..c801666a85fd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -114,7 +114,8 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp, return 0; } -/* Key & Mask from the stack comes unaligned in multiple iterations. +/* Key & Mask from the stack comes unaligned in multiple iterations of 4 bytes + * each(u32). * This routine consolidates such multiple unaligned values into one * field each for Key & Mask (for src and dst macs separately) * For example, @@ -178,14 +179,19 @@ bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions, static int bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, - struct flow_action_entry *act, u8 *eth_addr, + struct flow_action_entry *act, int act_idx, u8 *eth_addr, u8 *eth_addr_mask) { - u32 mask, val, offset; + size_t offset_of_ip6_daddr = offsetof(struct ipv6hdr, daddr); + size_t offset_of_ip6_saddr = offsetof(struct ipv6hdr, saddr); + u32 mask, val, offset, idx; u8 htype; offset = act->mangle.offset; htype = act->mangle.htype; + mask = ~act->mangle.mask; + val = act->mangle.val; + switch (htype) { case FLOW_ACT_MANGLE_HDR_TYPE_ETH: if (offset > PEDIT_OFFSET_SMAC_LAST_4_BYTES) { @@ -195,12 +201,73 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, return -EINVAL; } actions->flags |= BNXT_TC_ACTION_FLAG_L2_REWRITE; - mask = ~act->mangle.mask; - val = act->mangle.val; bnxt_set_l2_key_mask(val, mask, ð_addr[offset], ð_addr_mask[offset]); break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: + actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE; + actions->nat.l3_is_ipv4 = true; + if (offset == offsetof(struct iphdr, saddr)) { + actions->nat.src_xlate = true; + actions->nat.l3.ipv4.saddr.s_addr = htonl(val); + } else if (offset == offsetof(struct iphdr, daddr)) { + actions->nat.src_xlate = false; + actions->nat.l3.ipv4.daddr.s_addr = htonl(val); + } else { + netdev_err(bp->dev, + "%s: IPv4_hdr: Invalid pedit field\n", + __func__); + return -EINVAL; + } + + netdev_dbg(bp->dev, "nat.src_xlate = %d src IP: %pI4 dst ip : %pI4\n", + actions->nat.src_xlate, &actions->nat.l3.ipv4.saddr, + &actions->nat.l3.ipv4.daddr); + break; + + case FLOW_ACT_MANGLE_HDR_TYPE_IP6: + actions->flags |= BNXT_TC_ACTION_FLAG_NAT_XLATE; + actions->nat.l3_is_ipv4 = false; + if (offset >= offsetof(struct ipv6hdr, saddr) && + offset < offset_of_ip6_daddr) { + /* 16 byte IPv6 address comes in 4 iterations of + * 4byte chunks each + */ + actions->nat.src_xlate = true; + idx = (offset - offset_of_ip6_saddr) / 4; + /* First 4bytes will be copied to idx 0 and so on */ + actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val); + } else if (offset >= offset_of_ip6_daddr && + offset < offset_of_ip6_daddr + 16) { + actions->nat.src_xlate = false; + idx = (offset - offset_of_ip6_daddr) / 4; + actions->nat.l3.ipv6.saddr.s6_addr32[idx] = htonl(val); + } else { + netdev_err(bp->dev, + "%s: IPv6_hdr: Invalid pedit field\n", + __func__); + return -EINVAL; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: + /* HW does not support L4 rewrite alone without L3 + * rewrite + */ + if (!(actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE)) { + netdev_err(bp->dev, + "Need to specify L3 rewrite as well\n"); + return -EINVAL; + } + if (actions->nat.src_xlate) + actions->nat.l4.ports.sport = htons(val); + else + actions->nat.l4.ports.dport = htons(val); + netdev_dbg(bp->dev, "actions->nat.sport = %d dport = %d\n", + actions->nat.l4.ports.sport, + actions->nat.l4.ports.dport); + break; default: netdev_err(bp->dev, "%s: Unsupported pedit hdr type\n", __func__); @@ -258,7 +325,7 @@ static int bnxt_tc_parse_actions(struct bnxt *bp, break; /* Packet edit: L2 rewrite, NAT, NAPT */ case FLOW_ACTION_MANGLE: - rc = bnxt_tc_parse_pedit(bp, actions, act, + rc = bnxt_tc_parse_pedit(bp, actions, act, i, (u8 *)eth_addr, (u8 *)eth_addr_mask); if (rc) @@ -533,6 +600,67 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow, CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_L2_HEADER_REWRITE; } + if (actions->flags & BNXT_TC_ACTION_FLAG_NAT_XLATE) { + if (actions->nat.l3_is_ipv4) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_IPV4_ADDRESS; + + if (actions->nat.src_xlate) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC; + /* L3 source rewrite */ + req.nat_ip_address[0] = + actions->nat.l3.ipv4.saddr.s_addr; + /* L4 source port */ + if (actions->nat.l4.ports.sport) + req.nat_port = + actions->nat.l4.ports.sport; + } else { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST; + /* L3 destination rewrite */ + req.nat_ip_address[0] = + actions->nat.l3.ipv4.daddr.s_addr; + /* L4 destination port */ + if (actions->nat.l4.ports.dport) + req.nat_port = + actions->nat.l4.ports.dport; + } + netdev_dbg(bp->dev, + "req.nat_ip_address: %pI4 src_xlate: %d req.nat_port: %x\n", + req.nat_ip_address, actions->nat.src_xlate, + req.nat_port); + } else { + if (actions->nat.src_xlate) { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_SRC; + /* L3 source rewrite */ + memcpy(req.nat_ip_address, + actions->nat.l3.ipv6.saddr.s6_addr32, + sizeof(req.nat_ip_address)); + /* L4 source port */ + if (actions->nat.l4.ports.sport) + req.nat_port = + actions->nat.l4.ports.sport; + } else { + action_flags |= + CFA_FLOW_ALLOC_REQ_ACTION_FLAGS_NAT_DEST; + /* L3 destination rewrite */ + memcpy(req.nat_ip_address, + actions->nat.l3.ipv6.daddr.s6_addr32, + sizeof(req.nat_ip_address)); + /* L4 destination port */ + if (actions->nat.l4.ports.dport) + req.nat_port = + actions->nat.l4.ports.dport; + } + netdev_dbg(bp->dev, + "req.nat_ip_address: %pI6 src_xlate: %d req.nat_port: %x\n", + req.nat_ip_address, actions->nat.src_xlate, + req.nat_port); + } + } + if (actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_DECAP || actions->flags & BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP) { req.tunnel_handle = tunnel_handle; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h index 6d0d4857992b..286754903543 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h @@ -78,6 +78,7 @@ struct bnxt_tc_actions { #define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6) #define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7) #define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8) +#define BNXT_TC_ACTION_FLAG_NAT_XLATE BIT(9) u16 dst_fid; struct net_device *dst_dev; @@ -89,7 +90,15 @@ struct bnxt_tc_actions { #define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8 __be16 l2_rewrite_dmac[3]; __be16 l2_rewrite_smac[3]; - + struct { + bool src_xlate; /* true => translate src, + * false => translate dst + * Mutually exclusive, i.e cannot set both + */ + bool l3_is_ipv4; /* false means L3 is ipv6 */ + struct bnxt_tc_l3_key l3; + struct bnxt_tc_l4_key l4; + } nat; }; struct bnxt_tc_flow { -- cgit v1.2.3-59-g8ed1b From 627c89d00fb969f9b3b4f3156716149631d2796c Mon Sep 17 00:00:00 2001 From: Sriharsha Basavapatna Date: Thu, 31 Oct 2019 01:07:48 -0400 Subject: bnxt_en: flow_offload: offload tunnel decap rules via indirect callbacks The decap (VXLAN tunnel) flow rules are not getting offloaded with upstream kernel. This is because TC block callback infrastructure has been updated to use indirect callbacks to get offloaded rules from other higher level devices (such as tunnels), instead of ndo_setup_tc(). Since the decap rules are applied to the tunnel devices (e.g, vxlan_sys), the driver should register for indirect TC callback with tunnel devices to get the rules for offloading. This patch updates the driver to register and process indirect TC block callbacks from VXLAN tunnels. Signed-off-by: Sriharsha Basavapatna Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 +- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 12 +++ drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 153 ++++++++++++++++++++++++++- 3 files changed, 165 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c24caaaf05ca..71f9c9c53301 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10945,7 +10945,7 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data, } } -static LIST_HEAD(bnxt_block_cb_list); +LIST_HEAD(bnxt_block_cb_list); static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3e7d1fb1b0b1..a3545c846bfb 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -29,6 +29,8 @@ #include #endif +extern struct list_head bnxt_block_cb_list; + struct page_pool; struct tx_bd { @@ -1244,6 +1246,14 @@ struct bnxt_tc_flow_stats { u64 bytes; }; +#ifdef CONFIG_BNXT_FLOWER_OFFLOAD +struct bnxt_flower_indr_block_cb_priv { + struct net_device *tunnel_netdev; + struct bnxt *bp; + struct list_head list; +}; +#endif + struct bnxt_tc_info { bool enabled; @@ -1821,6 +1831,8 @@ struct bnxt { u16 *cfa_code_map; /* cfa_code -> vf_idx map */ u8 switch_id[8]; struct bnxt_tc_info *tc_info; + struct list_head tc_indr_block_list; + struct notifier_block tc_netdev_nb; struct dentry *debugfs_pdev; struct device *hwmon_dev; }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index c801666a85fd..174412a55e53 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "bnxt_hsi.h" #include "bnxt.h" @@ -1841,6 +1842,147 @@ int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid, } } +static int bnxt_tc_setup_indr_block_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + struct bnxt_flower_indr_block_cb_priv *priv = cb_priv; + struct flow_cls_offload *flower = type_data; + struct bnxt *bp = priv->bp; + + if (flower->common.chain_index) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_CLSFLOWER: + return bnxt_tc_setup_flower(bp, bp->pf.fw_fid, flower); + default: + return -EOPNOTSUPP; + } +} + +static struct bnxt_flower_indr_block_cb_priv * +bnxt_tc_indr_block_cb_lookup(struct bnxt *bp, struct net_device *netdev) +{ + struct bnxt_flower_indr_block_cb_priv *cb_priv; + + /* All callback list access should be protected by RTNL. */ + ASSERT_RTNL(); + + list_for_each_entry(cb_priv, &bp->tc_indr_block_list, list) + if (cb_priv->tunnel_netdev == netdev) + return cb_priv; + + return NULL; +} + +static void bnxt_tc_setup_indr_rel(void *cb_priv) +{ + struct bnxt_flower_indr_block_cb_priv *priv = cb_priv; + + list_del(&priv->list); + kfree(priv); +} + +static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp, + struct flow_block_offload *f) +{ + struct bnxt_flower_indr_block_cb_priv *cb_priv; + struct flow_block_cb *block_cb; + + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) + return -EOPNOTSUPP; + + switch (f->command) { + case FLOW_BLOCK_BIND: + cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL); + if (!cb_priv) + return -ENOMEM; + + cb_priv->tunnel_netdev = netdev; + cb_priv->bp = bp; + list_add(&cb_priv->list, &bp->tc_indr_block_list); + + block_cb = flow_block_cb_alloc(bnxt_tc_setup_indr_block_cb, + cb_priv, cb_priv, + bnxt_tc_setup_indr_rel); + if (IS_ERR(block_cb)) { + list_del(&cb_priv->list); + kfree(cb_priv); + return PTR_ERR(block_cb); + } + + flow_block_cb_add(block_cb, f); + list_add_tail(&block_cb->driver_list, &bnxt_block_cb_list); + break; + case FLOW_BLOCK_UNBIND: + cb_priv = bnxt_tc_indr_block_cb_lookup(bp, netdev); + if (!cb_priv) + return -ENOENT; + + block_cb = flow_block_cb_lookup(f->block, + bnxt_tc_setup_indr_block_cb, + cb_priv); + if (!block_cb) + return -ENOENT; + + flow_block_cb_remove(block_cb, f); + list_del(&block_cb->driver_list); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int bnxt_tc_setup_indr_cb(struct net_device *netdev, void *cb_priv, + enum tc_setup_type type, void *type_data) +{ + switch (type) { + case TC_SETUP_BLOCK: + return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data); + default: + return -EOPNOTSUPP; + } +} + +static bool bnxt_is_netdev_indr_offload(struct net_device *netdev) +{ + return netif_is_vxlan(netdev); +} + +static int bnxt_tc_indr_block_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *netdev; + struct bnxt *bp; + int rc; + + netdev = netdev_notifier_info_to_dev(ptr); + if (!bnxt_is_netdev_indr_offload(netdev)) + return NOTIFY_OK; + + bp = container_of(nb, struct bnxt, tc_netdev_nb); + + switch (event) { + case NETDEV_REGISTER: + rc = __flow_indr_block_cb_register(netdev, bp, + bnxt_tc_setup_indr_cb, + bp); + if (rc) + netdev_info(bp->dev, + "Failed to register indirect blk: dev: %s", + netdev->name); + break; + case NETDEV_UNREGISTER: + __flow_indr_block_cb_unregister(netdev, + bnxt_tc_setup_indr_cb, + bp); + break; + } + + return NOTIFY_DONE; +} + static const struct rhashtable_params bnxt_tc_flow_ht_params = { .head_offset = offsetof(struct bnxt_tc_flow_node, node), .key_offset = offsetof(struct bnxt_tc_flow_node, cookie), @@ -1924,7 +2066,15 @@ int bnxt_init_tc(struct bnxt *bp) bp->dev->hw_features |= NETIF_F_HW_TC; bp->dev->features |= NETIF_F_HW_TC; bp->tc_info = tc_info; - return 0; + + /* init indirect block notifications */ + INIT_LIST_HEAD(&bp->tc_indr_block_list); + bp->tc_netdev_nb.notifier_call = bnxt_tc_indr_block_event; + rc = register_netdevice_notifier(&bp->tc_netdev_nb); + if (!rc) + return 0; + + rhashtable_destroy(&tc_info->encap_table); destroy_decap_table: rhashtable_destroy(&tc_info->decap_table); @@ -1946,6 +2096,7 @@ void bnxt_shutdown_tc(struct bnxt *bp) if (!bnxt_tc_flower_enabled(bp)) return; + unregister_netdevice_notifier(&bp->tc_netdev_nb); rhashtable_destroy(&tc_info->flow_table); rhashtable_destroy(&tc_info->l2_table); rhashtable_destroy(&tc_info->decap_l2_table); -- cgit v1.2.3-59-g8ed1b From aa46dffff452f7c6d907c4e6a0062e2c53a87fc0 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 31 Oct 2019 01:07:49 -0400 Subject: bnxt_en: Improve bnxt_ulp_stop()/bnxt_ulp_start() call sequence. We call bnxt_ulp_stop() to notify the RDMA driver that some error or imminent reset is about to happen. After that we always call some variants of bnxt_close(). In the next patch, we will integrate the recently added error recovery with the RDMA driver. In response to ulp_stop, the RDMA driver may free MSIX vectors and that will also trigger bnxt_close(). To avoid bnxt_close() from being called twice, we set a new flag after ulp_stop is called. If the RDMA driver frees MSIX vectors while the new flag is set, we will not call bnxt_close(), knowing that it will happen in due course. With this change, we must make sure that the bnxt_close() call after ulp_stop will reset IRQ. Modify bnxt_reset_task() accordingly if we call ulp_stop. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 18 ++++++++++-------- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 10 ++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h | 3 ++- 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 71f9c9c53301..237b22057913 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -9927,12 +9927,15 @@ static void bnxt_reset_task(struct bnxt *bp, bool silent) if (netif_running(bp->dev)) { int rc; - if (!silent) + if (silent) { + bnxt_close_nic(bp, false, false); + bnxt_open_nic(bp, false, false); + } else { bnxt_ulp_stop(bp); - bnxt_close_nic(bp, false, false); - rc = bnxt_open_nic(bp, false, false); - if (!silent && !rc) - bnxt_ulp_start(bp); + bnxt_close_nic(bp, true, false); + rc = bnxt_open_nic(bp, true, false); + bnxt_ulp_start(bp, rc); + } } } @@ -12005,10 +12008,9 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) if (!err && netif_running(netdev)) err = bnxt_open(netdev); - if (!err) { + if (!err) result = PCI_ERS_RESULT_RECOVERED; - bnxt_ulp_start(bp); - } + bnxt_ulp_start(bp, err); } if (result != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index b2c160947fc8..077fd101be60 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -182,7 +182,7 @@ static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id) edev->ulp_tbl[ulp_id].msix_requested = 0; edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED; - if (netif_running(dev)) { + if (netif_running(dev) && !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) { bnxt_close_nic(bp, true, false); bnxt_open_nic(bp, true, false); } @@ -266,6 +266,7 @@ void bnxt_ulp_stop(struct bnxt *bp) if (!edev) return; + edev->flags |= BNXT_EN_FLAG_ULP_STOPPED; for (i = 0; i < BNXT_MAX_ULP; i++) { struct bnxt_ulp *ulp = &edev->ulp_tbl[i]; @@ -276,7 +277,7 @@ void bnxt_ulp_stop(struct bnxt *bp) } } -void bnxt_ulp_start(struct bnxt *bp) +void bnxt_ulp_start(struct bnxt *bp, int err) { struct bnxt_en_dev *edev = bp->edev; struct bnxt_ulp_ops *ops; @@ -285,6 +286,11 @@ void bnxt_ulp_start(struct bnxt *bp) if (!edev) return; + edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED; + + if (err) + return; + for (i = 0; i < BNXT_MAX_ULP; i++) { struct bnxt_ulp *ulp = &edev->ulp_tbl[i]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h index cd78453d0bf0..9895406b9830 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.h @@ -64,6 +64,7 @@ struct bnxt_en_dev { #define BNXT_EN_FLAG_ROCE_CAP (BNXT_EN_FLAG_ROCEV1_CAP | \ BNXT_EN_FLAG_ROCEV2_CAP) #define BNXT_EN_FLAG_MSIX_REQUESTED 0x4 + #define BNXT_EN_FLAG_ULP_STOPPED 0x8 const struct bnxt_en_ops *en_ops; struct bnxt_ulp ulp_tbl[BNXT_MAX_ULP]; }; @@ -92,7 +93,7 @@ int bnxt_get_ulp_msix_num(struct bnxt *bp); int bnxt_get_ulp_msix_base(struct bnxt *bp); int bnxt_get_ulp_stat_ctxs(struct bnxt *bp); void bnxt_ulp_stop(struct bnxt *bp); -void bnxt_ulp_start(struct bnxt *bp); +void bnxt_ulp_start(struct bnxt *bp, int err); void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs); void bnxt_ulp_shutdown(struct bnxt *bp); void bnxt_ulp_irq_stop(struct bnxt *bp); -- cgit v1.2.3-59-g8ed1b From f3a6d206c25ad9490f3a3c6d62baba9504227a75 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Thu, 31 Oct 2019 01:07:50 -0400 Subject: bnxt_en: Call bnxt_ulp_stop()/bnxt_ulp_start() during error recovery. Notify the RDMA driver by calling the bnxt_ulp_stop()/bnxt_ulp_start() hooks during error recovery. The current ULP IRQ start/stop sequence in error recovery (which is insufficient) is replaced with the full reset sequence when we call bnxt_ulp_stop()/bnxt_ulp_start(). Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 237b22057913..a8a2a6f79b6f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8762,6 +8762,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up) } if (resc_reinit || fw_reset) { if (fw_reset) { + if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) + bnxt_ulp_stop(bp); rc = bnxt_fw_init_one(bp); if (rc) { set_bit(BNXT_STATE_ABORT_ERR, &bp->state); @@ -9224,13 +9226,16 @@ static int bnxt_open(struct net_device *dev) if (rc) { bnxt_hwrm_if_change(bp, false); } else { - if (test_and_clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state) && - BNXT_PF(bp)) { - struct bnxt_pf_info *pf = &bp->pf; - int n = pf->active_vfs; + if (test_and_clear_bit(BNXT_STATE_FW_RESET_DET, &bp->state)) { + if (BNXT_PF(bp)) { + struct bnxt_pf_info *pf = &bp->pf; + int n = pf->active_vfs; - if (n) - bnxt_cfg_hw_sriov(bp, &n, true); + if (n) + bnxt_cfg_hw_sriov(bp, &n, true); + } + if (!test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) + bnxt_ulp_start(bp, 0); } bnxt_hwmon_open(bp); } @@ -10051,8 +10056,8 @@ static void bnxt_reset(struct bnxt *bp, bool silent) static void bnxt_fw_reset_close(struct bnxt *bp) { + bnxt_ulp_stop(bp); __bnxt_close_nic(bp, true, false); - bnxt_ulp_irq_stop(bp); bnxt_clear_int_mode(bp); bnxt_hwrm_func_drv_unrgtr(bp); bnxt_free_ctx_mem(bp); @@ -10734,13 +10739,13 @@ static void bnxt_fw_reset_task(struct work_struct *work) clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); dev_close(bp->dev); } - bnxt_ulp_irq_restart(bp, rc); - rtnl_unlock(); bp->fw_reset_state = 0; /* Make sure fw_reset_state is 0 before clearing the flag */ smp_mb__before_atomic(); clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + bnxt_ulp_start(bp, rc); + rtnl_unlock(); break; } return; -- cgit v1.2.3-59-g8ed1b From 6a68749dbd777b832e1d84265bd6d8b39d1843ac Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Thu, 31 Oct 2019 01:07:51 -0400 Subject: bnxt_en: Call bnxt_ulp_stop()/bnxt_ulp_start() during suspend/resume. Inform the RDMA driver to stop/start during suspend/resume. The RDMA driver needs to stop and start just like error recovery. Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a8a2a6f79b6f..477b8d7d94d1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -11901,6 +11901,7 @@ static int bnxt_suspend(struct device *device) int rc = 0; rtnl_lock(); + bnxt_ulp_stop(bp); if (netif_running(dev)) { netif_device_detach(dev); rc = bnxt_close(dev); @@ -11934,6 +11935,7 @@ static int bnxt_resume(struct device *device) } resume_exit: + bnxt_ulp_start(bp, rc); rtnl_unlock(); return rc; } -- cgit v1.2.3-59-g8ed1b From 52340b82cf1a9c8d466b6e36a0881bc44174b969 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 31 Oct 2019 11:23:37 -0700 Subject: hp100: Move 100BaseVG AnyLAN driver to staging 100BaseVG AnyLAN hasn't been useful since 1996 or so and even then didn't sell many devices. It's unlikely any are still in use. Move the driver to staging with the intent of removing it altogether one day. Signed-off-by: Joe Perches Acked-by: Jaroslav Kysela Signed-off-by: David S. Miller --- MAINTAINERS | 4 +- drivers/net/ethernet/Kconfig | 1 - drivers/net/ethernet/Makefile | 1 - drivers/net/ethernet/hp/Kconfig | 29 - drivers/net/ethernet/hp/Makefile | 6 - drivers/net/ethernet/hp/hp100.c | 3037 -------------------------------------- drivers/net/ethernet/hp/hp100.h | 611 -------- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/hp/Kconfig | 29 + drivers/staging/hp/Makefile | 6 + drivers/staging/hp/hp100.c | 3037 ++++++++++++++++++++++++++++++++++++++ drivers/staging/hp/hp100.h | 611 ++++++++ 13 files changed, 3688 insertions(+), 3687 deletions(-) delete mode 100644 drivers/net/ethernet/hp/Kconfig delete mode 100644 drivers/net/ethernet/hp/Makefile delete mode 100644 drivers/net/ethernet/hp/hp100.c delete mode 100644 drivers/net/ethernet/hp/hp100.h create mode 100644 drivers/staging/hp/Kconfig create mode 100644 drivers/staging/hp/Makefile create mode 100644 drivers/staging/hp/hp100.c create mode 100644 drivers/staging/hp/hp100.h (limited to 'drivers/net') diff --git a/MAINTAINERS b/MAINTAINERS index 29406ac2626c..fb9e7d9d11b7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7454,8 +7454,8 @@ F: drivers/platform/x86/tc1100-wmi.c HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series M: Jaroslav Kysela -S: Maintained -F: drivers/net/ethernet/hp/hp100.* +S: Obsolete +F: drivers/staging/hp/hp100.* HPET: High Precision Event Timers driver M: Clemens Ladisch diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index e8e9c166185d..4ded81b27d0a 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -78,7 +78,6 @@ source "drivers/net/ethernet/freescale/Kconfig" source "drivers/net/ethernet/fujitsu/Kconfig" source "drivers/net/ethernet/google/Kconfig" source "drivers/net/ethernet/hisilicon/Kconfig" -source "drivers/net/ethernet/hp/Kconfig" source "drivers/net/ethernet/huawei/Kconfig" source "drivers/net/ethernet/i825xx/Kconfig" source "drivers/net/ethernet/ibm/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 05abebc17804..f8f38dcb5f8a 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -41,7 +41,6 @@ obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/ obj-$(CONFIG_NET_VENDOR_FUJITSU) += fujitsu/ obj-$(CONFIG_NET_VENDOR_GOOGLE) += google/ obj-$(CONFIG_NET_VENDOR_HISILICON) += hisilicon/ -obj-$(CONFIG_NET_VENDOR_HP) += hp/ obj-$(CONFIG_NET_VENDOR_HUAWEI) += huawei/ obj-$(CONFIG_NET_VENDOR_IBM) += ibm/ obj-$(CONFIG_NET_VENDOR_INTEL) += intel/ diff --git a/drivers/net/ethernet/hp/Kconfig b/drivers/net/ethernet/hp/Kconfig deleted file mode 100644 index fb395cfe6b92..000000000000 --- a/drivers/net/ethernet/hp/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# HP network device configuration -# - -config NET_VENDOR_HP - bool "HP devices" - default y - depends on ISA || EISA || PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about HP cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_HP - -config HP100 - tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" - depends on (ISA || EISA || PCI) - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called hp100. - -endif # NET_VENDOR_HP diff --git a/drivers/net/ethernet/hp/Makefile b/drivers/net/ethernet/hp/Makefile deleted file mode 100644 index 5ed723bb11e2..000000000000 --- a/drivers/net/ethernet/hp/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the HP network device drivers. -# - -obj-$(CONFIG_HP100) += hp100.o diff --git a/drivers/net/ethernet/hp/hp100.c b/drivers/net/ethernet/hp/hp100.c deleted file mode 100644 index 6ec78f5c602f..000000000000 --- a/drivers/net/ethernet/hp/hp100.c +++ /dev/null @@ -1,3037 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* -** hp100.c -** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters -** -** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $ -** -** Based on the HP100 driver written by Jaroslav Kysela -** Extended for new busmaster capable chipsets by -** Siegfried "Frieder" Loeffler (dg1sek) -** -** Maintained by: Jaroslav Kysela -** -** This driver has only been tested with -** -- HP J2585B 10/100 Mbit/s PCI Busmaster -** -- HP J2585A 10/100 Mbit/s PCI -** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC -** -- HP J2973A 10 Mbit/s PCI 10base-T -** -- HP J2573 10/100 ISA -** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA -** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI -** -** but it should also work with the other CASCADE based adapters. -** -** TODO: -** - J2573 seems to hang sometimes when in shared memory mode. -** - Mode for Priority TX -** - Check PCI registers, performance might be improved? -** - To reduce interrupt load in busmaster, one could switch off -** the interrupts that are used to refill the queues whenever the -** queues are filled up to more than a certain threshold. -** - some updates for EISA version of card -** -** -** -** 1.57c -> 1.58 -** - used indent to change coding-style -** - added KTI DP-200 EISA ID -** - ioremap is also used for low (<1MB) memory (multi-architecture support) -** -** 1.57b -> 1.57c - Arnaldo Carvalho de Melo -** - release resources on failure in init_module -** -** 1.57 -> 1.57b - Jean II -** - fix spinlocks, SMP is now working ! -** -** 1.56 -> 1.57 -** - updates for new PCI interface for 2.1 kernels -** -** 1.55 -> 1.56 -** - removed printk in misc. interrupt and update statistics to allow -** monitoring of card status -** - timing changes in xmit routines, relogin to 100VG hub added when -** driver does reset -** - included fix for Compex FreedomLine PCI adapter -** -** 1.54 -> 1.55 -** - fixed bad initialization in init_module -** - added Compex FreedomLine adapter -** - some fixes in card initialization -** -** 1.53 -> 1.54 -** - added hardware multicast filter support (doesn't work) -** - little changes in hp100_sense_lan routine -** - added support for Coax and AUI (J2970) -** - fix for multiple cards and hp100_mode parameter (insmod) -** - fix for shared IRQ -** -** 1.52 -> 1.53 -** - fixed bug in multicast support -** -*/ - -#define HP100_DEFAULT_PRIORITY_TX 0 - -#undef HP100_DEBUG -#undef HP100_DEBUG_B /* Trace */ -#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ - -#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ -#undef HP100_DEBUG_TX -#undef HP100_DEBUG_IRQ -#undef HP100_DEBUG_RX - -#undef HP100_MULTICAST_FILTER /* Need to be debugged... */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "hp100.h" - -/* - * defines - */ - -#define HP100_BUS_ISA 0 -#define HP100_BUS_EISA 1 -#define HP100_BUS_PCI 2 - -#define HP100_REGION_SIZE 0x20 /* for ioports */ -#define HP100_SIG_LEN 8 /* same as EISA_SIG_LEN */ - -#define HP100_MAX_PACKET_SIZE (1536+4) -#define HP100_MIN_PACKET_SIZE 60 - -#ifndef HP100_DEFAULT_RX_RATIO -/* default - 75% onboard memory on the card are used for RX packets */ -#define HP100_DEFAULT_RX_RATIO 75 -#endif - -#ifndef HP100_DEFAULT_PRIORITY_TX -/* default - don't enable transmit outgoing packets as priority */ -#define HP100_DEFAULT_PRIORITY_TX 0 -#endif - -/* - * structures - */ - -struct hp100_private { - spinlock_t lock; - char id[HP100_SIG_LEN]; - u_short chip; - u_short soft_model; - u_int memory_size; - u_int virt_memory_size; - u_short rx_ratio; /* 1 - 99 */ - u_short priority_tx; /* != 0 - priority tx */ - u_short mode; /* PIO, Shared Mem or Busmaster */ - u_char bus; - struct pci_dev *pci_dev; - short mem_mapped; /* memory mapped access */ - void __iomem *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - unsigned long mem_ptr_phys; /* physical memory mapped area */ - short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ - int hub_status; /* was login to hub successful? */ - u_char mac1_mode; - u_char mac2_mode; - u_char hash_bytes[8]; - - /* Rings for busmaster mode: */ - hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ - hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ - hp100_ring_t *txrhead; /* Head (oldest) index into txring */ - hp100_ring_t *txrtail; /* Tail (newest) index into txring */ - - hp100_ring_t rxring[MAX_RX_PDL]; - hp100_ring_t txring[MAX_TX_PDL]; - - u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ - u_long whatever_offset; /* Offset to bus/phys/dma address */ - int rxrcommit; /* # Rx PDLs committed to adapter */ - int txrcommit; /* # Tx PDLs committed to adapter */ -}; - -/* - * variables - */ -#ifdef CONFIG_ISA -static const char *hp100_isa_tbl[] = { - "HWPF150", /* HP J2573 rev A */ - "HWP1950", /* HP J2573 */ -}; -#endif - -static const struct eisa_device_id hp100_eisa_tbl[] = { - { "HWPF180" }, /* HP J2577 rev A */ - { "HWP1920" }, /* HP 27248B */ - { "HWP1940" }, /* HP J2577 */ - { "HWP1990" }, /* HP J2577 */ - { "CPX0301" }, /* ReadyLink ENET100-VG4 */ - { "CPX0401" }, /* FreedomLine 100/VG */ - { "" } /* Mandatory final entry ! */ -}; -MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); - -static const struct pci_device_id hp100_pci_tbl[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,}, - {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, - {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, -/* {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */ - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); - -static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; -static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; -static int hp100_mode = 1; - -module_param(hp100_rx_ratio, int, 0); -module_param(hp100_priority_tx, int, 0); -module_param(hp100_mode, int, 0); - -/* - * prototypes - */ - -static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, - struct pci_dev *pci_dev); - - -static int hp100_open(struct net_device *dev); -static int hp100_close(struct net_device *dev); -static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, - struct net_device *dev); -static void hp100_rx(struct net_device *dev); -static struct net_device_stats *hp100_get_stats(struct net_device *dev); -static void hp100_misc_interrupt(struct net_device *dev); -static void hp100_update_stats(struct net_device *dev); -static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); -static void hp100_set_multicast_list(struct net_device *dev); -static irqreturn_t hp100_interrupt(int irq, void *dev_id); -static void hp100_start_interface(struct net_device *dev); -static void hp100_stop_interface(struct net_device *dev); -static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr); -static int hp100_sense_lan(struct net_device *dev); -static int hp100_login_to_vg_hub(struct net_device *dev, - u_short force_relogin); -static int hp100_down_vg_link(struct net_device *dev); -static void hp100_cascade_reset(struct net_device *dev, u_short enable); -static void hp100_BM_shutdown(struct net_device *dev); -static void hp100_mmuinit(struct net_device *dev); -static void hp100_init_pdls(struct net_device *dev); -static int hp100_init_rxpdl(struct net_device *dev, - register hp100_ring_t * ringptr, - register u_int * pdlptr); -static int hp100_init_txpdl(struct net_device *dev, - register hp100_ring_t * ringptr, - register u_int * pdlptr); -static void hp100_rxfill(struct net_device *dev); -static void hp100_hwinit(struct net_device *dev); -static void hp100_clean_txring(struct net_device *dev); -#ifdef HP100_DEBUG -static void hp100_RegisterDump(struct net_device *dev); -#endif - -/* Conversion to new PCI API : - * Convert an address in a kernel buffer to a bus/phys/dma address. - * This work *only* for memory fragments part of lp->page_vaddr, - * because it was properly DMA allocated via pci_alloc_consistent(), - * so we just need to "retrieve" the original mapping to bus/phys/dma - * address - Jean II */ -static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr) -{ - struct hp100_private *lp = netdev_priv(dev); - return ((u_long) ptr) + lp->whatever_offset; -} - -static inline u_int pdl_map_data(struct hp100_private *lp, void *data) -{ - return pci_map_single(lp->pci_dev, data, - MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); -} - -/* TODO: This function should not really be needed in a good design... */ -static void wait(void) -{ - mdelay(1); -} - -/* - * probe functions - * These functions should - if possible - avoid doing write operations - * since this could cause problems when the card is not installed. - */ - -/* - * Read board id and convert to string. - * Effectively same code as decode_eisa_sig - */ -static const char *hp100_read_id(int ioaddr) -{ - int i; - static char str[HP100_SIG_LEN]; - unsigned char sig[4], sum; - unsigned short rev; - - hp100_page(ID_MAC_ADDR); - sum = 0; - for (i = 0; i < 4; i++) { - sig[i] = hp100_inb(BOARD_ID + i); - sum += sig[i]; - } - - sum += hp100_inb(BOARD_ID + i); - if (sum != 0xff) - return NULL; /* bad checksum */ - - str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); - str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); - str[2] = (sig[1] & 0x1f) + ('A' - 1); - rev = (sig[2] << 8) | sig[3]; - sprintf(str + 3, "%04X", rev); - - return str; -} - -#ifdef CONFIG_ISA -static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) -{ - const char *sig; - int i; - - if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) - goto err; - - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - release_region(ioaddr, HP100_REGION_SIZE); - goto err; - } - - sig = hp100_read_id(ioaddr); - release_region(ioaddr, HP100_REGION_SIZE); - - if (sig == NULL) - goto err; - - for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) { - if (!strcmp(hp100_isa_tbl[i], sig)) - break; - - } - - if (i < ARRAY_SIZE(hp100_isa_tbl)) - return hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL); - err: - return -ENODEV; - -} -/* - * Probe for ISA board. - * EISA and PCI are handled by device infrastructure. - */ - -static int __init hp100_isa_probe(struct net_device *dev, int addr) -{ - int err = -ENODEV; - - /* Probe for a specific ISA address */ - if (addr > 0xff && addr < 0x400) - err = hp100_isa_probe1(dev, addr); - - else if (addr != 0) - err = -ENXIO; - - else { - /* Probe all ISA possible port regions */ - for (addr = 0x100; addr < 0x400; addr += 0x20) { - err = hp100_isa_probe1(dev, addr); - if (!err) - break; - } - } - return err; -} -#endif /* CONFIG_ISA */ - -#if !defined(MODULE) && defined(CONFIG_ISA) -struct net_device * __init hp100_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); - int err; - - if (!dev) - return ERR_PTR(-ENODEV); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: %s: probe\n", dev->name); -#endif - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - - err = hp100_isa_probe(dev, dev->base_addr); - if (err) - goto out; - - return dev; - out: - free_netdev(dev); - return ERR_PTR(err); -} -#endif /* !MODULE && CONFIG_ISA */ - -static const struct net_device_ops hp100_bm_netdev_ops = { - .ndo_open = hp100_open, - .ndo_stop = hp100_close, - .ndo_start_xmit = hp100_start_xmit_bm, - .ndo_get_stats = hp100_get_stats, - .ndo_set_rx_mode = hp100_set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static const struct net_device_ops hp100_netdev_ops = { - .ndo_open = hp100_open, - .ndo_stop = hp100_close, - .ndo_start_xmit = hp100_start_xmit, - .ndo_get_stats = hp100_get_stats, - .ndo_set_rx_mode = hp100_set_multicast_list, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, - struct pci_dev *pci_dev) -{ - int i; - int err = -ENODEV; - const char *eid; - u_int chip; - u_char uc; - u_int memory_size = 0, virt_memory_size = 0; - u_short local_mode, lsw; - short mem_mapped; - unsigned long mem_ptr_phys; - void __iomem *mem_ptr_virt; - struct hp100_private *lp; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4201, TRACE); - printk("hp100: %s: probe1\n", dev->name); -#endif - - /* memory region for programmed i/o */ - if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) - goto out1; - - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) - goto out2; - - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; -#ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: %s: Lassen Chip detected.\n", dev->name); - else - printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); -#endif - - dev->base_addr = ioaddr; - - eid = hp100_read_id(ioaddr); - if (eid == NULL) { /* bad checksum? */ - printk(KERN_WARNING "%s: bad ID checksum at base port 0x%x\n", - __func__, ioaddr); - goto out2; - } - - hp100_page(ID_MAC_ADDR); - for (i = uc = 0; i < 7; i++) - uc += hp100_inb(LAN_ADDR + i); - if (uc != 0xff) { - printk(KERN_WARNING - "%s: bad lan address checksum at port 0x%x)\n", - __func__, ioaddr); - err = -EIO; - goto out2; - } - - /* Make sure, that all registers are correctly updated... */ - - hp100_load_eeprom(dev, ioaddr); - wait(); - - /* - * Determine driver operation mode - * - * Use the variable "hp100_mode" upon insmod or as kernel parameter to - * force driver modes: - * hp100_mode=1 -> default, use busmaster mode if configured. - * hp100_mode=2 -> enable shared memory mode - * hp100_mode=3 -> force use of i/o mapped mode. - * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. - */ - - /* - * LSW values: - * 0x2278 -> J2585B, PnP shared memory mode - * 0x2270 -> J2585B, shared memory mode, 0xdc000 - * 0xa23c -> J2585B, I/O mapped mode - * 0x2240 -> EISA COMPEX, BusMaster (Shasta Chip) - * 0x2220 -> EISA HP, I/O (Shasta Chip) - * 0x2260 -> EISA HP, BusMaster (Shasta Chip) - */ - -#if 0 - local_mode = 0x2270; - hp100_outw(0xfefe, OPTION_LSW); - hp100_outw(local_mode | HP100_SET_LB | HP100_SET_HB, OPTION_LSW); -#endif - - /* hp100_mode value maybe used in future by another card */ - local_mode = hp100_mode; - if (local_mode < 1 || local_mode > 4) - local_mode = 1; /* default */ -#ifdef HP100_DEBUG - printk("hp100: %s: original LSW = 0x%x\n", dev->name, - hp100_inw(OPTION_LSW)); -#endif - - if (local_mode == 3) { - hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: IO mapped mode forced.\n"); - } else if (local_mode == 2) { - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: Shared memory mode requested.\n"); - } else if (local_mode == 4) { - if (chip == HP100_CHIPID_LASSEN) { - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: Busmaster mode requested.\n"); - } - local_mode = 1; - } - - if (local_mode == 1) { /* default behaviour */ - lsw = hp100_inw(OPTION_LSW); - - if ((lsw & HP100_IO_EN) && (~lsw & HP100_MEM_EN) && - (~lsw & (HP100_BM_WRITE | HP100_BM_READ))) { -#ifdef HP100_DEBUG - printk("hp100: %s: IO_EN bit is set on card.\n", dev->name); -#endif - local_mode = 3; - } else if (chip == HP100_CHIPID_LASSEN && - (lsw & (HP100_BM_WRITE | HP100_BM_READ)) == (HP100_BM_WRITE | HP100_BM_READ)) { - /* Conversion to new PCI API : - * I don't have the doc, but I assume that the card - * can map the full 32bit address space. - * Also, we can have EISA Busmaster cards (not tested), - * so beware !!! - Jean II */ - if((bus == HP100_BUS_PCI) && - (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)))) { - /* Gracefully fallback to shared memory */ - goto busmasterfail; - } - printk("hp100: Busmaster mode enabled.\n"); - hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - } else { - busmasterfail: -#ifdef HP100_DEBUG - printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name); - printk("hp100: %s: Trying shared memory mode.\n", dev->name); -#endif - /* In this case, try shared memory mode */ - local_mode = 2; - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ - } - } -#ifdef HP100_DEBUG - printk("hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW)); -#endif - - /* Check for shared memory on the card, eventually remap it */ - hp100_page(HW_MAP); - mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0); - mem_ptr_phys = 0UL; - mem_ptr_virt = NULL; - memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); - virt_memory_size = 0; - - /* For memory mapped or busmaster mode, we want the memory address */ - if (mem_mapped || (local_mode == 1)) { - mem_ptr_phys = (hp100_inw(MEM_MAP_LSW) | (hp100_inw(MEM_MAP_MSW) << 16)); - mem_ptr_phys &= ~0x1fff; /* 8k alignment */ - - if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: Can only use programmed i/o mode.\n"); - mem_ptr_phys = 0; - mem_mapped = 0; - local_mode = 3; /* Use programmed i/o */ - } - - /* We do not need access to shared memory in busmaster mode */ - /* However in slave mode we need to remap high (>1GB) card memory */ - if (local_mode != 1) { /* = not busmaster */ - /* We try with smaller memory sizes, if ioremap fails */ - for (virt_memory_size = memory_size; virt_memory_size > 16383; virt_memory_size >>= 1) { - if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, virt_memory_size)) == NULL) { -#ifdef HP100_DEBUG - printk("hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, mem_ptr_phys); -#endif - } else { -#ifdef HP100_DEBUG - printk("hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to %p.\n", dev->name, virt_memory_size, mem_ptr_phys, mem_ptr_virt); -#endif - break; - } - } - - if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); - local_mode = 3; - virt_memory_size = 0; - } - } - } - - if (local_mode == 3) { /* io mapped forced */ - mem_mapped = 0; - mem_ptr_phys = 0; - mem_ptr_virt = NULL; - printk("hp100: Using (slow) programmed i/o mode.\n"); - } - - /* Initialise the "private" data structure for this card. */ - lp = netdev_priv(dev); - - spin_lock_init(&lp->lock); - strlcpy(lp->id, eid, HP100_SIG_LEN); - lp->chip = chip; - lp->mode = local_mode; - lp->bus = bus; - lp->pci_dev = pci_dev; - lp->priority_tx = hp100_priority_tx; - lp->rx_ratio = hp100_rx_ratio; - lp->mem_ptr_phys = mem_ptr_phys; - lp->mem_ptr_virt = mem_ptr_virt; - hp100_page(ID_MAC_ADDR); - lp->soft_model = hp100_inb(SOFT_MODEL); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - memset(&lp->hash_bytes, 0x00, 8); - - dev->base_addr = ioaddr; - - lp->memory_size = memory_size; - lp->virt_memory_size = virt_memory_size; - lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - - if (lp->mode == 1) /* busmaster */ - dev->netdev_ops = &hp100_bm_netdev_ops; - else - dev->netdev_ops = &hp100_netdev_ops; - - /* Ask the card for which IRQ line it is configured */ - if (bus == HP100_BUS_PCI) { - dev->irq = pci_dev->irq; - } else { - hp100_page(HW_MAP); - dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK; - if (dev->irq == 2) - dev->irq = 9; - } - - if (lp->mode == 1) /* busmaster */ - dev->dma = 4; - - /* Ask the card for its MAC address and store it for later use. */ - hp100_page(ID_MAC_ADDR); - for (i = uc = 0; i < 6; i++) - dev->dev_addr[i] = hp100_inb(LAN_ADDR + i); - - /* Reset statistics (counters) */ - hp100_clear_stats(lp, ioaddr); - - /* If busmaster mode is wanted, a dma-capable memory area is needed for - * the rx and tx PDLs - * PCI cards can access the whole PC memory. Therefore GFP_DMA is not - * needed for the allocation of the memory area. - */ - - /* TODO: We do not need this with old cards, where PDLs are stored - * in the cards shared memory area. But currently, busmaster has been - * implemented/tested only with the lassen chip anyway... */ - if (lp->mode == 1) { /* busmaster */ - dma_addr_t page_baddr; - /* Get physically continuous memory for TX & RX PDLs */ - /* Conversion to new PCI API : - * Pages are always aligned and zeroed, no need to it ourself. - * Doc says should be OK for EISA bus as well - Jean II */ - lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr); - if (!lp->page_vaddr_algn) { - err = -ENOMEM; - goto out_mem_ptr; - } - lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); - -#ifdef HP100_DEBUG_BM - printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", dev->name, (u_int) lp->page_vaddr_algn, (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); -#endif - lp->rxrcommit = lp->txrcommit = 0; - lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - lp->txrhead = lp->txrtail = &(lp->txring[0]); - } - - /* Initialise the card. */ - /* (I'm not really sure if it's a good idea to do this during probing, but - * like this it's assured that the lan connection type can be sensed - * correctly) - */ - hp100_hwinit(dev); - - /* Try to find out which kind of LAN the card is connected to. */ - lp->lan_type = hp100_sense_lan(dev); - - /* Print out a message what about what we think we have probed. */ - printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq); - switch (bus) { - case HP100_BUS_EISA: - printk("EISA"); - break; - case HP100_BUS_PCI: - printk("PCI"); - break; - default: - printk("ISA"); - break; - } - printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio); - - if (lp->mode == 2) { /* memory mapped */ - printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys, - (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1); - if (mem_ptr_virt) - printk(" (virtual base %p)", mem_ptr_virt); - printk(".\n"); - - /* Set for info when doing ifconfig */ - dev->mem_start = mem_ptr_phys; - dev->mem_end = mem_ptr_phys + lp->memory_size; - } - - printk("hp100: "); - if (lp->lan_type != HP100_LAN_ERR) - printk("Adapter is attached to "); - switch (lp->lan_type) { - case HP100_LAN_100: - printk("100Mb/s Voice Grade AnyLAN network.\n"); - break; - case HP100_LAN_10: - printk("10Mb/s network (10baseT).\n"); - break; - case HP100_LAN_COAX: - printk("10Mb/s network (coax).\n"); - break; - default: - printk("Warning! Link down.\n"); - } - - err = register_netdev(dev); - if (err) - goto out3; - - return 0; -out3: - if (local_mode == 1) - pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f, - lp->page_vaddr_algn, - virt_to_whatever(dev, lp->page_vaddr_algn)); -out_mem_ptr: - if (mem_ptr_virt) - iounmap(mem_ptr_virt); -out2: - release_region(ioaddr, HP100_REGION_SIZE); -out1: - return err; -} - -/* This procedure puts the card into a stable init state */ -static void hp100_hwinit(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4202, TRACE); - printk("hp100: %s: hwinit\n", dev->name); -#endif - - /* Initialise the card. -------------------------------------------- */ - - /* Clear all pending Ints and disable Ints */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */ - - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { - hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */ - wait(); - } else { - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_cascade_reset(dev, 1); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - } - - /* Initiate EEPROM reload */ - hp100_load_eeprom(dev, 0); - - wait(); - - /* Go into reset again. */ - hp100_cascade_reset(dev, 1); - - /* Set Option Registers to a safe state */ - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | - HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB | - HP100_FAKE_INT | - HP100_INT_EN | - HP100_MEM_EN | - HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - - hp100_outb(HP100_PRIORITY_TX | - HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* TODO: Configure MMU for Ram Test. */ - /* TODO: Ram Test. */ - - /* Re-check if adapter is still at same i/o location */ - /* (If the base i/o in eeprom has been changed but the */ - /* registers had not been changed, a reload of the eeprom */ - /* would move the adapter to the address stored in eeprom */ - - /* TODO: Code to implement. */ - - /* Until here it was code from HWdiscover procedure. */ - /* Next comes code from mmuinit procedure of SCO BM driver which is - * called from HWconfigure in the SCO driver. */ - - /* Initialise MMU, eventually switch on Busmaster Mode, initialise - * multicast filter... - */ - hp100_mmuinit(dev); - - /* We don't turn the interrupts on here - this is done by start_interface. */ - wait(); /* TODO: Do we really need this? */ - - /* Enable Hardware (e.g. unreset) */ - hp100_cascade_reset(dev, 0); - - /* ------- initialisation complete ----------- */ - - /* Finally try to log in the Hub if there may be a VG connection. */ - if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR)) - hp100_login_to_vg_hub(dev, 0); /* relogin */ - -} - - -/* - * mmuinit - Reinitialise Cascade MMU and MAC settings. - * Note: Must already be in reset and leaves card in reset. - */ -static void hp100_mmuinit(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - int i; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4203, TRACE); - printk("hp100: %s: mmuinit\n", dev->name); -#endif - -#ifdef HP100_DEBUG - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n", dev->name); - return; - } -#endif - - /* Make sure IRQs are masked off and ack'ed. */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* - * Enable Hardware - * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En - * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable - * - Clear Priority, Advance Pkt and Xmit Cmd - */ - - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | HP100_RESET_HB | - HP100_IO_EN | - HP100_FAKE_INT | - HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { /* busmaster */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - } else if (lp->mode == 2) { /* memory mapped */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } else if (lp->mode == 3) { /* i/o mapped mode */ - hp100_outw(HP100_MMAP_DIS | HP100_SET_HB | - HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } - - hp100_page(HW_MAP); - hp100_outb(0, EARLYRXCFG); - hp100_outw(0, EARLYTXCFG); - - /* - * Enable Bus Master mode - */ - if (lp->mode == 1) { /* busmaster */ - /* Experimental: Set some PCI configuration bits */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */ - hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */ - - /* PCI Bus failures should result in a Misc. Interrupt */ - hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2); - - hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW); - hp100_page(HW_MAP); - /* Use Burst Mode and switch on PAGE_CK */ - hp100_orb(HP100_BM_BURST_RD | HP100_BM_BURST_WR, BM); - if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) - hp100_orb(HP100_BM_PAGE_CK, BM); - hp100_orb(HP100_BM_MASTER, BM); - } else { /* not busmaster */ - - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } - - /* - * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs - */ - hp100_page(MMU_CFG); - if (lp->mode == 1) { /* only needed for Busmaster */ - int xmit_stop, recv_stop; - - if ((lp->chip == HP100_CHIPID_RAINIER) || - (lp->chip == HP100_CHIPID_SHASTA)) { - int pdl_stop; - - /* - * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and - * 4 bytes for header). We will leave NUM_RXPDLS * 508 (rounded - * to the next higher 1k boundary) bytes for the rx-pdl's - * Note: For non-etr chips the transmit stop register must be - * programmed on a 1k boundary, i.e. bits 9:0 must be zero. - */ - pdl_stop = lp->memory_size; - xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff); - recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff); - hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP); -#ifdef HP100_DEBUG_BM - printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop); -#endif - } else { - /* ETR chip (Lassen) in busmaster mode */ - xmit_stop = (lp->memory_size) - 1; - recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff); - } - - hp100_outw(xmit_stop >> 4, TX_MEM_STOP); - hp100_outw(recv_stop >> 4, RX_MEM_STOP); -#ifdef HP100_DEBUG_BM - printk("hp100: %s: TX_STOP = 0x%x\n", dev->name, xmit_stop >> 4); - printk("hp100: %s: RX_STOP = 0x%x\n", dev->name, recv_stop >> 4); -#endif - } else { - /* Slave modes (memory mapped and programmed io) */ - hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP); - hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP); -#ifdef HP100_DEBUG - printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(TX_MEM_STOP)); - printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(RX_MEM_STOP)); -#endif - } - - /* Write MAC address into page 1 */ - hp100_page(MAC_ADDRESS); - for (i = 0; i < 6; i++) - hp100_outb(dev->dev_addr[i], MAC_ADDR + i); - - /* Zero the multicast hash registers */ - for (i = 0; i < 8; i++) - hp100_outb(0x0, HASH_BYTE0 + i); - - /* Set up MAC defaults */ - hp100_page(MAC_CTRL); - - /* Go to LAN Page and zero all filter bits */ - /* Zero accept error, accept multicast, accept broadcast and accept */ - /* all directed packet bits */ - hp100_andb(~(HP100_RX_EN | - HP100_TX_EN | - HP100_ACC_ERRORED | - HP100_ACC_MC | - HP100_ACC_BC | HP100_ACC_PHY), MAC_CFG_1); - - hp100_outb(0x00, MAC_CFG_2); - - /* Zero the frame format bit. This works around a training bug in the */ - /* new hubs. */ - hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */ - - if (lp->priority_tx) - hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW); - else - hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW); - - hp100_outb(HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* If busmaster, initialize the PDLs */ - if (lp->mode == 1) - hp100_init_pdls(dev); - - /* Go to performance page and initialize isr and imr registers */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ -} - -/* - * open/close functions - */ - -static int hp100_open(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; -#endif - -#ifdef HP100_DEBUG_B - hp100_outw(0x4204, TRACE); - printk("hp100: %s: open\n", dev->name); -#endif - - /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ - if (request_irq(dev->irq, hp100_interrupt, - lp->bus == HP100_BUS_PCI || lp->bus == - HP100_BUS_EISA ? IRQF_SHARED : 0, - dev->name, dev)) { - printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq); - return -EAGAIN; - } - - netif_trans_update(dev); /* prevent tx timeout */ - netif_start_queue(dev); - - lp->lan_type = hp100_sense_lan(dev); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - memset(&lp->hash_bytes, 0x00, 8); - - hp100_stop_interface(dev); - - hp100_hwinit(dev); - - hp100_start_interface(dev); /* sets mac modes, enables interrupts */ - - return 0; -} - -/* The close function is called when the interface is to be brought down */ -static int hp100_close(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4205, TRACE); - printk("hp100: %s: close\n", dev->name); -#endif - - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */ - - hp100_stop_interface(dev); - - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - - netif_stop_queue(dev); - - free_irq(dev->irq, dev); - -#ifdef HP100_DEBUG - printk("hp100: %s: close LSW = 0x%x\n", dev->name, - hp100_inw(OPTION_LSW)); -#endif - - return 0; -} - - -/* - * Configure the PDL Rx rings and LAN - */ -static void hp100_init_pdls(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); - hp100_ring_t *ringptr; - u_int *pageptr; /* Warning : increment by 4 - Jean II */ - int i; - -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; -#endif - -#ifdef HP100_DEBUG_B - hp100_outw(0x4206, TRACE); - printk("hp100: %s: init pdls\n", dev->name); -#endif - - if (!lp->page_vaddr_algn) - printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n", dev->name); - else { - /* pageptr shall point into the DMA accessible memory region */ - /* we use this pointer to status the upper limit of allocated */ - /* memory in the allocated page. */ - /* note: align the pointers to the pci cache line size */ - memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ - pageptr = lp->page_vaddr_algn; - - lp->rxrcommit = 0; - ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - - /* Initialise Rx Ring */ - for (i = MAX_RX_PDL - 1; i >= 0; i--) { - lp->rxring[i].next = ringptr; - ringptr = &(lp->rxring[i]); - pageptr += hp100_init_rxpdl(dev, ringptr, pageptr); - } - - /* Initialise Tx Ring */ - lp->txrcommit = 0; - ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); - for (i = MAX_TX_PDL - 1; i >= 0; i--) { - lp->txring[i].next = ringptr; - ringptr = &(lp->txring[i]); - pageptr += hp100_init_txpdl(dev, ringptr, pageptr); - } - } -} - - -/* These functions "format" the entries in the pdl structure */ -/* They return how much memory the fragments need. */ -static int hp100_init_rxpdl(struct net_device *dev, - register hp100_ring_t * ringptr, - register u32 * pdlptr) -{ - /* pdlptr is starting address for this pdl */ - - if (0 != (((unsigned long) pdlptr) & 0xf)) - printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%lx.\n", - dev->name, (unsigned long) pdlptr); - - ringptr->pdl = pdlptr + 1; - ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1); - ringptr->skb = NULL; - - /* - * Write address and length of first PDL Fragment (which is used for - * storing the RX-Header - * We use the 4 bytes _before_ the PDH in the pdl memory area to - * store this information. (PDH is at offset 0x04) - */ - /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ - - *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr); /* Address Frag 1 */ - *(pdlptr + 3) = 4; /* Length Frag 1 */ - - return roundup(MAX_RX_FRAG * 2 + 2, 4); -} - - -static int hp100_init_txpdl(struct net_device *dev, - register hp100_ring_t * ringptr, - register u32 * pdlptr) -{ - if (0 != (((unsigned long) pdlptr) & 0xf)) - printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%lx.\n", dev->name, (unsigned long) pdlptr); - - ringptr->pdl = pdlptr; /* +1; */ - ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */ - ringptr->skb = NULL; - - return roundup(MAX_TX_FRAG * 2 + 2, 4); -} - -/* - * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes - * for possible odd word alignment rounding up to next dword and set PDL - * address for fragment#2 - * Returns: 0 if unable to allocate skb_buff - * 1 if successful - */ -static int hp100_build_rx_pdl(hp100_ring_t * ringptr, - struct net_device *dev) -{ -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; -#endif -#ifdef HP100_DEBUG_BM - u_int *p; -#endif - -#ifdef HP100_DEBUG_B - hp100_outw(0x4207, TRACE); - printk("hp100: %s: build rx pdl\n", dev->name); -#endif - - /* Allocate skb buffer of maximum size */ - /* Note: This depends on the alloc_skb functions allocating more - * space than requested, i.e. aligning to 16bytes */ - - ringptr->skb = netdev_alloc_skb(dev, roundup(MAX_ETHER_SIZE + 2, 4)); - - if (NULL != ringptr->skb) { - /* - * Reserve 2 bytes at the head of the buffer to land the IP header - * on a long word boundary (According to the Network Driver section - * in the Linux KHG, this should help to increase performance.) - */ - skb_reserve(ringptr->skb, 2); - - ringptr->skb->data = skb_put(ringptr->skb, MAX_ETHER_SIZE); - - /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ - /* Note: 1st Fragment is used for the 4 byte packet status - * (receive header). Its PDL entries are set up by init_rxpdl. So - * here we only have to set up the PDL fragment entries for the data - * part. Those 4 bytes will be stored in the DMA memory region - * directly before the PDL. - */ -#ifdef HP100_DEBUG_BM - printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", - dev->name, (u_int) ringptr->pdl, - roundup(MAX_ETHER_SIZE + 2, 4), - (unsigned int) ringptr->skb->data); -#endif - - /* Conversion to new PCI API : map skbuf data to PCI bus. - * Doc says it's OK for EISA as well - Jean II */ - ringptr->pdl[0] = 0x00020000; /* Write PDH */ - ringptr->pdl[3] = pdl_map_data(netdev_priv(dev), - ringptr->skb->data); - ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ - -#ifdef HP100_DEBUG_BM - for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++) - printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n", dev->name, (u_int) p, (u_int) * p); -#endif - return 1; - } - /* else: */ - /* alloc_skb failed (no memory) -> still can receive the header - * fragment into PDL memory. make PDL safe by clearing msgptr and - * making the PDL only 1 fragment (i.e. the 4 byte packet status) - */ -#ifdef HP100_DEBUG_BM - printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", dev->name, (u_int) ringptr->pdl); -#endif - - ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */ - - return 0; -} - -/* - * hp100_rxfill - attempt to fill the Rx Ring will empty skb's - * - * Makes assumption that skb's are always contiguous memory areas and - * therefore PDLs contain only 2 physical fragments. - * - While the number of Rx PDLs with buffers is less than maximum - * a. Get a maximum packet size skb - * b. Put the physical address of the buffer into the PDL. - * c. Output physical address of PDL to adapter. - */ -static void hp100_rxfill(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - - struct hp100_private *lp = netdev_priv(dev); - hp100_ring_t *ringptr; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4208, TRACE); - printk("hp100: %s: rxfill\n", dev->name); -#endif - - hp100_page(PERFORMANCE); - - while (lp->rxrcommit < MAX_RX_PDL) { - /* - ** Attempt to get a buffer and build a Rx PDL. - */ - ringptr = lp->rxrtail; - if (0 == hp100_build_rx_pdl(ringptr, dev)) { - return; /* None available, return */ - } - - /* Hand this PDL over to the card */ - /* Note: This needs performance page selected! */ -#ifdef HP100_DEBUG_BM - printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", - dev->name, lp->rxrcommit, (u_int) ringptr->pdl, - (u_int) ringptr->pdl_paddr, (u_int) ringptr->pdl[3]); -#endif - - hp100_outl((u32) ringptr->pdl_paddr, RX_PDA); - - lp->rxrcommit += 1; - lp->rxrtail = ringptr->next; - } -} - -/* - * BM_shutdown - shutdown bus mastering and leave chip in reset state - */ - -static void hp100_BM_shutdown(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - unsigned long time; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4209, TRACE); - printk("hp100: %s: bm shutdown\n", dev->name); -#endif - - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */ - - /* Ensure Interrupts are off */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - /* Disable all MAC activity */ - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - /* If cascade MMU is not already in reset */ - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so - * MMU pointers will not be reset out from underneath - */ - hp100_page(MAC_CTRL); - for (time = 0; time < 5000; time++) { - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE)) - break; - } - - /* Shutdown algorithm depends on the generation of Cascade */ - if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */ - /* Disable Busmaster mode and wait for bit to go to zero. */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - /* 100 ms timeout */ - for (time = 0; time < 32000; time++) { - if (0 == (hp100_inb(BM) & HP100_BM_MASTER)) - break; - } - } else { /* Shasta or Rainier Shutdown/Reset */ - /* To ensure all bus master inloading activity has ceased, - * wait for no Rx PDAs or no Rx packets on card. - */ - hp100_page(PERFORMANCE); - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - /* RX_PDL: PDLs not executed. */ - /* RX_PKT_CNT: RX'd packets on card. */ - if ((hp100_inb(RX_PDL) == 0) && (hp100_inb(RX_PKT_CNT) == 0)) - break; - } - - if (time >= 10000) - printk("hp100: %s: BM shutdown error.\n", dev->name); - - /* To ensure all bus master outloading activity has ceased, - * wait until the Tx PDA count goes to zero or no more Tx space - * available in the Tx region of the card. - */ - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - if ((0 == hp100_inb(TX_PKT_CNT)) && - (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE))) - break; - } - - /* Disable Busmaster mode */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } /* end of shutdown procedure for non-etr parts */ - - hp100_cascade_reset(dev, 1); - } - hp100_page(PERFORMANCE); - /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ - /* Busmaster mode should be shut down now. */ -} - -static int hp100_check_lan(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); - - if (lp->lan_type < 0) { /* no LAN type detected yet? */ - hp100_stop_interface(dev); - if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { - printk("hp100: %s: no connection found - check wire\n", dev->name); - hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */ - return -EIO; - } - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); /* relogin */ - hp100_start_interface(dev); - } - return 0; -} - -/* - * transmit functions - */ - -/* tx function for busmaster mode */ -static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned long flags; - int i, ok_flag; - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - hp100_ring_t *ringptr; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4210, TRACE); - printk("hp100: %s: start_xmit_bm\n", dev->name); -#endif - if (skb->len <= 0) - goto drop; - - if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) - return NETDEV_TX_OK; - - /* Get Tx ring tail pointer */ - if (lp->txrtail->next == lp->txrhead) { - /* No memory. */ -#ifdef HP100_DEBUG - printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name); -#endif - /* not waited long enough since last tx? */ - if (time_before(jiffies, dev_trans_start(dev) + HZ)) - goto drop; - - if (hp100_check_lan(dev)) - goto drop; - - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { - /* we have a 100Mb/s adapter but it isn't connected to hub */ - printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - } else { - spin_lock_irqsave(&lp->lock, flags); - hp100_ints_off(); /* Useful ? Jean II */ - i = hp100_sense_lan(dev); - hp100_ints_on(); - spin_unlock_irqrestore(&lp->lock, flags); - if (i == HP100_LAN_ERR) - printk("hp100: %s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network settings must be changed!!! */ - printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - } else { - printk("hp100: %s: interface reset\n", dev->name); - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - } - } - - goto drop; - } - - /* - * we have to turn int's off before modifying this, otherwise - * a tx_pdl_cleanup could occur at the same time - */ - spin_lock_irqsave(&lp->lock, flags); - ringptr = lp->txrtail; - lp->txrtail = ringptr->next; - - /* Check whether packet has minimal packet size */ - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - ringptr->skb = skb; - ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ - if (lp->chip == HP100_CHIPID_SHASTA) { - /* TODO:Could someone who has the EISA card please check if this works? */ - ringptr->pdl[2] = i; - } else { /* Lassen */ - /* In the PDL, don't use the padded size but the real packet size: */ - ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ - } - /* Conversion to new PCI API : map skbuf data to PCI bus. - * Doc says it's OK for EISA as well - Jean II */ - ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE)); /* 1st Frag: Adr. of data */ - - /* Hand this PDL to the card. */ - hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ - - lp->txrcommit++; - - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - - spin_unlock_irqrestore(&lp->lock, flags); - - return NETDEV_TX_OK; - -drop: - dev_kfree_skb(skb); - return NETDEV_TX_OK; -} - - -/* clean_txring checks if packets have been sent by the card by reading - * the TX_PDL register from the performance page and comparing it to the - * number of committed packets. It then frees the skb's of the packets that - * obviously have been sent to the network. - * - * Needs the PERFORMANCE page selected. - */ -static void hp100_clean_txring(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - int donecount; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4211, TRACE); - printk("hp100: %s: clean txring\n", dev->name); -#endif - - /* How many PDLs have been transmitted? */ - donecount = (lp->txrcommit) - hp100_inb(TX_PDL); - -#ifdef HP100_DEBUG - if (donecount > MAX_TX_PDL) - printk("hp100: %s: Warning: More PDLs transmitted than committed to card???\n", dev->name); -#endif - - for (; 0 != donecount; donecount--) { -#ifdef HP100_DEBUG_BM - printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", - dev->name, (u_int) lp->txrhead->skb->data, - lp->txrcommit, hp100_inb(TX_PDL), donecount); -#endif - /* Conversion to new PCI API : NOP */ - pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE); - dev_consume_skb_any(lp->txrhead->skb); - lp->txrhead->skb = NULL; - lp->txrhead = lp->txrhead->next; - lp->txrcommit--; - } -} - -/* tx function for slave modes */ -static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - unsigned long flags; - int i, ok_flag; - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4212, TRACE); - printk("hp100: %s: start_xmit\n", dev->name); -#endif - if (skb->len <= 0) - goto drop; - - if (hp100_check_lan(dev)) - goto drop; - - /* If there is not enough free memory on the card... */ - i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; - if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) { -#ifdef HP100_DEBUG - printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i); -#endif - /* not waited long enough since last failed tx try? */ - if (time_before(jiffies, dev_trans_start(dev) + HZ)) { -#ifdef HP100_DEBUG - printk("hp100: %s: trans_start timing problem\n", - dev->name); -#endif - goto drop; - } - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { - /* we have a 100Mb/s adapter but it isn't connected to hub */ - printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - } else { - spin_lock_irqsave(&lp->lock, flags); - hp100_ints_off(); /* Useful ? Jean II */ - i = hp100_sense_lan(dev); - hp100_ints_on(); - spin_unlock_irqrestore(&lp->lock, flags); - if (i == HP100_LAN_ERR) - printk("hp100: %s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network setting must be changed!!! */ - printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - } else { - printk("hp100: %s: interface reset\n", dev->name); - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, 0); - hp100_start_interface(dev); - mdelay(1); - } - } - goto drop; - } - - for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { -#ifdef HP100_DEBUG_TX - printk("hp100: %s: start_xmit: busy\n", dev->name); -#endif - } - - spin_lock_irqsave(&lp->lock, flags); - hp100_ints_off(); - val = hp100_inw(IRQ_STATUS); - /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set - * when the current packet being transmitted on the wire is completed. */ - hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS); -#ifdef HP100_DEBUG_TX - printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", - dev->name, val, hp100_inw(IRQ_MASK), (int) skb->len); -#endif - - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - hp100_outw(i, DATA32); /* tell card the total packet length */ - hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ - - if (lp->mode == 2) { /* memory mapped */ - /* Note: The J2585B needs alignment to 32bits here! */ - memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); - if (!ok_flag) - memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); - } else { /* programmed i/o */ - outsl(ioaddr + HP100_REG_DATA32, skb->data, - (skb->len + 3) >> 2); - if (!ok_flag) - for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4) - hp100_outl(0, DATA32); - } - - hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */ - - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - hp100_ints_on(); - spin_unlock_irqrestore(&lp->lock, flags); - - dev_consume_skb_any(skb); - -#ifdef HP100_DEBUG_TX - printk("hp100: %s: start_xmit: end\n", dev->name); -#endif - - return NETDEV_TX_OK; - -drop: - dev_kfree_skb(skb); - return NETDEV_TX_OK; - -} - - -/* - * Receive Function (Non-Busmaster mode) - * Called when an "Receive Packet" interrupt occurs, i.e. the receive - * packet counter is non-zero. - * For non-busmaster, this function does the whole work of transferring - * the packet to the host memory and then up to higher layers via skb - * and netif_rx. - */ - -static void hp100_rx(struct net_device *dev) -{ - int packets, pkt_len; - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - u_int header; - struct sk_buff *skb; - -#ifdef DEBUG_B - hp100_outw(0x4213, TRACE); - printk("hp100: %s: rx\n", dev->name); -#endif - - /* First get indication of received lan packet */ - /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transferred of the card */ - packets = hp100_inb(RX_PKT_CNT); -#ifdef HP100_DEBUG_RX - if (packets > 1) - printk("hp100: %s: rx: waiting packets = %d\n", dev->name, packets); -#endif - - while (packets-- > 0) { - /* If ADV_NXT_PKT is still set, we have to wait until the card has */ - /* really advanced to the next packet. */ - for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); pkt_len++) { -#ifdef HP100_DEBUG_RX - printk ("hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets); -#endif - } - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - if (lp->mode == 2) { /* memory mapped mode */ - header = readl(lp->mem_ptr_virt); - } else /* programmed i/o */ - header = hp100_inl(DATA32); - - pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3; - -#ifdef HP100_DEBUG_RX - printk("hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", - dev->name, header & HP100_PKT_LEN_MASK, - (header >> 16) & 0xfff8, (header >> 16) & 7); -#endif - - /* Now we allocate the skb and transfer the data into it. */ - skb = netdev_alloc_skb(dev, pkt_len + 2); - if (skb == NULL) { /* Not enough memory->drop packet */ -#ifdef HP100_DEBUG - printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", - dev->name, pkt_len); -#endif - dev->stats.rx_dropped++; - } else { /* skb successfully allocated */ - - u_char *ptr; - - skb_reserve(skb,2); - - /* ptr to start of the sk_buff data area */ - skb_put(skb, pkt_len); - ptr = skb->data; - - /* Now transfer the data from the card into that area */ - if (lp->mode == 2) - memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len); - else /* io mapped */ - insl(ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2); - - skb->protocol = eth_type_trans(skb, dev); - -#ifdef HP100_DEBUG_RX - printk("hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - dev->name, ptr[0], ptr[1], ptr[2], ptr[3], - ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], - ptr[9], ptr[10], ptr[11]); -#endif - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - - /* Indicate the card that we have got the packet */ - hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW); - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - dev->stats.multicast++; - break; - } - } /* end of while(there are packets) loop */ -#ifdef HP100_DEBUG_RX - printk("hp100_rx: %s: end\n", dev->name); -#endif -} - -/* - * Receive Function for Busmaster Mode - */ -static void hp100_rx_bm(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - hp100_ring_t *ptr; - u_int header; - int pkt_len; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4214, TRACE); - printk("hp100: %s: rx_bm\n", dev->name); -#endif - -#ifdef HP100_DEBUG - if (0 == lp->rxrcommit) { - printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name); - return; - } else - /* RX_PKT_CNT states how many PDLs are currently formatted and available to - * the cards BM engine */ - if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { - printk("hp100: %s: More packets received than committed? RX_PKT_CNT=0x%x, commit=0x%x\n", - dev->name, hp100_inw(RX_PKT_CNT) & 0x00ff, - lp->rxrcommit); - return; - } -#endif - - while ((lp->rxrcommit > hp100_inb(RX_PDL))) { - /* - * The packet was received into the pdl pointed to by lp->rxrhead ( - * the oldest pdl in the ring - */ - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - - ptr = lp->rxrhead; - - header = *(ptr->pdl - 1); - pkt_len = (header & HP100_PKT_LEN_MASK); - - /* Conversion to new PCI API : NOP */ - pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); - -#ifdef HP100_DEBUG_BM - printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", - dev->name, (u_int) (ptr->pdl - 1), (u_int) header, - pkt_len, (header >> 16) & 0xfff8, (header >> 16) & 7); - printk("hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", - dev->name, hp100_inb(RX_PDL), hp100_inb(TX_PDL), - hp100_inb(RX_PKT_CNT), (u_int) * (ptr->pdl), - (u_int) * (ptr->pdl + 3), (u_int) * (ptr->pdl + 4)); -#endif - - if ((pkt_len >= MIN_ETHER_SIZE) && - (pkt_len <= MAX_ETHER_SIZE)) { - if (ptr->skb == NULL) { - printk("hp100: %s: rx_bm: skb null\n", dev->name); - /* can happen if we only allocated room for the pdh due to memory shortage. */ - dev->stats.rx_dropped++; - } else { - skb_trim(ptr->skb, pkt_len); /* Shorten it */ - ptr->skb->protocol = - eth_type_trans(ptr->skb, dev); - - netif_rx(ptr->skb); /* Up and away... */ - - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - dev->stats.multicast++; - break; - } - } else { -#ifdef HP100_DEBUG - printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n", dev->name, pkt_len); -#endif - if (ptr->skb != NULL) - dev_kfree_skb_any(ptr->skb); - dev->stats.rx_errors++; - } - - lp->rxrhead = lp->rxrhead->next; - - /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ - if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { - /* No space for skb, header can still be received. */ -#ifdef HP100_DEBUG - printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name); -#endif - return; - } else { /* successfully allocated new PDL - put it in ringlist at tail. */ - hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); - lp->rxrtail = lp->rxrtail->next; - } - - } -} - -/* - * statistics - */ -static struct net_device_stats *hp100_get_stats(struct net_device *dev) -{ - unsigned long flags; - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4215, TRACE); -#endif - - spin_lock_irqsave(&lp->lock, flags); - hp100_ints_off(); /* Useful ? Jean II */ - hp100_update_stats(dev); - hp100_ints_on(); - spin_unlock_irqrestore(&lp->lock, flags); - return &(dev->stats); -} - -static void hp100_update_stats(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - u_short val; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4216, TRACE); - printk("hp100: %s: update-stats\n", dev->name); -#endif - - /* Note: Statistics counters clear when read. */ - hp100_page(MAC_CTRL); - val = hp100_inw(DROPPED) & 0x0fff; - dev->stats.rx_errors += val; - dev->stats.rx_over_errors += val; - val = hp100_inb(CRC); - dev->stats.rx_errors += val; - dev->stats.rx_crc_errors += val; - val = hp100_inb(ABORT); - dev->stats.tx_errors += val; - dev->stats.tx_aborted_errors += val; - hp100_page(PERFORMANCE); -} - -static void hp100_misc_interrupt(struct net_device *dev) -{ -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; -#endif - -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; - hp100_outw(0x4216, TRACE); - printk("hp100: %s: misc_interrupt\n", dev->name); -#endif - - /* Note: Statistics counters clear when read. */ - dev->stats.rx_errors++; - dev->stats.tx_errors++; -} - -static void hp100_clear_stats(struct hp100_private *lp, int ioaddr) -{ - unsigned long flags; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4217, TRACE); - printk("hp100: %s: clear_stats\n", dev->name); -#endif - - spin_lock_irqsave(&lp->lock, flags); - hp100_page(MAC_CTRL); /* get all statistics bytes */ - hp100_inw(DROPPED); - hp100_inb(CRC); - hp100_inb(ABORT); - hp100_page(PERFORMANCE); - spin_unlock_irqrestore(&lp->lock, flags); -} - - -/* - * multicast setup - */ - -/* - * Set or clear the multicast filter for this adapter. - */ - -static void hp100_set_multicast_list(struct net_device *dev) -{ - unsigned long flags; - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4218, TRACE); - printk("hp100: %s: set_mc_list\n", dev->name); -#endif - - spin_lock_irqsave(&lp->lock, flags); - hp100_ints_off(); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - if (dev->flags & IFF_PROMISC) { - lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ - lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ - memset(&lp->hash_bytes, 0xff, 8); - } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { - lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ - lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ -#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ - if (dev->flags & IFF_ALLMULTI) { - /* set hash filter to receive all multicast packets */ - memset(&lp->hash_bytes, 0xff, 8); - } else { - int i, idx; - u_char *addrs; - struct netdev_hw_addr *ha; - - memset(&lp->hash_bytes, 0x00, 8); -#ifdef HP100_DEBUG - printk("hp100: %s: computing hash filter - mc_count = %i\n", - dev->name, netdev_mc_count(dev)); -#endif - netdev_for_each_mc_addr(ha, dev) { - addrs = ha->addr; -#ifdef HP100_DEBUG - printk("hp100: %s: multicast = %pM, ", - dev->name, addrs); -#endif - for (i = idx = 0; i < 6; i++) { - idx ^= *addrs++ & 0x3f; - printk(":%02x:", idx); - } -#ifdef HP100_DEBUG - printk("idx = %i\n", idx); -#endif - lp->hash_bytes[idx >> 3] |= (1 << (idx & 7)); - } - } -#else - memset(&lp->hash_bytes, 0xff, 8); -#endif - } else { - lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ - lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ - memset(&lp->hash_bytes, 0x00, 8); - } - - if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || - (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { - int i; - - hp100_outb(lp->mac2_mode, MAC_CFG_2); - hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ - hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ - - hp100_page(MAC_ADDRESS); - for (i = 0; i < 8; i++) - hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i); -#ifdef HP100_DEBUG - printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, lp->mac1_mode, lp->mac2_mode, - lp->hash_bytes[0], lp->hash_bytes[1], - lp->hash_bytes[2], lp->hash_bytes[3], - lp->hash_bytes[4], lp->hash_bytes[5], - lp->hash_bytes[6], lp->hash_bytes[7]); -#endif - - if (lp->lan_type == HP100_LAN_100) { -#ifdef HP100_DEBUG - printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); -#endif - lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */ - } - } else { - int i; - u_char old_hash_bytes[8]; - - hp100_page(MAC_ADDRESS); - for (i = 0; i < 8; i++) - old_hash_bytes[i] = hp100_inb(HASH_BYTE0 + i); - if (memcmp(old_hash_bytes, &lp->hash_bytes, 8)) { - for (i = 0; i < 8; i++) - hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i); -#ifdef HP100_DEBUG - printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, lp->hash_bytes[0], - lp->hash_bytes[1], lp->hash_bytes[2], - lp->hash_bytes[3], lp->hash_bytes[4], - lp->hash_bytes[5], lp->hash_bytes[6], - lp->hash_bytes[7]); -#endif - - if (lp->lan_type == HP100_LAN_100) { -#ifdef HP100_DEBUG - printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); -#endif - lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */ - } - } - } - - hp100_page(MAC_CTRL); - hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */ - - hp100_page(PERFORMANCE); - hp100_ints_on(); - spin_unlock_irqrestore(&lp->lock, flags); -} - -/* - * hardware interrupt handling - */ - -static irqreturn_t hp100_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct hp100_private *lp = netdev_priv(dev); - - int ioaddr; - u_int val; - - if (dev == NULL) - return IRQ_NONE; - ioaddr = dev->base_addr; - - spin_lock(&lp->lock); - - hp100_ints_off(); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4219, TRACE); -#endif - - /* hp100_page( PERFORMANCE ); */ - val = hp100_inw(IRQ_STATUS); -#ifdef HP100_DEBUG_IRQ - printk("hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", - dev->name, lp->mode, (u_int) val, hp100_inb(RX_PKT_CNT), - hp100_inb(RX_PDL), hp100_inb(TX_PKT_CNT), hp100_inb(TX_PDL)); -#endif - - if (val == 0) { /* might be a shared interrupt */ - spin_unlock(&lp->lock); - hp100_ints_on(); - return IRQ_NONE; - } - /* We're only interested in those interrupts we really enabled. */ - /* val &= hp100_inw( IRQ_MASK ); */ - - /* - * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL - * is considered executed whenever the RX_PDL data structure is no longer - * needed. - */ - if (val & HP100_RX_PDL_FILL_COMPL) { - if (lp->mode == 1) - hp100_rx_bm(dev); - else { - printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name); - } - } - - /* - * The RX_PACKET interrupt is set, when the receive packet counter is - * non zero. We use this interrupt for receiving in slave mode. In - * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill - * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then - * we somehow have missed a rx_pdl_fill_compl interrupt. - */ - - if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */ - if (lp->mode != 1) /* non busmaster */ - hp100_rx(dev); - else if (!(val & HP100_RX_PDL_FILL_COMPL)) { - /* Shouldn't happen - maybe we missed a RX_PDL_FILL Interrupt? */ - hp100_rx_bm(dev); - } - } - - /* - * Ack. that we have noticed the interrupt and thereby allow next one. - * Note that this is now done after the slave rx function, since first - * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt - * on the J2573. - */ - hp100_outw(val, IRQ_STATUS); - - /* - * RX_ERROR is set when a packet is dropped due to no memory resources on - * the card or when a RCV_ERR occurs. - * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists - * only in the 802.3 MAC and happens when 16 collisions occur during a TX - */ - if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) { -#ifdef HP100_DEBUG_IRQ - printk("hp100: %s: TX/RX Error IRQ\n", dev->name); -#endif - hp100_update_stats(dev); - if (lp->mode == 1) { - hp100_rxfill(dev); - hp100_clean_txring(dev); - } - } - - /* - * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. - */ - if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO))) - hp100_rxfill(dev); - - /* - * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire - * is completed - */ - if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE))) - hp100_clean_txring(dev); - - /* - * MISC_ERROR is set when either the LAN link goes down or a detected - * bus error occurs. - */ - if (val & HP100_MISC_ERROR) { /* New for J2585B */ -#ifdef HP100_DEBUG_IRQ - printk - ("hp100: %s: Misc. Error Interrupt - Check cabling.\n", - dev->name); -#endif - if (lp->mode == 1) { - hp100_clean_txring(dev); - hp100_rxfill(dev); - } - hp100_misc_interrupt(dev); - } - - spin_unlock(&lp->lock); - hp100_ints_on(); - return IRQ_HANDLED; -} - -/* - * some misc functions - */ - -static void hp100_start_interface(struct net_device *dev) -{ - unsigned long flags; - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4220, TRACE); - printk("hp100: %s: hp100_start_interface\n", dev->name); -#endif - - spin_lock_irqsave(&lp->lock, flags); - - /* Ensure the adapter does not want to request an interrupt when */ - /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */ - hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, - OPTION_LSW); - /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ - hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW); - - if (lp->mode == 1) { - /* Make sure BM bit is set... */ - hp100_page(HW_MAP); - hp100_orb(HP100_BM_MASTER, BM); - hp100_rxfill(dev); - } else if (lp->mode == 2) { - /* Enable memory mapping. Note: Don't do this when busmaster. */ - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - } - - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* enable a few interrupts: */ - if (lp->mode == 1) { /* busmaster mode */ - hp100_outw(HP100_RX_PDL_FILL_COMPL | - HP100_RX_PDA_ZERO | HP100_RX_ERROR | - /* HP100_RX_PACKET | */ - /* HP100_RX_EARLY_INT | */ HP100_SET_HB | - /* HP100_TX_PDA_ZERO | */ - HP100_TX_COMPLETE | - /* HP100_MISC_ERROR | */ - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } else { - hp100_outw(HP100_RX_PACKET | - HP100_RX_ERROR | HP100_SET_HB | - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } - - /* Note : before hp100_set_multicast_list(), because it will play with - * spinlock itself... Jean II */ - spin_unlock_irqrestore(&lp->lock, flags); - - /* Enable MAC Tx and RX, set MAC modes, ... */ - hp100_set_multicast_list(dev); -} - -static void hp100_stop_interface(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - u_int val; - -#ifdef HP100_DEBUG_B - printk("hp100: %s: hp100_stop_interface\n", dev->name); - hp100_outw(0x4221, TRACE); -#endif - - if (lp->mode == 1) - hp100_BM_shutdown(dev); - else { - /* Note: MMAP_DIS will be reenabled by start_interface */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB | - HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, - OPTION_LSW); - val = hp100_inw(OPTION_LSW); - - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - - if (!(val & HP100_HW_RST)) - return; /* If reset, imm. return ... */ - /* ... else: busy wait until idle */ - for (val = 0; val < 6000; val++) - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE)) { - hp100_page(PERFORMANCE); - return; - } - printk("hp100: %s: hp100_stop_interface - timeout\n", dev->name); - hp100_page(PERFORMANCE); - } -} - -static void hp100_load_eeprom(struct net_device *dev, u_short probe_ioaddr) -{ - int i; - int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4222, TRACE); -#endif - - hp100_page(EEPROM_CTRL); - hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL); - hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL); - for (i = 0; i < 10000; i++) - if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD)) - return; - printk("hp100: %s: hp100_load_eeprom - timeout\n", dev->name); -} - -/* Sense connection status. - * return values: LAN_10 - Connected to 10Mbit/s network - * LAN_100 - Connected to 100Mbit/s network - * LAN_ERR - not connected or 100Mbit/s Hub down - */ -static int hp100_sense_lan(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - u_short val_VG, val_10; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4223, TRACE); -#endif - - hp100_page(MAC_CTRL); - val_10 = hp100_inb(10_LAN_CFG_1); - val_VG = hp100_inb(VG_LAN_CFG_1); - hp100_page(PERFORMANCE); -#ifdef HP100_DEBUG - printk("hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", - dev->name, val_VG, val_10); -#endif - - if (val_10 & HP100_LINK_BEAT_ST) /* 10Mb connection is active */ - return HP100_LAN_10; - - if (val_10 & HP100_AUI_ST) { /* have we BNC or AUI onboard? */ - /* - * This can be overriden by dos utility, so if this has no effect, - * perhaps you need to download that utility from HP and set card - * back to "auto detect". - */ - val_10 |= HP100_AUI_SEL | HP100_LOW_TH; - hp100_page(MAC_CTRL); - hp100_outb(val_10, 10_LAN_CFG_1); - hp100_page(PERFORMANCE); - return HP100_LAN_COAX; - } - - /* Those cards don't have a 100 Mbit connector */ - if ( !strcmp(lp->id, "HWP1920") || - (lp->pci_dev && - lp->pci_dev->vendor == PCI_VENDOR_ID && - (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A || - lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A))) - return HP100_LAN_ERR; - - if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ - return HP100_LAN_100; - return HP100_LAN_ERR; -} - -static int hp100_down_vg_link(struct net_device *dev) -{ - struct hp100_private *lp = netdev_priv(dev); - int ioaddr = dev->base_addr; - unsigned long time; - long savelan, newlan; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4224, TRACE); - printk("hp100: %s: down_vg_link\n", dev->name); -#endif - - hp100_page(MAC_CTRL); - time = jiffies + (HZ / 4); - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - - if (time_after_eq(jiffies, time)) /* no signal->no logout */ - return 0; - - /* Drop the VG Link by clearing the link up cmd and load addr. */ - - hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1); - hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1); - - /* Conditionally stall for >250ms on Link-Up Status (to go down) */ - time = jiffies + (HZ / 2); - do { - if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - -#ifdef HP100_DEBUG - if (time_after_eq(jiffies, time)) - printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name); -#endif - - /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ - /* logout under traffic (even though all the status bits are cleared), */ - /* do this workaround to get the Rev 1 MAC in its idle state */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Reset VG MAC to insure it leaves the logoff state even if */ - /* the Hub is still emitting tones */ - hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); - udelay(1500); /* wait for >1ms */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ - udelay(1500); - } - - /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ - /* to get the VG mac to full reset. This is not req.d with later chips */ - /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ - /* selected again! This will be left to the connect hub function to */ - /* perform if desired. */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Have to write to 10 and 100VG control registers simultaneously */ - savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ - newlan &= ~(HP100_VG_SEL << 16); - newlan |= (HP100_DOT3_MAC) << 8; - hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ - hp100_outl(newlan, 10_LAN_CFG_1); - - /* Conditionally stall for 5sec on VG selected. */ - time = jiffies + (HZ * 5); - do { - if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - - hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ - hp100_outl(savelan, 10_LAN_CFG_1); - } - - time = jiffies + (3 * HZ); /* Timeout 3s */ - do { - if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - - if (time_before_eq(time, jiffies)) { -#ifdef HP100_DEBUG - printk("hp100: %s: down_vg_link: timeout\n", dev->name); -#endif - return -EIO; - } - - time = jiffies + (2 * HZ); /* This seems to take a while.... */ - do { - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - - return 0; -} - -static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - u_short val = 0; - unsigned long time; - int startst; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4225, TRACE); - printk("hp100: %s: login_to_vg_hub\n", dev->name); -#endif - - /* Initiate a login sequence iff VG MAC is enabled and either Load Address - * bit is zero or the force relogin flag is set (e.g. due to MAC address or - * promiscuous mode change) - */ - hp100_page(MAC_CTRL); - startst = hp100_inb(VG_LAN_CFG_1); - if ((force_relogin == 1) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) { -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: Start training\n", dev->name); -#endif - - /* Ensure VG Reset bit is 1 (i.e., do not reset) */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); - - /* If Lassen AND auto-select-mode AND VG tones were sensed on */ - /* entry then temporarily put them into force 100Mbit mode */ - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) - hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2); - - /* Drop the VG link by zeroing Link Up Command and Load Address */ - hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1); - -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: Bring down the link\n", dev->name); -#endif - - /* Wait for link to drop */ - time = jiffies + (HZ / 10); - do { - if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - - /* Start an addressed training and optionally request promiscuous port */ - if ((dev->flags) & IFF_PROMISC) { - hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2); - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } else { - hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2); - /* For ETR parts we need to reset the prom. bit in the training - * register, otherwise promiscious mode won't be disabled. - */ - if (lp->chip == HP100_CHIPID_LASSEN) { - hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } - } - - /* With ETR parts, frame format request bits can be set. */ - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); - - hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1); - - /* Note: Next wait could be omitted for Hood and earlier chips under */ - /* certain circumstances */ - /* TODO: check if hood/earlier and skip wait. */ - - /* Wait for either short timeout for VG tones or long for login */ - /* Wait for the card hardware to signalise link cable status ok... */ - hp100_page(MAC_CTRL); - time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */ - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_before(jiffies, time)); - - if (time_after_eq(jiffies, time)) { -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: Link cable status not ok? Training aborted.\n", dev->name); -#endif - } else { -#ifdef HP100_DEBUG_TRAINING - printk - ("hp100: %s: HUB tones detected. Trying to train.\n", - dev->name); -#endif - - time = jiffies + (2 * HZ); /* again a timeout */ - do { - val = hp100_inb(VG_LAN_CFG_1); - if ((val & (HP100_LINK_UP_ST))) { -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: Passed training.\n", dev->name); -#endif - break; - } - if (!in_interrupt()) - schedule_timeout_interruptible(1); - } while (time_after(time, jiffies)); - } - - /* If LINK_UP_ST is set, then we are logged into the hub. */ - if (time_before_eq(jiffies, time) && (val & HP100_LINK_UP_ST)) { -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: Successfully logged into the HUB.\n", dev->name); - if (lp->chip == HP100_CHIPID_LASSEN) { - val = hp100_inw(TRAIN_ALLOW); - printk("hp100: %s: Card supports 100VG MAC Version \"%s\" ", - dev->name, (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre"); - printk("Driver will use MAC Version \"%s\"\n", (val & HP100_HUB_MACVER) ? "802.12" : "Pre"); - printk("hp100: %s: Frame format is %s.\n", dev->name, (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3"); - } -#endif - } else { - /* If LINK_UP_ST is not set, login was not successful */ - printk("hp100: %s: Problem logging into the HUB.\n", dev->name); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Check allowed Register to find out why there is a problem. */ - val = hp100_inw(TRAIN_ALLOW); /* won't work on non-ETR card */ -#ifdef HP100_DEBUG_TRAINING - printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val); -#endif - if (val & HP100_MALLOW_ACCDENIED) - printk("hp100: %s: HUB access denied.\n", dev->name); - if (val & HP100_MALLOW_CONFIGURE) - printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name); - if (val & HP100_MALLOW_DUPADDR) - printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name); - } - } - - /* If we have put the chip into forced 100 Mbit mode earlier, go back */ - /* to auto-select mode */ - - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) { - hp100_page(MAC_CTRL); - hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2); - } - - val = hp100_inb(VG_LAN_CFG_1); - - /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ - hp100_page(PERFORMANCE); - hp100_outw(HP100_MISC_ERROR, IRQ_STATUS); - - if (val & HP100_LINK_UP_ST) - return 0; /* login was ok */ - else { - printk("hp100: %s: Training failed.\n", dev->name); - hp100_down_vg_link(dev); - return -EIO; - } - } - /* no forced relogin & already link there->no training. */ - return -EIO; -} - -static void hp100_cascade_reset(struct net_device *dev, u_short enable) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = netdev_priv(dev); - -#ifdef HP100_DEBUG_B - hp100_outw(0x4226, TRACE); - printk("hp100: %s: cascade_reset\n", dev->name); -#endif - - if (enable) { - hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Lassen requires a PCI transmit fifo reset */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_orb(HP100_PCI_RESET, PCICTRL2); - /* Wait for min. 300 ns */ - /* we can't use jiffies here, because it may be */ - /* that we have disabled the timer... */ - udelay(400); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_page(PERFORMANCE); - } - } else { /* bring out of reset */ - hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW); - udelay(400); - hp100_page(PERFORMANCE); - } -} - -#ifdef HP100_DEBUG -void hp100_RegisterDump(struct net_device *dev) -{ - int ioaddr = dev->base_addr; - int Page; - int Register; - - /* Dump common registers */ - printk("hp100: %s: Cascade Register Dump\n", dev->name); - printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID)); - printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING)); - printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW)); - printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW)); - - /* Dump paged registers */ - for (Page = 0; Page < 8; Page++) { - /* Dump registers */ - printk("page: 0x%.2x\n", Page); - outw(Page, ioaddr + 0x02); - for (Register = 0x8; Register < 0x22; Register += 2) { - /* Display Register contents except data port */ - if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) { - printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register)); - } - } - } - hp100_page(PERFORMANCE); -} -#endif - - -static void cleanup_dev(struct net_device *d) -{ - struct hp100_private *p = netdev_priv(d); - - unregister_netdev(d); - release_region(d->base_addr, HP100_REGION_SIZE); - - if (p->mode == 1) /* busmaster */ - pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, - p->page_vaddr_algn, - virt_to_whatever(d, p->page_vaddr_algn)); - if (p->mem_ptr_virt) - iounmap(p->mem_ptr_virt); - - free_netdev(d); -} - -static int hp100_eisa_probe(struct device *gendev) -{ - struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); - struct eisa_device *edev = to_eisa_device(gendev); - int err; - - if (!dev) - return -ENOMEM; - - SET_NETDEV_DEV(dev, &edev->dev); - - err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL); - if (err) - goto out1; - -#ifdef HP100_DEBUG - printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, - dev->base_addr); -#endif - dev_set_drvdata(gendev, dev); - return 0; - out1: - free_netdev(dev); - return err; -} - -static int hp100_eisa_remove(struct device *gendev) -{ - struct net_device *dev = dev_get_drvdata(gendev); - cleanup_dev(dev); - return 0; -} - -static struct eisa_driver hp100_eisa_driver = { - .id_table = hp100_eisa_tbl, - .driver = { - .name = "hp100", - .probe = hp100_eisa_probe, - .remove = hp100_eisa_remove, - } -}; - -static int hp100_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct net_device *dev; - int ioaddr; - u_short pci_command; - int err; - - if (pci_enable_device(pdev)) - return -ENODEV; - - dev = alloc_etherdev(sizeof(struct hp100_private)); - if (!dev) { - err = -ENOMEM; - goto out0; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_IO)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); - } - - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); -#endif - pci_command |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); - } - - ioaddr = pci_resource_start(pdev, 0); - err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); - if (err) - goto out1; - -#ifdef HP100_DEBUG - printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); -#endif - pci_set_drvdata(pdev, dev); - return 0; - out1: - free_netdev(dev); - out0: - pci_disable_device(pdev); - return err; -} - -static void hp100_pci_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - cleanup_dev(dev); - pci_disable_device(pdev); -} - - -static struct pci_driver hp100_pci_driver = { - .name = "hp100", - .id_table = hp100_pci_tbl, - .probe = hp100_pci_probe, - .remove = hp100_pci_remove, -}; - -/* - * module section - */ - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jaroslav Kysela , " - "Siegfried \"Frieder\" Loeffler (dg1sek) "); -MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters"); - -/* - * Note: to register three isa devices, use: - * option hp100 hp100_port=0,0,0 - * to register one card at io 0x280 as eth239, use: - * option hp100 hp100_port=0x280 - */ -#if defined(MODULE) && defined(CONFIG_ISA) -#define HP100_DEVICES 5 -/* Parameters set by insmod */ -static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 }; -module_param_hw_array(hp100_port, int, ioport, NULL, 0); - -/* List of devices */ -static struct net_device *hp100_devlist[HP100_DEVICES]; - -static int __init hp100_isa_init(void) -{ - struct net_device *dev; - int i, err, cards = 0; - - /* Don't autoprobe ISA bus */ - if (hp100_port[0] == 0) - return -ENODEV; - - /* Loop on all possible base addresses */ - for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) { - dev = alloc_etherdev(sizeof(struct hp100_private)); - if (!dev) { - while (cards > 0) - cleanup_dev(hp100_devlist[--cards]); - - return -ENOMEM; - } - - err = hp100_isa_probe(dev, hp100_port[i]); - if (!err) - hp100_devlist[cards++] = dev; - else - free_netdev(dev); - } - - return cards > 0 ? 0 : -ENODEV; -} - -static void hp100_isa_cleanup(void) -{ - int i; - - for (i = 0; i < HP100_DEVICES; i++) { - struct net_device *dev = hp100_devlist[i]; - if (dev) - cleanup_dev(dev); - } -} -#else -#define hp100_isa_init() (0) -#define hp100_isa_cleanup() do { } while(0) -#endif - -static int __init hp100_module_init(void) -{ - int err; - - err = hp100_isa_init(); - if (err && err != -ENODEV) - goto out; - err = eisa_driver_register(&hp100_eisa_driver); - if (err && err != -ENODEV) - goto out2; - err = pci_register_driver(&hp100_pci_driver); - if (err && err != -ENODEV) - goto out3; - out: - return err; - out3: - eisa_driver_unregister (&hp100_eisa_driver); - out2: - hp100_isa_cleanup(); - goto out; -} - - -static void __exit hp100_module_exit(void) -{ - hp100_isa_cleanup(); - eisa_driver_unregister (&hp100_eisa_driver); - pci_unregister_driver (&hp100_pci_driver); -} - -module_init(hp100_module_init) -module_exit(hp100_module_exit) diff --git a/drivers/net/ethernet/hp/hp100.h b/drivers/net/ethernet/hp/hp100.h deleted file mode 100644 index 7239b94c9de5..000000000000 --- a/drivers/net/ethernet/hp/hp100.h +++ /dev/null @@ -1,611 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. - * - * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ - * - * Authors: Jaroslav Kysela, - * Siegfried Loeffler - * - * This driver is based on the 'hpfepkt' crynwr packet driver. - */ - -/**************************************************************************** - * Hardware Constants - ****************************************************************************/ - -/* - * Page Identifiers - * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02) - */ - -#define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */ -#define HP100_PAGE_MAC_ADDRESS 0x1 /* Page 1 */ -#define HP100_PAGE_HW_MAP 0x2 /* Page 2 */ -#define HP100_PAGE_EEPROM_CTRL 0x3 /* Page 3 */ -#define HP100_PAGE_MAC_CTRL 0x4 /* Page 4 */ -#define HP100_PAGE_MMU_CFG 0x5 /* Page 5 */ -#define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */ -#define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */ - - -/* Registers that are present on all pages */ - -#define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */ -#define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */ -#define HP100_REG_PAGING 0x02 /* R: (16),15:4 Card ID */ - /* W: (16),3:0 Switch pages */ -#define HP100_REG_OPTION_LSW 0x04 /* RW: (16) Select card functions */ -#define HP100_REG_OPTION_MSW 0x06 /* RW: (16) Select card functions */ - -/* Page 0 - Performance */ - -#define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */ -#define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */ -#define HP100_REG_FRAGMENT_LEN 0x0c /* W: (16)12:0 Current fragment len */ -/* Note: For 32 bit systems, fragment len and offset registers are available */ -/* at offset 0x28 and 0x2c, where they can be written as 32bit values. */ -#define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */ -#define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */ -#define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */ -#define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */ -#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */ -#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */ -#define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */ -#define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */ -#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */ -#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */ -#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */ - /* which point to a PDL */ -#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */ -#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */ -#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */ -#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */ -#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */ -#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */ -#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */ - -/* Page 1 - MAC Address/Hash Table */ - -#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */ -#define HP100_REG_HASH_BYTE0 0x10 /* RW: (8) Cards multicast filter */ - -/* Page 2 - Hardware Mapping */ - -#define HP100_REG_MEM_MAP_LSW 0x08 /* RW: (16) LSW of cards mem addr */ -#define HP100_REG_MEM_MAP_MSW 0x0a /* RW: (16) MSW of cards mem addr */ -#define HP100_REG_IO_MAP 0x0c /* RW: (8) Cards I/O address */ -#define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */ -#define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */ -#define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */ - -/* New on Page 2 for ETR chips: */ -#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */ -#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */ -#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */ -#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */ -#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */ -#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */ -#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */ -#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */ -#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */ - -/* Page 3 - EEPROM/Boot ROM */ - -#define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */ -#define HP100_REG_BOOTROM_CTRL 0x0a - -/* Page 4 - LAN Configuration (MAC_CTRL) */ - -#define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */ -#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */ -#define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */ -#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */ -#define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */ -#define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */ -#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ -#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ -#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts can't fit in mem */ -#define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */ -#define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */ -#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register. */ -#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */ - -/* Page 5 - MMU */ - -#define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */ -#define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */ -#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */ -#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */ - -/* Page 6 - Card ID/Physical LAN Address */ - -#define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */ -#define HP100_REG_BOARD_IO_CHCK 0x0c /* R: (8) Added to ID to get FFh */ -#define HP100_REG_SOFT_MODEL 0x0d /* R: (8) Config program defined */ -#define HP100_REG_LAN_ADDR 0x10 /* R: (8) MAC addr of card */ -#define HP100_REG_LAN_ADDR_CHCK 0x16 /* R: (8) Added to addr to get FFh */ - -/* Page 7 - MMU Current Pointers */ - -#define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */ -#define HP100_REG_PTR_RXEND 0x0a /* R: (16) Current end of Rx ring */ -#define HP100_REG_PTR_TXSTART 0x0c /* R: (16) Current begin of Tx ring */ -#define HP100_REG_PTR_TXEND 0x0e /* R: (16) Current end of Rx ring */ -#define HP100_REG_PTR_RPDLSTART 0x10 -#define HP100_REG_PTR_RPDLEND 0x12 -#define HP100_REG_PTR_RINGPTRS 0x14 -#define HP100_REG_PTR_MEMDEBUG 0x1a -/* ------------------------------------------------------------------------ */ - - -/* - * Hardware ID Register I (Always available, HW_ID, Offset 0x00) - */ -#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */ - -/* - * Hardware ID Register 2 & Paging Register - * (Always available, PAGING, Offset 0x02) - * Bits 15:4 are for the Chip ID - */ -#define HP100_CHIPID_MASK 0xFFF0 -#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */ - /* EISA BM/SL, MCA16/32 SL, ISA SL */ -#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM, */ - /* PCI SL, MCA16/32 SL, ISA SL */ -#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */ - /* LRF supported */ - -/* - * Option Registers I and II - * (Always available, OPTION_LSW, Offset 0x04-0x05) - */ -#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */ -#define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */ - /* system mem. before Rx interrupt */ -#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */ - /* MMAP_DIS must be 0 and MEM_EN */ - /* must be 1 for memory-mapped */ - /* mode to be enabled */ -#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */ -#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */ -#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */ -#define HP100_TRI_INT 0x0200 /* 0:Don't, 1:Do tri-state the int */ -#define HP100_MEM_EN 0x0040 /* Config program set this to */ - /* 0:Disable, 1:Enable mem map. */ - /* See MMAP_DIS. */ -#define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */ -#define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */ -#define HP100_FAKE_INT 0x0008 /* 1:int */ -#define HP100_INT_EN 0x0004 /* 1:Enable ints from card */ -#define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */ - /* NIC reset on 0 to 1 transition */ - -/* - * Option Register III - * (Always available, OPTION_MSW, Offset 0x06) - */ -#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */ -#define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */ -#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */ - /* h/w will set to 0 when done */ -#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */ - /* will set to 0 when done */ - -/* - * Interrupt Status Registers I and II - * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09) - * Note: With old chips, these Registers will clear when 1 is written to them - * with new chips this depends on setting of CLR_ISMODE - */ -#define HP100_RX_EARLY_INT 0x2000 -#define HP100_RX_PDA_ZERO 0x1000 -#define HP100_RX_PDL_FILL_COMPL 0x0800 -#define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */ -#define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */ -#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */ -#define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */ -#define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */ -#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error */ -#define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */ - -/* - * Xmit Memory Free Count - * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit) - */ -#define HP100_AUTO_COMPARE 0x80000000 /* Tx Space avail & pkts<255 */ -#define HP100_FREE_SPACE 0x7fffffe0 /* Tx free memory */ - -/* - * IRQ Channel - * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d) - */ -#define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes asserts NOWS signal */ -#define HP100_IRQ_SCRAMBLE 0x40 -#define HP100_BOND_HP 0x20 -#define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */ - /* (Only valid on EISA cards) */ -#define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */ - -/* - * SRAM Parameters - * (Page HW_MAP, SRAM, Offset 0x0e) - */ -#define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */ -#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits) */ - -/* - * Bus Master Register - * (Page HW_MAP, BM, Offset 0x0f) - */ -#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */ - /* memory to chip (tx) */ -#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */ - /* memory to chip (rx) */ -#define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */ -#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in */ - /* an EISA system */ -#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */ - - -/* - * Mode Control Register I - * (Page HW_MAP, MODECTRL1, Offset0x10) - */ -#define HP100_TX_DUALQ 0x10 - /* If set and BM -> dual tx pda queues */ -#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */ - /* interrupts on read (etr only?) */ -#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */ - /* from the eeprom */ -#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */ -#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */ - /* first three data elements of a PDL */ - /* on the first access. */ -#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */ - -/* - * Mode Control Register II - * (Page HW_MAP, MODECTRL2, Offset0x11) - */ -#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */ - /* certain resources */ -#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */ -#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */ - /* written back to system mem */ -#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */ - /* interrupt */ - -/* - * PCI Configuration and Control Register I - * (Page HW_MAP, PCICTRL1, Offset 0x12) - */ -#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */ -#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */ - /* bios */ -#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */ - /* simultaneously with PCI decodes */ -#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */ -#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */ - -/* - * PCI Configuration and Control Register II - * (Page HW_MAP, PCICTRL2, Offset 0x13) - */ -#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */ -#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */ -#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */ -#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */ -#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */ - /* pci stop if cascade not ready */ -#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity */ -#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */ - -/* - * Early TX Configuration and Control Register - * (Page HW_MAP, EARLYTXCFG, Offset 0x16) - */ -#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */ -#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */ -#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */ -#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */ -#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */ - -/* - * Early RX Configuration and Control Register - * (Page HW_MAP, EARLYRXCFG, Offset 0x18) - */ -#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */ -#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */ -#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the - * early rx circuit will start the - * dma of received packet into system - * memory for BM */ - -/* - * Serial Devices Control Register - * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08) - */ -#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */ - /* When it goes back to 0, load is */ - /* complete. This should take ~600us. */ - -/* - * 10MB LAN Control and Configuration Register I - * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08) - */ -#define HP100_MAC10_SEL 0xc0 /* Get bits to indicate MAC */ -#define HP100_AUI_SEL 0x20 /* Status of AUI selection */ -#define HP100_LOW_TH 0x10 /* 0:No, 1:Yes allow better cabling */ -#define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */ -#define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */ -#define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */ - /* been reversed */ -#define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */ - -/* - * 10 MB LAN Control and Configuration Register II - * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09) - */ -#define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */ - /* after Tx.Only used for AUI. */ -#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */ -#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */ - -/* - * MAC Selection, use with MAC10_SEL bits - */ -#define HP100_AUTO_SEL_10 0x0 /* Auto select */ -#define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */ -#define HP100_XCVR_7213 0x2 /* 7213 transceiver */ -#define HP100_XCVR_82503 0x3 /* 82503 transceiver */ - -/* - * 100MB LAN Training Register - * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12) - */ -#define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */ -#define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */ -#define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */ - /* promiscuous */ -#define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */ - /* be a cascaded repeater */ - -/* - * 100MB LAN Control and Configuration Register - * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a) - */ -#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */ -#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */ -#define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */ - /* from hub */ -#define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */ - /* 100ms later the link status */ - /* bits are valid */ -#define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */ - /* 100ms later the link status */ - /* bits are valid */ -#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */ - /* after LinkUp Cmd is given and set */ - /* when training has completed. */ -#define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */ -#define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */ - - -/* - * MAC Configuration Register I - * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c) - */ -#define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */ -#define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */ -#define HP100_RX_EN 0x20 /* 1: allow receiving of pkts */ -#define HP100_TX_EN 0x10 /* 1: allow transmitting of pkts */ -#define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */ -#define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */ -#define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */ -#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL phys. pkts */ -#define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */ -#define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */ -#define HP100_MAC1MODE2 0x00 -#define HP100_MAC1MODE3 HP100_MAC1MODE2 | HP100_ACC_BC -#define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC -#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */ -#define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */ -/* Note MODE6 will receive all GOOD packets on the LAN. This really needs - a mode 7 defined to be LAN Analyzer mode, which will receive errored and - runt packets, and keep the CRC bytes. */ -#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED - -/* - * MAC Configuration Register II - * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d) - */ -#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */ -#define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */ -#define HP100_LBK_XCVR 0x20 /* 0:No, 1:Yes loopback through MAC & */ - /* transceiver */ -#define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */ -#define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */ -#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring - * group addr that maches NA mask */ -#define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */ - /* The length will reflect this. */ -#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional - * addrs that match FA mask (page1) */ -#define HP100_MAC2MODEMASK 0x02 -#define HP100_MAC2MODE1 0x00 -#define HP100_MAC2MODE2 0x00 -#define HP100_MAC2MODE3 0x00 -#define HP100_MAC2MODE4 0x00 -#define HP100_MAC2MODE5 0x00 -#define HP100_MAC2MODE6 0x00 -#define HP100_MAC2MODE7 KEEP_CRC - -/* - * MAC Configuration Register III - * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e) - */ -#define HP100_PACKET_PACE 0x03 /* Packet Pacing: - * 00: No packet pacing - * 01: 8 to 16 uS delay - * 10: 16 to 32 uS delay - * 11: 32 to 64 uS delay - */ -#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and - * TCP/IP Checksumming enabled. */ -#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */ - -/* - * MAC Configuration Register IV - * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f) - */ -#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL - * Signal, 1=100VG, 0=10Mbit sel. */ -#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion - * of the Misc. Interrupt */ - -/* - * 100 MB LAN Training Request/Allowed Registers - * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only) - */ -#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be - * a cascaded repeater - * 0: ... wants to be a DTE */ -#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode - * 00: Rcv only unicast packets - * specifically addr to this - * endnode - * 10: Rcv all pckts fwded by - * the local repeater */ -#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */ -#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */ -#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */ -#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */ -#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an - * end node is allowed */ -#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode - * 00: Rcv only unicast packets - * specifically addr to this - * endnode - * 10: Rcv all pckts fwded by - * the local repeater */ -#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format - * 00: 802.3 format will be used - * 10: 802.5 format will be used */ -#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */ -#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */ -#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */ -#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */ - /* protocol of repeater */ - -/* ****************************************************************************** */ - -/* - * Set/Reset bits - */ -#define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */ -#define HP100_SET_LB 0x0001 /* HB sets upper byte, LB sets lower byte */ -#define HP100_RESET_HB 0x0000 /* For readability when resetting bits */ -#define HP100_RESET_LB 0x0000 /* For readability when resetting bits */ - -/* - * Misc. Constants - */ -#define HP100_LAN_100 100 /* lan_type value for VG */ -#define HP100_LAN_10 10 /* lan_type value for 10BaseT */ -#define HP100_LAN_COAX 9 /* lan_type value for Coax */ -#define HP100_LAN_ERR (-1) /* lan_type value for link down */ - -/* - * Bus Master Data Structures ---------------------------------------------- - */ - -#define MAX_RX_PDL 30 /* Card limit = 31 */ -#define MAX_RX_FRAG 2 /* Don't need more... */ -#define MAX_TX_PDL 29 -#define MAX_TX_FRAG 2 /* Limit = 31 */ - -/* Define total PDL area size in bytes (should be 4096) */ -/* This is the size of kernel (dma) memory that will be allocated. */ -#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16 - -/* Ethernet Packet Sizes */ -#define MIN_ETHER_SIZE 60 -#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */ - /* skb buffer when busmastering */ - -/* Tx or Rx Ring Entry */ -typedef struct hp100_ring { - u_int *pdl; /* Address of PDLs PDH, dword before - * this address is used for rx hdr */ - u_int pdl_paddr; /* Physical address of PDL */ - struct sk_buff *skb; - struct hp100_ring *next; -} hp100_ring_t; - - - -/* Mask for Header Descriptor */ -#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */ - - -/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED - bit in the MAC Configuration Register 1 is set. */ -#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */ -#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */ -#define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */ -#define HP100_BAD_SYMBOL_ERR 0x1000 /* 0:No, 1:Yes invalid symbol received */ -#define HP100_RCV_IPM_ERR 0x0800 /* 0:No, 1:Yes pkt had an invalid packet */ - /* marker */ -#define HP100_SYMBOL_BAL_ERR 0x0400 /* 0:No, 1:Yes symbol balance error */ -#define HP100_VG_ALN_ERR 0x0200 /* 0:No, 1:Yes non-octet received */ -#define HP100_TRUNC_ERR 0x0100 /* 0:No, 1:Yes the packet was truncated */ -#define HP100_RUNT_ERR 0x0040 /* 0:No, 1:Yes pkt length < Min Pkt */ - /* Length Reg. */ -#define HP100_ALN_ERR 0x0010 /* 0:No, 1:Yes align error. */ -#define HP100_CRC_ERR 0x0008 /* 0:No, 1:Yes CRC occurred. */ - -/* The last three bits indicate the type of destination address */ - -#define HP100_MULTI_ADDR_HASH 0x0006 /* 110: Addr multicast, matched hash */ -#define HP100_BROADCAST_ADDR 0x0003 /* x11: Addr broadcast */ -#define HP100_MULTI_ADDR_NO_HASH 0x0002 /* 010: Addr multicast, didn't match hash */ -#define HP100_PHYS_ADDR_MATCH 0x0001 /* x01: Addr was physical and mine */ -#define HP100_PHYS_ADDR_NO_MATCH 0x0000 /* x00: Addr was physical but not mine */ - -/* - * macros - */ - -#define hp100_inb( reg ) \ - inb( ioaddr + HP100_REG_##reg ) -#define hp100_inw( reg ) \ - inw( ioaddr + HP100_REG_##reg ) -#define hp100_inl( reg ) \ - inl( ioaddr + HP100_REG_##reg ) -#define hp100_outb( data, reg ) \ - outb( data, ioaddr + HP100_REG_##reg ) -#define hp100_outw( data, reg ) \ - outw( data, ioaddr + HP100_REG_##reg ) -#define hp100_outl( data, reg ) \ - outl( data, ioaddr + HP100_REG_##reg ) -#define hp100_orb( data, reg ) \ - outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg ) -#define hp100_orw( data, reg ) \ - outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg ) -#define hp100_andb( data, reg ) \ - outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg ) -#define hp100_andw( data, reg ) \ - outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg ) - -#define hp100_page( page ) \ - outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING ) -#define hp100_ints_off() \ - outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW ) -#define hp100_ints_on() \ - outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW ) -#define hp100_mem_map_enable() \ - outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW ) -#define hp100_mem_map_disable() \ - outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW ) diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 6f1fa4c849a1..333308fe807e 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig" source "drivers/staging/qlge/Kconfig" +source "drivers/staging/hp/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a90f9b308c8d..e4943cd63e98 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_USB_WUSB) += wusbcore/ obj-$(CONFIG_EXFAT_FS) += exfat/ obj-$(CONFIG_QLGE) += qlge/ +obj-$(CONFIG_NET_VENDOR_HP) += hp/ diff --git a/drivers/staging/hp/Kconfig b/drivers/staging/hp/Kconfig new file mode 100644 index 000000000000..fb395cfe6b92 --- /dev/null +++ b/drivers/staging/hp/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# HP network device configuration +# + +config NET_VENDOR_HP + bool "HP devices" + default y + depends on ISA || EISA || PCI + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about HP cards. If you say Y, you will be asked for + your specific card in the following questions. + +if NET_VENDOR_HP + +config HP100 + tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" + depends on (ISA || EISA || PCI) + ---help--- + If you have a network (Ethernet) card of this type, say Y here. + + To compile this driver as a module, choose M here. The module + will be called hp100. + +endif # NET_VENDOR_HP diff --git a/drivers/staging/hp/Makefile b/drivers/staging/hp/Makefile new file mode 100644 index 000000000000..5ed723bb11e2 --- /dev/null +++ b/drivers/staging/hp/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the HP network device drivers. +# + +obj-$(CONFIG_HP100) += hp100.o diff --git a/drivers/staging/hp/hp100.c b/drivers/staging/hp/hp100.c new file mode 100644 index 000000000000..6ec78f5c602f --- /dev/null +++ b/drivers/staging/hp/hp100.c @@ -0,0 +1,3037 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +** hp100.c +** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters +** +** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $ +** +** Based on the HP100 driver written by Jaroslav Kysela +** Extended for new busmaster capable chipsets by +** Siegfried "Frieder" Loeffler (dg1sek) +** +** Maintained by: Jaroslav Kysela +** +** This driver has only been tested with +** -- HP J2585B 10/100 Mbit/s PCI Busmaster +** -- HP J2585A 10/100 Mbit/s PCI +** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC +** -- HP J2973A 10 Mbit/s PCI 10base-T +** -- HP J2573 10/100 ISA +** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA +** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI +** +** but it should also work with the other CASCADE based adapters. +** +** TODO: +** - J2573 seems to hang sometimes when in shared memory mode. +** - Mode for Priority TX +** - Check PCI registers, performance might be improved? +** - To reduce interrupt load in busmaster, one could switch off +** the interrupts that are used to refill the queues whenever the +** queues are filled up to more than a certain threshold. +** - some updates for EISA version of card +** +** +** +** 1.57c -> 1.58 +** - used indent to change coding-style +** - added KTI DP-200 EISA ID +** - ioremap is also used for low (<1MB) memory (multi-architecture support) +** +** 1.57b -> 1.57c - Arnaldo Carvalho de Melo +** - release resources on failure in init_module +** +** 1.57 -> 1.57b - Jean II +** - fix spinlocks, SMP is now working ! +** +** 1.56 -> 1.57 +** - updates for new PCI interface for 2.1 kernels +** +** 1.55 -> 1.56 +** - removed printk in misc. interrupt and update statistics to allow +** monitoring of card status +** - timing changes in xmit routines, relogin to 100VG hub added when +** driver does reset +** - included fix for Compex FreedomLine PCI adapter +** +** 1.54 -> 1.55 +** - fixed bad initialization in init_module +** - added Compex FreedomLine adapter +** - some fixes in card initialization +** +** 1.53 -> 1.54 +** - added hardware multicast filter support (doesn't work) +** - little changes in hp100_sense_lan routine +** - added support for Coax and AUI (J2970) +** - fix for multiple cards and hp100_mode parameter (insmod) +** - fix for shared IRQ +** +** 1.52 -> 1.53 +** - fixed bug in multicast support +** +*/ + +#define HP100_DEFAULT_PRIORITY_TX 0 + +#undef HP100_DEBUG +#undef HP100_DEBUG_B /* Trace */ +#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ + +#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ +#undef HP100_DEBUG_TX +#undef HP100_DEBUG_IRQ +#undef HP100_DEBUG_RX + +#undef HP100_MULTICAST_FILTER /* Need to be debugged... */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "hp100.h" + +/* + * defines + */ + +#define HP100_BUS_ISA 0 +#define HP100_BUS_EISA 1 +#define HP100_BUS_PCI 2 + +#define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_SIG_LEN 8 /* same as EISA_SIG_LEN */ + +#define HP100_MAX_PACKET_SIZE (1536+4) +#define HP100_MIN_PACKET_SIZE 60 + +#ifndef HP100_DEFAULT_RX_RATIO +/* default - 75% onboard memory on the card are used for RX packets */ +#define HP100_DEFAULT_RX_RATIO 75 +#endif + +#ifndef HP100_DEFAULT_PRIORITY_TX +/* default - don't enable transmit outgoing packets as priority */ +#define HP100_DEFAULT_PRIORITY_TX 0 +#endif + +/* + * structures + */ + +struct hp100_private { + spinlock_t lock; + char id[HP100_SIG_LEN]; + u_short chip; + u_short soft_model; + u_int memory_size; + u_int virt_memory_size; + u_short rx_ratio; /* 1 - 99 */ + u_short priority_tx; /* != 0 - priority tx */ + u_short mode; /* PIO, Shared Mem or Busmaster */ + u_char bus; + struct pci_dev *pci_dev; + short mem_mapped; /* memory mapped access */ + void __iomem *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + unsigned long mem_ptr_phys; /* physical memory mapped area */ + short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ + int hub_status; /* was login to hub successful? */ + u_char mac1_mode; + u_char mac2_mode; + u_char hash_bytes[8]; + + /* Rings for busmaster mode: */ + hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ + hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ + hp100_ring_t *txrhead; /* Head (oldest) index into txring */ + hp100_ring_t *txrtail; /* Tail (newest) index into txring */ + + hp100_ring_t rxring[MAX_RX_PDL]; + hp100_ring_t txring[MAX_TX_PDL]; + + u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + u_long whatever_offset; /* Offset to bus/phys/dma address */ + int rxrcommit; /* # Rx PDLs committed to adapter */ + int txrcommit; /* # Tx PDLs committed to adapter */ +}; + +/* + * variables + */ +#ifdef CONFIG_ISA +static const char *hp100_isa_tbl[] = { + "HWPF150", /* HP J2573 rev A */ + "HWP1950", /* HP J2573 */ +}; +#endif + +static const struct eisa_device_id hp100_eisa_tbl[] = { + { "HWPF180" }, /* HP J2577 rev A */ + { "HWP1920" }, /* HP 27248B */ + { "HWP1940" }, /* HP J2577 */ + { "HWP1990" }, /* HP J2577 */ + { "CPX0301" }, /* ReadyLink ENET100-VG4 */ + { "CPX0401" }, /* FreedomLine 100/VG */ + { "" } /* Mandatory final entry ! */ +}; +MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl); + +static const struct pci_device_id hp100_pci_tbl[] = { + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,}, + {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,}, +/* {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */ + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, hp100_pci_tbl); + +static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; +static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; +static int hp100_mode = 1; + +module_param(hp100_rx_ratio, int, 0); +module_param(hp100_priority_tx, int, 0); +module_param(hp100_mode, int, 0); + +/* + * prototypes + */ + +static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, + struct pci_dev *pci_dev); + + +static int hp100_open(struct net_device *dev); +static int hp100_close(struct net_device *dev); +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev); +static void hp100_rx(struct net_device *dev); +static struct net_device_stats *hp100_get_stats(struct net_device *dev); +static void hp100_misc_interrupt(struct net_device *dev); +static void hp100_update_stats(struct net_device *dev); +static void hp100_clear_stats(struct hp100_private *lp, int ioaddr); +static void hp100_set_multicast_list(struct net_device *dev); +static irqreturn_t hp100_interrupt(int irq, void *dev_id); +static void hp100_start_interface(struct net_device *dev); +static void hp100_stop_interface(struct net_device *dev); +static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr); +static int hp100_sense_lan(struct net_device *dev); +static int hp100_login_to_vg_hub(struct net_device *dev, + u_short force_relogin); +static int hp100_down_vg_link(struct net_device *dev); +static void hp100_cascade_reset(struct net_device *dev, u_short enable); +static void hp100_BM_shutdown(struct net_device *dev); +static void hp100_mmuinit(struct net_device *dev); +static void hp100_init_pdls(struct net_device *dev); +static int hp100_init_rxpdl(struct net_device *dev, + register hp100_ring_t * ringptr, + register u_int * pdlptr); +static int hp100_init_txpdl(struct net_device *dev, + register hp100_ring_t * ringptr, + register u_int * pdlptr); +static void hp100_rxfill(struct net_device *dev); +static void hp100_hwinit(struct net_device *dev); +static void hp100_clean_txring(struct net_device *dev); +#ifdef HP100_DEBUG +static void hp100_RegisterDump(struct net_device *dev); +#endif + +/* Conversion to new PCI API : + * Convert an address in a kernel buffer to a bus/phys/dma address. + * This work *only* for memory fragments part of lp->page_vaddr, + * because it was properly DMA allocated via pci_alloc_consistent(), + * so we just need to "retrieve" the original mapping to bus/phys/dma + * address - Jean II */ +static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr) +{ + struct hp100_private *lp = netdev_priv(dev); + return ((u_long) ptr) + lp->whatever_offset; +} + +static inline u_int pdl_map_data(struct hp100_private *lp, void *data) +{ + return pci_map_single(lp->pci_dev, data, + MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); +} + +/* TODO: This function should not really be needed in a good design... */ +static void wait(void) +{ + mdelay(1); +} + +/* + * probe functions + * These functions should - if possible - avoid doing write operations + * since this could cause problems when the card is not installed. + */ + +/* + * Read board id and convert to string. + * Effectively same code as decode_eisa_sig + */ +static const char *hp100_read_id(int ioaddr) +{ + int i; + static char str[HP100_SIG_LEN]; + unsigned char sig[4], sum; + unsigned short rev; + + hp100_page(ID_MAC_ADDR); + sum = 0; + for (i = 0; i < 4; i++) { + sig[i] = hp100_inb(BOARD_ID + i); + sum += sig[i]; + } + + sum += hp100_inb(BOARD_ID + i); + if (sum != 0xff) + return NULL; /* bad checksum */ + + str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1); + str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1); + str[2] = (sig[1] & 0x1f) + ('A' - 1); + rev = (sig[2] << 8) | sig[3]; + sprintf(str + 3, "%04X", rev); + + return str; +} + +#ifdef CONFIG_ISA +static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) +{ + const char *sig; + int i; + + if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) + goto err; + + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { + release_region(ioaddr, HP100_REGION_SIZE); + goto err; + } + + sig = hp100_read_id(ioaddr); + release_region(ioaddr, HP100_REGION_SIZE); + + if (sig == NULL) + goto err; + + for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) { + if (!strcmp(hp100_isa_tbl[i], sig)) + break; + + } + + if (i < ARRAY_SIZE(hp100_isa_tbl)) + return hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL); + err: + return -ENODEV; + +} +/* + * Probe for ISA board. + * EISA and PCI are handled by device infrastructure. + */ + +static int __init hp100_isa_probe(struct net_device *dev, int addr) +{ + int err = -ENODEV; + + /* Probe for a specific ISA address */ + if (addr > 0xff && addr < 0x400) + err = hp100_isa_probe1(dev, addr); + + else if (addr != 0) + err = -ENXIO; + + else { + /* Probe all ISA possible port regions */ + for (addr = 0x100; addr < 0x400; addr += 0x20) { + err = hp100_isa_probe1(dev, addr); + if (!err) + break; + } + } + return err; +} +#endif /* CONFIG_ISA */ + +#if !defined(MODULE) && defined(CONFIG_ISA) +struct net_device * __init hp100_probe(int unit) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + int err; + + if (!dev) + return ERR_PTR(-ENODEV); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4200, TRACE); + printk("hp100: %s: probe\n", dev->name); +#endif + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + err = hp100_isa_probe(dev, dev->base_addr); + if (err) + goto out; + + return dev; + out: + free_netdev(dev); + return ERR_PTR(err); +} +#endif /* !MODULE && CONFIG_ISA */ + +static const struct net_device_ops hp100_bm_netdev_ops = { + .ndo_open = hp100_open, + .ndo_stop = hp100_close, + .ndo_start_xmit = hp100_start_xmit_bm, + .ndo_get_stats = hp100_get_stats, + .ndo_set_rx_mode = hp100_set_multicast_list, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +static const struct net_device_ops hp100_netdev_ops = { + .ndo_open = hp100_open, + .ndo_stop = hp100_close, + .ndo_start_xmit = hp100_start_xmit, + .ndo_get_stats = hp100_get_stats, + .ndo_set_rx_mode = hp100_set_multicast_list, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, + struct pci_dev *pci_dev) +{ + int i; + int err = -ENODEV; + const char *eid; + u_int chip; + u_char uc; + u_int memory_size = 0, virt_memory_size = 0; + u_short local_mode, lsw; + short mem_mapped; + unsigned long mem_ptr_phys; + void __iomem *mem_ptr_virt; + struct hp100_private *lp; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4201, TRACE); + printk("hp100: %s: probe1\n", dev->name); +#endif + + /* memory region for programmed i/o */ + if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100")) + goto out1; + + if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) + goto out2; + + chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; +#ifdef HP100_DEBUG + if (chip == HP100_CHIPID_SHASTA) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_RAINIER) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if (chip == HP100_CHIPID_LASSEN) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip); +#endif + + dev->base_addr = ioaddr; + + eid = hp100_read_id(ioaddr); + if (eid == NULL) { /* bad checksum? */ + printk(KERN_WARNING "%s: bad ID checksum at base port 0x%x\n", + __func__, ioaddr); + goto out2; + } + + hp100_page(ID_MAC_ADDR); + for (i = uc = 0; i < 7; i++) + uc += hp100_inb(LAN_ADDR + i); + if (uc != 0xff) { + printk(KERN_WARNING + "%s: bad lan address checksum at port 0x%x)\n", + __func__, ioaddr); + err = -EIO; + goto out2; + } + + /* Make sure, that all registers are correctly updated... */ + + hp100_load_eeprom(dev, ioaddr); + wait(); + + /* + * Determine driver operation mode + * + * Use the variable "hp100_mode" upon insmod or as kernel parameter to + * force driver modes: + * hp100_mode=1 -> default, use busmaster mode if configured. + * hp100_mode=2 -> enable shared memory mode + * hp100_mode=3 -> force use of i/o mapped mode. + * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. + */ + + /* + * LSW values: + * 0x2278 -> J2585B, PnP shared memory mode + * 0x2270 -> J2585B, shared memory mode, 0xdc000 + * 0xa23c -> J2585B, I/O mapped mode + * 0x2240 -> EISA COMPEX, BusMaster (Shasta Chip) + * 0x2220 -> EISA HP, I/O (Shasta Chip) + * 0x2260 -> EISA HP, BusMaster (Shasta Chip) + */ + +#if 0 + local_mode = 0x2270; + hp100_outw(0xfefe, OPTION_LSW); + hp100_outw(local_mode | HP100_SET_LB | HP100_SET_HB, OPTION_LSW); +#endif + + /* hp100_mode value maybe used in future by another card */ + local_mode = hp100_mode; + if (local_mode < 1 || local_mode > 4) + local_mode = 1; /* default */ +#ifdef HP100_DEBUG + printk("hp100: %s: original LSW = 0x%x\n", dev->name, + hp100_inw(OPTION_LSW)); +#endif + + if (local_mode == 3) { + hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + printk("hp100: IO mapped mode forced.\n"); + } else if (local_mode == 2) { + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + printk("hp100: Shared memory mode requested.\n"); + } else if (local_mode == 4) { + if (chip == HP100_CHIPID_LASSEN) { + hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + printk("hp100: Busmaster mode requested.\n"); + } + local_mode = 1; + } + + if (local_mode == 1) { /* default behaviour */ + lsw = hp100_inw(OPTION_LSW); + + if ((lsw & HP100_IO_EN) && (~lsw & HP100_MEM_EN) && + (~lsw & (HP100_BM_WRITE | HP100_BM_READ))) { +#ifdef HP100_DEBUG + printk("hp100: %s: IO_EN bit is set on card.\n", dev->name); +#endif + local_mode = 3; + } else if (chip == HP100_CHIPID_LASSEN && + (lsw & (HP100_BM_WRITE | HP100_BM_READ)) == (HP100_BM_WRITE | HP100_BM_READ)) { + /* Conversion to new PCI API : + * I don't have the doc, but I assume that the card + * can map the full 32bit address space. + * Also, we can have EISA Busmaster cards (not tested), + * so beware !!! - Jean II */ + if((bus == HP100_BUS_PCI) && + (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)))) { + /* Gracefully fallback to shared memory */ + goto busmasterfail; + } + printk("hp100: Busmaster mode enabled.\n"); + hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + } else { + busmasterfail: +#ifdef HP100_DEBUG + printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name); + printk("hp100: %s: Trying shared memory mode.\n", dev->name); +#endif + /* In this case, try shared memory mode */ + local_mode = 2; + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ + } + } +#ifdef HP100_DEBUG + printk("hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW)); +#endif + + /* Check for shared memory on the card, eventually remap it */ + hp100_page(HW_MAP); + mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0); + mem_ptr_phys = 0UL; + mem_ptr_virt = NULL; + memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); + virt_memory_size = 0; + + /* For memory mapped or busmaster mode, we want the memory address */ + if (mem_mapped || (local_mode == 1)) { + mem_ptr_phys = (hp100_inw(MEM_MAP_LSW) | (hp100_inw(MEM_MAP_MSW) << 16)); + mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + + if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) { + printk("hp100: Can only use programmed i/o mode.\n"); + mem_ptr_phys = 0; + mem_mapped = 0; + local_mode = 3; /* Use programmed i/o */ + } + + /* We do not need access to shared memory in busmaster mode */ + /* However in slave mode we need to remap high (>1GB) card memory */ + if (local_mode != 1) { /* = not busmaster */ + /* We try with smaller memory sizes, if ioremap fails */ + for (virt_memory_size = memory_size; virt_memory_size > 16383; virt_memory_size >>= 1) { + if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, virt_memory_size)) == NULL) { +#ifdef HP100_DEBUG + printk("hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, mem_ptr_phys); +#endif + } else { +#ifdef HP100_DEBUG + printk("hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to %p.\n", dev->name, virt_memory_size, mem_ptr_phys, mem_ptr_virt); +#endif + break; + } + } + + if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ + printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); + local_mode = 3; + virt_memory_size = 0; + } + } + } + + if (local_mode == 3) { /* io mapped forced */ + mem_mapped = 0; + mem_ptr_phys = 0; + mem_ptr_virt = NULL; + printk("hp100: Using (slow) programmed i/o mode.\n"); + } + + /* Initialise the "private" data structure for this card. */ + lp = netdev_priv(dev); + + spin_lock_init(&lp->lock); + strlcpy(lp->id, eid, HP100_SIG_LEN); + lp->chip = chip; + lp->mode = local_mode; + lp->bus = bus; + lp->pci_dev = pci_dev; + lp->priority_tx = hp100_priority_tx; + lp->rx_ratio = hp100_rx_ratio; + lp->mem_ptr_phys = mem_ptr_phys; + lp->mem_ptr_virt = mem_ptr_virt; + hp100_page(ID_MAC_ADDR); + lp->soft_model = hp100_inb(SOFT_MODEL); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset(&lp->hash_bytes, 0x00, 8); + + dev->base_addr = ioaddr; + + lp->memory_size = memory_size; + lp->virt_memory_size = virt_memory_size; + lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ + + if (lp->mode == 1) /* busmaster */ + dev->netdev_ops = &hp100_bm_netdev_ops; + else + dev->netdev_ops = &hp100_netdev_ops; + + /* Ask the card for which IRQ line it is configured */ + if (bus == HP100_BUS_PCI) { + dev->irq = pci_dev->irq; + } else { + hp100_page(HW_MAP); + dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK; + if (dev->irq == 2) + dev->irq = 9; + } + + if (lp->mode == 1) /* busmaster */ + dev->dma = 4; + + /* Ask the card for its MAC address and store it for later use. */ + hp100_page(ID_MAC_ADDR); + for (i = uc = 0; i < 6; i++) + dev->dev_addr[i] = hp100_inb(LAN_ADDR + i); + + /* Reset statistics (counters) */ + hp100_clear_stats(lp, ioaddr); + + /* If busmaster mode is wanted, a dma-capable memory area is needed for + * the rx and tx PDLs + * PCI cards can access the whole PC memory. Therefore GFP_DMA is not + * needed for the allocation of the memory area. + */ + + /* TODO: We do not need this with old cards, where PDLs are stored + * in the cards shared memory area. But currently, busmaster has been + * implemented/tested only with the lassen chip anyway... */ + if (lp->mode == 1) { /* busmaster */ + dma_addr_t page_baddr; + /* Get physically continuous memory for TX & RX PDLs */ + /* Conversion to new PCI API : + * Pages are always aligned and zeroed, no need to it ourself. + * Doc says should be OK for EISA bus as well - Jean II */ + lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr); + if (!lp->page_vaddr_algn) { + err = -ENOMEM; + goto out_mem_ptr; + } + lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn); + +#ifdef HP100_DEBUG_BM + printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", dev->name, (u_int) lp->page_vaddr_algn, (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); +#endif + lp->rxrcommit = lp->txrcommit = 0; + lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + lp->txrhead = lp->txrtail = &(lp->txring[0]); + } + + /* Initialise the card. */ + /* (I'm not really sure if it's a good idea to do this during probing, but + * like this it's assured that the lan connection type can be sensed + * correctly) + */ + hp100_hwinit(dev); + + /* Try to find out which kind of LAN the card is connected to. */ + lp->lan_type = hp100_sense_lan(dev); + + /* Print out a message what about what we think we have probed. */ + printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq); + switch (bus) { + case HP100_BUS_EISA: + printk("EISA"); + break; + case HP100_BUS_PCI: + printk("PCI"); + break; + default: + printk("ISA"); + break; + } + printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio); + + if (lp->mode == 2) { /* memory mapped */ + printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys, + (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1); + if (mem_ptr_virt) + printk(" (virtual base %p)", mem_ptr_virt); + printk(".\n"); + + /* Set for info when doing ifconfig */ + dev->mem_start = mem_ptr_phys; + dev->mem_end = mem_ptr_phys + lp->memory_size; + } + + printk("hp100: "); + if (lp->lan_type != HP100_LAN_ERR) + printk("Adapter is attached to "); + switch (lp->lan_type) { + case HP100_LAN_100: + printk("100Mb/s Voice Grade AnyLAN network.\n"); + break; + case HP100_LAN_10: + printk("10Mb/s network (10baseT).\n"); + break; + case HP100_LAN_COAX: + printk("10Mb/s network (coax).\n"); + break; + default: + printk("Warning! Link down.\n"); + } + + err = register_netdev(dev); + if (err) + goto out3; + + return 0; +out3: + if (local_mode == 1) + pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f, + lp->page_vaddr_algn, + virt_to_whatever(dev, lp->page_vaddr_algn)); +out_mem_ptr: + if (mem_ptr_virt) + iounmap(mem_ptr_virt); +out2: + release_region(ioaddr, HP100_REGION_SIZE); +out1: + return err; +} + +/* This procedure puts the card into a stable init state */ +static void hp100_hwinit(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4202, TRACE); + printk("hp100: %s: hwinit\n", dev->name); +#endif + + /* Initialise the card. -------------------------------------------- */ + + /* Clear all pending Ints and disable Ints */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */ + + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if (lp->mode == 1) { + hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */ + wait(); + } else { + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + hp100_cascade_reset(dev, 1); + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); + } + + /* Initiate EEPROM reload */ + hp100_load_eeprom(dev, 0); + + wait(); + + /* Go into reset again. */ + hp100_cascade_reset(dev, 1); + + /* Set Option Registers to a safe state */ + hp100_outw(HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | + HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB | + HP100_FAKE_INT | + HP100_INT_EN | + HP100_MEM_EN | + HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw(HP100_TRI_INT | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); + + hp100_outb(HP100_PRIORITY_TX | + HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); + + /* TODO: Configure MMU for Ram Test. */ + /* TODO: Ram Test. */ + + /* Re-check if adapter is still at same i/o location */ + /* (If the base i/o in eeprom has been changed but the */ + /* registers had not been changed, a reload of the eeprom */ + /* would move the adapter to the address stored in eeprom */ + + /* TODO: Code to implement. */ + + /* Until here it was code from HWdiscover procedure. */ + /* Next comes code from mmuinit procedure of SCO BM driver which is + * called from HWconfigure in the SCO driver. */ + + /* Initialise MMU, eventually switch on Busmaster Mode, initialise + * multicast filter... + */ + hp100_mmuinit(dev); + + /* We don't turn the interrupts on here - this is done by start_interface. */ + wait(); /* TODO: Do we really need this? */ + + /* Enable Hardware (e.g. unreset) */ + hp100_cascade_reset(dev, 0); + + /* ------- initialisation complete ----------- */ + + /* Finally try to log in the Hub if there may be a VG connection. */ + if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR)) + hp100_login_to_vg_hub(dev, 0); /* relogin */ + +} + + +/* + * mmuinit - Reinitialise Cascade MMU and MAC settings. + * Note: Must already be in reset and leaves card in reset. + */ +static void hp100_mmuinit(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + int i; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4203, TRACE); + printk("hp100: %s: mmuinit\n", dev->name); +#endif + +#ifdef HP100_DEBUG + if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { + printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n", dev->name); + return; + } +#endif + + /* Make sure IRQs are masked off and ack'ed. */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + + /* + * Enable Hardware + * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En + * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable + * - Clear Priority, Advance Pkt and Xmit Cmd + */ + + hp100_outw(HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | HP100_RESET_HB | + HP100_IO_EN | + HP100_FAKE_INT | + HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if (lp->mode == 1) { /* busmaster */ + hp100_outw(HP100_BM_WRITE | + HP100_BM_READ | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); + } else if (lp->mode == 2) { /* memory mapped */ + hp100_outw(HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); + hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); + hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + } else if (lp->mode == 3) { /* i/o mapped mode */ + hp100_outw(HP100_MMAP_DIS | HP100_SET_HB | + HP100_IO_EN | HP100_SET_LB, OPTION_LSW); + } + + hp100_page(HW_MAP); + hp100_outb(0, EARLYRXCFG); + hp100_outw(0, EARLYTXCFG); + + /* + * Enable Bus Master mode + */ + if (lp->mode == 1) { /* busmaster */ + /* Experimental: Set some PCI configuration bits */ + hp100_page(HW_MAP); + hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */ + hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */ + + /* PCI Bus failures should result in a Misc. Interrupt */ + hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2); + + hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW); + hp100_page(HW_MAP); + /* Use Burst Mode and switch on PAGE_CK */ + hp100_orb(HP100_BM_BURST_RD | HP100_BM_BURST_WR, BM); + if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) + hp100_orb(HP100_BM_PAGE_CK, BM); + hp100_orb(HP100_BM_MASTER, BM); + } else { /* not busmaster */ + + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + } + + /* + * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs + */ + hp100_page(MMU_CFG); + if (lp->mode == 1) { /* only needed for Busmaster */ + int xmit_stop, recv_stop; + + if ((lp->chip == HP100_CHIPID_RAINIER) || + (lp->chip == HP100_CHIPID_SHASTA)) { + int pdl_stop; + + /* + * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and + * 4 bytes for header). We will leave NUM_RXPDLS * 508 (rounded + * to the next higher 1k boundary) bytes for the rx-pdl's + * Note: For non-etr chips the transmit stop register must be + * programmed on a 1k boundary, i.e. bits 9:0 must be zero. + */ + pdl_stop = lp->memory_size; + xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff); + recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff); + hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP); +#ifdef HP100_DEBUG_BM + printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop); +#endif + } else { + /* ETR chip (Lassen) in busmaster mode */ + xmit_stop = (lp->memory_size) - 1; + recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff); + } + + hp100_outw(xmit_stop >> 4, TX_MEM_STOP); + hp100_outw(recv_stop >> 4, RX_MEM_STOP); +#ifdef HP100_DEBUG_BM + printk("hp100: %s: TX_STOP = 0x%x\n", dev->name, xmit_stop >> 4); + printk("hp100: %s: RX_STOP = 0x%x\n", dev->name, recv_stop >> 4); +#endif + } else { + /* Slave modes (memory mapped and programmed io) */ + hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP); + hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP); +#ifdef HP100_DEBUG + printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(TX_MEM_STOP)); + printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(RX_MEM_STOP)); +#endif + } + + /* Write MAC address into page 1 */ + hp100_page(MAC_ADDRESS); + for (i = 0; i < 6; i++) + hp100_outb(dev->dev_addr[i], MAC_ADDR + i); + + /* Zero the multicast hash registers */ + for (i = 0; i < 8; i++) + hp100_outb(0x0, HASH_BYTE0 + i); + + /* Set up MAC defaults */ + hp100_page(MAC_CTRL); + + /* Go to LAN Page and zero all filter bits */ + /* Zero accept error, accept multicast, accept broadcast and accept */ + /* all directed packet bits */ + hp100_andb(~(HP100_RX_EN | + HP100_TX_EN | + HP100_ACC_ERRORED | + HP100_ACC_MC | + HP100_ACC_BC | HP100_ACC_PHY), MAC_CFG_1); + + hp100_outb(0x00, MAC_CFG_2); + + /* Zero the frame format bit. This works around a training bug in the */ + /* new hubs. */ + hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */ + + if (lp->priority_tx) + hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW); + else + hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW); + + hp100_outb(HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); + + /* If busmaster, initialize the PDLs */ + if (lp->mode == 1) + hp100_init_pdls(dev); + + /* Go to performance page and initialize isr and imr registers */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ +} + +/* + * open/close functions + */ + +static int hp100_open(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw(0x4204, TRACE); + printk("hp100: %s: open\n", dev->name); +#endif + + /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ + if (request_irq(dev->irq, hp100_interrupt, + lp->bus == HP100_BUS_PCI || lp->bus == + HP100_BUS_EISA ? IRQF_SHARED : 0, + dev->name, dev)) { + printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq); + return -EAGAIN; + } + + netif_trans_update(dev); /* prevent tx timeout */ + netif_start_queue(dev); + + lp->lan_type = hp100_sense_lan(dev); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset(&lp->hash_bytes, 0x00, 8); + + hp100_stop_interface(dev); + + hp100_hwinit(dev); + + hp100_start_interface(dev); /* sets mac modes, enables interrupts */ + + return 0; +} + +/* The close function is called when the interface is to be brought down */ +static int hp100_close(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4205, TRACE); + printk("hp100: %s: close\n", dev->name); +#endif + + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */ + + hp100_stop_interface(dev); + + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + + netif_stop_queue(dev); + + free_irq(dev->irq, dev); + +#ifdef HP100_DEBUG + printk("hp100: %s: close LSW = 0x%x\n", dev->name, + hp100_inw(OPTION_LSW)); +#endif + + return 0; +} + + +/* + * Configure the PDL Rx rings and LAN + */ +static void hp100_init_pdls(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); + hp100_ring_t *ringptr; + u_int *pageptr; /* Warning : increment by 4 - Jean II */ + int i; + +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw(0x4206, TRACE); + printk("hp100: %s: init pdls\n", dev->name); +#endif + + if (!lp->page_vaddr_algn) + printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n", dev->name); + else { + /* pageptr shall point into the DMA accessible memory region */ + /* we use this pointer to status the upper limit of allocated */ + /* memory in the allocated page. */ + /* note: align the pointers to the pci cache line size */ + memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ + pageptr = lp->page_vaddr_algn; + + lp->rxrcommit = 0; + ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + + /* Initialise Rx Ring */ + for (i = MAX_RX_PDL - 1; i >= 0; i--) { + lp->rxring[i].next = ringptr; + ringptr = &(lp->rxring[i]); + pageptr += hp100_init_rxpdl(dev, ringptr, pageptr); + } + + /* Initialise Tx Ring */ + lp->txrcommit = 0; + ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); + for (i = MAX_TX_PDL - 1; i >= 0; i--) { + lp->txring[i].next = ringptr; + ringptr = &(lp->txring[i]); + pageptr += hp100_init_txpdl(dev, ringptr, pageptr); + } + } +} + + +/* These functions "format" the entries in the pdl structure */ +/* They return how much memory the fragments need. */ +static int hp100_init_rxpdl(struct net_device *dev, + register hp100_ring_t * ringptr, + register u32 * pdlptr) +{ + /* pdlptr is starting address for this pdl */ + + if (0 != (((unsigned long) pdlptr) & 0xf)) + printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%lx.\n", + dev->name, (unsigned long) pdlptr); + + ringptr->pdl = pdlptr + 1; + ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1); + ringptr->skb = NULL; + + /* + * Write address and length of first PDL Fragment (which is used for + * storing the RX-Header + * We use the 4 bytes _before_ the PDH in the pdl memory area to + * store this information. (PDH is at offset 0x04) + */ + /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ + + *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr); /* Address Frag 1 */ + *(pdlptr + 3) = 4; /* Length Frag 1 */ + + return roundup(MAX_RX_FRAG * 2 + 2, 4); +} + + +static int hp100_init_txpdl(struct net_device *dev, + register hp100_ring_t * ringptr, + register u32 * pdlptr) +{ + if (0 != (((unsigned long) pdlptr) & 0xf)) + printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%lx.\n", dev->name, (unsigned long) pdlptr); + + ringptr->pdl = pdlptr; /* +1; */ + ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */ + ringptr->skb = NULL; + + return roundup(MAX_TX_FRAG * 2 + 2, 4); +} + +/* + * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes + * for possible odd word alignment rounding up to next dword and set PDL + * address for fragment#2 + * Returns: 0 if unable to allocate skb_buff + * 1 if successful + */ +static int hp100_build_rx_pdl(hp100_ring_t * ringptr, + struct net_device *dev) +{ +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif +#ifdef HP100_DEBUG_BM + u_int *p; +#endif + +#ifdef HP100_DEBUG_B + hp100_outw(0x4207, TRACE); + printk("hp100: %s: build rx pdl\n", dev->name); +#endif + + /* Allocate skb buffer of maximum size */ + /* Note: This depends on the alloc_skb functions allocating more + * space than requested, i.e. aligning to 16bytes */ + + ringptr->skb = netdev_alloc_skb(dev, roundup(MAX_ETHER_SIZE + 2, 4)); + + if (NULL != ringptr->skb) { + /* + * Reserve 2 bytes at the head of the buffer to land the IP header + * on a long word boundary (According to the Network Driver section + * in the Linux KHG, this should help to increase performance.) + */ + skb_reserve(ringptr->skb, 2); + + ringptr->skb->data = skb_put(ringptr->skb, MAX_ETHER_SIZE); + + /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ + /* Note: 1st Fragment is used for the 4 byte packet status + * (receive header). Its PDL entries are set up by init_rxpdl. So + * here we only have to set up the PDL fragment entries for the data + * part. Those 4 bytes will be stored in the DMA memory region + * directly before the PDL. + */ +#ifdef HP100_DEBUG_BM + printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", + dev->name, (u_int) ringptr->pdl, + roundup(MAX_ETHER_SIZE + 2, 4), + (unsigned int) ringptr->skb->data); +#endif + + /* Conversion to new PCI API : map skbuf data to PCI bus. + * Doc says it's OK for EISA as well - Jean II */ + ringptr->pdl[0] = 0x00020000; /* Write PDH */ + ringptr->pdl[3] = pdl_map_data(netdev_priv(dev), + ringptr->skb->data); + ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ + +#ifdef HP100_DEBUG_BM + for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++) + printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n", dev->name, (u_int) p, (u_int) * p); +#endif + return 1; + } + /* else: */ + /* alloc_skb failed (no memory) -> still can receive the header + * fragment into PDL memory. make PDL safe by clearing msgptr and + * making the PDL only 1 fragment (i.e. the 4 byte packet status) + */ +#ifdef HP100_DEBUG_BM + printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", dev->name, (u_int) ringptr->pdl); +#endif + + ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */ + + return 0; +} + +/* + * hp100_rxfill - attempt to fill the Rx Ring will empty skb's + * + * Makes assumption that skb's are always contiguous memory areas and + * therefore PDLs contain only 2 physical fragments. + * - While the number of Rx PDLs with buffers is less than maximum + * a. Get a maximum packet size skb + * b. Put the physical address of the buffer into the PDL. + * c. Output physical address of PDL to adapter. + */ +static void hp100_rxfill(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + + struct hp100_private *lp = netdev_priv(dev); + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4208, TRACE); + printk("hp100: %s: rxfill\n", dev->name); +#endif + + hp100_page(PERFORMANCE); + + while (lp->rxrcommit < MAX_RX_PDL) { + /* + ** Attempt to get a buffer and build a Rx PDL. + */ + ringptr = lp->rxrtail; + if (0 == hp100_build_rx_pdl(ringptr, dev)) { + return; /* None available, return */ + } + + /* Hand this PDL over to the card */ + /* Note: This needs performance page selected! */ +#ifdef HP100_DEBUG_BM + printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", + dev->name, lp->rxrcommit, (u_int) ringptr->pdl, + (u_int) ringptr->pdl_paddr, (u_int) ringptr->pdl[3]); +#endif + + hp100_outl((u32) ringptr->pdl_paddr, RX_PDA); + + lp->rxrcommit += 1; + lp->rxrtail = ringptr->next; + } +} + +/* + * BM_shutdown - shutdown bus mastering and leave chip in reset state + */ + +static void hp100_BM_shutdown(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + unsigned long time; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4209, TRACE); + printk("hp100: %s: bm shutdown\n", dev->name); +#endif + + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */ + + /* Ensure Interrupts are off */ + hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); + + /* Disable all MAC activity */ + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ + + /* If cascade MMU is not already in reset */ + if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { + /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so + * MMU pointers will not be reset out from underneath + */ + hp100_page(MAC_CTRL); + for (time = 0; time < 5000; time++) { + if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE)) + break; + } + + /* Shutdown algorithm depends on the generation of Cascade */ + if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */ + /* Disable Busmaster mode and wait for bit to go to zero. */ + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + /* 100 ms timeout */ + for (time = 0; time < 32000; time++) { + if (0 == (hp100_inb(BM) & HP100_BM_MASTER)) + break; + } + } else { /* Shasta or Rainier Shutdown/Reset */ + /* To ensure all bus master inloading activity has ceased, + * wait for no Rx PDAs or no Rx packets on card. + */ + hp100_page(PERFORMANCE); + /* 100 ms timeout */ + for (time = 0; time < 10000; time++) { + /* RX_PDL: PDLs not executed. */ + /* RX_PKT_CNT: RX'd packets on card. */ + if ((hp100_inb(RX_PDL) == 0) && (hp100_inb(RX_PKT_CNT) == 0)) + break; + } + + if (time >= 10000) + printk("hp100: %s: BM shutdown error.\n", dev->name); + + /* To ensure all bus master outloading activity has ceased, + * wait until the Tx PDA count goes to zero or no more Tx space + * available in the Tx region of the card. + */ + /* 100 ms timeout */ + for (time = 0; time < 10000; time++) { + if ((0 == hp100_inb(TX_PKT_CNT)) && + (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE))) + break; + } + + /* Disable Busmaster mode */ + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM); + } /* end of shutdown procedure for non-etr parts */ + + hp100_cascade_reset(dev, 1); + } + hp100_page(PERFORMANCE); + /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ + /* Busmaster mode should be shut down now. */ +} + +static int hp100_check_lan(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); + + if (lp->lan_type < 0) { /* no LAN type detected yet? */ + hp100_stop_interface(dev); + if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { + printk("hp100: %s: no connection found - check wire\n", dev->name); + hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */ + return -EIO; + } + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); /* relogin */ + hp100_start_interface(dev); + } + return 0; +} + +/* + * transmit functions + */ + +/* tx function for busmaster mode */ +static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb, + struct net_device *dev) +{ + unsigned long flags; + int i, ok_flag; + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4210, TRACE); + printk("hp100: %s: start_xmit_bm\n", dev->name); +#endif + if (skb->len <= 0) + goto drop; + + if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + + /* Get Tx ring tail pointer */ + if (lp->txrtail->next == lp->txrhead) { + /* No memory. */ +#ifdef HP100_DEBUG + printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name); +#endif + /* not waited long enough since last tx? */ + if (time_before(jiffies, dev_trans_start(dev) + HZ)) + goto drop; + + if (hp100_check_lan(dev)) + goto drop; + + if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { + /* we have a 100Mb/s adapter but it isn't connected to hub */ + printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name); + hp100_stop_interface(dev); + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + } else { + spin_lock_irqsave(&lp->lock, flags); + hp100_ints_off(); /* Useful ? Jean II */ + i = hp100_sense_lan(dev); + hp100_ints_on(); + spin_unlock_irqrestore(&lp->lock, flags); + if (i == HP100_LAN_ERR) + printk("hp100: %s: link down detected\n", dev->name); + else if (lp->lan_type != i) { /* cable change! */ + /* it's very hard - all network settings must be changed!!! */ + printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); + lp->lan_type = i; + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + } else { + printk("hp100: %s: interface reset\n", dev->name); + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + } + } + + goto drop; + } + + /* + * we have to turn int's off before modifying this, otherwise + * a tx_pdl_cleanup could occur at the same time + */ + spin_lock_irqsave(&lp->lock, flags); + ringptr = lp->txrtail; + lp->txrtail = ringptr->next; + + /* Check whether packet has minimal packet size */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + ringptr->skb = skb; + ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ + if (lp->chip == HP100_CHIPID_SHASTA) { + /* TODO:Could someone who has the EISA card please check if this works? */ + ringptr->pdl[2] = i; + } else { /* Lassen */ + /* In the PDL, don't use the padded size but the real packet size: */ + ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ + } + /* Conversion to new PCI API : map skbuf data to PCI bus. + * Doc says it's OK for EISA as well - Jean II */ + ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE)); /* 1st Frag: Adr. of data */ + + /* Hand this PDL to the card. */ + hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ + + lp->txrcommit++; + + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + spin_unlock_irqrestore(&lp->lock, flags); + + return NETDEV_TX_OK; + +drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + +/* clean_txring checks if packets have been sent by the card by reading + * the TX_PDL register from the performance page and comparing it to the + * number of committed packets. It then frees the skb's of the packets that + * obviously have been sent to the network. + * + * Needs the PERFORMANCE page selected. + */ +static void hp100_clean_txring(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); + int ioaddr = dev->base_addr; + int donecount; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4211, TRACE); + printk("hp100: %s: clean txring\n", dev->name); +#endif + + /* How many PDLs have been transmitted? */ + donecount = (lp->txrcommit) - hp100_inb(TX_PDL); + +#ifdef HP100_DEBUG + if (donecount > MAX_TX_PDL) + printk("hp100: %s: Warning: More PDLs transmitted than committed to card???\n", dev->name); +#endif + + for (; 0 != donecount; donecount--) { +#ifdef HP100_DEBUG_BM + printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", + dev->name, (u_int) lp->txrhead->skb->data, + lp->txrcommit, hp100_inb(TX_PDL), donecount); +#endif + /* Conversion to new PCI API : NOP */ + pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE); + dev_consume_skb_any(lp->txrhead->skb); + lp->txrhead->skb = NULL; + lp->txrhead = lp->txrhead->next; + lp->txrcommit--; + } +} + +/* tx function for slave modes */ +static netdev_tx_t hp100_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + unsigned long flags; + int i, ok_flag; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4212, TRACE); + printk("hp100: %s: start_xmit\n", dev->name); +#endif + if (skb->len <= 0) + goto drop; + + if (hp100_check_lan(dev)) + goto drop; + + /* If there is not enough free memory on the card... */ + i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; + if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) { +#ifdef HP100_DEBUG + printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i); +#endif + /* not waited long enough since last failed tx try? */ + if (time_before(jiffies, dev_trans_start(dev) + HZ)) { +#ifdef HP100_DEBUG + printk("hp100: %s: trans_start timing problem\n", + dev->name); +#endif + goto drop; + } + if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) { + /* we have a 100Mb/s adapter but it isn't connected to hub */ + printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name); + hp100_stop_interface(dev); + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + } else { + spin_lock_irqsave(&lp->lock, flags); + hp100_ints_off(); /* Useful ? Jean II */ + i = hp100_sense_lan(dev); + hp100_ints_on(); + spin_unlock_irqrestore(&lp->lock, flags); + if (i == HP100_LAN_ERR) + printk("hp100: %s: link down detected\n", dev->name); + else if (lp->lan_type != i) { /* cable change! */ + /* it's very hard - all network setting must be changed!!! */ + printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); + lp->lan_type = i; + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + } else { + printk("hp100: %s: interface reset\n", dev->name); + hp100_stop_interface(dev); + if (lp->lan_type == HP100_LAN_100) + lp->hub_status = hp100_login_to_vg_hub(dev, 0); + hp100_start_interface(dev); + mdelay(1); + } + } + goto drop; + } + + for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { +#ifdef HP100_DEBUG_TX + printk("hp100: %s: start_xmit: busy\n", dev->name); +#endif + } + + spin_lock_irqsave(&lp->lock, flags); + hp100_ints_off(); + val = hp100_inw(IRQ_STATUS); + /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set + * when the current packet being transmitted on the wire is completed. */ + hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS); +#ifdef HP100_DEBUG_TX + printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", + dev->name, val, hp100_inw(IRQ_MASK), (int) skb->len); +#endif + + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + hp100_outw(i, DATA32); /* tell card the total packet length */ + hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ + + if (lp->mode == 2) { /* memory mapped */ + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); + if (!ok_flag) + memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); + } else { /* programmed i/o */ + outsl(ioaddr + HP100_REG_DATA32, skb->data, + (skb->len + 3) >> 2); + if (!ok_flag) + for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4) + hp100_outl(0, DATA32); + } + + hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */ + + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + hp100_ints_on(); + spin_unlock_irqrestore(&lp->lock, flags); + + dev_consume_skb_any(skb); + +#ifdef HP100_DEBUG_TX + printk("hp100: %s: start_xmit: end\n", dev->name); +#endif + + return NETDEV_TX_OK; + +drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; + +} + + +/* + * Receive Function (Non-Busmaster mode) + * Called when an "Receive Packet" interrupt occurs, i.e. the receive + * packet counter is non-zero. + * For non-busmaster, this function does the whole work of transferring + * the packet to the host memory and then up to higher layers via skb + * and netif_rx. + */ + +static void hp100_rx(struct net_device *dev) +{ + int packets, pkt_len; + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + u_int header; + struct sk_buff *skb; + +#ifdef DEBUG_B + hp100_outw(0x4213, TRACE); + printk("hp100: %s: rx\n", dev->name); +#endif + + /* First get indication of received lan packet */ + /* RX_PKT_CND indicates the number of packets which have been fully */ + /* received onto the card but have not been fully transferred of the card */ + packets = hp100_inb(RX_PKT_CNT); +#ifdef HP100_DEBUG_RX + if (packets > 1) + printk("hp100: %s: rx: waiting packets = %d\n", dev->name, packets); +#endif + + while (packets-- > 0) { + /* If ADV_NXT_PKT is still set, we have to wait until the card has */ + /* really advanced to the next packet. */ + for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); pkt_len++) { +#ifdef HP100_DEBUG_RX + printk ("hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets); +#endif + } + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + if (lp->mode == 2) { /* memory mapped mode */ + header = readl(lp->mem_ptr_virt); + } else /* programmed i/o */ + header = hp100_inl(DATA32); + + pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3; + +#ifdef HP100_DEBUG_RX + printk("hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", + dev->name, header & HP100_PKT_LEN_MASK, + (header >> 16) & 0xfff8, (header >> 16) & 7); +#endif + + /* Now we allocate the skb and transfer the data into it. */ + skb = netdev_alloc_skb(dev, pkt_len + 2); + if (skb == NULL) { /* Not enough memory->drop packet */ +#ifdef HP100_DEBUG + printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", + dev->name, pkt_len); +#endif + dev->stats.rx_dropped++; + } else { /* skb successfully allocated */ + + u_char *ptr; + + skb_reserve(skb,2); + + /* ptr to start of the sk_buff data area */ + skb_put(skb, pkt_len); + ptr = skb->data; + + /* Now transfer the data from the card into that area */ + if (lp->mode == 2) + memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len); + else /* io mapped */ + insl(ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2); + + skb->protocol = eth_type_trans(skb, dev); + +#ifdef HP100_DEBUG_RX + printk("hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + dev->name, ptr[0], ptr[1], ptr[2], ptr[3], + ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], + ptr[9], ptr[10], ptr[11]); +#endif + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + } + + /* Indicate the card that we have got the packet */ + hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW); + + switch (header & 0x00070000) { + case (HP100_MULTI_ADDR_HASH << 16): + case (HP100_MULTI_ADDR_NO_HASH << 16): + dev->stats.multicast++; + break; + } + } /* end of while(there are packets) loop */ +#ifdef HP100_DEBUG_RX + printk("hp100_rx: %s: end\n", dev->name); +#endif +} + +/* + * Receive Function for Busmaster Mode + */ +static void hp100_rx_bm(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + hp100_ring_t *ptr; + u_int header; + int pkt_len; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4214, TRACE); + printk("hp100: %s: rx_bm\n", dev->name); +#endif + +#ifdef HP100_DEBUG + if (0 == lp->rxrcommit) { + printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name); + return; + } else + /* RX_PKT_CNT states how many PDLs are currently formatted and available to + * the cards BM engine */ + if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { + printk("hp100: %s: More packets received than committed? RX_PKT_CNT=0x%x, commit=0x%x\n", + dev->name, hp100_inw(RX_PKT_CNT) & 0x00ff, + lp->rxrcommit); + return; + } +#endif + + while ((lp->rxrcommit > hp100_inb(RX_PDL))) { + /* + * The packet was received into the pdl pointed to by lp->rxrhead ( + * the oldest pdl in the ring + */ + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + + ptr = lp->rxrhead; + + header = *(ptr->pdl - 1); + pkt_len = (header & HP100_PKT_LEN_MASK); + + /* Conversion to new PCI API : NOP */ + pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE); + +#ifdef HP100_DEBUG_BM + printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", + dev->name, (u_int) (ptr->pdl - 1), (u_int) header, + pkt_len, (header >> 16) & 0xfff8, (header >> 16) & 7); + printk("hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", + dev->name, hp100_inb(RX_PDL), hp100_inb(TX_PDL), + hp100_inb(RX_PKT_CNT), (u_int) * (ptr->pdl), + (u_int) * (ptr->pdl + 3), (u_int) * (ptr->pdl + 4)); +#endif + + if ((pkt_len >= MIN_ETHER_SIZE) && + (pkt_len <= MAX_ETHER_SIZE)) { + if (ptr->skb == NULL) { + printk("hp100: %s: rx_bm: skb null\n", dev->name); + /* can happen if we only allocated room for the pdh due to memory shortage. */ + dev->stats.rx_dropped++; + } else { + skb_trim(ptr->skb, pkt_len); /* Shorten it */ + ptr->skb->protocol = + eth_type_trans(ptr->skb, dev); + + netif_rx(ptr->skb); /* Up and away... */ + + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + } + + switch (header & 0x00070000) { + case (HP100_MULTI_ADDR_HASH << 16): + case (HP100_MULTI_ADDR_NO_HASH << 16): + dev->stats.multicast++; + break; + } + } else { +#ifdef HP100_DEBUG + printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n", dev->name, pkt_len); +#endif + if (ptr->skb != NULL) + dev_kfree_skb_any(ptr->skb); + dev->stats.rx_errors++; + } + + lp->rxrhead = lp->rxrhead->next; + + /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ + if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { + /* No space for skb, header can still be received. */ +#ifdef HP100_DEBUG + printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name); +#endif + return; + } else { /* successfully allocated new PDL - put it in ringlist at tail. */ + hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); + lp->rxrtail = lp->rxrtail->next; + } + + } +} + +/* + * statistics + */ +static struct net_device_stats *hp100_get_stats(struct net_device *dev) +{ + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4215, TRACE); +#endif + + spin_lock_irqsave(&lp->lock, flags); + hp100_ints_off(); /* Useful ? Jean II */ + hp100_update_stats(dev); + hp100_ints_on(); + spin_unlock_irqrestore(&lp->lock, flags); + return &(dev->stats); +} + +static void hp100_update_stats(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + u_short val; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4216, TRACE); + printk("hp100: %s: update-stats\n", dev->name); +#endif + + /* Note: Statistics counters clear when read. */ + hp100_page(MAC_CTRL); + val = hp100_inw(DROPPED) & 0x0fff; + dev->stats.rx_errors += val; + dev->stats.rx_over_errors += val; + val = hp100_inb(CRC); + dev->stats.rx_errors += val; + dev->stats.rx_crc_errors += val; + val = hp100_inb(ABORT); + dev->stats.tx_errors += val; + dev->stats.tx_aborted_errors += val; + hp100_page(PERFORMANCE); +} + +static void hp100_misc_interrupt(struct net_device *dev) +{ +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; +#endif + +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; + hp100_outw(0x4216, TRACE); + printk("hp100: %s: misc_interrupt\n", dev->name); +#endif + + /* Note: Statistics counters clear when read. */ + dev->stats.rx_errors++; + dev->stats.tx_errors++; +} + +static void hp100_clear_stats(struct hp100_private *lp, int ioaddr) +{ + unsigned long flags; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4217, TRACE); + printk("hp100: %s: clear_stats\n", dev->name); +#endif + + spin_lock_irqsave(&lp->lock, flags); + hp100_page(MAC_CTRL); /* get all statistics bytes */ + hp100_inw(DROPPED); + hp100_inb(CRC); + hp100_inb(ABORT); + hp100_page(PERFORMANCE); + spin_unlock_irqrestore(&lp->lock, flags); +} + + +/* + * multicast setup + */ + +/* + * Set or clear the multicast filter for this adapter. + */ + +static void hp100_set_multicast_list(struct net_device *dev) +{ + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4218, TRACE); + printk("hp100: %s: set_mc_list\n", dev->name); +#endif + + spin_lock_irqsave(&lp->lock, flags); + hp100_ints_off(); + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ + + if (dev->flags & IFF_PROMISC) { + lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ + lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ + memset(&lp->hash_bytes, 0xff, 8); + } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) { + lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ + lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ +#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ + if (dev->flags & IFF_ALLMULTI) { + /* set hash filter to receive all multicast packets */ + memset(&lp->hash_bytes, 0xff, 8); + } else { + int i, idx; + u_char *addrs; + struct netdev_hw_addr *ha; + + memset(&lp->hash_bytes, 0x00, 8); +#ifdef HP100_DEBUG + printk("hp100: %s: computing hash filter - mc_count = %i\n", + dev->name, netdev_mc_count(dev)); +#endif + netdev_for_each_mc_addr(ha, dev) { + addrs = ha->addr; +#ifdef HP100_DEBUG + printk("hp100: %s: multicast = %pM, ", + dev->name, addrs); +#endif + for (i = idx = 0; i < 6; i++) { + idx ^= *addrs++ & 0x3f; + printk(":%02x:", idx); + } +#ifdef HP100_DEBUG + printk("idx = %i\n", idx); +#endif + lp->hash_bytes[idx >> 3] |= (1 << (idx & 7)); + } + } +#else + memset(&lp->hash_bytes, 0xff, 8); +#endif + } else { + lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ + lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ + memset(&lp->hash_bytes, 0x00, 8); + } + + if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || + (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { + int i; + + hp100_outb(lp->mac2_mode, MAC_CFG_2); + hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ + hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ + + hp100_page(MAC_ADDRESS); + for (i = 0; i < 8; i++) + hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i); +#ifdef HP100_DEBUG + printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, lp->mac1_mode, lp->mac2_mode, + lp->hash_bytes[0], lp->hash_bytes[1], + lp->hash_bytes[2], lp->hash_bytes[3], + lp->hash_bytes[4], lp->hash_bytes[5], + lp->hash_bytes[6], lp->hash_bytes[7]); +#endif + + if (lp->lan_type == HP100_LAN_100) { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */ + } + } else { + int i; + u_char old_hash_bytes[8]; + + hp100_page(MAC_ADDRESS); + for (i = 0; i < 8; i++) + old_hash_bytes[i] = hp100_inb(HASH_BYTE0 + i); + if (memcmp(old_hash_bytes, &lp->hash_bytes, 8)) { + for (i = 0; i < 8; i++) + hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i); +#ifdef HP100_DEBUG + printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, lp->hash_bytes[0], + lp->hash_bytes[1], lp->hash_bytes[2], + lp->hash_bytes[3], lp->hash_bytes[4], + lp->hash_bytes[5], lp->hash_bytes[6], + lp->hash_bytes[7]); +#endif + + if (lp->lan_type == HP100_LAN_100) { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */ + } + } + } + + hp100_page(MAC_CTRL); + hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ + HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */ + + hp100_page(PERFORMANCE); + hp100_ints_on(); + spin_unlock_irqrestore(&lp->lock, flags); +} + +/* + * hardware interrupt handling + */ + +static irqreturn_t hp100_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct hp100_private *lp = netdev_priv(dev); + + int ioaddr; + u_int val; + + if (dev == NULL) + return IRQ_NONE; + ioaddr = dev->base_addr; + + spin_lock(&lp->lock); + + hp100_ints_off(); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4219, TRACE); +#endif + + /* hp100_page( PERFORMANCE ); */ + val = hp100_inw(IRQ_STATUS); +#ifdef HP100_DEBUG_IRQ + printk("hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", + dev->name, lp->mode, (u_int) val, hp100_inb(RX_PKT_CNT), + hp100_inb(RX_PDL), hp100_inb(TX_PKT_CNT), hp100_inb(TX_PDL)); +#endif + + if (val == 0) { /* might be a shared interrupt */ + spin_unlock(&lp->lock); + hp100_ints_on(); + return IRQ_NONE; + } + /* We're only interested in those interrupts we really enabled. */ + /* val &= hp100_inw( IRQ_MASK ); */ + + /* + * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL + * is considered executed whenever the RX_PDL data structure is no longer + * needed. + */ + if (val & HP100_RX_PDL_FILL_COMPL) { + if (lp->mode == 1) + hp100_rx_bm(dev); + else { + printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name); + } + } + + /* + * The RX_PACKET interrupt is set, when the receive packet counter is + * non zero. We use this interrupt for receiving in slave mode. In + * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill + * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then + * we somehow have missed a rx_pdl_fill_compl interrupt. + */ + + if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */ + if (lp->mode != 1) /* non busmaster */ + hp100_rx(dev); + else if (!(val & HP100_RX_PDL_FILL_COMPL)) { + /* Shouldn't happen - maybe we missed a RX_PDL_FILL Interrupt? */ + hp100_rx_bm(dev); + } + } + + /* + * Ack. that we have noticed the interrupt and thereby allow next one. + * Note that this is now done after the slave rx function, since first + * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt + * on the J2573. + */ + hp100_outw(val, IRQ_STATUS); + + /* + * RX_ERROR is set when a packet is dropped due to no memory resources on + * the card or when a RCV_ERR occurs. + * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists + * only in the 802.3 MAC and happens when 16 collisions occur during a TX + */ + if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) { +#ifdef HP100_DEBUG_IRQ + printk("hp100: %s: TX/RX Error IRQ\n", dev->name); +#endif + hp100_update_stats(dev); + if (lp->mode == 1) { + hp100_rxfill(dev); + hp100_clean_txring(dev); + } + } + + /* + * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. + */ + if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO))) + hp100_rxfill(dev); + + /* + * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire + * is completed + */ + if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE))) + hp100_clean_txring(dev); + + /* + * MISC_ERROR is set when either the LAN link goes down or a detected + * bus error occurs. + */ + if (val & HP100_MISC_ERROR) { /* New for J2585B */ +#ifdef HP100_DEBUG_IRQ + printk + ("hp100: %s: Misc. Error Interrupt - Check cabling.\n", + dev->name); +#endif + if (lp->mode == 1) { + hp100_clean_txring(dev); + hp100_rxfill(dev); + } + hp100_misc_interrupt(dev); + } + + spin_unlock(&lp->lock); + hp100_ints_on(); + return IRQ_HANDLED; +} + +/* + * some misc functions + */ + +static void hp100_start_interface(struct net_device *dev) +{ + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4220, TRACE); + printk("hp100: %s: hp100_start_interface\n", dev->name); +#endif + + spin_lock_irqsave(&lp->lock, flags); + + /* Ensure the adapter does not want to request an interrupt when */ + /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */ + hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, + OPTION_LSW); + /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ + hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW); + + if (lp->mode == 1) { + /* Make sure BM bit is set... */ + hp100_page(HW_MAP); + hp100_orb(HP100_BM_MASTER, BM); + hp100_rxfill(dev); + } else if (lp->mode == 2) { + /* Enable memory mapping. Note: Don't do this when busmaster. */ + hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); + } + + hp100_page(PERFORMANCE); + hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ + hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + + /* enable a few interrupts: */ + if (lp->mode == 1) { /* busmaster mode */ + hp100_outw(HP100_RX_PDL_FILL_COMPL | + HP100_RX_PDA_ZERO | HP100_RX_ERROR | + /* HP100_RX_PACKET | */ + /* HP100_RX_EARLY_INT | */ HP100_SET_HB | + /* HP100_TX_PDA_ZERO | */ + HP100_TX_COMPLETE | + /* HP100_MISC_ERROR | */ + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); + } else { + hp100_outw(HP100_RX_PACKET | + HP100_RX_ERROR | HP100_SET_HB | + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); + } + + /* Note : before hp100_set_multicast_list(), because it will play with + * spinlock itself... Jean II */ + spin_unlock_irqrestore(&lp->lock, flags); + + /* Enable MAC Tx and RX, set MAC modes, ... */ + hp100_set_multicast_list(dev); +} + +static void hp100_stop_interface(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); + int ioaddr = dev->base_addr; + u_int val; + +#ifdef HP100_DEBUG_B + printk("hp100: %s: hp100_stop_interface\n", dev->name); + hp100_outw(0x4221, TRACE); +#endif + + if (lp->mode == 1) + hp100_BM_shutdown(dev); + else { + /* Note: MMAP_DIS will be reenabled by start_interface */ + hp100_outw(HP100_INT_EN | HP100_RESET_LB | + HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, + OPTION_LSW); + val = hp100_inw(OPTION_LSW); + + hp100_page(MAC_CTRL); + hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); + + if (!(val & HP100_HW_RST)) + return; /* If reset, imm. return ... */ + /* ... else: busy wait until idle */ + for (val = 0; val < 6000; val++) + if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE)) { + hp100_page(PERFORMANCE); + return; + } + printk("hp100: %s: hp100_stop_interface - timeout\n", dev->name); + hp100_page(PERFORMANCE); + } +} + +static void hp100_load_eeprom(struct net_device *dev, u_short probe_ioaddr) +{ + int i; + int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4222, TRACE); +#endif + + hp100_page(EEPROM_CTRL); + hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL); + hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL); + for (i = 0; i < 10000; i++) + if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD)) + return; + printk("hp100: %s: hp100_load_eeprom - timeout\n", dev->name); +} + +/* Sense connection status. + * return values: LAN_10 - Connected to 10Mbit/s network + * LAN_100 - Connected to 100Mbit/s network + * LAN_ERR - not connected or 100Mbit/s Hub down + */ +static int hp100_sense_lan(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + u_short val_VG, val_10; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4223, TRACE); +#endif + + hp100_page(MAC_CTRL); + val_10 = hp100_inb(10_LAN_CFG_1); + val_VG = hp100_inb(VG_LAN_CFG_1); + hp100_page(PERFORMANCE); +#ifdef HP100_DEBUG + printk("hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", + dev->name, val_VG, val_10); +#endif + + if (val_10 & HP100_LINK_BEAT_ST) /* 10Mb connection is active */ + return HP100_LAN_10; + + if (val_10 & HP100_AUI_ST) { /* have we BNC or AUI onboard? */ + /* + * This can be overriden by dos utility, so if this has no effect, + * perhaps you need to download that utility from HP and set card + * back to "auto detect". + */ + val_10 |= HP100_AUI_SEL | HP100_LOW_TH; + hp100_page(MAC_CTRL); + hp100_outb(val_10, 10_LAN_CFG_1); + hp100_page(PERFORMANCE); + return HP100_LAN_COAX; + } + + /* Those cards don't have a 100 Mbit connector */ + if ( !strcmp(lp->id, "HWP1920") || + (lp->pci_dev && + lp->pci_dev->vendor == PCI_VENDOR_ID && + (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A || + lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A))) + return HP100_LAN_ERR; + + if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ + return HP100_LAN_100; + return HP100_LAN_ERR; +} + +static int hp100_down_vg_link(struct net_device *dev) +{ + struct hp100_private *lp = netdev_priv(dev); + int ioaddr = dev->base_addr; + unsigned long time; + long savelan, newlan; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4224, TRACE); + printk("hp100: %s: down_vg_link\n", dev->name); +#endif + + hp100_page(MAC_CTRL); + time = jiffies + (HZ / 4); + do { + if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + + if (time_after_eq(jiffies, time)) /* no signal->no logout */ + return 0; + + /* Drop the VG Link by clearing the link up cmd and load addr. */ + + hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1); + hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1); + + /* Conditionally stall for >250ms on Link-Up Status (to go down) */ + time = jiffies + (HZ / 2); + do { + if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + +#ifdef HP100_DEBUG + if (time_after_eq(jiffies, time)) + printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name); +#endif + + /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ + /* logout under traffic (even though all the status bits are cleared), */ + /* do this workaround to get the Rev 1 MAC in its idle state */ + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Reset VG MAC to insure it leaves the logoff state even if */ + /* the Hub is still emitting tones */ + hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); + udelay(1500); /* wait for >1ms */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ + udelay(1500); + } + + /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ + /* to get the VG mac to full reset. This is not req.d with later chips */ + /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ + /* selected again! This will be left to the connect hub function to */ + /* perform if desired. */ + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Have to write to 10 and 100VG control registers simultaneously */ + savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ + newlan &= ~(HP100_VG_SEL << 16); + newlan |= (HP100_DOT3_MAC) << 8; + hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ + hp100_outl(newlan, 10_LAN_CFG_1); + + /* Conditionally stall for 5sec on VG selected. */ + time = jiffies + (HZ * 5); + do { + if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + + hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ + hp100_outl(savelan, 10_LAN_CFG_1); + } + + time = jiffies + (3 * HZ); /* Timeout 3s */ + do { + if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + + if (time_before_eq(time, jiffies)) { +#ifdef HP100_DEBUG + printk("hp100: %s: down_vg_link: timeout\n", dev->name); +#endif + return -EIO; + } + + time = jiffies + (2 * HZ); /* This seems to take a while.... */ + do { + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + + return 0; +} + +static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + u_short val = 0; + unsigned long time; + int startst; + +#ifdef HP100_DEBUG_B + hp100_outw(0x4225, TRACE); + printk("hp100: %s: login_to_vg_hub\n", dev->name); +#endif + + /* Initiate a login sequence iff VG MAC is enabled and either Load Address + * bit is zero or the force relogin flag is set (e.g. due to MAC address or + * promiscuous mode change) + */ + hp100_page(MAC_CTRL); + startst = hp100_inb(VG_LAN_CFG_1); + if ((force_relogin == 1) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) { +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: Start training\n", dev->name); +#endif + + /* Ensure VG Reset bit is 1 (i.e., do not reset) */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); + + /* If Lassen AND auto-select-mode AND VG tones were sensed on */ + /* entry then temporarily put them into force 100Mbit mode */ + if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) + hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2); + + /* Drop the VG link by zeroing Link Up Command and Load Address */ + hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1); + +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: Bring down the link\n", dev->name); +#endif + + /* Wait for link to drop */ + time = jiffies + (HZ / 10); + do { + if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + + /* Start an addressed training and optionally request promiscuous port */ + if ((dev->flags) & IFF_PROMISC) { + hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2); + if (lp->chip == HP100_CHIPID_LASSEN) + hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST); + } else { + hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2); + /* For ETR parts we need to reset the prom. bit in the training + * register, otherwise promiscious mode won't be disabled. + */ + if (lp->chip == HP100_CHIPID_LASSEN) { + hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST); + } + } + + /* With ETR parts, frame format request bits can be set. */ + if (lp->chip == HP100_CHIPID_LASSEN) + hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); + + hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1); + + /* Note: Next wait could be omitted for Hood and earlier chips under */ + /* certain circumstances */ + /* TODO: check if hood/earlier and skip wait. */ + + /* Wait for either short timeout for VG tones or long for login */ + /* Wait for the card hardware to signalise link cable status ok... */ + hp100_page(MAC_CTRL); + time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */ + do { + if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) + break; + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_before(jiffies, time)); + + if (time_after_eq(jiffies, time)) { +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: Link cable status not ok? Training aborted.\n", dev->name); +#endif + } else { +#ifdef HP100_DEBUG_TRAINING + printk + ("hp100: %s: HUB tones detected. Trying to train.\n", + dev->name); +#endif + + time = jiffies + (2 * HZ); /* again a timeout */ + do { + val = hp100_inb(VG_LAN_CFG_1); + if ((val & (HP100_LINK_UP_ST))) { +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: Passed training.\n", dev->name); +#endif + break; + } + if (!in_interrupt()) + schedule_timeout_interruptible(1); + } while (time_after(time, jiffies)); + } + + /* If LINK_UP_ST is set, then we are logged into the hub. */ + if (time_before_eq(jiffies, time) && (val & HP100_LINK_UP_ST)) { +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: Successfully logged into the HUB.\n", dev->name); + if (lp->chip == HP100_CHIPID_LASSEN) { + val = hp100_inw(TRAIN_ALLOW); + printk("hp100: %s: Card supports 100VG MAC Version \"%s\" ", + dev->name, (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre"); + printk("Driver will use MAC Version \"%s\"\n", (val & HP100_HUB_MACVER) ? "802.12" : "Pre"); + printk("hp100: %s: Frame format is %s.\n", dev->name, (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3"); + } +#endif + } else { + /* If LINK_UP_ST is not set, login was not successful */ + printk("hp100: %s: Problem logging into the HUB.\n", dev->name); + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Check allowed Register to find out why there is a problem. */ + val = hp100_inw(TRAIN_ALLOW); /* won't work on non-ETR card */ +#ifdef HP100_DEBUG_TRAINING + printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val); +#endif + if (val & HP100_MALLOW_ACCDENIED) + printk("hp100: %s: HUB access denied.\n", dev->name); + if (val & HP100_MALLOW_CONFIGURE) + printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name); + if (val & HP100_MALLOW_DUPADDR) + printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name); + } + } + + /* If we have put the chip into forced 100 Mbit mode earlier, go back */ + /* to auto-select mode */ + + if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) { + hp100_page(MAC_CTRL); + hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2); + } + + val = hp100_inb(VG_LAN_CFG_1); + + /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ + hp100_page(PERFORMANCE); + hp100_outw(HP100_MISC_ERROR, IRQ_STATUS); + + if (val & HP100_LINK_UP_ST) + return 0; /* login was ok */ + else { + printk("hp100: %s: Training failed.\n", dev->name); + hp100_down_vg_link(dev); + return -EIO; + } + } + /* no forced relogin & already link there->no training. */ + return -EIO; +} + +static void hp100_cascade_reset(struct net_device *dev, u_short enable) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = netdev_priv(dev); + +#ifdef HP100_DEBUG_B + hp100_outw(0x4226, TRACE); + printk("hp100: %s: cascade_reset\n", dev->name); +#endif + + if (enable) { + hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW); + if (lp->chip == HP100_CHIPID_LASSEN) { + /* Lassen requires a PCI transmit fifo reset */ + hp100_page(HW_MAP); + hp100_andb(~HP100_PCI_RESET, PCICTRL2); + hp100_orb(HP100_PCI_RESET, PCICTRL2); + /* Wait for min. 300 ns */ + /* we can't use jiffies here, because it may be */ + /* that we have disabled the timer... */ + udelay(400); + hp100_andb(~HP100_PCI_RESET, PCICTRL2); + hp100_page(PERFORMANCE); + } + } else { /* bring out of reset */ + hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW); + udelay(400); + hp100_page(PERFORMANCE); + } +} + +#ifdef HP100_DEBUG +void hp100_RegisterDump(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + int Page; + int Register; + + /* Dump common registers */ + printk("hp100: %s: Cascade Register Dump\n", dev->name); + printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID)); + printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING)); + printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW)); + printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW)); + + /* Dump paged registers */ + for (Page = 0; Page < 8; Page++) { + /* Dump registers */ + printk("page: 0x%.2x\n", Page); + outw(Page, ioaddr + 0x02); + for (Register = 0x8; Register < 0x22; Register += 2) { + /* Display Register contents except data port */ + if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) { + printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register)); + } + } + } + hp100_page(PERFORMANCE); +} +#endif + + +static void cleanup_dev(struct net_device *d) +{ + struct hp100_private *p = netdev_priv(d); + + unregister_netdev(d); + release_region(d->base_addr, HP100_REGION_SIZE); + + if (p->mode == 1) /* busmaster */ + pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f, + p->page_vaddr_algn, + virt_to_whatever(d, p->page_vaddr_algn)); + if (p->mem_ptr_virt) + iounmap(p->mem_ptr_virt); + + free_netdev(d); +} + +static int hp100_eisa_probe(struct device *gendev) +{ + struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); + struct eisa_device *edev = to_eisa_device(gendev); + int err; + + if (!dev) + return -ENOMEM; + + SET_NETDEV_DEV(dev, &edev->dev); + + err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL); + if (err) + goto out1; + +#ifdef HP100_DEBUG + printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name, + dev->base_addr); +#endif + dev_set_drvdata(gendev, dev); + return 0; + out1: + free_netdev(dev); + return err; +} + +static int hp100_eisa_remove(struct device *gendev) +{ + struct net_device *dev = dev_get_drvdata(gendev); + cleanup_dev(dev); + return 0; +} + +static struct eisa_driver hp100_eisa_driver = { + .id_table = hp100_eisa_tbl, + .driver = { + .name = "hp100", + .probe = hp100_eisa_probe, + .remove = hp100_eisa_remove, + } +}; + +static int hp100_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + int ioaddr; + u_short pci_command; + int err; + + if (pci_enable_device(pdev)) + return -ENODEV; + + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + err = -ENOMEM; + goto out0; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + if (!(pci_command & PCI_COMMAND_IO)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_IO; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + if (!(pci_command & PCI_COMMAND_MASTER)) { +#ifdef HP100_DEBUG + printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name); +#endif + pci_command |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, pci_command); + } + + ioaddr = pci_resource_start(pdev, 0); + err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev); + if (err) + goto out1; + +#ifdef HP100_DEBUG + printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr); +#endif + pci_set_drvdata(pdev, dev); + return 0; + out1: + free_netdev(dev); + out0: + pci_disable_device(pdev); + return err; +} + +static void hp100_pci_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + cleanup_dev(dev); + pci_disable_device(pdev); +} + + +static struct pci_driver hp100_pci_driver = { + .name = "hp100", + .id_table = hp100_pci_tbl, + .probe = hp100_pci_probe, + .remove = hp100_pci_remove, +}; + +/* + * module section + */ + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jaroslav Kysela , " + "Siegfried \"Frieder\" Loeffler (dg1sek) "); +MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters"); + +/* + * Note: to register three isa devices, use: + * option hp100 hp100_port=0,0,0 + * to register one card at io 0x280 as eth239, use: + * option hp100 hp100_port=0x280 + */ +#if defined(MODULE) && defined(CONFIG_ISA) +#define HP100_DEVICES 5 +/* Parameters set by insmod */ +static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 }; +module_param_hw_array(hp100_port, int, ioport, NULL, 0); + +/* List of devices */ +static struct net_device *hp100_devlist[HP100_DEVICES]; + +static int __init hp100_isa_init(void) +{ + struct net_device *dev; + int i, err, cards = 0; + + /* Don't autoprobe ISA bus */ + if (hp100_port[0] == 0) + return -ENODEV; + + /* Loop on all possible base addresses */ + for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) { + dev = alloc_etherdev(sizeof(struct hp100_private)); + if (!dev) { + while (cards > 0) + cleanup_dev(hp100_devlist[--cards]); + + return -ENOMEM; + } + + err = hp100_isa_probe(dev, hp100_port[i]); + if (!err) + hp100_devlist[cards++] = dev; + else + free_netdev(dev); + } + + return cards > 0 ? 0 : -ENODEV; +} + +static void hp100_isa_cleanup(void) +{ + int i; + + for (i = 0; i < HP100_DEVICES; i++) { + struct net_device *dev = hp100_devlist[i]; + if (dev) + cleanup_dev(dev); + } +} +#else +#define hp100_isa_init() (0) +#define hp100_isa_cleanup() do { } while(0) +#endif + +static int __init hp100_module_init(void) +{ + int err; + + err = hp100_isa_init(); + if (err && err != -ENODEV) + goto out; + err = eisa_driver_register(&hp100_eisa_driver); + if (err && err != -ENODEV) + goto out2; + err = pci_register_driver(&hp100_pci_driver); + if (err && err != -ENODEV) + goto out3; + out: + return err; + out3: + eisa_driver_unregister (&hp100_eisa_driver); + out2: + hp100_isa_cleanup(); + goto out; +} + + +static void __exit hp100_module_exit(void) +{ + hp100_isa_cleanup(); + eisa_driver_unregister (&hp100_eisa_driver); + pci_unregister_driver (&hp100_pci_driver); +} + +module_init(hp100_module_init) +module_exit(hp100_module_exit) diff --git a/drivers/staging/hp/hp100.h b/drivers/staging/hp/hp100.h new file mode 100644 index 000000000000..7239b94c9de5 --- /dev/null +++ b/drivers/staging/hp/hp100.h @@ -0,0 +1,611 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. + * + * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ + * + * Authors: Jaroslav Kysela, + * Siegfried Loeffler + * + * This driver is based on the 'hpfepkt' crynwr packet driver. + */ + +/**************************************************************************** + * Hardware Constants + ****************************************************************************/ + +/* + * Page Identifiers + * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02) + */ + +#define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */ +#define HP100_PAGE_MAC_ADDRESS 0x1 /* Page 1 */ +#define HP100_PAGE_HW_MAP 0x2 /* Page 2 */ +#define HP100_PAGE_EEPROM_CTRL 0x3 /* Page 3 */ +#define HP100_PAGE_MAC_CTRL 0x4 /* Page 4 */ +#define HP100_PAGE_MMU_CFG 0x5 /* Page 5 */ +#define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */ +#define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */ + + +/* Registers that are present on all pages */ + +#define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */ +#define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */ +#define HP100_REG_PAGING 0x02 /* R: (16),15:4 Card ID */ + /* W: (16),3:0 Switch pages */ +#define HP100_REG_OPTION_LSW 0x04 /* RW: (16) Select card functions */ +#define HP100_REG_OPTION_MSW 0x06 /* RW: (16) Select card functions */ + +/* Page 0 - Performance */ + +#define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */ +#define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */ +#define HP100_REG_FRAGMENT_LEN 0x0c /* W: (16)12:0 Current fragment len */ +/* Note: For 32 bit systems, fragment len and offset registers are available */ +/* at offset 0x28 and 0x2c, where they can be written as 32bit values. */ +#define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */ +#define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */ +#define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */ +#define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */ +#define HP100_REG_TX_PDA_L 0x14 /* W: (32) BM: Ptr to PDL, Low Pri */ +#define HP100_REG_TX_PDA_H 0x1c /* W: (32) BM: Ptr to PDL, High Pri */ +#define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */ +#define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */ +#define HP100_REG_RX_PDL 0x1a /* R: (8) BM: # rx pdl not executed */ +#define HP100_REG_TX_PDL 0x1b /* R: (8) BM: # tx pdl not executed */ +#define HP100_REG_RX_PDA 0x18 /* W: (32) BM: Up to 31 addresses */ + /* which point to a PDL */ +#define HP100_REG_SL_EARLY 0x1c /* (32) Enhanced Slave Early Rx */ +#define HP100_REG_STAT_DROPPED 0x20 /* R (12) Dropped Packet Counter */ +#define HP100_REG_STAT_ERRORED 0x22 /* R (8) Errored Packet Counter */ +#define HP100_REG_STAT_ABORT 0x23 /* R (8) Abort Counter/OW Coll. Flag */ +#define HP100_REG_RX_RING 0x24 /* W (32) Slave: RX Ring Pointers */ +#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */ +#define HP100_REG_32_OFFSET 0x2c /* W (16) Slave: Offset Register */ + +/* Page 1 - MAC Address/Hash Table */ + +#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */ +#define HP100_REG_HASH_BYTE0 0x10 /* RW: (8) Cards multicast filter */ + +/* Page 2 - Hardware Mapping */ + +#define HP100_REG_MEM_MAP_LSW 0x08 /* RW: (16) LSW of cards mem addr */ +#define HP100_REG_MEM_MAP_MSW 0x0a /* RW: (16) MSW of cards mem addr */ +#define HP100_REG_IO_MAP 0x0c /* RW: (8) Cards I/O address */ +#define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */ +#define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */ +#define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */ + +/* New on Page 2 for ETR chips: */ +#define HP100_REG_MODECTRL1 0x10 /* RW: (8) Mode Control 1 */ +#define HP100_REG_MODECTRL2 0x11 /* RW: (8) Mode Control 2 */ +#define HP100_REG_PCICTRL1 0x12 /* RW: (8) PCI Cfg 1 */ +#define HP100_REG_PCICTRL2 0x13 /* RW: (8) PCI Cfg 2 */ +#define HP100_REG_PCIBUSMLAT 0x15 /* RW: (8) PCI Bus Master Latency */ +#define HP100_REG_EARLYTXCFG 0x16 /* RW: (16) Early TX Cfg/Cntrl Reg */ +#define HP100_REG_EARLYRXCFG 0x18 /* RW: (8) Early RX Cfg/Cntrl Reg */ +#define HP100_REG_ISAPNPCFG1 0x1a /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */ +#define HP100_REG_ISAPNPCFG2 0x1b /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */ + +/* Page 3 - EEPROM/Boot ROM */ + +#define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */ +#define HP100_REG_BOOTROM_CTRL 0x0a + +/* Page 4 - LAN Configuration (MAC_CTRL) */ + +#define HP100_REG_10_LAN_CFG_1 0x08 /* RW: (8) Set 10M XCVR functions */ +#define HP100_REG_10_LAN_CFG_2 0x09 /* RW: (8) 10M XCVR functions */ +#define HP100_REG_VG_LAN_CFG_1 0x0a /* RW: (8) Set 100M XCVR functions */ +#define HP100_REG_VG_LAN_CFG_2 0x0b /* RW: (8) 100M LAN Training cfgregs */ +#define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */ +#define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */ +#define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ +#define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ +#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts can't fit in mem */ +#define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */ +#define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */ +#define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register. */ +#define HP100_REG_TRAIN_ALLOW 0x16 /* R: (16) Hub allowed register */ + +/* Page 5 - MMU */ + +#define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */ +#define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */ +#define HP100_REG_PDL_MEM_STOP 0x10 /* Not used by 802.12 devices */ +#define HP100_REG_ECB_MEM_STOP 0x14 /* I've no idea what this is */ + +/* Page 6 - Card ID/Physical LAN Address */ + +#define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */ +#define HP100_REG_BOARD_IO_CHCK 0x0c /* R: (8) Added to ID to get FFh */ +#define HP100_REG_SOFT_MODEL 0x0d /* R: (8) Config program defined */ +#define HP100_REG_LAN_ADDR 0x10 /* R: (8) MAC addr of card */ +#define HP100_REG_LAN_ADDR_CHCK 0x16 /* R: (8) Added to addr to get FFh */ + +/* Page 7 - MMU Current Pointers */ + +#define HP100_REG_PTR_RXSTART 0x08 /* R: (16) Current begin of Rx ring */ +#define HP100_REG_PTR_RXEND 0x0a /* R: (16) Current end of Rx ring */ +#define HP100_REG_PTR_TXSTART 0x0c /* R: (16) Current begin of Tx ring */ +#define HP100_REG_PTR_TXEND 0x0e /* R: (16) Current end of Rx ring */ +#define HP100_REG_PTR_RPDLSTART 0x10 +#define HP100_REG_PTR_RPDLEND 0x12 +#define HP100_REG_PTR_RINGPTRS 0x14 +#define HP100_REG_PTR_MEMDEBUG 0x1a +/* ------------------------------------------------------------------------ */ + + +/* + * Hardware ID Register I (Always available, HW_ID, Offset 0x00) + */ +#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */ + +/* + * Hardware ID Register 2 & Paging Register + * (Always available, PAGING, Offset 0x02) + * Bits 15:4 are for the Chip ID + */ +#define HP100_CHIPID_MASK 0xFFF0 +#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */ + /* EISA BM/SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_RAINIER 0x5360 /* Not 802.12 compliant EISA BM, */ + /* PCI SL, MCA16/32 SL, ISA SL */ +#define HP100_CHIPID_LASSEN 0x5370 /* 802.12 compliant PCI BM, PCI SL */ + /* LRF supported */ + +/* + * Option Registers I and II + * (Always available, OPTION_LSW, Offset 0x04-0x05) + */ +#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */ +#define HP100_RX_HDR 0x4000 /* 0:Dis., 1:Enable putting pkt into */ + /* system mem. before Rx interrupt */ +#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable mem.mapping. */ + /* MMAP_DIS must be 0 and MEM_EN */ + /* must be 1 for memory-mapped */ + /* mode to be enabled */ +#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */ +#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */ +#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */ +#define HP100_TRI_INT 0x0200 /* 0:Don't, 1:Do tri-state the int */ +#define HP100_MEM_EN 0x0040 /* Config program set this to */ + /* 0:Disable, 1:Enable mem map. */ + /* See MMAP_DIS. */ +#define HP100_IO_EN 0x0020 /* 1:Enable I/O transfers */ +#define HP100_BOOT_EN 0x0010 /* 1:Enable boot ROM access */ +#define HP100_FAKE_INT 0x0008 /* 1:int */ +#define HP100_INT_EN 0x0004 /* 1:Enable ints from card */ +#define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */ + /* NIC reset on 0 to 1 transition */ + +/* + * Option Register III + * (Always available, OPTION_MSW, Offset 0x06) + */ +#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */ +#define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */ +#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue */ + /* h/w will set to 0 when done */ +#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w */ + /* will set to 0 when done */ + +/* + * Interrupt Status Registers I and II + * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09) + * Note: With old chips, these Registers will clear when 1 is written to them + * with new chips this depends on setting of CLR_ISMODE + */ +#define HP100_RX_EARLY_INT 0x2000 +#define HP100_RX_PDA_ZERO 0x1000 +#define HP100_RX_PDL_FILL_COMPL 0x0800 +#define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */ +#define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */ +#define HP100_TX_PDA_ZERO 0x0020 /* 1 when PDA count goes to zero */ +#define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */ +#define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */ +#define HP100_MISC_ERROR 0x0004 /* 0:No, 1:Lan Link down or bus error */ +#define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */ + +/* + * Xmit Memory Free Count + * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit) + */ +#define HP100_AUTO_COMPARE 0x80000000 /* Tx Space avail & pkts<255 */ +#define HP100_FREE_SPACE 0x7fffffe0 /* Tx free memory */ + +/* + * IRQ Channel + * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d) + */ +#define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes asserts NOWS signal */ +#define HP100_IRQ_SCRAMBLE 0x40 +#define HP100_BOND_HP 0x20 +#define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */ + /* (Only valid on EISA cards) */ +#define HP100_IRQMASK 0x0F /* Isolate the IRQ bits */ + +/* + * SRAM Parameters + * (Page HW_MAP, SRAM, Offset 0x0e) + */ +#define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */ +#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count(put index in lwr bits) */ + +/* + * Bus Master Register + * (Page HW_MAP, BM, Offset 0x0f) + */ +#define HP100_BM_BURST_RD 0x01 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (tx) */ +#define HP100_BM_BURST_WR 0x02 /* EISA only: 1=Use burst trans. fm system */ + /* memory to chip (rx) */ +#define HP100_BM_MASTER 0x04 /* 0:Slave, 1:BM mode */ +#define HP100_BM_PAGE_CK 0x08 /* This bit should be set whenever in */ + /* an EISA system */ +#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */ + + +/* + * Mode Control Register I + * (Page HW_MAP, MODECTRL1, Offset0x10) + */ +#define HP100_TX_DUALQ 0x10 + /* If set and BM -> dual tx pda queues */ +#define HP100_ISR_CLRMODE 0x02 /* If set ISR will clear all pending */ + /* interrupts on read (etr only?) */ +#define HP100_EE_NOLOAD 0x04 /* Status whether res will be loaded */ + /* from the eeprom */ +#define HP100_TX_CNT_FLG 0x08 /* Controls Early TX Reg Cnt Field */ +#define HP100_PDL_USE3 0x10 /* If set BM engine will read only */ + /* first three data elements of a PDL */ + /* on the first access. */ +#define HP100_BUSTYPE_MASK 0xe0 /* Three bit bus type info */ + +/* + * Mode Control Register II + * (Page HW_MAP, MODECTRL2, Offset0x11) + */ +#define HP100_EE_MASK 0x0f /* Tell EEPROM circuit not to load */ + /* certain resources */ +#define HP100_DIS_CANCEL 0x20 /* For tx dualq mode operation */ +#define HP100_EN_PDL_WB 0x40 /* 1: Status of PDL completion may be */ + /* written back to system mem */ +#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */ + /* interrupt */ + +/* + * PCI Configuration and Control Register I + * (Page HW_MAP, PCICTRL1, Offset 0x12) + */ +#define HP100_LO_MEM 0x01 /* 1: Mapped Mem requested below 1MB */ +#define HP100_NO_MEM 0x02 /* 1: Disables Req for sysmem to PCI */ + /* bios */ +#define HP100_USE_ISA 0x04 /* 1: isa type decodes will occur */ + /* simultaneously with PCI decodes */ +#define HP100_IRQ_HI_MASK 0xf0 /* pgmed by pci bios */ +#define HP100_PCI_IRQ_HI_MASK 0x78 /* Isolate 4 bits for PCI IRQ */ + +/* + * PCI Configuration and Control Register II + * (Page HW_MAP, PCICTRL2, Offset 0x13) + */ +#define HP100_RD_LINE_PDL 0x01 /* 1: PCI command Memory Read Line en */ +#define HP100_RD_TX_DATA_MASK 0x06 /* choose PCI memread cmds for TX */ +#define HP100_MWI 0x08 /* 1: en. PCI memory write invalidate */ +#define HP100_ARB_MODE 0x10 /* Select PCI arbitor type */ +#define HP100_STOP_EN 0x20 /* Enables PCI state machine to issue */ + /* pci stop if cascade not ready */ +#define HP100_IGNORE_PAR 0x40 /* 1: PCI state machine ignores parity */ +#define HP100_PCI_RESET 0x80 /* 0->1: Reset PCI block */ + +/* + * Early TX Configuration and Control Register + * (Page HW_MAP, EARLYTXCFG, Offset 0x16) + */ +#define HP100_EN_EARLY_TX 0x8000 /* 1=Enable Early TX */ +#define HP100_EN_ADAPTIVE 0x4000 /* 1=Enable adaptive mode */ +#define HP100_EN_TX_UR_IRQ 0x2000 /* reserved, must be 0 */ +#define HP100_EN_LOW_TX 0x1000 /* reserved, must be 0 */ +#define HP100_ET_CNT_MASK 0x0fff /* bits 11..0: ET counters */ + +/* + * Early RX Configuration and Control Register + * (Page HW_MAP, EARLYRXCFG, Offset 0x18) + */ +#define HP100_EN_EARLY_RX 0x80 /* 1=Enable Early RX */ +#define HP100_EN_LOW_RX 0x40 /* reserved, must be 0 */ +#define HP100_RX_TRIP_MASK 0x1f /* bits 4..0: threshold at which the + * early rx circuit will start the + * dma of received packet into system + * memory for BM */ + +/* + * Serial Devices Control Register + * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08) + */ +#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads EEPROM into registers. */ + /* When it goes back to 0, load is */ + /* complete. This should take ~600us. */ + +/* + * 10MB LAN Control and Configuration Register I + * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08) + */ +#define HP100_MAC10_SEL 0xc0 /* Get bits to indicate MAC */ +#define HP100_AUI_SEL 0x20 /* Status of AUI selection */ +#define HP100_LOW_TH 0x10 /* 0:No, 1:Yes allow better cabling */ +#define HP100_LINK_BEAT_DIS 0x08 /* 0:Enable, 1:Disable link beat */ +#define HP100_LINK_BEAT_ST 0x04 /* 0:No, 1:Yes link beat being Rx */ +#define HP100_R_ROL_ST 0x02 /* 0:No, 1:Yes Rx twisted pair has */ + /* been reversed */ +#define HP100_AUI_ST 0x01 /* 0:No, 1:Yes use AUI on TP card */ + +/* + * 10 MB LAN Control and Configuration Register II + * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09) + */ +#define HP100_SQU_ST 0x01 /* 0:No, 1:Yes collision signal sent */ + /* after Tx.Only used for AUI. */ +#define HP100_FULLDUP 0x02 /* 1: LXT901 XCVR fullduplx enabled */ +#define HP100_DOT3_MAC 0x04 /* 1: DOT 3 Mac sel. unless Autosel */ + +/* + * MAC Selection, use with MAC10_SEL bits + */ +#define HP100_AUTO_SEL_10 0x0 /* Auto select */ +#define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */ +#define HP100_XCVR_7213 0x2 /* 7213 transceiver */ +#define HP100_XCVR_82503 0x3 /* 82503 transceiver */ + +/* + * 100MB LAN Training Register + * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12) + */ +#define HP100_FRAME_FORMAT 0x08 /* 0:802.3, 1:802.5 frames */ +#define HP100_BRIDGE 0x04 /* 0:No, 1:Yes tell hub i am a bridge */ +#define HP100_PROM_MODE 0x02 /* 0:No, 1:Yes tell hub card is */ + /* promiscuous */ +#define HP100_REPEATER 0x01 /* 0:No, 1:Yes tell hub MAC wants to */ + /* be a cascaded repeater */ + +/* + * 100MB LAN Control and Configuration Register + * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a) + */ +#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */ +#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */ +#define HP100_LINK_CABLE_ST 0x20 /* 0:No, 1:Yes cable can hear tones */ + /* from hub */ +#define HP100_LOAD_ADDR 0x10 /* 0->1 card addr will be sent */ + /* 100ms later the link status */ + /* bits are valid */ +#define HP100_LINK_CMD 0x08 /* 0->1 link will attempt to log in. */ + /* 100ms later the link status */ + /* bits are valid */ +#define HP100_TRN_DONE 0x04 /* NEW ETR-Chips only: Will be reset */ + /* after LinkUp Cmd is given and set */ + /* when training has completed. */ +#define HP100_LINK_GOOD_ST 0x02 /* 0:No, 1:Yes cable passed training */ +#define HP100_VG_RESET 0x01 /* 0:Yes, 1:No reset the 100VG MAC */ + + +/* + * MAC Configuration Register I + * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c) + */ +#define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */ +#define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */ +#define HP100_RX_EN 0x20 /* 1: allow receiving of pkts */ +#define HP100_TX_EN 0x10 /* 1: allow transmitting of pkts */ +#define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */ +#define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */ +#define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */ +#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL phys. pkts */ +#define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */ +#define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */ +#define HP100_MAC1MODE2 0x00 +#define HP100_MAC1MODE3 HP100_MAC1MODE2 | HP100_ACC_BC +#define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC +#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */ +#define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */ +/* Note MODE6 will receive all GOOD packets on the LAN. This really needs + a mode 7 defined to be LAN Analyzer mode, which will receive errored and + runt packets, and keep the CRC bytes. */ +#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED + +/* + * MAC Configuration Register II + * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d) + */ +#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */ +#define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */ +#define HP100_LBK_XCVR 0x20 /* 0:No, 1:Yes loopback through MAC & */ + /* transceiver */ +#define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */ +#define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */ +#define HP100_ACCNA 0x04 /* 1: For 802.5: Accept only token ring + * group addr that maches NA mask */ +#define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */ + /* The length will reflect this. */ +#define HP100_ACCFA 0x01 /* 1: For 802.5: Accept only functional + * addrs that match FA mask (page1) */ +#define HP100_MAC2MODEMASK 0x02 +#define HP100_MAC2MODE1 0x00 +#define HP100_MAC2MODE2 0x00 +#define HP100_MAC2MODE3 0x00 +#define HP100_MAC2MODE4 0x00 +#define HP100_MAC2MODE5 0x00 +#define HP100_MAC2MODE6 0x00 +#define HP100_MAC2MODE7 KEEP_CRC + +/* + * MAC Configuration Register III + * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e) + */ +#define HP100_PACKET_PACE 0x03 /* Packet Pacing: + * 00: No packet pacing + * 01: 8 to 16 uS delay + * 10: 16 to 32 uS delay + * 11: 32 to 64 uS delay + */ +#define HP100_LRF_EN 0x04 /* 1: External LAN Rcv Filter and + * TCP/IP Checksumming enabled. */ +#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */ + +/* + * MAC Configuration Register IV + * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f) + */ +#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL + * Signal, 1=100VG, 0=10Mbit sel. */ +#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion + * of the Misc. Interrupt */ + +/* + * 100 MB LAN Training Request/Allowed Registers + * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only) + */ +#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be + * a cascaded repeater + * 0: ... wants to be a DTE */ +#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */ +#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */ +#define HP100_MACRQ_FRAMEFMT_802_5 0x0010 /* 10: 802.5 format is requested */ +#define HP100_CARD_MACVER 0xe000 /* R: 3 bit Cards 100VG MAC version */ +#define HP100_MALLOW_REPEATER 0x0001 /* If reset, requested access as an + * end node is allowed */ +#define HP100_MALLOW_PROMSC 0x0004 /* 2 bits: Promiscious mode + * 00: Rcv only unicast packets + * specifically addr to this + * endnode + * 10: Rcv all pckts fwded by + * the local repeater */ +#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format + * 00: 802.3 format will be used + * 10: 802.5 format will be used */ +#define HP100_MALLOW_ACCDENIED 0x0400 /* N bit */ +#define HP100_MALLOW_CONFIGURE 0x0f00 /* C bit */ +#define HP100_MALLOW_DUPADDR 0x1000 /* D bit */ +#define HP100_HUB_MACVER 0xe000 /* R: 3 bit 802.12 MAC/RMAC training */ + /* protocol of repeater */ + +/* ****************************************************************************** */ + +/* + * Set/Reset bits + */ +#define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */ +#define HP100_SET_LB 0x0001 /* HB sets upper byte, LB sets lower byte */ +#define HP100_RESET_HB 0x0000 /* For readability when resetting bits */ +#define HP100_RESET_LB 0x0000 /* For readability when resetting bits */ + +/* + * Misc. Constants + */ +#define HP100_LAN_100 100 /* lan_type value for VG */ +#define HP100_LAN_10 10 /* lan_type value for 10BaseT */ +#define HP100_LAN_COAX 9 /* lan_type value for Coax */ +#define HP100_LAN_ERR (-1) /* lan_type value for link down */ + +/* + * Bus Master Data Structures ---------------------------------------------- + */ + +#define MAX_RX_PDL 30 /* Card limit = 31 */ +#define MAX_RX_FRAG 2 /* Don't need more... */ +#define MAX_TX_PDL 29 +#define MAX_TX_FRAG 2 /* Limit = 31 */ + +/* Define total PDL area size in bytes (should be 4096) */ +/* This is the size of kernel (dma) memory that will be allocated. */ +#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16 + +/* Ethernet Packet Sizes */ +#define MIN_ETHER_SIZE 60 +#define MAX_ETHER_SIZE 1514 /* Needed for preallocation of */ + /* skb buffer when busmastering */ + +/* Tx or Rx Ring Entry */ +typedef struct hp100_ring { + u_int *pdl; /* Address of PDLs PDH, dword before + * this address is used for rx hdr */ + u_int pdl_paddr; /* Physical address of PDL */ + struct sk_buff *skb; + struct hp100_ring *next; +} hp100_ring_t; + + + +/* Mask for Header Descriptor */ +#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */ + + +/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED + bit in the MAC Configuration Register 1 is set. */ +#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */ +#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */ +#define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */ +#define HP100_BAD_SYMBOL_ERR 0x1000 /* 0:No, 1:Yes invalid symbol received */ +#define HP100_RCV_IPM_ERR 0x0800 /* 0:No, 1:Yes pkt had an invalid packet */ + /* marker */ +#define HP100_SYMBOL_BAL_ERR 0x0400 /* 0:No, 1:Yes symbol balance error */ +#define HP100_VG_ALN_ERR 0x0200 /* 0:No, 1:Yes non-octet received */ +#define HP100_TRUNC_ERR 0x0100 /* 0:No, 1:Yes the packet was truncated */ +#define HP100_RUNT_ERR 0x0040 /* 0:No, 1:Yes pkt length < Min Pkt */ + /* Length Reg. */ +#define HP100_ALN_ERR 0x0010 /* 0:No, 1:Yes align error. */ +#define HP100_CRC_ERR 0x0008 /* 0:No, 1:Yes CRC occurred. */ + +/* The last three bits indicate the type of destination address */ + +#define HP100_MULTI_ADDR_HASH 0x0006 /* 110: Addr multicast, matched hash */ +#define HP100_BROADCAST_ADDR 0x0003 /* x11: Addr broadcast */ +#define HP100_MULTI_ADDR_NO_HASH 0x0002 /* 010: Addr multicast, didn't match hash */ +#define HP100_PHYS_ADDR_MATCH 0x0001 /* x01: Addr was physical and mine */ +#define HP100_PHYS_ADDR_NO_MATCH 0x0000 /* x00: Addr was physical but not mine */ + +/* + * macros + */ + +#define hp100_inb( reg ) \ + inb( ioaddr + HP100_REG_##reg ) +#define hp100_inw( reg ) \ + inw( ioaddr + HP100_REG_##reg ) +#define hp100_inl( reg ) \ + inl( ioaddr + HP100_REG_##reg ) +#define hp100_outb( data, reg ) \ + outb( data, ioaddr + HP100_REG_##reg ) +#define hp100_outw( data, reg ) \ + outw( data, ioaddr + HP100_REG_##reg ) +#define hp100_outl( data, reg ) \ + outl( data, ioaddr + HP100_REG_##reg ) +#define hp100_orb( data, reg ) \ + outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg ) +#define hp100_orw( data, reg ) \ + outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg ) +#define hp100_andb( data, reg ) \ + outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg ) +#define hp100_andw( data, reg ) \ + outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg ) + +#define hp100_page( page ) \ + outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING ) +#define hp100_ints_off() \ + outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW ) +#define hp100_ints_on() \ + outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW ) +#define hp100_mem_map_enable() \ + outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW ) +#define hp100_mem_map_disable() \ + outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW ) -- cgit v1.2.3-59-g8ed1b From e019cb536d046ea1c7ba5d370845ea362610b348 Mon Sep 17 00:00:00 2001 From: Qing Huang Date: Mon, 28 Oct 2019 23:34:56 +0000 Subject: net/mlx5: Fixed a typo in a comment in esw_del_uc_addr() Changed "managerss" to "managers". Fixes: a1b3839ac4a4 ("net/mlx5: E-Switch, Properly refer to the esw manager vport") Signed-off-by: Qing Huang Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 30aae76b6a1d..4c18ac1299ae 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -530,7 +530,7 @@ static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) u16 vport = vaddr->vport; int err = 0; - /* Skip mlx5_mpfs_del_mac for eswitch managerss, + /* Skip mlx5_mpfs_del_mac for eswitch managers, * it is already done by its netdev in mlx5e_execute_l2_action */ if (!vaddr->mpfs || esw->manager_vport == vport) -- cgit v1.2.3-59-g8ed1b From 6d94e610e4b6a77007d50952d3c859d3e300c0ab Mon Sep 17 00:00:00 2001 From: Vu Pham Date: Mon, 28 Oct 2019 23:34:58 +0000 Subject: net/mlx5: E-Switch, Rename egress config to generic name Refactor vport egress config in offloads mode Refactoring vport egress configuration in offloads mode that includes egress prio tag configuration. This makes code symmetric to ingress configuration. Signed-off-by: Vu Pham Reviewed-by: Parav Pandit Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 50 +++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 00d71db15f22..506cea8181f9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1864,32 +1864,16 @@ static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw, struct mlx5_flow_spec *spec; int err = 0; - if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) - return 0; - /* For prio tag mode, there is only 1 FTEs: * 1) prio tag packets - pop the prio tag VLAN, allow * Unmatched traffic is allowed by default */ - - esw_vport_cleanup_egress_rules(esw, vport); - - err = esw_vport_enable_egress_acl(esw, vport); - if (err) { - mlx5_core_warn(esw->dev, - "failed to enable egress acl (%d) on vport[%d]\n", - err, vport->vport); - return err; - } - esw_debug(esw->dev, "vport[%d] configure prio tag egress rules\n", vport->vport); spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) { - err = -ENOMEM; - goto out_no_mem; - } + if (!spec) + return -ENOMEM; /* prio tag vlan rule - pop it so VF receives untagged packets */ MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); @@ -1909,14 +1893,9 @@ static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw, "vport[%d] configure egress pop prio tag vlan rule failed, err(%d)\n", vport->vport, err); vport->egress.allowed_vlan = NULL; - goto out; } -out: kvfree(spec); -out_no_mem: - if (err) - esw_vport_cleanup_egress_rules(esw, vport); return err; } @@ -1961,6 +1940,29 @@ out: return err; } +static int esw_vport_egress_config(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + int err; + + if (!MLX5_CAP_GEN(esw->dev, prio_tag_required)) + return 0; + + esw_vport_cleanup_egress_rules(esw, vport); + + err = esw_vport_enable_egress_acl(esw, vport); + if (err) + return err; + + esw_debug(esw->dev, "vport(%d) configure egress rules\n", vport->vport); + + err = esw_vport_egress_prio_tag_config(esw, vport); + if (err) + esw_vport_disable_egress_acl(esw, vport); + + return err; +} + static bool esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw) { @@ -1996,7 +1998,7 @@ static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) goto err_ingress; if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { - err = esw_vport_egress_prio_tag_config(esw, vport); + err = esw_vport_egress_config(esw, vport); if (err) goto err_egress; } -- cgit v1.2.3-59-g8ed1b From b1a3380aa709082761c1dba89234ac16c19037c6 Mon Sep 17 00:00:00 2001 From: Vu Pham Date: Mon, 28 Oct 2019 23:35:00 +0000 Subject: net/mlx5: E-Switch, Rename ingress acl config in offloads mode Changing the function name esw_ingress_acl_common_config() to esw_ingress_acl_config() to be consistent with egress config function naming in offloads mode. Signed-off-by: Vu Pham Reviewed-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 506cea8181f9..48adec168a7c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1899,8 +1899,8 @@ static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw, return err; } -static int esw_vport_ingress_common_config(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int esw_vport_ingress_config(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int err; @@ -1993,7 +1993,7 @@ static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA; mlx5_esw_for_all_vports(esw, i, vport) { - err = esw_vport_ingress_common_config(esw, vport); + err = esw_vport_ingress_config(esw, vport); if (err) goto err_ingress; -- cgit v1.2.3-59-g8ed1b From fdde49e00b9d2041086568b52670043a8def96ff Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:03 +0000 Subject: net/mlx5: E-switch, Introduce and use vlan rule config helper Between legacy mode and switchdev mode, only two fields are changed, vlan_tag and flow action. Hence to avoid duplicte code between two modes, introduce and and use helper function to configure allowed VLAN rule. While at it, get rid of duplicate debug message. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 68 ++++++++++++++-------- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 4 ++ .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 54 ++++------------- 3 files changed, 58 insertions(+), 68 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 4c18ac1299ae..ef7d84a1dbc2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1328,6 +1328,43 @@ out: return err; } +int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + u16 vlan_id, u32 flow_action) +{ + struct mlx5_flow_act flow_act = {}; + struct mlx5_flow_spec *spec; + int err = 0; + + if (vport->egress.allowed_vlan) + return -EEXIST; + + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); + MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); + MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id); + + spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; + flow_act.action = flow_action; + vport->egress.allowed_vlan = + mlx5_add_flow_rules(vport->egress.acl, spec, + &flow_act, NULL, 0); + if (IS_ERR(vport->egress.allowed_vlan)) { + err = PTR_ERR(vport->egress.allowed_vlan); + esw_warn(esw->dev, + "vport[%d] configure egress vlan rule failed, err(%d)\n", + vport->vport, err); + vport->egress.allowed_vlan = NULL; + } + + kvfree(spec); + return err; +} + static int esw_vport_egress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { @@ -1358,34 +1395,17 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); - spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) { - err = -ENOMEM; - goto out; - } - /* Allowed vlan rule */ - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); - MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vport->info.vlan); + err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, vport->info.vlan, + MLX5_FLOW_CONTEXT_ACTION_ALLOW); + if (err) + return err; - spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW; - vport->egress.allowed_vlan = - mlx5_add_flow_rules(vport->egress.acl, spec, - &flow_act, NULL, 0); - if (IS_ERR(vport->egress.allowed_vlan)) { - err = PTR_ERR(vport->egress.allowed_vlan); - esw_warn(esw->dev, - "vport[%d] configure egress allowed vlan rule failed, err(%d)\n", - vport->vport, err); - vport->egress.allowed_vlan = NULL; + /* Drop others rule (star rule) */ + spec = kvzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) goto out; - } - /* Drop others rule (star rule) */ - memset(spec, 0, sizeof(*spec)); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; /* Attach egress drop flow counter */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 6bd6f5895244..1824b0ad7c9f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -421,6 +421,10 @@ int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw, int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw, u16 vport, u16 vlan, u8 qos, u8 set_flags); +int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + u16 vlan_id, u32 flow_action); + static inline bool mlx5_eswitch_vlan_actions_supported(struct mlx5_core_dev *dev, u8 vlan_depth) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 48adec168a7c..f0c7abd09120 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1857,48 +1857,6 @@ void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, } } -static int esw_vport_egress_prio_tag_config(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) -{ - struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_spec *spec; - int err = 0; - - /* For prio tag mode, there is only 1 FTEs: - * 1) prio tag packets - pop the prio tag VLAN, allow - * Unmatched traffic is allowed by default - */ - esw_debug(esw->dev, - "vport[%d] configure prio tag egress rules\n", vport->vport); - - spec = kvzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - - /* prio tag vlan rule - pop it so VF receives untagged packets */ - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); - MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); - MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, 0); - - spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; - flow_act.action = MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | - MLX5_FLOW_CONTEXT_ACTION_ALLOW; - vport->egress.allowed_vlan = - mlx5_add_flow_rules(vport->egress.acl, spec, - &flow_act, NULL, 0); - if (IS_ERR(vport->egress.allowed_vlan)) { - err = PTR_ERR(vport->egress.allowed_vlan); - esw_warn(esw->dev, - "vport[%d] configure egress pop prio tag vlan rule failed, err(%d)\n", - vport->vport, err); - vport->egress.allowed_vlan = NULL; - } - - kvfree(spec); - return err; -} - static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { @@ -1954,9 +1912,17 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, if (err) return err; - esw_debug(esw->dev, "vport(%d) configure egress rules\n", vport->vport); + /* For prio tag mode, there is only 1 FTEs: + * 1) prio tag packets - pop the prio tag VLAN, allow + * Unmatched traffic is allowed by default + */ + esw_debug(esw->dev, + "vport[%d] configure prio tag egress rules\n", vport->vport); - err = esw_vport_egress_prio_tag_config(esw, vport); + /* prio tag vlan rule - pop it so VF receives untagged packets */ + err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, 0, + MLX5_FLOW_CONTEXT_ACTION_VLAN_POP | + MLX5_FLOW_CONTEXT_ACTION_ALLOW); if (err) esw_vport_disable_egress_acl(esw, vport); -- cgit v1.2.3-59-g8ed1b From ea2300e02a71207b11111a44cbe7185a94f78a72 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:05 +0000 Subject: net/mlx5: Introduce and use mlx5_esw_is_manager_vport() Currently esw_enable_vport() does vport check for zero to enable drop counters regardless of execution on ECPF/PF. While esw_disable_vport() considers such scenario. To keep consistency across code for checking for manager_vport, introduce and use mlx5_esw_is_manager_vport() to check if a specified vport is eswitch manager vport or not. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 13 +++++++------ drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 6 ++++++ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index ef7d84a1dbc2..fa1228a8005f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -501,7 +501,7 @@ static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) /* Skip mlx5_mpfs_add_mac for eswitch_managers, * it is already done by its netdev in mlx5e_execute_l2_action */ - if (esw->manager_vport == vport) + if (mlx5_esw_is_manager_vport(esw, vport)) goto fdb_add; err = mlx5_mpfs_add_mac(esw->dev, mac); @@ -533,7 +533,7 @@ static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr) /* Skip mlx5_mpfs_del_mac for eswitch managers, * it is already done by its netdev in mlx5e_execute_l2_action */ - if (!vaddr->mpfs || esw->manager_vport == vport) + if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport)) goto fdb_del; err = mlx5_mpfs_del_mac(esw->dev, mac); @@ -1639,7 +1639,7 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, u16 vport_num = vport->vport; int flags; - if (esw->manager_vport == vport_num) + if (mlx5_esw_is_manager_vport(esw, vport_num)) return; mlx5_modify_vport_admin_state(esw->dev, @@ -1713,7 +1713,8 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); /* Create steering drop counters for ingress and egress ACLs */ - if (vport_num && esw->mode == MLX5_ESWITCH_LEGACY) + if (!mlx5_esw_is_manager_vport(esw, vport_num) && + esw->mode == MLX5_ESWITCH_LEGACY) esw_vport_create_drop_counters(vport); /* Restore old vport configuration */ @@ -1731,7 +1732,7 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, /* Esw manager is trusted by default. Host PF (vport 0) is trusted as well * in smartNIC as it's a vport group manager. */ - if (esw->manager_vport == vport_num || + if (mlx5_esw_is_manager_vport(esw, vport_num) || (!vport_num && mlx5_core_is_ecpf(esw->dev))) vport->info.trusted = true; @@ -1766,7 +1767,7 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, esw_vport_change_handle_locked(vport); vport->enabled_events = 0; esw_vport_disable_qos(esw, vport); - if (esw->manager_vport != vport_num && + if (!mlx5_esw_is_manager_vport(esw, vport_num) && esw->mode == MLX5_ESWITCH_LEGACY) { mlx5_modify_vport_admin_state(esw->dev, MLX5_VPORT_STATE_OP_MOD_ESW_VPORT, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 1824b0ad7c9f..75e69644d70e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -463,6 +463,12 @@ static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev) MLX5_VPORT_ECPF : MLX5_VPORT_PF; } +static inline bool +mlx5_esw_is_manager_vport(const struct mlx5_eswitch *esw, u16 vport_num) +{ + return esw->manager_vport == vport_num; +} + static inline u16 mlx5_eswitch_first_host_vport_num(struct mlx5_core_dev *dev) { return mlx5_core_is_ecpf_esw_manager(dev) ? -- cgit v1.2.3-59-g8ed1b From 99ecd64631ef9873619be493c711afb83aff75fc Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:07 +0000 Subject: net/mlx5: Correct comment for legacy fields fdb_table is used for both legacy and offloads mode. It was incorrect to comment that fdb_table is legacy specific. Hence, fix the comment to reflect that fdb_table is used in legacy and offloads mode. Fixes: 131ce7014043 ("net/mlx5: E-Switch, Remove redundant mc_promisc NULL check") Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 75e69644d70e..a41d4aad9d28 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -217,8 +217,8 @@ enum { struct mlx5_eswitch { struct mlx5_core_dev *dev; struct mlx5_nb nb; - /* legacy data structures */ struct mlx5_eswitch_fdb fdb_table; + /* legacy data structures */ struct hlist_head mc_table[MLX5_L2_ADDR_HASH_SIZE]; struct esw_mc_addr mc_promisc; /* end of legacy */ -- cgit v1.2.3-59-g8ed1b From d68316b5a1046b489097c5e5e24139548b79971f Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:10 +0000 Subject: net/mlx5: Move metdata fields under offloads structure Metadata fields are offload mode specific. To improve code readability, move metadata under offloads structure. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 6 ++-- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 33 +++++++++++----------- 2 files changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index a41d4aad9d28..5f862992b9c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -69,11 +69,13 @@ struct vport_ingress { struct mlx5_flow_group *allow_spoofchk_only_grp; struct mlx5_flow_group *allow_untagged_only_grp; struct mlx5_flow_group *drop_grp; - struct mlx5_modify_hdr *modify_metadata; - struct mlx5_flow_handle *modify_metadata_rule; struct mlx5_flow_handle *allow_rule; struct mlx5_flow_handle *drop_rule; struct mlx5_fc *drop_counter; + struct { + struct mlx5_modify_hdr *modify_metadata; + struct mlx5_flow_handle *modify_metadata_rule; + } offloads; }; struct vport_egress { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index f0c7abd09120..874e70e3792a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1778,9 +1778,9 @@ static int esw_vport_ingress_prio_tag_config(struct mlx5_eswitch *esw, flow_act.vlan[0].vid = 0; flow_act.vlan[0].prio = 0; - if (vport->ingress.modify_metadata_rule) { + if (vport->ingress.offloads.modify_metadata_rule) { flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR; - flow_act.modify_hdr = vport->ingress.modify_metadata; + flow_act.modify_hdr = vport->ingress.offloads.modify_metadata; } vport->ingress.allow_rule = @@ -1816,11 +1816,11 @@ static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, MLX5_SET(set_action_in, action, data, mlx5_eswitch_get_vport_metadata_for_match(esw, vport->vport)); - vport->ingress.modify_metadata = + vport->ingress.offloads.modify_metadata = mlx5_modify_header_alloc(esw->dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, 1, action); - if (IS_ERR(vport->ingress.modify_metadata)) { - err = PTR_ERR(vport->ingress.modify_metadata); + if (IS_ERR(vport->ingress.offloads.modify_metadata)) { + err = PTR_ERR(vport->ingress.offloads.modify_metadata); esw_warn(esw->dev, "failed to alloc modify header for vport %d ingress acl (%d)\n", vport->vport, err); @@ -1828,32 +1828,33 @@ static int esw_vport_add_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, } flow_act.action = MLX5_FLOW_CONTEXT_ACTION_MOD_HDR | MLX5_FLOW_CONTEXT_ACTION_ALLOW; - flow_act.modify_hdr = vport->ingress.modify_metadata; - vport->ingress.modify_metadata_rule = mlx5_add_flow_rules(vport->ingress.acl, - &spec, &flow_act, NULL, 0); - if (IS_ERR(vport->ingress.modify_metadata_rule)) { - err = PTR_ERR(vport->ingress.modify_metadata_rule); + flow_act.modify_hdr = vport->ingress.offloads.modify_metadata; + vport->ingress.offloads.modify_metadata_rule = + mlx5_add_flow_rules(vport->ingress.acl, + &spec, &flow_act, NULL, 0); + if (IS_ERR(vport->ingress.offloads.modify_metadata_rule)) { + err = PTR_ERR(vport->ingress.offloads.modify_metadata_rule); esw_warn(esw->dev, "failed to add setting metadata rule for vport %d ingress acl, err(%d)\n", vport->vport, err); - vport->ingress.modify_metadata_rule = NULL; + vport->ingress.offloads.modify_metadata_rule = NULL; goto out; } out: if (err) - mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata); + mlx5_modify_header_dealloc(esw->dev, vport->ingress.offloads.modify_metadata); return err; } void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (vport->ingress.modify_metadata_rule) { - mlx5_del_flow_rules(vport->ingress.modify_metadata_rule); - mlx5_modify_header_dealloc(esw->dev, vport->ingress.modify_metadata); + if (vport->ingress.offloads.modify_metadata_rule) { + mlx5_del_flow_rules(vport->ingress.offloads.modify_metadata_rule); + mlx5_modify_header_dealloc(esw->dev, vport->ingress.offloads.modify_metadata); - vport->ingress.modify_metadata_rule = NULL; + vport->ingress.offloads.modify_metadata_rule = NULL; } } -- cgit v1.2.3-59-g8ed1b From 853b53520c9d11db7652e3603665b0ad475741a5 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:11 +0000 Subject: net/mlx5: Move legacy drop counter and rule under legacy structure To improve code readability, move legacy drop counters and droup rule under legacy structure. While at it, (a) prefix drop flow counters helper with legacy_. (b) nullify the rule pointers only if they were valid. Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 82 ++++++++++++----------- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 12 ++-- 2 files changed, 50 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index fa1228a8005f..0dd5e5d5ea35 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1040,14 +1040,15 @@ out: void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) + if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) { mlx5_del_flow_rules(vport->egress.allowed_vlan); + vport->egress.allowed_vlan = NULL; + } - if (!IS_ERR_OR_NULL(vport->egress.drop_rule)) - mlx5_del_flow_rules(vport->egress.drop_rule); - - vport->egress.allowed_vlan = NULL; - vport->egress.drop_rule = NULL; + if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) { + mlx5_del_flow_rules(vport->egress.legacy.drop_rule); + vport->egress.legacy.drop_rule = NULL; + } } void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, @@ -1202,14 +1203,15 @@ out: void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (!IS_ERR_OR_NULL(vport->ingress.drop_rule)) - mlx5_del_flow_rules(vport->ingress.drop_rule); + if (!IS_ERR_OR_NULL(vport->ingress.legacy.drop_rule)) { + mlx5_del_flow_rules(vport->ingress.legacy.drop_rule); + vport->ingress.legacy.drop_rule = NULL; + } - if (!IS_ERR_OR_NULL(vport->ingress.allow_rule)) + if (!IS_ERR_OR_NULL(vport->ingress.allow_rule)) { mlx5_del_flow_rules(vport->ingress.allow_rule); - - vport->ingress.drop_rule = NULL; - vport->ingress.allow_rule = NULL; + vport->ingress.allow_rule = NULL; + } esw_vport_del_ingress_acl_modify_metadata(esw, vport); } @@ -1238,7 +1240,7 @@ void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - struct mlx5_fc *counter = vport->ingress.drop_counter; + struct mlx5_fc *counter = vport->ingress.legacy.drop_counter; struct mlx5_flow_destination drop_ctr_dst = {0}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {0}; @@ -1309,15 +1311,15 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, dst = &drop_ctr_dst; dest_num++; } - vport->ingress.drop_rule = + vport->ingress.legacy.drop_rule = mlx5_add_flow_rules(vport->ingress.acl, spec, &flow_act, dst, dest_num); - if (IS_ERR(vport->ingress.drop_rule)) { - err = PTR_ERR(vport->ingress.drop_rule); + if (IS_ERR(vport->ingress.legacy.drop_rule)) { + err = PTR_ERR(vport->ingress.legacy.drop_rule); esw_warn(esw->dev, "vport[%d] configure ingress drop rule, err(%d)\n", vport->vport, err); - vport->ingress.drop_rule = NULL; + vport->ingress.legacy.drop_rule = NULL; goto out; } @@ -1368,7 +1370,7 @@ int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw, static int esw_vport_egress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - struct mlx5_fc *counter = vport->egress.drop_counter; + struct mlx5_fc *counter = vport->egress.legacy.drop_counter; struct mlx5_flow_destination drop_ctr_dst = {0}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {0}; @@ -1416,15 +1418,15 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw, dst = &drop_ctr_dst; dest_num++; } - vport->egress.drop_rule = + vport->egress.legacy.drop_rule = mlx5_add_flow_rules(vport->egress.acl, spec, &flow_act, dst, dest_num); - if (IS_ERR(vport->egress.drop_rule)) { - err = PTR_ERR(vport->egress.drop_rule); + if (IS_ERR(vport->egress.legacy.drop_rule)) { + err = PTR_ERR(vport->egress.legacy.drop_rule); esw_warn(esw->dev, "vport[%d] configure egress drop rule failed, err(%d)\n", vport->vport, err); - vport->egress.drop_rule = NULL; + vport->egress.legacy.drop_rule = NULL; } out: kvfree(spec); @@ -1667,39 +1669,39 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, } } -static void esw_vport_create_drop_counters(struct mlx5_vport *vport) +static void esw_legacy_vport_create_drop_counters(struct mlx5_vport *vport) { struct mlx5_core_dev *dev = vport->dev; if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) { - vport->ingress.drop_counter = mlx5_fc_create(dev, false); - if (IS_ERR(vport->ingress.drop_counter)) { + vport->ingress.legacy.drop_counter = mlx5_fc_create(dev, false); + if (IS_ERR(vport->ingress.legacy.drop_counter)) { esw_warn(dev, "vport[%d] configure ingress drop rule counter failed\n", vport->vport); - vport->ingress.drop_counter = NULL; + vport->ingress.legacy.drop_counter = NULL; } } if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) { - vport->egress.drop_counter = mlx5_fc_create(dev, false); - if (IS_ERR(vport->egress.drop_counter)) { + vport->egress.legacy.drop_counter = mlx5_fc_create(dev, false); + if (IS_ERR(vport->egress.legacy.drop_counter)) { esw_warn(dev, "vport[%d] configure egress drop rule counter failed\n", vport->vport); - vport->egress.drop_counter = NULL; + vport->egress.legacy.drop_counter = NULL; } } } -static void esw_vport_destroy_drop_counters(struct mlx5_vport *vport) +static void esw_legacy_vport_destroy_drop_counters(struct mlx5_vport *vport) { struct mlx5_core_dev *dev = vport->dev; - if (vport->ingress.drop_counter) - mlx5_fc_destroy(dev, vport->ingress.drop_counter); - if (vport->egress.drop_counter) - mlx5_fc_destroy(dev, vport->egress.drop_counter); + if (vport->ingress.legacy.drop_counter) + mlx5_fc_destroy(dev, vport->ingress.legacy.drop_counter); + if (vport->egress.legacy.drop_counter) + mlx5_fc_destroy(dev, vport->egress.legacy.drop_counter); } static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, @@ -1715,7 +1717,7 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, /* Create steering drop counters for ingress and egress ACLs */ if (!mlx5_esw_is_manager_vport(esw, vport_num) && esw->mode == MLX5_ESWITCH_LEGACY) - esw_vport_create_drop_counters(vport); + esw_legacy_vport_create_drop_counters(vport); /* Restore old vport configuration */ esw_apply_vport_conf(esw, vport); @@ -1775,7 +1777,7 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, MLX5_VPORT_ADMIN_STATE_DOWN); esw_vport_disable_egress_acl(esw, vport); esw_vport_disable_ingress_acl(esw, vport); - esw_vport_destroy_drop_counters(vport); + esw_legacy_vport_destroy_drop_counters(vport); } esw->enabled_vports--; mutex_unlock(&esw->state_lock); @@ -2495,12 +2497,12 @@ static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev, if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY) return 0; - if (vport->egress.drop_counter) - mlx5_fc_query(dev, vport->egress.drop_counter, + if (vport->egress.legacy.drop_counter) + mlx5_fc_query(dev, vport->egress.legacy.drop_counter, &stats->rx_dropped, &bytes); - if (vport->ingress.drop_counter) - mlx5_fc_query(dev, vport->ingress.drop_counter, + if (vport->ingress.legacy.drop_counter) + mlx5_fc_query(dev, vport->ingress.legacy.drop_counter, &stats->tx_dropped, &bytes); if (!MLX5_CAP_GEN(dev, receive_discard_vport_down) && diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 5f862992b9c8..ec0ef7c5d539 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -70,8 +70,10 @@ struct vport_ingress { struct mlx5_flow_group *allow_untagged_only_grp; struct mlx5_flow_group *drop_grp; struct mlx5_flow_handle *allow_rule; - struct mlx5_flow_handle *drop_rule; - struct mlx5_fc *drop_counter; + struct { + struct mlx5_flow_handle *drop_rule; + struct mlx5_fc *drop_counter; + } legacy; struct { struct mlx5_modify_hdr *modify_metadata; struct mlx5_flow_handle *modify_metadata_rule; @@ -83,8 +85,10 @@ struct vport_egress { struct mlx5_flow_group *allowed_vlans_grp; struct mlx5_flow_group *drop_grp; struct mlx5_flow_handle *allowed_vlan; - struct mlx5_flow_handle *drop_rule; - struct mlx5_fc *drop_counter; + struct { + struct mlx5_flow_handle *drop_rule; + struct mlx5_fc *drop_counter; + } legacy; }; struct mlx5_vport_drop_stats { -- cgit v1.2.3-59-g8ed1b From 77b094305b1ba23e716bb34d3e33c8fe30a5f487 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:13 +0000 Subject: net/mlx5: Tide up state_lock and vport enabled flag usage When eswitch is disabled, vport event handler is unregistered. This unregistration already synchronizes with running EQ event handler in below code flow. mlx5_eswitch_disable() mlx5_eswitch_event_handlers_unregister() mlx5_eq_notifier_unregister() atomic_notifier_chain_unregister() synchronize_rcu() notifier_callchain eswitch_vport_event() queue_work() Additionally vport->enabled flag is set under state_lock during esw_enable_vport() but is not read under state_lock in (a) esw_disable_vport() and (b) under atomic context eswitch_vport_event(). It is also necessary to synchronize with already scheduled vport event. This is already achieved using below sequence. mlx5_eswitch_event_handlers_unregister() [..] flush_workqueue() Hence, (a) Remove vport->enabled check in eswitch_vport_event() which doesn't make any sense. (b) Remove redundant flush_workqueue() on every vport disable. (c) Keep esw_disable_vport() symmetric with esw_enable_vport() for state_lock. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 0dd5e5d5ea35..f15ffb8f5cac 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1750,18 +1750,16 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, { u16 vport_num = vport->vport; + mutex_lock(&esw->state_lock); if (!vport->enabled) - return; + goto done; esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num); /* Mark this vport as disabled to discard new events */ vport->enabled = false; - /* Wait for current already scheduled events to complete */ - flush_workqueue(esw->work_queue); /* Disable events from this vport */ arm_vport_context_events_cmd(esw->dev, vport->vport, 0); - mutex_lock(&esw->state_lock); /* We don't assume VFs will cleanup after themselves. * Calling vport change handler while vport is disabled will cleanup * the vport resources. @@ -1780,6 +1778,8 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, esw_legacy_vport_destroy_drop_counters(vport); } esw->enabled_vports--; + +done: mutex_unlock(&esw->state_lock); } @@ -1793,12 +1793,8 @@ static int eswitch_vport_event(struct notifier_block *nb, vport_num = be16_to_cpu(eqe->data.vport_change.vport_num); vport = mlx5_eswitch_get_vport(esw, vport_num); - if (IS_ERR(vport)) - return NOTIFY_OK; - - if (vport->enabled) + if (!IS_ERR(vport)) queue_work(esw->work_queue, &vport->vport_change_handler); - return NOTIFY_OK; } -- cgit v1.2.3-59-g8ed1b From 925a6acc77a70f8b5bfd0df75e36557aa400b0a0 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:15 +0000 Subject: net/mlx5: E-switch, Prepare code to handle vport enable error In subsequent patch, esw_enable_vport() could fail and return error. Prepare code to handle such error. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 62 ++++++++++++++++------ drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 5 +- 3 files changed, 50 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index f15ffb8f5cac..0bdaef508e74 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -452,6 +452,13 @@ static int esw_create_legacy_table(struct mlx5_eswitch *esw) return err; } +static void esw_destroy_legacy_table(struct mlx5_eswitch *esw) +{ + esw_cleanup_vepa_rules(esw); + esw_destroy_legacy_fdb_table(esw); + esw_destroy_legacy_vepa_table(esw); +} + #define MLX5_LEGACY_SRIOV_VPORT_EVENTS (MLX5_VPORT_UC_ADDR_CHANGE | \ MLX5_VPORT_MC_ADDR_CHANGE | \ MLX5_VPORT_PROMISC_CHANGE) @@ -464,15 +471,10 @@ static int esw_legacy_enable(struct mlx5_eswitch *esw) if (ret) return ret; - mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS); - return 0; -} - -static void esw_destroy_legacy_table(struct mlx5_eswitch *esw) -{ - esw_cleanup_vepa_rules(esw); - esw_destroy_legacy_fdb_table(esw); - esw_destroy_legacy_vepa_table(esw); + ret = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS); + if (ret) + esw_destroy_legacy_table(esw); + return ret; } static void esw_legacy_disable(struct mlx5_eswitch *esw) @@ -1704,8 +1706,8 @@ static void esw_legacy_vport_destroy_drop_counters(struct mlx5_vport *vport) mlx5_fc_destroy(dev, vport->egress.legacy.drop_counter); } -static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, - enum mlx5_eswitch_vport_event enabled_events) +static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, + enum mlx5_eswitch_vport_event enabled_events) { u16 vport_num = vport->vport; @@ -1743,6 +1745,7 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, esw->enabled_vports++; esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num); mutex_unlock(&esw->state_lock); + return 0; } static void esw_disable_vport(struct mlx5_eswitch *esw, @@ -1856,26 +1859,51 @@ static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw) /* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs * whichever are present on the eswitch. */ -void +int mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events) { struct mlx5_vport *vport; + int num_vfs; + int ret; int i; /* Enable PF vport */ vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF); - esw_enable_vport(esw, vport, enabled_events); + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + return ret; - /* Enable ECPF vports */ + /* Enable ECPF vport */ if (mlx5_ecpf_vport_exists(esw->dev)) { vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF); - esw_enable_vport(esw, vport, enabled_events); + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + goto ecpf_err; } /* Enable VF vports */ - mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) - esw_enable_vport(esw, vport, enabled_events); + mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) { + ret = esw_enable_vport(esw, vport, enabled_events); + if (ret) + goto vf_err; + } + return 0; + +vf_err: + num_vfs = i - 1; + mlx5_esw_for_each_vf_vport_reverse(esw, i, vport, num_vfs) + esw_disable_vport(esw, vport); + + if (mlx5_ecpf_vport_exists(esw->dev)) { + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF); + esw_disable_vport(esw, vport); + } + +ecpf_err: + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF); + esw_disable_vport(esw, vport); + return ret; } /* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index ec0ef7c5d539..36edee35f155 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -609,7 +609,7 @@ bool mlx5_eswitch_is_vf_vport(const struct mlx5_eswitch *esw, u16 vport_num); void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs); int mlx5_esw_funcs_changed_handler(struct notifier_block *nb, unsigned long type, void *data); -void +int mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events); void mlx5_eswitch_disable_pf_vf_vports(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 874e70e3792a..98df1eeee873 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -2139,7 +2139,9 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) if (err) goto err_vport_metadata; - mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE); + err = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_VPORT_UC_ADDR_CHANGE); + if (err) + goto err_vports; err = esw_offloads_load_all_reps(esw); if (err) @@ -2152,6 +2154,7 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) err_reps: mlx5_eswitch_disable_pf_vf_vports(esw); +err_vports: esw_set_passing_vport_metadata(esw, false); err_vport_metadata: esw_offloads_steering_cleanup(esw); -- cgit v1.2.3-59-g8ed1b From f5d0c01d65adba2b898836894d200e85c8a8def3 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:17 +0000 Subject: net/mlx5: E-switch, Legacy introduce and use per vport acl tables APIs Introduce and use per vport ACL tables creation and destroy APIs, so that subsequently patch can use them during enabling/disabling a vport in unified way for legacy vs offloads mode. Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 73 +++++++++++++++++++---- 1 file changed, 60 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 0bdaef508e74..47555e272dda 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1663,12 +1663,6 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, SET_VLAN_STRIP | SET_VLAN_INSERT : 0; modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos, flags); - - /* Only legacy mode needs ACLs */ - if (esw->mode == MLX5_ESWITCH_LEGACY) { - esw_vport_ingress_config(esw, vport); - esw_vport_egress_config(esw, vport); - } } static void esw_legacy_vport_create_drop_counters(struct mlx5_vport *vport) @@ -1706,10 +1700,59 @@ static void esw_legacy_vport_destroy_drop_counters(struct mlx5_vport *vport) mlx5_fc_destroy(dev, vport->egress.legacy.drop_counter); } +static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + int ret; + + /* Only non manager vports need ACL in legacy mode */ + if (mlx5_esw_is_manager_vport(esw, vport->vport)) + return 0; + + ret = esw_vport_ingress_config(esw, vport); + if (ret) + return ret; + + ret = esw_vport_egress_config(esw, vport); + if (ret) + esw_vport_disable_ingress_acl(esw, vport); + + return ret; +} + +static int esw_vport_setup_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + if (esw->mode == MLX5_ESWITCH_LEGACY) + return esw_vport_create_legacy_acl_tables(esw, vport); + + return 0; +} + +static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) + +{ + if (mlx5_esw_is_manager_vport(esw, vport->vport)) + return; + + esw_vport_disable_egress_acl(esw, vport); + esw_vport_disable_ingress_acl(esw, vport); + esw_legacy_vport_destroy_drop_counters(vport); +} + +static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + if (esw->mode == MLX5_ESWITCH_LEGACY) + esw_vport_destroy_legacy_acl_tables(esw, vport); +} + static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, enum mlx5_eswitch_vport_event enabled_events) { u16 vport_num = vport->vport; + int ret; mutex_lock(&esw->state_lock); WARN_ON(vport->enabled); @@ -1724,6 +1767,10 @@ static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, /* Restore old vport configuration */ esw_apply_vport_conf(esw, vport); + ret = esw_vport_setup_acl(esw, vport); + if (ret) + goto done; + /* Attach vport to the eswitch rate limiter */ if (esw_vport_enable_qos(esw, vport, vport->info.max_rate, vport->qos.bw_share)) @@ -1744,8 +1791,9 @@ static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, esw->enabled_vports++; esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num); +done: mutex_unlock(&esw->state_lock); - return 0; + return ret; } static void esw_disable_vport(struct mlx5_eswitch *esw, @@ -1770,16 +1818,15 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, esw_vport_change_handle_locked(vport); vport->enabled_events = 0; esw_vport_disable_qos(esw, vport); - if (!mlx5_esw_is_manager_vport(esw, vport_num) && - esw->mode == MLX5_ESWITCH_LEGACY) { + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + esw->mode == MLX5_ESWITCH_LEGACY) mlx5_modify_vport_admin_state(esw->dev, MLX5_VPORT_STATE_OP_MOD_ESW_VPORT, vport_num, 1, MLX5_VPORT_ADMIN_STATE_DOWN); - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); - esw_legacy_vport_destroy_drop_counters(vport); - } + + esw_vport_cleanup_acl(esw, vport); esw->enabled_vports--; done: -- cgit v1.2.3-59-g8ed1b From b7752f8341c4fecc4720fbd58f868e114a57fdea Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:19 +0000 Subject: net/mlx5: Move ACL drop counters life cycle close to ACL lifecycle It is better to create/destroy ACL related drop counters where the actual drop rule ACLs are created/destroyed, so that ACL configuration is self contained for ingress and egress. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 74 +++++++++++------------ 1 file changed, 35 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 47555e272dda..0e5113167739 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1665,58 +1665,55 @@ static void esw_apply_vport_conf(struct mlx5_eswitch *esw, flags); } -static void esw_legacy_vport_create_drop_counters(struct mlx5_vport *vport) +static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - struct mlx5_core_dev *dev = vport->dev; + int ret; - if (MLX5_CAP_ESW_INGRESS_ACL(dev, flow_counter)) { - vport->ingress.legacy.drop_counter = mlx5_fc_create(dev, false); + /* Only non manager vports need ACL in legacy mode */ + if (mlx5_esw_is_manager_vport(esw, vport->vport)) + return 0; + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + MLX5_CAP_ESW_INGRESS_ACL(esw->dev, flow_counter)) { + vport->ingress.legacy.drop_counter = mlx5_fc_create(esw->dev, false); if (IS_ERR(vport->ingress.legacy.drop_counter)) { - esw_warn(dev, + esw_warn(esw->dev, "vport[%d] configure ingress drop rule counter failed\n", vport->vport); vport->ingress.legacy.drop_counter = NULL; } } - if (MLX5_CAP_ESW_EGRESS_ACL(dev, flow_counter)) { - vport->egress.legacy.drop_counter = mlx5_fc_create(dev, false); + ret = esw_vport_ingress_config(esw, vport); + if (ret) + goto ingress_err; + + if (!mlx5_esw_is_manager_vport(esw, vport->vport) && + MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) { + vport->egress.legacy.drop_counter = mlx5_fc_create(esw->dev, false); if (IS_ERR(vport->egress.legacy.drop_counter)) { - esw_warn(dev, + esw_warn(esw->dev, "vport[%d] configure egress drop rule counter failed\n", vport->vport); vport->egress.legacy.drop_counter = NULL; } } -} - -static void esw_legacy_vport_destroy_drop_counters(struct mlx5_vport *vport) -{ - struct mlx5_core_dev *dev = vport->dev; - - if (vport->ingress.legacy.drop_counter) - mlx5_fc_destroy(dev, vport->ingress.legacy.drop_counter); - if (vport->egress.legacy.drop_counter) - mlx5_fc_destroy(dev, vport->egress.legacy.drop_counter); -} - -static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) -{ - int ret; - - /* Only non manager vports need ACL in legacy mode */ - if (mlx5_esw_is_manager_vport(esw, vport->vport)) - return 0; - - ret = esw_vport_ingress_config(esw, vport); - if (ret) - return ret; ret = esw_vport_egress_config(esw, vport); if (ret) - esw_vport_disable_ingress_acl(esw, vport); + goto egress_err; + + return 0; +egress_err: + esw_vport_disable_ingress_acl(esw, vport); + mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); + vport->egress.legacy.drop_counter = NULL; + +ingress_err: + mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter); + vport->ingress.legacy.drop_counter = NULL; return ret; } @@ -1737,8 +1734,12 @@ static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw, return; esw_vport_disable_egress_acl(esw, vport); + mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); + vport->egress.legacy.drop_counter = NULL; + esw_vport_disable_ingress_acl(esw, vport); - esw_legacy_vport_destroy_drop_counters(vport); + mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter); + vport->ingress.legacy.drop_counter = NULL; } static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw, @@ -1759,11 +1760,6 @@ static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num); - /* Create steering drop counters for ingress and egress ACLs */ - if (!mlx5_esw_is_manager_vport(esw, vport_num) && - esw->mode == MLX5_ESWITCH_LEGACY) - esw_legacy_vport_create_drop_counters(vport); - /* Restore old vport configuration */ esw_apply_vport_conf(esw, vport); -- cgit v1.2.3-59-g8ed1b From 89a0f1fb16adca959ea1485a856fbcfcd1d24208 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:20 +0000 Subject: net/mlx5: E-switch, Offloads introduce and use per vport acl tables APIs Introduce and use per vport ACL tables creation and destroy APIs, so that subsequently patch can use them during enabling/disabling a vport. Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 49 ++++++++++++++-------- 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 98df1eeee873..94eb18ae33a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1950,6 +1950,32 @@ esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw) return true; } +static int +esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + int err; + + err = esw_vport_ingress_config(esw, vport); + if (err) + return err; + + if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { + err = esw_vport_egress_config(esw, vport); + if (err) + esw_vport_disable_ingress_acl(esw, vport); + } + return err; +} + +static void +esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + esw_vport_disable_egress_acl(esw, vport); + esw_vport_disable_ingress_acl(esw, vport); +} + static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) { struct mlx5_vport *vport; @@ -1960,15 +1986,9 @@ static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA; mlx5_esw_for_all_vports(esw, i, vport) { - err = esw_vport_ingress_config(esw, vport); + err = esw_vport_create_offloads_acl_tables(esw, vport); if (err) - goto err_ingress; - - if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { - err = esw_vport_egress_config(esw, vport); - if (err) - goto err_egress; - } + goto err_acl_table; } if (mlx5_eswitch_vport_match_metadata_enabled(esw)) @@ -1976,13 +1996,10 @@ static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) return 0; -err_egress: - esw_vport_disable_ingress_acl(esw, vport); -err_ingress: +err_acl_table: for (j = MLX5_VPORT_PF; j < i; j++) { vport = &esw->vports[j]; - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_destroy_offloads_acl_tables(esw, vport); } return err; @@ -1993,10 +2010,8 @@ static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw) struct mlx5_vport *vport; int i; - mlx5_esw_for_all_vports(esw, i, vport) { - esw_vport_disable_egress_acl(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); - } + mlx5_esw_for_all_vports(esw, i, vport) + esw_vport_destroy_offloads_acl_tables(esw, vport); esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA; } -- cgit v1.2.3-59-g8ed1b From 748da30b376e034ae54b53e7e38e15cfa2bf4dda Mon Sep 17 00:00:00 2001 From: Vu Pham Date: Mon, 28 Oct 2019 23:35:22 +0000 Subject: net/mlx5: E-switch, Offloads shift ACL programming during enable/disable vport Currently legacy mode enables ACL while enabling vport, while offloads mode enable ACL when moving to offloads mode. Bring consistency to both modes by enabling/disabling ACL when enabling/disabling a vport. It also eliminates creating ingress ACL table on unused ECPF vport in offloads mode. Signed-off-by: Vu Pham Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 6 ++-- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 7 ++++ .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 42 +++++++--------------- 3 files changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 0e5113167739..1ce6ae1c446e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1722,8 +1722,8 @@ static int esw_vport_setup_acl(struct mlx5_eswitch *esw, { if (esw->mode == MLX5_ESWITCH_LEGACY) return esw_vport_create_legacy_acl_tables(esw, vport); - - return 0; + else + return esw_vport_create_offloads_acl_tables(esw, vport); } static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw, @@ -1747,6 +1747,8 @@ static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw, { if (esw->mode == MLX5_ESWITCH_LEGACY) esw_vport_destroy_legacy_acl_tables(esw, vport); + else + esw_vport_destroy_offloads_acl_tables(esw, vport); } static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 36edee35f155..d926bdacbdcc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -614,6 +614,13 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw, enum mlx5_eswitch_vport_event enabled_events); void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw); +int +esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); +void +esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, + struct mlx5_vport *vport); + #else /* CONFIG_MLX5_ESWITCH */ /* eswitch API stubs */ static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 94eb18ae33a4..ce30ead90617 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1950,7 +1950,7 @@ esw_check_vport_match_metadata_supported(const struct mlx5_eswitch *esw) return true; } -static int +int esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { @@ -1968,7 +1968,7 @@ esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, return err; } -static void +void esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { @@ -1976,43 +1976,27 @@ esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, esw_vport_disable_ingress_acl(esw, vport); } -static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw) +static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw) { struct mlx5_vport *vport; - int i, j; int err; if (esw_check_vport_match_metadata_supported(esw)) esw->flags |= MLX5_ESWITCH_VPORT_MATCH_METADATA; - mlx5_esw_for_all_vports(esw, i, vport) { - err = esw_vport_create_offloads_acl_tables(esw, vport); - if (err) - goto err_acl_table; - } - - if (mlx5_eswitch_vport_match_metadata_enabled(esw)) - esw_info(esw->dev, "Use metadata reg_c as source vport to match\n"); - - return 0; - -err_acl_table: - for (j = MLX5_VPORT_PF; j < i; j++) { - vport = &esw->vports[j]; - esw_vport_destroy_offloads_acl_tables(esw, vport); - } - + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK); + err = esw_vport_create_offloads_acl_tables(esw, vport); + if (err) + esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA; return err; } -static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw) +static void esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch *esw) { struct mlx5_vport *vport; - int i; - - mlx5_esw_for_all_vports(esw, i, vport) - esw_vport_destroy_offloads_acl_tables(esw, vport); + vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK); + esw_vport_destroy_offloads_acl_tables(esw, vport); esw->flags &= ~MLX5_ESWITCH_VPORT_MATCH_METADATA; } @@ -2030,7 +2014,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw) memset(&esw->fdb_table.offloads, 0, sizeof(struct offloads_fdb)); mutex_init(&esw->fdb_table.offloads.fdb_prio_lock); - err = esw_create_offloads_acl_tables(esw); + err = esw_create_uplink_offloads_acl_tables(esw); if (err) return err; @@ -2055,7 +2039,7 @@ create_ft_err: esw_destroy_offloads_fdb_tables(esw); create_fdb_err: - esw_destroy_offloads_acl_tables(esw); + esw_destroy_uplink_offloads_acl_tables(esw); return err; } @@ -2065,7 +2049,7 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw) esw_destroy_vport_rx_group(esw); esw_destroy_offloads_table(esw); esw_destroy_offloads_fdb_tables(esw); - esw_destroy_offloads_acl_tables(esw); + esw_destroy_uplink_offloads_acl_tables(esw); } static void -- cgit v1.2.3-59-g8ed1b From a962d7a61e2404cda6a89bfa5cc193c62223bb5e Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:24 +0000 Subject: net/mlx5: Restrict metadata disablement to offloads mode Now that there is clear separation for acl setup/cleanup between legacy and offloads mode, limit metdata disablement to offloads mode. Signed-off-by: Parav Pandit Reviewed-by: Vu Pham Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 -- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 2 -- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 9 ++++++--- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 1ce6ae1c446e..61459c06f56c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1214,8 +1214,6 @@ void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, mlx5_del_flow_rules(vport->ingress.allow_rule); vport->ingress.allow_rule = NULL; } - - esw_vport_del_ingress_acl_modify_metadata(esw, vport); } void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index d926bdacbdcc..aa3588446cba 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -267,8 +267,6 @@ void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index ce30ead90617..b536c8fa0061 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1847,8 +1847,8 @@ out: return err; } -void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { if (vport->ingress.offloads.modify_metadata_rule) { mlx5_del_flow_rules(vport->ingress.offloads.modify_metadata_rule); @@ -1962,8 +1962,10 @@ esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, if (mlx5_eswitch_is_vf_vport(esw, vport->vport)) { err = esw_vport_egress_config(esw, vport); - if (err) + if (err) { + esw_vport_del_ingress_acl_modify_metadata(esw, vport); esw_vport_disable_ingress_acl(esw, vport); + } } return err; } @@ -1973,6 +1975,7 @@ esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { esw_vport_disable_egress_acl(esw, vport); + esw_vport_del_ingress_acl_modify_metadata(esw, vport); esw_vport_disable_ingress_acl(esw, vport); } -- cgit v1.2.3-59-g8ed1b From 10652f39943ec19d32a6fa44a8523b0d40abcbcf Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:26 +0000 Subject: net/mlx5: Refactor ingress acl configuration Drop, untagged, spoof check and untagged spoof check flow groups are limited to legacy mode only. Therefore, following refactoring is done to (a) improve code readability (b) have better code split between legacy and offloads mode 1. Move legacy flow groups under legacy structure 2. Add validity check for group deletion 3. Restrict scope of esw_vport_disable_ingress_acl to legacy mode 4. Rename esw_vport_enable_ingress_acl() to esw_vport_create_ingress_acl_table() and limit its scope to table creation 5. Introduce legacy flow groups creation helper esw_legacy_create_ingress_acl_groups() and keep its scope to legacy mode 6. Reduce offloads ingress groups from 4 to just 1 metadata group per vport 7. Removed redundant IS_ERR_OR_NULL as entries are marked NULL on free. 8. Shortern error message to remove redundant 'E-switch' Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 228 ++++++++++++--------- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 19 +- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 67 +++++- 3 files changed, 200 insertions(+), 114 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 61459c06f56c..cc8d43d8c469 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1070,57 +1070,21 @@ void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, vport->egress.acl = NULL; } -int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static int +esw_vport_create_legacy_ingress_acl_groups(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_core_dev *dev = esw->dev; - struct mlx5_flow_namespace *root_ns; - struct mlx5_flow_table *acl; struct mlx5_flow_group *g; void *match_criteria; u32 *flow_group_in; - /* The ingress acl table contains 4 groups - * (2 active rules at the same time - - * 1 allow rule from one of the first 3 groups. - * 1 drop rule from the last group): - * 1)Allow untagged traffic with smac=original mac. - * 2)Allow untagged traffic. - * 3)Allow traffic with smac=original mac. - * 4)Drop all other traffic. - */ - int table_size = 4; - int err = 0; - - if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) - return -EOPNOTSUPP; - - if (!IS_ERR_OR_NULL(vport->ingress.acl)) - return 0; - - esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", - vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); - - root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, - mlx5_eswitch_vport_num_to_index(esw, vport->vport)); - if (!root_ns) { - esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", vport->vport); - return -EOPNOTSUPP; - } + int err; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; - acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); - if (IS_ERR(acl)) { - err = PTR_ERR(acl); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress flow Table, err(%d)\n", - vport->vport, err); - goto out; - } - vport->ingress.acl = acl; - match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1130,14 +1094,14 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, 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); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged spoofchk flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create untagged spoofchk flow group, err(%d)\n", vport->vport, err); - goto out; + goto spoof_err; } - vport->ingress.allow_untagged_spoofchk_grp = g; + vport->ingress.legacy.allow_untagged_spoofchk_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1145,14 +1109,14 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress untagged flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create untagged flow group, err(%d)\n", vport->vport, err); - goto out; + goto untagged_err; } - vport->ingress.allow_untagged_only_grp = g; + vport->ingress.legacy.allow_untagged_only_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); @@ -1161,80 +1125,134 @@ int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 2); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 2); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress spoofchk flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create spoofchk flow group, err(%d)\n", vport->vport, err); - goto out; + goto allow_spoof_err; } - vport->ingress.allow_spoofchk_only_grp = g; + vport->ingress.legacy.allow_spoofchk_only_grp = g; memset(flow_group_in, 0, inlen); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 3); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 3); - g = mlx5_create_flow_group(acl, flow_group_in); + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); if (IS_ERR(g)) { err = PTR_ERR(g); - esw_warn(dev, "Failed to create E-Switch vport[%d] ingress drop flow group, err(%d)\n", + esw_warn(dev, "vport[%d] ingress create drop flow group, err(%d)\n", vport->vport, err); - goto out; + goto drop_err; } - vport->ingress.drop_grp = g; + vport->ingress.legacy.drop_grp = g; + kvfree(flow_group_in); + return 0; -out: - if (err) { - if (!IS_ERR_OR_NULL(vport->ingress.allow_spoofchk_only_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_spoofchk_only_grp); - if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_only_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_untagged_only_grp); - if (!IS_ERR_OR_NULL(vport->ingress.allow_untagged_spoofchk_grp)) - mlx5_destroy_flow_group( - vport->ingress.allow_untagged_spoofchk_grp); - if (!IS_ERR_OR_NULL(vport->ingress.acl)) - mlx5_destroy_flow_table(vport->ingress.acl); +drop_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_spoofchk_only_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp); + vport->ingress.legacy.allow_spoofchk_only_grp = NULL; } - +allow_spoof_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_only_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp); + vport->ingress.legacy.allow_untagged_only_grp = NULL; + } +untagged_err: + if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_spoofchk_grp)) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp); + vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL; + } +spoof_err: kvfree(flow_group_in); return err; } +int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, int table_size) +{ + struct mlx5_core_dev *dev = esw->dev; + struct mlx5_flow_namespace *root_ns; + struct mlx5_flow_table *acl; + int vport_index; + int err; + + if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support)) + return -EOPNOTSUPP; + + esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n", + vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size)); + + vport_index = mlx5_eswitch_vport_num_to_index(esw, vport->vport); + root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS, + vport_index); + if (!root_ns) { + esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n", + vport->vport); + return -EOPNOTSUPP; + } + + acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport); + if (IS_ERR(acl)) { + err = PTR_ERR(acl); + esw_warn(dev, "vport[%d] ingress create flow Table, err(%d)\n", + vport->vport, err); + return err; + } + vport->ingress.acl = acl; + return 0; +} + +void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport) +{ + if (!vport->ingress.acl) + return; + + mlx5_destroy_flow_table(vport->ingress.acl); + vport->ingress.acl = NULL; +} + void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { - if (!IS_ERR_OR_NULL(vport->ingress.legacy.drop_rule)) { + if (vport->ingress.legacy.drop_rule) { mlx5_del_flow_rules(vport->ingress.legacy.drop_rule); vport->ingress.legacy.drop_rule = NULL; } - if (!IS_ERR_OR_NULL(vport->ingress.allow_rule)) { + if (vport->ingress.allow_rule) { mlx5_del_flow_rules(vport->ingress.allow_rule); vport->ingress.allow_rule = NULL; } } -void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport) +static void esw_vport_disable_legacy_ingress_acl(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) { - if (IS_ERR_OR_NULL(vport->ingress.acl)) + if (!vport->ingress.acl) return; esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport); esw_vport_cleanup_ingress_rules(esw, vport); - mlx5_destroy_flow_group(vport->ingress.allow_spoofchk_only_grp); - mlx5_destroy_flow_group(vport->ingress.allow_untagged_only_grp); - mlx5_destroy_flow_group(vport->ingress.allow_untagged_spoofchk_grp); - mlx5_destroy_flow_group(vport->ingress.drop_grp); - mlx5_destroy_flow_table(vport->ingress.acl); - vport->ingress.acl = NULL; - vport->ingress.drop_grp = NULL; - vport->ingress.allow_spoofchk_only_grp = NULL; - vport->ingress.allow_untagged_only_grp = NULL; - vport->ingress.allow_untagged_spoofchk_grp = NULL; + if (vport->ingress.legacy.allow_spoofchk_only_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp); + vport->ingress.legacy.allow_spoofchk_only_grp = NULL; + } + if (vport->ingress.legacy.allow_untagged_only_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp); + vport->ingress.legacy.allow_untagged_only_grp = NULL; + } + if (vport->ingress.legacy.allow_untagged_spoofchk_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp); + vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL; + } + if (vport->ingress.legacy.drop_grp) { + mlx5_destroy_flow_group(vport->ingress.legacy.drop_grp); + vport->ingress.legacy.drop_grp = NULL; + } + esw_vport_destroy_ingress_acl_table(vport); } static int esw_vport_ingress_config(struct mlx5_eswitch *esw, @@ -1249,19 +1267,36 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, int err = 0; u8 *smac_v; + /* The ingress acl table contains 4 groups + * (2 active rules at the same time - + * 1 allow rule from one of the first 3 groups. + * 1 drop rule from the last group): + * 1)Allow untagged traffic with smac=original mac. + * 2)Allow untagged traffic. + * 3)Allow traffic with smac=original mac. + * 4)Drop all other traffic. + */ + int table_size = 4; + esw_vport_cleanup_ingress_rules(esw, vport); if (!vport->info.vlan && !vport->info.qos && !vport->info.spoofchk) { - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); return 0; } - err = esw_vport_enable_ingress_acl(esw, vport); - if (err) { - mlx5_core_warn(esw->dev, - "failed to enable ingress acl (%d) on vport[%d]\n", - err, vport->vport); - return err; + if (!vport->ingress.acl) { + err = esw_vport_create_ingress_acl_table(esw, vport, table_size); + if (err) { + esw_warn(esw->dev, + "vport[%d] enable ingress acl err (%d)\n", + err, vport->vport); + return err; + } + + err = esw_vport_create_legacy_ingress_acl_groups(esw, vport); + if (err) + goto out; } esw_debug(esw->dev, @@ -1322,10 +1357,11 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, vport->ingress.legacy.drop_rule = NULL; goto out; } + kvfree(spec); + return 0; out: - if (err) - esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); kvfree(spec); return err; } @@ -1705,7 +1741,7 @@ static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw, return 0; egress_err: - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); vport->egress.legacy.drop_counter = NULL; @@ -1735,7 +1771,7 @@ static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw, mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); vport->egress.legacy.drop_counter = NULL; - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_disable_legacy_ingress_acl(esw, vport); mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter); vport->ingress.legacy.drop_counter = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index aa3588446cba..5e91735726b7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -65,16 +65,17 @@ struct vport_ingress { struct mlx5_flow_table *acl; - struct mlx5_flow_group *allow_untagged_spoofchk_grp; - struct mlx5_flow_group *allow_spoofchk_only_grp; - struct mlx5_flow_group *allow_untagged_only_grp; - struct mlx5_flow_group *drop_grp; - struct mlx5_flow_handle *allow_rule; + struct mlx5_flow_handle *allow_rule; struct { + struct mlx5_flow_group *allow_spoofchk_only_grp; + struct mlx5_flow_group *allow_untagged_spoofchk_grp; + struct mlx5_flow_group *allow_untagged_only_grp; + struct mlx5_flow_group *drop_grp; struct mlx5_flow_handle *drop_rule; struct mlx5_fc *drop_counter; } legacy; struct { + struct mlx5_flow_group *metadata_grp; struct mlx5_modify_hdr *modify_metadata; struct mlx5_flow_handle *modify_metadata_rule; } offloads; @@ -257,16 +258,16 @@ void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw); int esw_offloads_init_reps(struct mlx5_eswitch *esw); void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); +int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw, + struct mlx5_vport *vport, + int table_size); +void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport); void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw, struct mlx5_vport *vport); int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw, struct mlx5_vport *vport); -void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw, - struct mlx5_vport *vport); int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index b536c8fa0061..807372a7211b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1858,6 +1858,44 @@ static void esw_vport_del_ingress_acl_modify_metadata(struct mlx5_eswitch *esw, } } +static int esw_vport_create_ingress_acl_group(struct mlx5_eswitch *esw, + struct mlx5_vport *vport) +{ + int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); + struct mlx5_flow_group *g; + u32 *flow_group_in; + int ret = 0; + + flow_group_in = kvzalloc(inlen, GFP_KERNEL); + if (!flow_group_in) + return -ENOMEM; + + memset(flow_group_in, 0, inlen); + 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); + + g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in); + if (IS_ERR(g)) { + ret = PTR_ERR(g); + esw_warn(esw->dev, + "Failed to create vport[%d] ingress metdata group, err(%d)\n", + vport->vport, ret); + goto grp_err; + } + vport->ingress.offloads.metadata_grp = g; +grp_err: + kvfree(flow_group_in); + return ret; +} + +static void esw_vport_destroy_ingress_acl_group(struct mlx5_vport *vport) +{ + if (vport->ingress.offloads.metadata_grp) { + mlx5_destroy_flow_group(vport->ingress.offloads.metadata_grp); + vport->ingress.offloads.metadata_grp = NULL; + } +} + static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { @@ -1868,8 +1906,7 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, return 0; esw_vport_cleanup_ingress_rules(esw, vport); - - err = esw_vport_enable_ingress_acl(esw, vport); + err = esw_vport_create_ingress_acl_table(esw, vport, 1); if (err) { esw_warn(esw->dev, "failed to enable ingress acl (%d) on vport[%d]\n", @@ -1877,25 +1914,34 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, return err; } + err = esw_vport_create_ingress_acl_group(esw, vport); + if (err) + goto group_err; + esw_debug(esw->dev, "vport[%d] configure ingress rules\n", vport->vport); if (mlx5_eswitch_vport_match_metadata_enabled(esw)) { err = esw_vport_add_ingress_acl_modify_metadata(esw, vport); if (err) - goto out; + goto metadata_err; } if (MLX5_CAP_GEN(esw->dev, prio_tag_required) && mlx5_eswitch_is_vf_vport(esw, vport->vport)) { err = esw_vport_ingress_prio_tag_config(esw, vport); if (err) - goto out; + goto prio_tag_err; } + return 0; -out: - if (err) - esw_vport_disable_ingress_acl(esw, vport); +prio_tag_err: + esw_vport_del_ingress_acl_modify_metadata(esw, vport); +metadata_err: + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_group(vport); +group_err: + esw_vport_destroy_ingress_acl_table(vport); return err; } @@ -1964,7 +2010,8 @@ esw_vport_create_offloads_acl_tables(struct mlx5_eswitch *esw, err = esw_vport_egress_config(esw, vport); if (err) { esw_vport_del_ingress_acl_modify_metadata(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_table(vport); } } return err; @@ -1976,7 +2023,9 @@ esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw, { esw_vport_disable_egress_acl(esw, vport); esw_vport_del_ingress_acl_modify_metadata(esw, vport); - esw_vport_disable_ingress_acl(esw, vport); + esw_vport_cleanup_ingress_rules(esw, vport); + esw_vport_destroy_ingress_acl_group(vport); + esw_vport_destroy_ingress_acl_table(vport); } static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw) -- cgit v1.2.3-59-g8ed1b From 238302fae0216cb2e6a087ba403f3ecc3450b18b Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 23:35:28 +0000 Subject: net/mlx5: E-switch, Enable metadata on own vport Currently on ECPF, metadata is enabled on the ECPF vport = 0xfffe (manager vport). Metadata when supported, must be enabled on own vport which is used to pass metadata to vport of NIC Rx Flow Table. Due to this error, traffic tagged by ingress ACL is not processed correctly at NIC rx flow table level which is supposed to work on metadata tag. Hence, instead of working on eswitch manager vport, always working on eswitch own vport regardless of PF or ECPF. Given that mlx5_eswitch_query/modify_esw_vport_context() is used to access other vport in legacy mode and own vport settings in switchdev mode, extend low level API to explicitly specify other_vport. Fixes: c1286050cf47 ("net/mlx5: E-Switch, Pass metadata from FDB to eswitch manager") Signed-off-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 29 ++++++++-------------- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 6 +++-- .../ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 +-- 3 files changed, 16 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index cc8d43d8c469..24c2217a4ce8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -111,42 +111,32 @@ static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport, } /* E-Switch vport context HW commands */ -static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, - void *in, int inlen) +int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, + void *in, int inlen) { u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0}; MLX5_SET(modify_esw_vport_context_in, in, opcode, MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT); MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); - MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport); return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out)); } -int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, - void *in, int inlen) -{ - return modify_esw_vport_context_cmd(esw->dev, vport, in, inlen); -} - -static int query_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport, - void *out, int outlen) +int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, + void *out, int outlen) { u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {}; MLX5_SET(query_esw_vport_context_in, in, opcode, MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT); MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport); - MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1); + MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport); return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen); } -int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, - void *out, int outlen) -{ - return query_esw_vport_context_cmd(esw->dev, vport, out, outlen); -} - static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, u16 vlan, u8 qos, u8 set_flags) { @@ -179,7 +169,8 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport, MLX5_SET(modify_esw_vport_context_in, in, field_select.vport_cvlan_insert, 1); - return modify_esw_vport_context_cmd(dev, vport, in, sizeof(in)); + return mlx5_eswitch_modify_esw_vport_context(dev, vport, true, + in, sizeof(in)); } /* E-Switch FDB */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 5e91735726b7..a05b948a6287 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -297,9 +297,11 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw, struct ifla_vf_stats *vf_stats); void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule); -int mlx5_eswitch_modify_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, +int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, void *in, int inlen); -int mlx5_eswitch_query_esw_vport_context(struct mlx5_eswitch *esw, u16 vport, +int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport, + bool other_vport, void *out, int outlen); struct mlx5_flow_spec; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 807372a7211b..59eebcae5df6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -600,7 +600,7 @@ static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable) if (!mlx5_eswitch_vport_match_metadata_enabled(esw)) return 0; - err = mlx5_eswitch_query_esw_vport_context(esw, esw->manager_vport, + err = mlx5_eswitch_query_esw_vport_context(esw->dev, 0, false, out, sizeof(out)); if (err) return err; @@ -619,7 +619,7 @@ static int esw_set_passing_vport_metadata(struct mlx5_eswitch *esw, bool enable) MLX5_SET(modify_esw_vport_context_in, in, field_select.fdb_to_vport_reg_c_id, 1); - return mlx5_eswitch_modify_esw_vport_context(esw, esw->manager_vport, + return mlx5_eswitch_modify_esw_vport_context(esw->dev, 0, false, in, sizeof(in)); } -- cgit v1.2.3-59-g8ed1b From 40416d8ede651d26ce334f496a336aa1d38d1c97 Mon Sep 17 00:00:00 2001 From: Hamdan Igbaria Date: Sun, 8 Sep 2019 13:46:25 +0300 Subject: net/mlx5: DR, Replace CRC32 implementation to use kernel lib Use kernel function to calculate crc32 Instead of dr implementation since it has the same algorithm "slice by 8". Fixes: 26d688e33f88 ("net/mlx5: DR, Add Steering entry (STE) utilities") Signed-off-by: Hamdan Igbaria Reviewed-by: Alex Vesker Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/Makefile | 2 +- .../mellanox/mlx5/core/steering/dr_crc32.c | 98 ---------------------- .../mellanox/mlx5/core/steering/dr_domain.c | 3 - .../ethernet/mellanox/mlx5/core/steering/dr_ste.c | 10 ++- .../mellanox/mlx5/core/steering/dr_types.h | 3 - 5 files changed, 10 insertions(+), 106 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile index 5708fcc079ca..a6f390fdb971 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile +++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile @@ -70,7 +70,7 @@ mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/t mlx5_core-$(CONFIG_MLX5_SW_STEERING) += steering/dr_domain.o steering/dr_table.o \ steering/dr_matcher.o steering/dr_rule.o \ - steering/dr_icm_pool.o steering/dr_crc32.o \ + steering/dr_icm_pool.o \ steering/dr_ste.o steering/dr_send.o \ steering/dr_cmd.o steering/dr_fw.o \ steering/dr_action.o steering/fs_dr.o diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c deleted file mode 100644 index 9e2eccbb1eb8..000000000000 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_crc32.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB -/* Copyright (c) 2019 Mellanox Technologies. */ - -/* Copyright (c) 2011-2015 Stephan Brumme. All rights reserved. - * Slicing-by-16 contributed by Bulat Ziganshin - * - * This software is provided 'as-is', without any express or implied warranty. - * In no event will the author be held liable for any damages arising from the - * of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. - * 2. If you use this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * 3. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * - * Taken from http://create.stephan-brumme.com/crc32/ and adapted. - */ - -#include "dr_types.h" - -#define DR_STE_CRC_POLY 0xEDB88320L - -static u32 dr_ste_crc_tab32[8][256]; - -static void dr_crc32_calc_lookup_entry(u32 (*tbl)[256], u8 i, u8 j) -{ - tbl[i][j] = (tbl[i - 1][j] >> 8) ^ tbl[0][tbl[i - 1][j] & 0xff]; -} - -void mlx5dr_crc32_init_table(void) -{ - u32 crc, i, j; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 0; j < 8; j++) { - if (crc & 0x00000001L) - crc = (crc >> 1) ^ DR_STE_CRC_POLY; - else - crc = crc >> 1; - } - dr_ste_crc_tab32[0][i] = crc; - } - - /* Init CRC lookup tables according to crc_slice_8 algorithm */ - for (i = 0; i < 256; i++) { - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 1, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 2, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 3, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 4, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 5, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 6, i); - dr_crc32_calc_lookup_entry(dr_ste_crc_tab32, 7, i); - } -} - -/* Compute CRC32 (Slicing-by-8 algorithm) */ -u32 mlx5dr_crc32_slice8_calc(const void *input_data, size_t length) -{ - const u32 *curr = (const u32 *)input_data; - const u8 *curr_char; - u32 crc = 0, one, two; - - if (!input_data) - return 0; - - /* Process eight bytes at once (Slicing-by-8) */ - while (length >= 8) { - one = *curr++ ^ crc; - two = *curr++; - - crc = dr_ste_crc_tab32[0][(two >> 24) & 0xff] - ^ dr_ste_crc_tab32[1][(two >> 16) & 0xff] - ^ dr_ste_crc_tab32[2][(two >> 8) & 0xff] - ^ dr_ste_crc_tab32[3][two & 0xff] - ^ dr_ste_crc_tab32[4][(one >> 24) & 0xff] - ^ dr_ste_crc_tab32[5][(one >> 16) & 0xff] - ^ dr_ste_crc_tab32[6][(one >> 8) & 0xff] - ^ dr_ste_crc_tab32[7][one & 0xff]; - - length -= 8; - } - - curr_char = (const u8 *)curr; - /* Remaining 1 to 7 bytes (standard algorithm) */ - while (length-- != 0) - crc = (crc >> 8) ^ dr_ste_crc_tab32[0][(crc & 0xff) - ^ *curr_char++]; - - return ((crc >> 24) & 0xff) | ((crc << 8) & 0xff0000) | - ((crc >> 8) & 0xff00) | ((crc << 24) & 0xff000000); -} 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 5b24732b18c0..a9da961d4d2f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_domain.c @@ -326,9 +326,6 @@ mlx5dr_domain_create(struct mlx5_core_dev *mdev, enum mlx5dr_domain_type type) goto uninit_resourses; } - /* Init CRC table for htbl CRC calculation */ - mlx5dr_crc32_init_table(); - return dmn; uninit_resourses: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c index 4efe1b0be4a8..7e9d6cfc356f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c @@ -2,6 +2,7 @@ /* Copyright (c) 2019 Mellanox Technologies. */ #include +#include #include "dr_types.h" #define DR_STE_CRC_POLY 0xEDB88320L @@ -107,6 +108,13 @@ struct dr_hw_ste_format { u8 mask[DR_STE_SIZE_MASK]; }; +static u32 dr_ste_crc32_calc(const void *input_data, size_t length) +{ + u32 crc = crc32(0, input_data, length); + + return htonl(crc); +} + u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) { struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; @@ -128,7 +136,7 @@ u32 mlx5dr_ste_calc_hash_index(u8 *hw_ste_p, struct mlx5dr_ste_htbl *htbl) bit = bit >> 1; } - crc32 = mlx5dr_crc32_slice8_calc(masked, DR_STE_SIZE_TAG); + crc32 = dr_ste_crc32_calc(masked, DR_STE_SIZE_TAG); index = crc32 & (htbl->chunk->num_of_entries - 1); return index; 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 1cb3769d4e3c..d6d9bc5f4adf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -962,9 +962,6 @@ void mlx5dr_ste_copy_param(u8 match_criteria, struct mlx5dr_match_param *set_param, struct mlx5dr_match_parameters *mask); -void mlx5dr_crc32_init_table(void); -u32 mlx5dr_crc32_slice8_calc(const void *input_data, size_t length); - struct mlx5dr_qp { struct mlx5_core_dev *mdev; struct mlx5_wq_qp wq; -- cgit v1.2.3-59-g8ed1b From cc4db579e69b4c92a51fdc9f44bc671b40427824 Mon Sep 17 00:00:00 2001 From: Igor Leshenko Date: Thu, 5 Sep 2019 18:56:28 +0300 Subject: net/mlx5: FPGA, support network cards with standalone FPGA Not all mlx5 cards with FPGA device use it for network processing. mlx5_core driver configures network connection to FPGA device for all mlx5 cards with installed FPGA. If FPGA is not a part of network path, driver crashes in this case Check FPGA name in function mlx5_fpga_device_start() and continue integrate FPGA into packets flow only for dedicated cards. Currently there are Newton and Edison cards. Signed-off-by: Igor Leshenko Reviewed-by: Meir Lichtinger Reviewed-by: Boris Pismenny Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h | 10 ++-- .../net/ethernet/mellanox/mlx5/core/fpga/core.c | 61 +++++++++++++++------- 2 files changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h index eb8b0fe0b4e1..11621d265d7e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h @@ -35,11 +35,11 @@ #include -enum mlx5_fpga_device_id { - MLX5_FPGA_DEVICE_UNKNOWN = 0, - MLX5_FPGA_DEVICE_KU040 = 1, - MLX5_FPGA_DEVICE_KU060 = 2, - MLX5_FPGA_DEVICE_KU060_2 = 3, +enum mlx5_fpga_id { + MLX5_FPGA_NEWTON = 0, + MLX5_FPGA_EDISON = 1, + MLX5_FPGA_MORSE = 2, + MLX5_FPGA_MORSEQ = 3, }; enum mlx5_fpga_image { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c index d046d1ec2a86..2ce4241459ce 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c @@ -81,19 +81,28 @@ static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image) } } -static const char *mlx5_fpga_device_name(u32 device) +static const char *mlx5_fpga_name(u32 fpga_id) { - switch (device) { - case MLX5_FPGA_DEVICE_KU040: - return "ku040"; - case MLX5_FPGA_DEVICE_KU060: - return "ku060"; - case MLX5_FPGA_DEVICE_KU060_2: - return "ku060_2"; - case MLX5_FPGA_DEVICE_UNKNOWN: - default: - return "unknown"; + static char ret[32]; + + switch (fpga_id) { + case MLX5_FPGA_NEWTON: + return "Newton"; + case MLX5_FPGA_EDISON: + return "Edison"; + case MLX5_FPGA_MORSE: + return "Morse"; + case MLX5_FPGA_MORSEQ: + return "MorseQ"; } + + snprintf(ret, sizeof(ret), "Unknown %d", fpga_id); + return ret; +} + +static int mlx5_is_fpga_lookaside(u32 fpga_id) +{ + return fpga_id != MLX5_FPGA_NEWTON && fpga_id != MLX5_FPGA_EDISON; } static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) @@ -110,8 +119,12 @@ static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev) fdev->last_admin_image = query.admin_image; fdev->last_oper_image = query.oper_image; - mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n", - query.status, query.admin_image, query.oper_image); + mlx5_fpga_info(fdev, "Status %u; Admin image %u; Oper image %u\n", + query.status, query.admin_image, query.oper_image); + + /* for FPGA lookaside projects FPGA load status is not important */ + if (mlx5_is_fpga_lookaside(MLX5_CAP_FPGA(fdev->mdev, fpga_id))) + return 0; if (query.status != MLX5_FPGA_STATUS_SUCCESS) { mlx5_fpga_err(fdev, "%s image failed to load; status %u\n", @@ -167,25 +180,30 @@ int mlx5_fpga_device_start(struct mlx5_core_dev *mdev) struct mlx5_fpga_device *fdev = mdev->fpga; unsigned int max_num_qps; unsigned long flags; - u32 fpga_device_id; + u32 fpga_id; int err; if (!fdev) return 0; - err = mlx5_fpga_device_load_check(fdev); + err = mlx5_fpga_caps(fdev->mdev); if (err) goto out; - err = mlx5_fpga_caps(fdev->mdev); + err = mlx5_fpga_device_load_check(fdev); if (err) goto out; - fpga_device_id = MLX5_CAP_FPGA(fdev->mdev, fpga_device); - mlx5_fpga_info(fdev, "%s:%u; %s image, version %u; SBU %06x:%04x version %d\n", - mlx5_fpga_device_name(fpga_device_id), - fpga_device_id, + fpga_id = MLX5_CAP_FPGA(fdev->mdev, fpga_id); + mlx5_fpga_info(fdev, "FPGA card %s:%u\n", mlx5_fpga_name(fpga_id), fpga_id); + + /* No QPs if FPGA does not participate in net processing */ + if (mlx5_is_fpga_lookaside(fpga_id)) + goto out; + + mlx5_fpga_info(fdev, "%s(%d): image, version %u; SBU %06x:%04x version %d\n", mlx5_fpga_image_name(fdev->last_oper_image), + fdev->last_oper_image, MLX5_CAP_FPGA(fdev->mdev, image_version), MLX5_CAP_FPGA(fdev->mdev, ieee_vendor_id), MLX5_CAP_FPGA(fdev->mdev, sandbox_product_id), @@ -264,6 +282,9 @@ void mlx5_fpga_device_stop(struct mlx5_core_dev *mdev) if (!fdev) return; + if (mlx5_is_fpga_lookaside(MLX5_CAP_FPGA(fdev->mdev, fpga_id))) + return; + spin_lock_irqsave(&fdev->state_lock, flags); if (fdev->state != MLX5_FPGA_STATUS_SUCCESS) { spin_unlock_irqrestore(&fdev->state_lock, flags); -- cgit v1.2.3-59-g8ed1b From 32680da7103439095ba8c2dbe30c3e4d0e05e4c2 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Fri, 13 Sep 2019 00:59:02 +0800 Subject: net/mlx5: Remove unneeded variable in mlx5_unload_one mlx5_unload_one do not need local variable to store different value, Hence just remove it. Signed-off-by: zhong jiang Acked-by: Saeed Mahameed Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index e47dd7c1b909..c9a091d3226c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1228,8 +1228,6 @@ function_teardown: static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) { - int err = 0; - if (cleanup) { mlx5_unregister_device(dev); mlx5_drain_health_wq(dev); @@ -1257,7 +1255,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) mlx5_function_teardown(dev, cleanup); out: mutex_unlock(&dev->intf_state_mutex); - return err; + return 0; } static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) -- cgit v1.2.3-59-g8ed1b From 556b9d16d3f53d1e72b988f37501bb7e6d3f358b Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Tue, 3 Sep 2019 17:45:47 +0300 Subject: net/mlx5: Clear VF's configuration on disabling SRIOV When setting number of VFs to 0 (disable SRIOV), clear VF's configuration. Signed-off-by: Aya Levin Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 13 ++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 10 +++++----- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 30aae76b6a1d..89a2806eceb8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1831,6 +1831,15 @@ static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw) flush_workqueue(esw->work_queue); } +static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw) +{ + struct mlx5_vport *vport; + int i; + + mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) + memset(&vport->info, 0, sizeof(vport->info)); +} + /* Public E-Switch API */ #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev)) @@ -1923,7 +1932,7 @@ abort: return err; } -void mlx5_eswitch_disable(struct mlx5_eswitch *esw) +void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) { int old_mode; @@ -1952,6 +1961,8 @@ void mlx5_eswitch_disable(struct mlx5_eswitch *esw) mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB); mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH); } + if (clear_vf) + mlx5_eswitch_clear_vf_vports_info(esw); } int mlx5_eswitch_init(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 6bd6f5895244..804a7ed2b969 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -270,7 +270,7 @@ int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, int mlx5_eswitch_init(struct mlx5_core_dev *dev); void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw); int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode); -void mlx5_eswitch_disable(struct mlx5_eswitch *esw); +void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf); int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, u16 vport, u8 mac[ETH_ALEN]); int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw, @@ -603,7 +603,7 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw); static inline int mlx5_eswitch_init(struct mlx5_core_dev *dev) { return 0; } static inline void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw) {} static inline int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode) { return 0; } -static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw) {} +static inline void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf) {} static inline bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1) { return true; } static inline bool mlx5_eswitch_is_funcs_handler(struct mlx5_core_dev *dev) { return false; } static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 00d71db15f22..cbd88f42350e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1370,7 +1370,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw, return -EINVAL; } - mlx5_eswitch_disable(esw); + mlx5_eswitch_disable(esw, false); mlx5_eswitch_update_num_of_vfs(esw, esw->dev->priv.sriov.num_vfs); err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_OFFLOADS); if (err) { @@ -2196,7 +2196,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw, { int err, err1; - mlx5_eswitch_disable(esw); + mlx5_eswitch_disable(esw, false); err = mlx5_eswitch_enable(esw, MLX5_ESWITCH_LEGACY); if (err) { NL_SET_ERR_MSG_MOD(extack, "Failed setting eswitch to legacy"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index 61fcfd8b39b4..f641f1336402 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -108,7 +108,7 @@ enable_vfs_hca: return 0; } -static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) +static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev, bool clear_vf) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; int num_vfs = pci_num_vf(dev->pdev); @@ -127,7 +127,7 @@ static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev) } if (MLX5_ESWITCH_MANAGER(dev)) - mlx5_eswitch_disable(dev->priv.eswitch); + mlx5_eswitch_disable(dev->priv.eswitch, clear_vf); if (mlx5_wait_for_pages(dev, &dev->priv.vfs_pages)) mlx5_core_warn(dev, "timeout reclaiming VFs pages\n"); @@ -147,7 +147,7 @@ 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); + mlx5_device_disable_sriov(dev, true); } return err; } @@ -157,7 +157,7 @@ static void mlx5_sriov_disable(struct pci_dev *pdev) struct mlx5_core_dev *dev = pci_get_drvdata(pdev); pci_disable_sriov(pdev); - mlx5_device_disable_sriov(dev); + mlx5_device_disable_sriov(dev, true); } int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs) @@ -192,7 +192,7 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev) if (!mlx5_core_is_pf(dev)) return; - mlx5_device_disable_sriov(dev); + mlx5_device_disable_sriov(dev, false); } static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev) -- cgit v1.2.3-59-g8ed1b From ae2741e2b6ce2bf1b656b1152c4ef147ff35b096 Mon Sep 17 00:00:00 2001 From: Vlad Buslov Date: Wed, 11 Sep 2019 21:14:54 +0300 Subject: net/mlx5e: Verify that rule has at least one fwd/drop action Currently, mlx5 tc layer doesn't verify that rule has at least one forward or drop action which leads to following firmware syndrome when user tries to offload such action: [ 1824.860501] mlx5_core 0000:81:00.0: mlx5_cmd_check:753:(pid 29458): SET_FLOW_TABLE_ENTRY(0x936) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x144b7a) Add check at the end of parse_tc_fdb_actions() that verifies that resulting attribute has action fwd or drop flag set. Signed-off-by: Vlad Buslov Reviewed-by: Paul Blakey Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 3e78a727f3e6..8c4bce940bfb 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -3423,6 +3423,12 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; } + if (!(attr->action & + (MLX5_FLOW_CONTEXT_ACTION_FWD_DEST | MLX5_FLOW_CONTEXT_ACTION_DROP))) { + NL_SET_ERR_MSG(extack, "Rule must have at least one forward/drop action"); + return -EOPNOTSUPP; + } + if (attr->split_count > 0 && !mlx5_esw_has_fwd_fdb(priv->mdev)) { NL_SET_ERR_MSG_MOD(extack, "current firmware doesn't support split rule for port mirroring"); -- cgit v1.2.3-59-g8ed1b From 84c7af637512be9c3254189bd5910dae0d2a8602 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Thu, 19 Sep 2019 17:22:19 -0500 Subject: net/mlx5: Do not hold group lock while allocating FTE in software FTE memory allocation using alloc_fte() doesn't have any dependency on the flow group. Hence, do not hold flow group lock while performing alloc_fte(). This helps to reduce contention of flow group lock. Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 3bbb49354829..e5591f4f19b7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1814,6 +1814,13 @@ search_again_locked: return rule; } + fte = alloc_fte(ft, spec, flow_act); + if (IS_ERR(fte)) { + up_write_ref_node(&ft->node, false); + err = PTR_ERR(fte); + goto err_alloc_fte; + } + nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); up_write_ref_node(&ft->node, false); @@ -1821,17 +1828,9 @@ search_again_locked: if (err) goto err_release_fg; - fte = alloc_fte(ft, spec, flow_act); - if (IS_ERR(fte)) { - err = PTR_ERR(fte); - goto err_release_fg; - } - err = insert_fte(g, fte); - if (err) { - kmem_cache_free(steering->ftes_cache, fte); + if (err) goto err_release_fg; - } nested_down_write_ref_node(&fte->node, FS_LOCK_CHILD); up_write_ref_node(&g->node, false); @@ -1843,6 +1842,8 @@ search_again_locked: err_release_fg: up_write_ref_node(&g->node, false); + kmem_cache_free(steering->ftes_cache, fte); +err_alloc_fte: tree_put_node(&g->node, false); return ERR_PTR(err); } -- cgit v1.2.3-59-g8ed1b From 7dee607ed0e04500459db53001d8e02f8831f084 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Wed, 18 Sep 2019 18:50:32 -0500 Subject: net/mlx5: Support lockless FTE read lookups During connection tracking offloads with high number of connections, (40K connections per second), flow table group lock contention is observed. To improve the performance by reducing lock contention, lockless FTE read lookup is performed as described below. Each flow table entry is refcounted. Flow table entry is removed when refcount drops to zero. rhash table allows rcu protected lookup. Each hash table entry insertion and removal is write lock protected. Hence, it is possible to perform lockless lookup in rhash table using following scheme. (a) Guard FTE entry lookup per group using rcu read lock. (b) Before freeing the FTE entry, wait for all readers to finish accessing the FTE. Below example of one reader and write in parallel racing, shows protection in effect with rcu lock. lookup_fte_locked() rcu_read_lock(); search_hash_table() existing_flow_group_write_lock(); tree_put_node(fte) drop_ref_cnt(fte) del_sw_fte(fte) del_hash_table_entry(); call_rcu(); existing_flow_group_write_unlock(); get_ref_cnt(fte) fails rcu_read_unlock(); rcu grace period(); [..] kmem_cache_free(fte); Signed-off-by: Parav Pandit Reviewed-by: Mark Bloch Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 70 ++++++++++++++++++----- drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 1 + 2 files changed, 56 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index e5591f4f19b7..0246f5cdd355 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -531,9 +531,16 @@ static void del_hw_fte(struct fs_node *node) } } +static void del_sw_fte_rcu(struct rcu_head *head) +{ + struct fs_fte *fte = container_of(head, struct fs_fte, rcu); + struct mlx5_flow_steering *steering = get_steering(&fte->node); + + kmem_cache_free(steering->ftes_cache, fte); +} + static void del_sw_fte(struct fs_node *node) { - struct mlx5_flow_steering *steering = get_steering(node); struct mlx5_flow_group *fg; struct fs_fte *fte; int err; @@ -546,7 +553,8 @@ static void del_sw_fte(struct fs_node *node) rhash_fte); WARN_ON(err); ida_simple_remove(&fg->fte_allocator, fte->index - fg->start_index); - kmem_cache_free(steering->ftes_cache, fte); + + call_rcu(&fte->rcu, del_sw_fte_rcu); } static void del_hw_flow_group(struct fs_node *node) @@ -1623,22 +1631,47 @@ static u64 matched_fgs_get_version(struct list_head *match_head) } static struct fs_fte * -lookup_fte_locked(struct mlx5_flow_group *g, - const u32 *match_value, - bool take_write) +lookup_fte_for_write_locked(struct mlx5_flow_group *g, const u32 *match_value) { struct fs_fte *fte_tmp; - if (take_write) - nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); - else - nested_down_read_ref_node(&g->node, FS_LOCK_PARENT); - fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, match_value, - rhash_fte); + nested_down_write_ref_node(&g->node, FS_LOCK_PARENT); + + fte_tmp = rhashtable_lookup_fast(&g->ftes_hash, match_value, rhash_fte); if (!fte_tmp || !tree_get_node(&fte_tmp->node)) { fte_tmp = NULL; goto out; } + + if (!fte_tmp->node.active) { + tree_put_node(&fte_tmp->node, false); + fte_tmp = NULL; + goto out; + } + nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD); + +out: + up_write_ref_node(&g->node, false); + return fte_tmp; +} + +static struct fs_fte * +lookup_fte_for_read_locked(struct mlx5_flow_group *g, const u32 *match_value) +{ + struct fs_fte *fte_tmp; + + if (!tree_get_node(&g->node)) + return NULL; + + rcu_read_lock(); + fte_tmp = rhashtable_lookup(&g->ftes_hash, match_value, rhash_fte); + if (!fte_tmp || !tree_get_node(&fte_tmp->node)) { + rcu_read_unlock(); + fte_tmp = NULL; + goto out; + } + rcu_read_unlock(); + if (!fte_tmp->node.active) { tree_put_node(&fte_tmp->node, false); fte_tmp = NULL; @@ -1646,14 +1679,21 @@ lookup_fte_locked(struct mlx5_flow_group *g, } nested_down_write_ref_node(&fte_tmp->node, FS_LOCK_CHILD); + out: - if (take_write) - up_write_ref_node(&g->node, false); - else - up_read_ref_node(&g->node); + tree_put_node(&g->node, false); return fte_tmp; } +static struct fs_fte * +lookup_fte_locked(struct mlx5_flow_group *g, const u32 *match_value, bool write) +{ + if (write) + return lookup_fte_for_write_locked(g, match_value); + else + return lookup_fte_for_read_locked(g, match_value); +} + static struct mlx5_flow_handle * try_add_to_existing_fg(struct mlx5_flow_table *ft, struct list_head *match_head, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 00717eba2256..f278298b0f6e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -202,6 +202,7 @@ struct fs_fte { enum fs_fte_status status; struct mlx5_fc *counter; struct rhash_head hash; + struct rcu_head rcu; int modify_mask; }; -- cgit v1.2.3-59-g8ed1b From 130c7b46c93d313ca07d85a30d90021e424c7e9b Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Tue, 7 May 2019 08:56:38 -0700 Subject: net/mlx5e: TX, Dump WQs wqe descriptors on CQE with error events Dump the Work Queue's TX WQE descriptor when a completion with error is received. Example: [5.331832] mlx5_core 0000:00:04.0 enp0s4: Error cqe on cqn 0xa, ci 0x1, TXQ-SQ qpn 0xe, opcode 0xd, syndrome 0x2, vendor syndrome 0x0 [5.333127] 00000000: 55 65 02 75 31 fe c2 d2 6b 6c 62 1e f9 e1 d8 5c [5.333837] 00000010: d3 b2 6c b8 89 e4 84 20 0b f4 3c e0 f3 75 41 ca [5.334568] 00000020: 46 00 00 00 cd 70 a0 92 18 3a 01 de 00 00 00 00 [5.335313] 00000030: 7d bc 05 89 b2 e9 00 02 1e 00 00 0e 00 00 30 d2 [5.335972] WQE DUMP: WQ size 1024 WQ cur size 0, WQE index 0x0, len: 64 [5.336710] 00000000: 00 00 00 1e 00 00 0e 04 00 00 00 08 00 00 00 00 [5.337524] 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 12 33 33 [5.338151] 00000020: 00 00 00 16 52 54 00 00 00 01 86 dd 60 00 00 00 [5.338740] 00000030: 00 00 00 48 00 00 00 00 00 00 00 00 66 ba 58 14 Signed-off-by: Saeed Mahameed Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 6 ++++++ drivers/net/ethernet/mellanox/mlx5/core/wq.c | 18 ++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/wq.h | 1 + 3 files changed, 25 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index d3a67a9b4eba..29730f52e315 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -458,8 +458,14 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget) if (unlikely(get_cqe_opcode(cqe) == MLX5_CQE_REQ_ERR)) { if (!test_and_set_bit(MLX5E_SQ_STATE_RECOVERING, &sq->state)) { + struct mlx5e_tx_wqe_info *wi; + u16 ci; + + ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc); + wi = &sq->db.wqe_info[ci]; mlx5e_dump_error_cqe(sq, (struct mlx5_err_cqe *)cqe); + mlx5_wq_cyc_wqe_dump(&sq->wq, ci, wi->num_wqebbs); queue_work(cq->channel->priv->wq, &sq->recover_work); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index dd2315ce4441..dab2625e1e59 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -96,6 +96,24 @@ err_db_free: return err; } +void mlx5_wq_cyc_wqe_dump(struct mlx5_wq_cyc *wq, u16 ix, u8 nstrides) +{ + size_t len; + void *wqe; + + if (!net_ratelimit()) + return; + + nstrides = max_t(u8, nstrides, 1); + + len = nstrides << wq->fbc.log_stride; + wqe = mlx5_wq_cyc_get_wqe(wq, ix); + + pr_info("WQE DUMP: WQ size %d WQ cur size %d, WQE index 0x%x, len: %ld\n", + mlx5_wq_cyc_get_size(wq), wq->cur_sz, ix, len); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, 16, 1, wqe, len, false); +} + int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *qpc, struct mlx5_wq_qp *wq, struct mlx5_wq_ctrl *wq_ctrl) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index 55791f71a778..27338c3c6136 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -79,6 +79,7 @@ struct mlx5_wq_ll { int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *wqc, struct mlx5_wq_cyc *wq, struct mlx5_wq_ctrl *wq_ctrl); +void mlx5_wq_cyc_wqe_dump(struct mlx5_wq_cyc *wq, u16 ix, u8 nstrides); u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq); int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, -- cgit v1.2.3-59-g8ed1b From 769619ee39dfa8297a1fe2bc2865eb1e73a9f824 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Wed, 16 Oct 2019 13:29:16 +0300 Subject: net/mlx5: WQ, Move short getters into header file Move short Work Queue API getter functions into the WQ header file. Signed-off-by: Tariq Toukan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/wq.c | 20 -------------------- drivers/net/ethernet/mellanox/mlx5/core/wq.h | 24 ++++++++++++++++++++---- 2 files changed, 20 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index dab2625e1e59..f2a0e72285ba 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -34,26 +34,6 @@ #include "wq.h" #include "mlx5_core.h" -u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq) -{ - return (u32)wq->fbc.sz_m1 + 1; -} - -u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq) -{ - return wq->fbc.sz_m1 + 1; -} - -u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq) -{ - return wq->fbc.log_stride; -} - -u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq) -{ - return (u32)wq->fbc.sz_m1 + 1; -} - static u32 wq_get_byte_sz(u8 log_sz, u8 log_stride) { return ((u32)1 << log_sz) << log_stride; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index 27338c3c6136..d9a94bc223c0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -80,7 +80,6 @@ int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *wqc, struct mlx5_wq_cyc *wq, struct mlx5_wq_ctrl *wq_ctrl); void mlx5_wq_cyc_wqe_dump(struct mlx5_wq_cyc *wq, u16 ix, u8 nstrides); -u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq); int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *qpc, struct mlx5_wq_qp *wq, @@ -89,16 +88,18 @@ int mlx5_wq_qp_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *cqc, struct mlx5_cqwq *wq, struct mlx5_wq_ctrl *wq_ctrl); -u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq); -u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq); int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, void *wqc, struct mlx5_wq_ll *wq, struct mlx5_wq_ctrl *wq_ctrl); -u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq); void mlx5_wq_destroy(struct mlx5_wq_ctrl *wq_ctrl); +static inline u32 mlx5_wq_cyc_get_size(struct mlx5_wq_cyc *wq) +{ + return (u32)wq->fbc.sz_m1 + 1; +} + static inline int mlx5_wq_cyc_is_full(struct mlx5_wq_cyc *wq) { return wq->cur_sz == wq->sz; @@ -169,6 +170,16 @@ static inline int mlx5_wq_cyc_cc_bigger(u16 cc1, u16 cc2) return !equal && !smaller; } +static inline u32 mlx5_cqwq_get_size(struct mlx5_cqwq *wq) +{ + return wq->fbc.sz_m1 + 1; +} + +static inline u8 mlx5_cqwq_get_log_stride_size(struct mlx5_cqwq *wq) +{ + return wq->fbc.log_stride; +} + static inline u32 mlx5_cqwq_ctr2ix(struct mlx5_cqwq *wq, u32 ctr) { return ctr & wq->fbc.sz_m1; @@ -225,6 +236,11 @@ static inline struct mlx5_cqe64 *mlx5_cqwq_get_cqe(struct mlx5_cqwq *wq) return cqe; } +static inline u32 mlx5_wq_ll_get_size(struct mlx5_wq_ll *wq) +{ + return (u32)wq->fbc.sz_m1 + 1; +} + static inline int mlx5_wq_ll_is_full(struct mlx5_wq_ll *wq) { return wq->cur_sz == wq->fbc.sz_m1; -- cgit v1.2.3-59-g8ed1b From 88f30bbcbaaa1b124fcc622ff49e3d427da9c96c Mon Sep 17 00:00:00 2001 From: Dmytro Linkin Date: Wed, 2 Oct 2019 07:37:08 +0000 Subject: net/mlx5e: Bit sized fields rewrite support This patch doesn't change any functionality, but is a pre-step for adding support for rewriting of bit-sized fields, like DSCP and ECN in IPv4 header, similar fields in IPv6, etc. Signed-off-by: Dmytro Linkin Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 122 ++++++++++++------------ 1 file changed, 62 insertions(+), 60 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 8c4bce940bfb..67b73a00f8fa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2238,13 +2238,14 @@ out_err: struct mlx5_fields { u8 field; - u8 size; + u8 field_bsize; + u32 field_mask; u32 offset; u32 match_offset; }; -#define OFFLOAD(fw_field, size, field, off, match_field) \ - {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, size, \ +#define OFFLOAD(fw_field, field_bsize, field_mask, field, off, match_field) \ + {MLX5_ACTION_IN_FIELD_OUT_ ## fw_field, field_bsize, field_mask, \ offsetof(struct pedit_headers, field) + (off), \ MLX5_BYTE_OFF(fte_match_set_lyr_2_4, match_field)} @@ -2262,18 +2263,18 @@ struct mlx5_fields { }) static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp, - void *matchmaskp, int size) + void *matchmaskp, u8 bsize) { bool same = false; - switch (size) { - case sizeof(u8): + switch (bsize) { + case 8: same = SAME_VAL_MASK(u8, valp, maskp, matchvalp, matchmaskp); break; - case sizeof(u16): + case 16: same = SAME_VAL_MASK(u16, valp, maskp, matchvalp, matchmaskp); break; - case sizeof(u32): + case 32: same = SAME_VAL_MASK(u32, valp, maskp, matchvalp, matchmaskp); break; } @@ -2282,41 +2283,42 @@ static bool cmp_val_mask(void *valp, void *maskp, void *matchvalp, } static struct mlx5_fields fields[] = { - OFFLOAD(DMAC_47_16, 4, eth.h_dest[0], 0, dmac_47_16), - OFFLOAD(DMAC_15_0, 2, eth.h_dest[4], 0, dmac_15_0), - OFFLOAD(SMAC_47_16, 4, eth.h_source[0], 0, smac_47_16), - OFFLOAD(SMAC_15_0, 2, eth.h_source[4], 0, smac_15_0), - OFFLOAD(ETHERTYPE, 2, eth.h_proto, 0, ethertype), - OFFLOAD(FIRST_VID, 2, vlan.h_vlan_TCI, 0, first_vid), - - OFFLOAD(IP_TTL, 1, ip4.ttl, 0, ttl_hoplimit), - OFFLOAD(SIPV4, 4, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4), - OFFLOAD(DIPV4, 4, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), - - OFFLOAD(SIPV6_127_96, 4, ip6.saddr.s6_addr32[0], 0, + OFFLOAD(DMAC_47_16, 32, U32_MAX, eth.h_dest[0], 0, dmac_47_16), + OFFLOAD(DMAC_15_0, 16, U16_MAX, eth.h_dest[4], 0, dmac_15_0), + OFFLOAD(SMAC_47_16, 32, U32_MAX, eth.h_source[0], 0, smac_47_16), + OFFLOAD(SMAC_15_0, 16, U16_MAX, eth.h_source[4], 0, smac_15_0), + OFFLOAD(ETHERTYPE, 16, U16_MAX, eth.h_proto, 0, ethertype), + OFFLOAD(FIRST_VID, 16, U16_MAX, vlan.h_vlan_TCI, 0, first_vid), + + OFFLOAD(IP_TTL, 8, U8_MAX, ip4.ttl, 0, ttl_hoplimit), + OFFLOAD(SIPV4, 32, U32_MAX, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4), + OFFLOAD(DIPV4, 32, U32_MAX, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), + + OFFLOAD(SIPV6_127_96, 32, U32_MAX, ip6.saddr.s6_addr32[0], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[0]), - OFFLOAD(SIPV6_95_64, 4, ip6.saddr.s6_addr32[1], 0, + OFFLOAD(SIPV6_95_64, 32, U32_MAX, ip6.saddr.s6_addr32[1], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[4]), - OFFLOAD(SIPV6_63_32, 4, ip6.saddr.s6_addr32[2], 0, + OFFLOAD(SIPV6_63_32, 32, U32_MAX, ip6.saddr.s6_addr32[2], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[8]), - OFFLOAD(SIPV6_31_0, 4, ip6.saddr.s6_addr32[3], 0, + OFFLOAD(SIPV6_31_0, 32, U32_MAX, ip6.saddr.s6_addr32[3], 0, src_ipv4_src_ipv6.ipv6_layout.ipv6[12]), - OFFLOAD(DIPV6_127_96, 4, ip6.daddr.s6_addr32[0], 0, + OFFLOAD(DIPV6_127_96, 32, U32_MAX, ip6.daddr.s6_addr32[0], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[0]), - OFFLOAD(DIPV6_95_64, 4, ip6.daddr.s6_addr32[1], 0, + OFFLOAD(DIPV6_95_64, 32, U32_MAX, ip6.daddr.s6_addr32[1], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[4]), - OFFLOAD(DIPV6_63_32, 4, ip6.daddr.s6_addr32[2], 0, + OFFLOAD(DIPV6_63_32, 32, U32_MAX, ip6.daddr.s6_addr32[2], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[8]), - OFFLOAD(DIPV6_31_0, 4, ip6.daddr.s6_addr32[3], 0, + OFFLOAD(DIPV6_31_0, 32, U32_MAX, ip6.daddr.s6_addr32[3], 0, dst_ipv4_dst_ipv6.ipv6_layout.ipv6[12]), - OFFLOAD(IPV6_HOPLIMIT, 1, ip6.hop_limit, 0, ttl_hoplimit), + OFFLOAD(IPV6_HOPLIMIT, 8, U8_MAX, ip6.hop_limit, 0, ttl_hoplimit), - OFFLOAD(TCP_SPORT, 2, tcp.source, 0, tcp_sport), - OFFLOAD(TCP_DPORT, 2, tcp.dest, 0, tcp_dport), - OFFLOAD(TCP_FLAGS, 1, tcp.ack_seq, 5, tcp_flags), + OFFLOAD(TCP_SPORT, 16, U16_MAX, tcp.source, 0, tcp_sport), + OFFLOAD(TCP_DPORT, 16, U16_MAX, tcp.dest, 0, tcp_dport), + /* in linux iphdr tcp_flags is 8 bits long */ + OFFLOAD(TCP_FLAGS, 8, U8_MAX, tcp.ack_seq, 5, tcp_flags), - OFFLOAD(UDP_SPORT, 2, udp.source, 0, udp_sport), - OFFLOAD(UDP_DPORT, 2, udp.dest, 0, udp_dport), + OFFLOAD(UDP_SPORT, 16, U16_MAX, udp.source, 0, udp_sport), + OFFLOAD(UDP_DPORT, 16, U16_MAX, udp.dest, 0, udp_dport), }; /* On input attr->max_mod_hdr_actions tells how many HW actions can be parsed at @@ -2329,19 +2331,17 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, struct netlink_ext_ack *extack) { struct pedit_headers *set_masks, *add_masks, *set_vals, *add_vals; - void *headers_c = get_match_headers_criteria(*action_flags, - &parse_attr->spec); - void *headers_v = get_match_headers_value(*action_flags, - &parse_attr->spec); int i, action_size, nactions, max_actions, first, last, next_z; - void *s_masks_p, *a_masks_p, *vals_p; + void *headers_c, *headers_v, *action, *vals_p; + u32 *s_masks_p, *a_masks_p, s_mask, a_mask; struct mlx5_fields *f; - u8 cmd, field_bsize; - u32 s_mask, a_mask; unsigned long mask; __be32 mask_be32; __be16 mask_be16; - void *action; + u8 cmd; + + headers_c = get_match_headers_criteria(*action_flags, &parse_attr->spec); + headers_v = get_match_headers_value(*action_flags, &parse_attr->spec); set_masks = &hdrs[0].masks; add_masks = &hdrs[1].masks; @@ -2366,8 +2366,8 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, s_masks_p = (void *)set_masks + f->offset; a_masks_p = (void *)add_masks + f->offset; - memcpy(&s_mask, s_masks_p, f->size); - memcpy(&a_mask, a_masks_p, f->size); + s_mask = *s_masks_p & f->field_mask; + a_mask = *a_masks_p & f->field_mask; if (!s_mask && !a_mask) /* nothing to offload here */ continue; @@ -2396,38 +2396,34 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, vals_p = (void *)set_vals + f->offset; /* don't rewrite if we have a match on the same value */ if (cmp_val_mask(vals_p, s_masks_p, match_val, - match_mask, f->size)) + match_mask, f->field_bsize)) skip = true; /* clear to denote we consumed this field */ - memset(s_masks_p, 0, f->size); + *s_masks_p &= ~f->field_mask; } else { - u32 zero = 0; - cmd = MLX5_ACTION_TYPE_ADD; mask = a_mask; vals_p = (void *)add_vals + f->offset; /* add 0 is no change */ - if (!memcmp(vals_p, &zero, f->size)) + if ((*(u32 *)vals_p & f->field_mask) == 0) skip = true; /* clear to denote we consumed this field */ - memset(a_masks_p, 0, f->size); + *a_masks_p &= ~f->field_mask; } if (skip) continue; - field_bsize = f->size * BITS_PER_BYTE; - - if (field_bsize == 32) { + if (f->field_bsize == 32) { mask_be32 = *(__be32 *)&mask; mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32)); - } else if (field_bsize == 16) { + } else if (f->field_bsize == 16) { mask_be16 = *(__be16 *)&mask; mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16)); } - first = find_first_bit(&mask, field_bsize); - next_z = find_next_zero_bit(&mask, field_bsize, first); - last = find_last_bit(&mask, field_bsize); + first = find_first_bit(&mask, f->field_bsize); + next_z = find_next_zero_bit(&mask, f->field_bsize, first); + last = find_last_bit(&mask, f->field_bsize); if (first < next_z && next_z < last) { NL_SET_ERR_MSG_MOD(extack, "rewrite of few sub-fields isn't supported"); @@ -2440,16 +2436,22 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs, MLX5_SET(set_action_in, action, field, f->field); if (cmd == MLX5_ACTION_TYPE_SET) { - MLX5_SET(set_action_in, action, offset, first); + int start; + + /* if field is bit sized it can start not from first bit */ + start = find_first_bit((unsigned long *)&f->field_mask, + f->field_bsize); + + MLX5_SET(set_action_in, action, offset, first - start); /* length is num of bits to be written, zero means length of 32 */ MLX5_SET(set_action_in, action, length, (last - first + 1)); } - if (field_bsize == 32) + if (f->field_bsize == 32) MLX5_SET(set_action_in, action, data, ntohl(*(__be32 *)vals_p) >> first); - else if (field_bsize == 16) + else if (f->field_bsize == 16) MLX5_SET(set_action_in, action, data, ntohs(*(__be16 *)vals_p) >> first); - else if (field_bsize == 8) + else if (f->field_bsize == 8) MLX5_SET(set_action_in, action, data, *(u8 *)vals_p >> first); action += action_size; -- cgit v1.2.3-59-g8ed1b From ab9341b54969a2d02dbb7819e2f17c2f0d9cf5b5 Mon Sep 17 00:00:00 2001 From: Dmytro Linkin Date: Mon, 7 Oct 2019 10:48:00 +0000 Subject: net/mlx5e: Add ToS (DSCP) header rewrite support Add support for rewriting of DSCP part of ToS field. Next commands, for example, can be used to offload rewrite action: OVS: $ ovs-ofctl add-flow ovs-sriov "ip, in_port=REP, \ actions=mod_nw_tos:68, output:NIC" iproute2 (used retain mask, as tc command rewrite whole ToS field): $ tc filter add dev REP ingress protocol ip prio 1 flower skip_sw \ ip_proto icmp action pedit munge ip tos set 68 retain 0xfc pipe \ action mirred egress redirect dev NIC Signed-off-by: Dmytro Linkin Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 67b73a00f8fa..4b4be896383f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2290,6 +2290,7 @@ static struct mlx5_fields fields[] = { OFFLOAD(ETHERTYPE, 16, U16_MAX, eth.h_proto, 0, ethertype), OFFLOAD(FIRST_VID, 16, U16_MAX, vlan.h_vlan_TCI, 0, first_vid), + OFFLOAD(IP_DSCP, 8, 0xfc, ip4.tos, 0, ip_dscp), OFFLOAD(IP_TTL, 8, U8_MAX, ip4.ttl, 0, ttl_hoplimit), OFFLOAD(SIPV4, 32, U32_MAX, ip4.saddr, 0, src_ipv4_src_ipv6.ipv4_layout.ipv4), OFFLOAD(DIPV4, 32, U32_MAX, ip4.daddr, 0, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), -- cgit v1.2.3-59-g8ed1b From 5a212e0cac548e5e4fb3f2ba1b5b2f6c8949687d Mon Sep 17 00:00:00 2001 From: Li RongQing Date: Thu, 24 Oct 2019 16:23:33 +0800 Subject: net/mlx5: rate limit alloc_ent error messages when debug a bug, which triggers TX hang, and kernel log is spammed with the following info message [ 1172.044764] mlx5_core 0000:21:00.0: cmd_work_handler:930:(pid 8): failed to allocate command entry Signed-off-by: Li RongQing Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index ea934cd02448..34cba97f7bf4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -866,7 +866,7 @@ static void cmd_work_handler(struct work_struct *work) if (!ent->page_queue) { alloc_ret = alloc_ent(cmd); if (alloc_ret < 0) { - mlx5_core_err(dev, "failed to allocate command entry\n"); + mlx5_core_err_rl(dev, "failed to allocate command entry\n"); if (ent->callback) { ent->callback(-EAGAIN, ent->context); mlx5_free_cmd_msg(dev, ent->out); -- cgit v1.2.3-59-g8ed1b From 84d2dbb0aaaf1098aa2c2ca07003bf3f973732ac Mon Sep 17 00:00:00 2001 From: Erez Alfasi Date: Mon, 16 Sep 2019 13:59:58 +0300 Subject: net/mlx5: LAG, Use port enumerators Instead of using explicit array indexes, simply use ports enumerators to make the code more readable. Fixes: 7907f23adc18 ("net/mlx5: Implement RoCE LAG feature") Signed-off-by: Erez Alfasi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag.c | 65 +++++++++++++----------- drivers/net/ethernet/mellanox/mlx5/core/lag.h | 5 ++ drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c | 56 ++++++++++---------- 3 files changed, 69 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag.c index c5ef2ff26465..fc0d9583475d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.c @@ -145,34 +145,35 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, { *port1 = 1; *port2 = 2; - if (!tracker->netdev_state[0].tx_enabled || - !tracker->netdev_state[0].link_up) { + if (!tracker->netdev_state[MLX5_LAG_P1].tx_enabled || + !tracker->netdev_state[MLX5_LAG_P1].link_up) { *port1 = 2; return; } - if (!tracker->netdev_state[1].tx_enabled || - !tracker->netdev_state[1].link_up) + if (!tracker->netdev_state[MLX5_LAG_P2].tx_enabled || + !tracker->netdev_state[MLX5_LAG_P2].link_up) *port2 = 1; } void mlx5_modify_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; u8 v2p_port1, v2p_port2; int err; mlx5_infer_tx_affinity_mapping(tracker, &v2p_port1, &v2p_port2); - if (v2p_port1 != ldev->v2p_map[0] || - v2p_port2 != ldev->v2p_map[1]) { - ldev->v2p_map[0] = v2p_port1; - ldev->v2p_map[1] = v2p_port2; + if (v2p_port1 != ldev->v2p_map[MLX5_LAG_P1] || + v2p_port2 != ldev->v2p_map[MLX5_LAG_P2]) { + ldev->v2p_map[MLX5_LAG_P1] = v2p_port1; + ldev->v2p_map[MLX5_LAG_P2] = v2p_port2; mlx5_core_info(dev0, "modify lag map port 1:%d port 2:%d", - ldev->v2p_map[0], ldev->v2p_map[1]); + ldev->v2p_map[MLX5_LAG_P1], + ldev->v2p_map[MLX5_LAG_P2]); err = mlx5_cmd_modify_lag(dev0, v2p_port1, v2p_port2); if (err) @@ -185,16 +186,17 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, static int mlx5_create_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; int err; - mlx5_infer_tx_affinity_mapping(tracker, &ldev->v2p_map[0], - &ldev->v2p_map[1]); + mlx5_infer_tx_affinity_mapping(tracker, &ldev->v2p_map[MLX5_LAG_P1], + &ldev->v2p_map[MLX5_LAG_P2]); mlx5_core_info(dev0, "lag map port 1:%d port 2:%d", - ldev->v2p_map[0], ldev->v2p_map[1]); + ldev->v2p_map[MLX5_LAG_P1], ldev->v2p_map[MLX5_LAG_P2]); - err = mlx5_cmd_create_lag(dev0, ldev->v2p_map[0], ldev->v2p_map[1]); + err = mlx5_cmd_create_lag(dev0, ldev->v2p_map[MLX5_LAG_P1], + ldev->v2p_map[MLX5_LAG_P2]); if (err) mlx5_core_err(dev0, "Failed to create LAG (%d)\n", @@ -207,7 +209,7 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, u8 flags) { bool roce_lag = !!(flags & MLX5_LAG_FLAG_ROCE); - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; int err; err = mlx5_create_lag(ldev, tracker); @@ -229,7 +231,7 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, static int mlx5_deactivate_lag(struct mlx5_lag *ldev) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; + struct mlx5_core_dev *dev0 = ldev->pf[MLX5_LAG_P1].dev; bool roce_lag = __mlx5_lag_is_roce(ldev); int err; @@ -252,14 +254,15 @@ static int mlx5_deactivate_lag(struct mlx5_lag *ldev) static bool mlx5_lag_check_prereq(struct mlx5_lag *ldev) { - if (!ldev->pf[0].dev || !ldev->pf[1].dev) + if (!ldev->pf[MLX5_LAG_P1].dev || !ldev->pf[MLX5_LAG_P2].dev) return false; #ifdef CONFIG_MLX5_ESWITCH - return mlx5_esw_lag_prereq(ldev->pf[0].dev, ldev->pf[1].dev); + return mlx5_esw_lag_prereq(ldev->pf[MLX5_LAG_P1].dev, + ldev->pf[MLX5_LAG_P2].dev); #else - return (!mlx5_sriov_is_enabled(ldev->pf[0].dev) && - !mlx5_sriov_is_enabled(ldev->pf[1].dev)); + return (!mlx5_sriov_is_enabled(ldev->pf[MLX5_LAG_P1].dev) && + !mlx5_sriov_is_enabled(ldev->pf[MLX5_LAG_P2].dev)); #endif } @@ -285,8 +288,8 @@ static void mlx5_lag_remove_ib_devices(struct mlx5_lag *ldev) static void mlx5_do_bond(struct mlx5_lag *ldev) { - struct mlx5_core_dev *dev0 = ldev->pf[0].dev; - struct mlx5_core_dev *dev1 = ldev->pf[1].dev; + 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; @@ -692,10 +695,11 @@ struct net_device *mlx5_lag_get_roce_netdev(struct mlx5_core_dev *dev) goto unlock; if (ldev->tracker.tx_type == NETDEV_LAG_TX_TYPE_ACTIVEBACKUP) { - ndev = ldev->tracker.netdev_state[0].tx_enabled ? - ldev->pf[0].netdev : ldev->pf[1].netdev; + ndev = ldev->tracker.netdev_state[MLX5_LAG_P1].tx_enabled ? + ldev->pf[MLX5_LAG_P1].netdev : + ldev->pf[MLX5_LAG_P2].netdev; } else { - ndev = ldev->pf[0].netdev; + ndev = ldev->pf[MLX5_LAG_P1].netdev; } if (ndev) dev_hold(ndev); @@ -717,7 +721,8 @@ bool mlx5_lag_intf_add(struct mlx5_interface *intf, struct mlx5_priv *priv) return true; ldev = mlx5_lag_dev_get(dev); - if (!ldev || !__mlx5_lag_is_roce(ldev) || ldev->pf[0].dev == dev) + if (!ldev || !__mlx5_lag_is_roce(ldev) || + ldev->pf[MLX5_LAG_P1].dev == dev) return true; /* If bonded, we do not add an IB device for PF1. */ @@ -746,11 +751,11 @@ int mlx5_lag_query_cong_counters(struct mlx5_core_dev *dev, ldev = mlx5_lag_dev_get(dev); if (ldev && __mlx5_lag_is_roce(ldev)) { num_ports = MLX5_MAX_PORTS; - mdev[0] = ldev->pf[0].dev; - mdev[1] = ldev->pf[1].dev; + mdev[MLX5_LAG_P1] = ldev->pf[MLX5_LAG_P1].dev; + mdev[MLX5_LAG_P2] = ldev->pf[MLX5_LAG_P2].dev; } else { num_ports = 1; - mdev[0] = dev; + mdev[MLX5_LAG_P1] = dev; } for (i = 0; i < num_ports; ++i) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag.h index 1dea0b1c9826..f1068aac6406 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag.h @@ -7,6 +7,11 @@ #include "mlx5_core.h" #include "lag_mp.h" +enum { + MLX5_LAG_P1, + MLX5_LAG_P2, +}; + enum { MLX5_LAG_FLAG_ROCE = 1 << 0, MLX5_LAG_FLAG_SRIOV = 1 << 1, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c index 13e2944b1274..5169864dd656 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c @@ -11,10 +11,11 @@ static bool mlx5_lag_multipath_check_prereq(struct mlx5_lag *ldev) { - if (!ldev->pf[0].dev || !ldev->pf[1].dev) + if (!ldev->pf[MLX5_LAG_P1].dev || !ldev->pf[MLX5_LAG_P2].dev) return false; - return mlx5_esw_multipath_prereq(ldev->pf[0].dev, ldev->pf[1].dev); + return mlx5_esw_multipath_prereq(ldev->pf[MLX5_LAG_P1].dev, + ldev->pf[MLX5_LAG_P2].dev); } static bool __mlx5_lag_is_multipath(struct mlx5_lag *ldev) @@ -52,36 +53,36 @@ static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, int port) switch (port) { case 0: - tracker.netdev_state[0].tx_enabled = true; - tracker.netdev_state[1].tx_enabled = true; - tracker.netdev_state[0].link_up = true; - tracker.netdev_state[1].link_up = true; + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P1].link_up = true; + tracker.netdev_state[MLX5_LAG_P2].link_up = true; break; case 1: - tracker.netdev_state[0].tx_enabled = true; - tracker.netdev_state[0].link_up = true; - tracker.netdev_state[1].tx_enabled = false; - tracker.netdev_state[1].link_up = false; + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P1].link_up = true; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = false; + tracker.netdev_state[MLX5_LAG_P2].link_up = false; break; case 2: - tracker.netdev_state[0].tx_enabled = false; - tracker.netdev_state[0].link_up = false; - tracker.netdev_state[1].tx_enabled = true; - tracker.netdev_state[1].link_up = true; + tracker.netdev_state[MLX5_LAG_P1].tx_enabled = false; + tracker.netdev_state[MLX5_LAG_P1].link_up = false; + tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; + tracker.netdev_state[MLX5_LAG_P2].link_up = true; break; default: - mlx5_core_warn(ldev->pf[0].dev, "Invalid affinity port %d", - port); + mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev, + "Invalid affinity port %d", port); return; } - if (tracker.netdev_state[0].tx_enabled) - mlx5_notifier_call_chain(ldev->pf[0].dev->priv.events, + if (tracker.netdev_state[MLX5_LAG_P1].tx_enabled) + mlx5_notifier_call_chain(ldev->pf[MLX5_LAG_P1].dev->priv.events, MLX5_DEV_EVENT_PORT_AFFINITY, (void *)0); - if (tracker.netdev_state[1].tx_enabled) - mlx5_notifier_call_chain(ldev->pf[1].dev->priv.events, + if (tracker.netdev_state[MLX5_LAG_P2].tx_enabled) + mlx5_notifier_call_chain(ldev->pf[MLX5_LAG_P2].dev->priv.events, MLX5_DEV_EVENT_PORT_AFFINITY, (void *)0); @@ -141,11 +142,12 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, /* Verify next hops are ports of the same hca */ fib_nh0 = fib_info_nh(fi, 0); fib_nh1 = fib_info_nh(fi, 1); - if (!(fib_nh0->fib_nh_dev == ldev->pf[0].netdev && - fib_nh1->fib_nh_dev == ldev->pf[1].netdev) && - !(fib_nh0->fib_nh_dev == ldev->pf[1].netdev && - fib_nh1->fib_nh_dev == ldev->pf[0].netdev)) { - mlx5_core_warn(ldev->pf[0].dev, "Multipath offload require two ports of the same HCA\n"); + if (!(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev && + fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev) && + !(fib_nh0->fib_nh_dev == ldev->pf[MLX5_LAG_P2].netdev && + fib_nh1->fib_nh_dev == ldev->pf[MLX5_LAG_P1].netdev)) { + mlx5_core_warn(ldev->pf[MLX5_LAG_P1].dev, + "Multipath offload require two ports of the same HCA\n"); return; } @@ -267,8 +269,8 @@ static int mlx5_lag_fib_event(struct notifier_block *nb, return notifier_from_errno(-EINVAL); } fib_dev = fib_info_nh(fen_info->fi, 0)->fib_nh_dev; - if (fib_dev != ldev->pf[0].netdev && - fib_dev != ldev->pf[1].netdev) { + if (fib_dev != ldev->pf[MLX5_LAG_P1].netdev && + fib_dev != ldev->pf[MLX5_LAG_P2].netdev) { return NOTIFY_DONE; } fib_work = mlx5_lag_init_fib_work(ldev, event); -- cgit v1.2.3-59-g8ed1b From 1cdc14e9d134a48d86673fd75a6abcbe0e58a29c Mon Sep 17 00:00:00 2001 From: Erez Alfasi Date: Mon, 16 Sep 2019 14:34:55 +0300 Subject: net/mlx5: LAG, Use affinity type enumerators Instead of using explicit indexes, simply use affinity type enumerators to make the code more readable. Fixes: 544fe7c2e654 ("net/mlx5e: Activate HW multipath and handle port affinity based on FIB events") Signed-off-by: Erez Alfasi Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c | 13 +++++++------ drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h | 6 ++++++ 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c index 5169864dd656..b70afa310ad2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.c @@ -44,7 +44,8 @@ bool mlx5_lag_is_multipath(struct mlx5_core_dev *dev) * 2 - set affinity to port 2. * **/ -static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, int port) +static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, + enum mlx5_lag_port_affinity port) { struct lag_tracker tracker; @@ -52,19 +53,19 @@ static void mlx5_lag_set_port_affinity(struct mlx5_lag *ldev, int port) return; switch (port) { - case 0: + case MLX5_LAG_NORMAL_AFFINITY: tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; tracker.netdev_state[MLX5_LAG_P1].link_up = true; tracker.netdev_state[MLX5_LAG_P2].link_up = true; break; - case 1: + case MLX5_LAG_P1_AFFINITY: tracker.netdev_state[MLX5_LAG_P1].tx_enabled = true; tracker.netdev_state[MLX5_LAG_P1].link_up = true; tracker.netdev_state[MLX5_LAG_P2].tx_enabled = false; tracker.netdev_state[MLX5_LAG_P2].link_up = false; break; - case 2: + case MLX5_LAG_P2_AFFINITY: tracker.netdev_state[MLX5_LAG_P1].tx_enabled = false; tracker.netdev_state[MLX5_LAG_P1].link_up = false; tracker.netdev_state[MLX5_LAG_P2].tx_enabled = true; @@ -159,7 +160,7 @@ static void mlx5_lag_fib_route_event(struct mlx5_lag *ldev, mlx5_activate_lag(ldev, &tracker, MLX5_LAG_FLAG_MULTIPATH); } - mlx5_lag_set_port_affinity(ldev, 0); + mlx5_lag_set_port_affinity(ldev, MLX5_LAG_NORMAL_AFFINITY); mp->mfi = fi; } @@ -184,7 +185,7 @@ static void mlx5_lag_fib_nexthop_event(struct mlx5_lag *ldev, } } else if (event == FIB_EVENT_NH_ADD && fib_info_num_path(fi) == 2) { - mlx5_lag_set_port_affinity(ldev, 0); + mlx5_lag_set_port_affinity(ldev, MLX5_LAG_NORMAL_AFFINITY); } } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h index 6d14b1100be9..79be89e9c7a4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag_mp.h @@ -7,6 +7,12 @@ #include "lag.h" #include "mlx5_core.h" +enum mlx5_lag_port_affinity { + MLX5_LAG_NORMAL_AFFINITY, + MLX5_LAG_P1_AFFINITY, + MLX5_LAG_P2_AFFINITY, +}; + struct lag_mp { struct notifier_block fib_nb; struct fib_info *mfi; /* used in tracking fib events */ -- cgit v1.2.3-59-g8ed1b From 667f264676c7f83f57a7695010f889d6fd36dcbf Mon Sep 17 00:00:00 2001 From: Alex Vesker Date: Sun, 27 Oct 2019 09:10:17 +0200 Subject: net/mlx5: DR, Support IPv4 and IPv6 mixed matcher Until now SW steering supported matchers that are IPv4 and IPv6. The limitation was mixed matchers in which the outer header IP version was different from the inner header IP version. To support the mixed matcher we create all the possible ste_builder combinations, once we create a rule we select the correct one to be used for rule creation. Signed-off-by: Alex Vesker Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/steering/dr_matcher.c | 65 +++++++++++----------- .../ethernet/mellanox/mlx5/core/steering/dr_rule.c | 13 +++-- .../mellanox/mlx5/core/steering/dr_types.h | 17 ++++-- 3 files changed, 52 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c index 67dea7698fc9..5db947df8763 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c @@ -146,17 +146,15 @@ dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_domain *dmn) int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6) + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) { - if (ipv6) { - nic_matcher->ste_builder = nic_matcher->ste_builder6; - nic_matcher->num_of_builders = nic_matcher->num_of_builders6; - } else { - nic_matcher->ste_builder = nic_matcher->ste_builder4; - nic_matcher->num_of_builders = nic_matcher->num_of_builders4; - } + nic_matcher->ste_builder = + nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; + nic_matcher->num_of_builders = + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; - if (!nic_matcher->num_of_builders) { + if (!nic_matcher->ste_builder) { mlx5dr_dbg(matcher->tbl->dmn, "Rule not supported on this matcher due to IP related fields\n"); return -EINVAL; @@ -167,26 +165,19 @@ int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6) + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv) { struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn; struct mlx5dr_domain *dmn = matcher->tbl->dmn; struct mlx5dr_match_param mask = {}; struct mlx5dr_match_misc3 *misc3; struct mlx5dr_ste_build *sb; - u8 *num_of_builders; bool inner, rx; int idx = 0; int ret, i; - if (ipv6) { - sb = nic_matcher->ste_builder6; - num_of_builders = &nic_matcher->num_of_builders6; - } else { - sb = nic_matcher->ste_builder4; - num_of_builders = &nic_matcher->num_of_builders4; - } - + sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv]; rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX; /* Create a temporary mask to track and clear used mask fields */ @@ -249,7 +240,7 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer)) mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); - if (ipv6) { + if (outer_ipv == DR_RULE_IPV6) { if (dr_mask_is_dst_addr_set(&mask.outer)) mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, inner, rx); @@ -325,7 +316,7 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner)) mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx); - if (ipv6) { + if (inner_ipv == DR_RULE_IPV6) { if (dr_mask_is_dst_addr_set(&mask.inner)) mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask, inner, rx); @@ -373,7 +364,8 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, } } - *num_of_builders = idx; + nic_matcher->ste_builder = sb; + nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx; return 0; } @@ -524,24 +516,33 @@ static void dr_matcher_uninit(struct mlx5dr_matcher *matcher) } } -static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, - struct mlx5dr_matcher_rx_tx *nic_matcher) +static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) { struct mlx5dr_domain *dmn = matcher->tbl->dmn; - int ret, ret_v4, ret_v6; - ret_v4 = dr_matcher_set_ste_builders(matcher, nic_matcher, false); - ret_v6 = dr_matcher_set_ste_builders(matcher, nic_matcher, true); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4); + dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6); - if (ret_v4 && ret_v6) { + if (!nic_matcher->ste_builder) { mlx5dr_dbg(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n"); return -EINVAL; } - if (!ret_v4) - nic_matcher->ste_builder = nic_matcher->ste_builder4; - else - nic_matcher->ste_builder = nic_matcher->ste_builder6; + return 0; +} + +static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher, + struct mlx5dr_matcher_rx_tx *nic_matcher) +{ + struct mlx5dr_domain *dmn = matcher->tbl->dmn; + int ret; + + ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher); + if (ret) + return ret; nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, DR_CHUNK_SIZE_1, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c index e8b656075c6f..90c79a133692 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_rule.c @@ -954,12 +954,12 @@ static int dr_rule_destroy_rule(struct mlx5dr_rule *rule) return 0; } -static bool dr_rule_is_ipv6(struct mlx5dr_match_param *param) +static enum mlx5dr_ipv dr_rule_get_ipv(struct mlx5dr_match_spec *spec) { - return (param->outer.ip_version == 6 || - param->inner.ip_version == 6 || - param->outer.ethertype == ETH_P_IPV6 || - param->inner.ethertype == ETH_P_IPV6); + if (spec->ip_version == 6 || spec->ethertype == ETH_P_IPV6) + return DR_RULE_IPV6; + + return DR_RULE_IPV4; } static bool dr_rule_skip(enum mlx5dr_domain_type domain, @@ -1023,7 +1023,8 @@ dr_rule_create_rule_nic(struct mlx5dr_rule *rule, ret = mlx5dr_matcher_select_builders(matcher, nic_matcher, - dr_rule_is_ipv6(param)); + dr_rule_get_ipv(¶m->outer), + dr_rule_get_ipv(¶m->inner)); if (ret) goto out_err; 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 d6d9bc5f4adf..c1f45a60ee6b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -106,6 +106,12 @@ enum mlx5dr_action_type { DR_ACTION_TYP_MAX, }; +enum mlx5dr_ipv { + DR_RULE_IPV4, + DR_RULE_IPV6, + DR_RULE_IPV_MAX, +}; + struct mlx5dr_icm_pool; struct mlx5dr_icm_chunk; struct mlx5dr_icm_bucket; @@ -679,11 +685,11 @@ struct mlx5dr_matcher_rx_tx { struct mlx5dr_ste_htbl *s_htbl; struct mlx5dr_ste_htbl *e_anchor; struct mlx5dr_ste_build *ste_builder; - struct mlx5dr_ste_build ste_builder4[DR_RULE_MAX_STES]; - struct mlx5dr_ste_build ste_builder6[DR_RULE_MAX_STES]; + struct mlx5dr_ste_build ste_builder_arr[DR_RULE_IPV_MAX] + [DR_RULE_IPV_MAX] + [DR_RULE_MAX_STES]; u8 num_of_builders; - u8 num_of_builders4; - u8 num_of_builders6; + u8 num_of_builders_arr[DR_RULE_IPV_MAX][DR_RULE_IPV_MAX]; u64 default_icm_addr; struct mlx5dr_table_rx_tx *nic_tbl; }; @@ -812,7 +818,8 @@ mlx5dr_matcher_supp_flex_parser_icmp_v6(struct mlx5dr_cmd_caps *caps) int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, - bool ipv6); + enum mlx5dr_ipv outer_ipv, + enum mlx5dr_ipv inner_ipv); static inline u32 mlx5dr_icm_pool_chunk_size_to_entries(enum mlx5dr_icm_chunk_size chunk_size) -- cgit v1.2.3-59-g8ed1b From eff380aaffedb279b69d160061e2c01f9df5da96 Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Thu, 24 Oct 2019 01:11:17 -0700 Subject: ice: Introduce ice_base.c Remove a few uses of kernel configuration flags from ice_lib.c by introducing a new source file ice_base.c. Also move corresponding function prototypes from ice_lib.h to ice_base.h and include ice_base.h where required. Signed-off-by: Anirudh Venkataramanan Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice.h | 8 + drivers/net/ethernet/intel/ice/ice_base.c | 767 ++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_base.h | 31 + drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 1 + drivers/net/ethernet/intel/ice/ice_lib.c | 787 +---------------------- drivers/net/ethernet/intel/ice/ice_lib.h | 39 -- drivers/net/ethernet/intel/ice/ice_main.c | 1 + drivers/net/ethernet/intel/ice/ice_txrx.h | 2 - drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 1 + 10 files changed, 811 insertions(+), 827 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_base.c create mode 100644 drivers/net/ethernet/intel/ice/ice_base.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 9edde960b4f2..101313e55a11 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -13,6 +13,7 @@ ice-y := ice_main.o \ ice_nvm.o \ ice_switch.o \ ice_sched.o \ + ice_base.o \ ice_lib.o \ ice_txrx.o \ ice_flex_pipe.o \ diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 45e100666049..0b5aa8feae26 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -127,6 +127,14 @@ extern const char ice_drv_ver[]; ICE_PROMISC_VLAN_TX | \ ICE_PROMISC_VLAN_RX) +struct ice_txq_meta { + u32 q_teid; /* Tx-scheduler element identifier */ + u16 q_id; /* Entry in VSI's txq_map bitmap */ + u16 q_handle; /* Relative index of Tx queue within TC */ + u16 vsi_idx; /* VSI index that Tx queue belongs to */ + u8 tc; /* TC number that Tx queue belongs to */ +}; + struct ice_tc_info { u16 qoffset; u16 qcount_tx; diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c new file mode 100644 index 000000000000..735922a4d632 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -0,0 +1,767 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Intel Corporation. */ + +#include "ice_base.h" +#include "ice_dcb_lib.h" + +/** + * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI + * @qs_cfg: gathered variables needed for PF->VSI queues assignment + * + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap + */ +static int __ice_vsi_get_qs_contig(struct ice_qs_cfg *qs_cfg) +{ + int offset, i; + + mutex_lock(qs_cfg->qs_mutex); + offset = bitmap_find_next_zero_area(qs_cfg->pf_map, qs_cfg->pf_map_size, + 0, qs_cfg->q_count, 0); + if (offset >= qs_cfg->pf_map_size) { + mutex_unlock(qs_cfg->qs_mutex); + return -ENOMEM; + } + + bitmap_set(qs_cfg->pf_map, offset, qs_cfg->q_count); + for (i = 0; i < qs_cfg->q_count; i++) + qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = i + offset; + mutex_unlock(qs_cfg->qs_mutex); + + return 0; +} + +/** + * __ice_vsi_get_qs_sc - Assign a scattered queues from PF to VSI + * @qs_cfg: gathered variables needed for pf->vsi queues assignment + * + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap + */ +static int __ice_vsi_get_qs_sc(struct ice_qs_cfg *qs_cfg) +{ + int i, index = 0; + + mutex_lock(qs_cfg->qs_mutex); + for (i = 0; i < qs_cfg->q_count; i++) { + index = find_next_zero_bit(qs_cfg->pf_map, + qs_cfg->pf_map_size, index); + if (index >= qs_cfg->pf_map_size) + goto err_scatter; + set_bit(index, qs_cfg->pf_map); + qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = index; + } + mutex_unlock(qs_cfg->qs_mutex); + + return 0; +err_scatter: + for (index = 0; index < i; index++) { + clear_bit(qs_cfg->vsi_map[index], qs_cfg->pf_map); + qs_cfg->vsi_map[index + qs_cfg->vsi_map_offset] = 0; + } + mutex_unlock(qs_cfg->qs_mutex); + + return -ENOMEM; +} + +/** + * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled + * @pf: the PF being configured + * @pf_q: the PF queue + * @ena: enable or disable state of the queue + * + * This routine will wait for the given Rx queue of the PF to reach the + * enabled or disabled state. + * Returns -ETIMEDOUT in case of failing to reach the requested state after + * multiple retries; else will return 0 in case of success. + */ +static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena) +{ + int i; + + for (i = 0; i < ICE_Q_WAIT_MAX_RETRY; i++) { + if (ena == !!(rd32(&pf->hw, QRX_CTRL(pf_q)) & + QRX_CTRL_QENA_STAT_M)) + return 0; + + usleep_range(20, 40); + } + + return -ETIMEDOUT; +} + +/** + * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector + * @vsi: the VSI being configured + * @v_idx: index of the vector in the VSI struct + * + * We allocate one q_vector. If allocation fails we return -ENOMEM. + */ +static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) +{ + struct ice_pf *pf = vsi->back; + struct ice_q_vector *q_vector; + + /* allocate q_vector */ + q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); + if (!q_vector) + return -ENOMEM; + + q_vector->vsi = vsi; + q_vector->v_idx = v_idx; + if (vsi->type == ICE_VSI_VF) + goto out; + /* only set affinity_mask if the CPU is online */ + if (cpu_online(v_idx)) + cpumask_set_cpu(v_idx, &q_vector->affinity_mask); + + /* This will not be called in the driver load path because the netdev + * will not be created yet. All other cases with register the NAPI + * handler here (i.e. resume, reset/rebuild, etc.) + */ + if (vsi->netdev) + netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll, + NAPI_POLL_WEIGHT); + +out: + /* tie q_vector and VSI together */ + vsi->q_vectors[v_idx] = q_vector; + + return 0; +} + +/** + * ice_free_q_vector - Free memory allocated for a specific interrupt vector + * @vsi: VSI having the memory freed + * @v_idx: index of the vector to be freed + */ +static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) +{ + struct ice_q_vector *q_vector; + struct ice_pf *pf = vsi->back; + struct ice_ring *ring; + + if (!vsi->q_vectors[v_idx]) { + dev_dbg(&pf->pdev->dev, "Queue vector at index %d not found\n", + v_idx); + return; + } + q_vector = vsi->q_vectors[v_idx]; + + ice_for_each_ring(ring, q_vector->tx) + ring->q_vector = NULL; + ice_for_each_ring(ring, q_vector->rx) + ring->q_vector = NULL; + + /* only VSI with an associated netdev is set up with NAPI */ + if (vsi->netdev) + netif_napi_del(&q_vector->napi); + + devm_kfree(&pf->pdev->dev, q_vector); + vsi->q_vectors[v_idx] = NULL; +} + +/** + * ice_cfg_itr_gran - set the ITR granularity to 2 usecs if not already set + * @hw: board specific structure + */ +static void ice_cfg_itr_gran(struct ice_hw *hw) +{ + u32 regval = rd32(hw, GLINT_CTL); + + /* no need to update global register if ITR gran is already set */ + if (!(regval & GLINT_CTL_DIS_AUTOMASK_M) && + (((regval & GLINT_CTL_ITR_GRAN_200_M) >> + GLINT_CTL_ITR_GRAN_200_S) == ICE_ITR_GRAN_US) && + (((regval & GLINT_CTL_ITR_GRAN_100_M) >> + GLINT_CTL_ITR_GRAN_100_S) == ICE_ITR_GRAN_US) && + (((regval & GLINT_CTL_ITR_GRAN_50_M) >> + GLINT_CTL_ITR_GRAN_50_S) == ICE_ITR_GRAN_US) && + (((regval & GLINT_CTL_ITR_GRAN_25_M) >> + GLINT_CTL_ITR_GRAN_25_S) == ICE_ITR_GRAN_US)) + return; + + regval = ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_200_S) & + GLINT_CTL_ITR_GRAN_200_M) | + ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_100_S) & + GLINT_CTL_ITR_GRAN_100_M) | + ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_50_S) & + GLINT_CTL_ITR_GRAN_50_M) | + ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_25_S) & + GLINT_CTL_ITR_GRAN_25_M); + wr32(hw, GLINT_CTL, regval); +} + +/** + * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance + * @ring: The Tx ring to configure + * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized + * @pf_q: queue index in the PF space + * + * Configure the Tx descriptor ring in TLAN context. + */ +static void +ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) +{ + struct ice_vsi *vsi = ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + + tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; + + tlan_ctx->port_num = vsi->port_info->lport; + + /* Transmit Queue Length */ + tlan_ctx->qlen = ring->count; + + ice_set_cgd_num(tlan_ctx, ring); + + /* PF number */ + tlan_ctx->pf_num = hw->pf_id; + + /* queue belongs to a specific VSI type + * VF / VM index should be programmed per vmvf_type setting: + * for vmvf_type = VF, it is VF number between 0-256 + * for vmvf_type = VM, it is VM number between 0-767 + * for PF or EMP this field should be set to zero + */ + switch (vsi->type) { + case ICE_VSI_LB: + /* fall through */ + case ICE_VSI_PF: + tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; + break; + case ICE_VSI_VF: + /* Firmware expects vmvf_num to be absolute VF ID */ + tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_id; + tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF; + break; + default: + return; + } + + /* make sure the context is associated with the right VSI */ + tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx); + + tlan_ctx->tso_ena = ICE_TX_LEGACY; + tlan_ctx->tso_qnum = pf_q; + + /* Legacy or Advanced Host Interface: + * 0: Advanced Host Interface + * 1: Legacy Host Interface + */ + tlan_ctx->legacy_int = ICE_TX_LEGACY; +} + +/** + * ice_setup_rx_ctx - Configure a receive ring context + * @ring: The Rx ring to configure + * + * Configure the Rx descriptor ring in RLAN context. + */ +int ice_setup_rx_ctx(struct ice_ring *ring) +{ + struct ice_vsi *vsi = ring->vsi; + struct ice_hw *hw = &vsi->back->hw; + u32 rxdid = ICE_RXDID_FLEX_NIC; + struct ice_rlan_ctx rlan_ctx; + u32 regval; + u16 pf_q; + int err; + + /* what is Rx queue number in global space of 2K Rx queues */ + pf_q = vsi->rxq_map[ring->q_index]; + + /* clear the context structure first */ + memset(&rlan_ctx, 0, sizeof(rlan_ctx)); + + rlan_ctx.base = ring->dma >> 7; + + rlan_ctx.qlen = ring->count; + + /* Receive Packet Data Buffer Size. + * The Packet Data Buffer Size is defined in 128 byte units. + */ + rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; + + /* use 32 byte descriptors */ + rlan_ctx.dsize = 1; + + /* Strip the Ethernet CRC bytes before the packet is posted to host + * memory. + */ + rlan_ctx.crcstrip = 1; + + /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */ + rlan_ctx.l2tsel = 1; + + rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT; + rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT; + rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT; + + /* This controls whether VLAN is stripped from inner headers + * The VLAN in the inner L2 header is stripped to the receive + * descriptor if enabled by this flag. + */ + rlan_ctx.showiv = 0; + + /* Max packet size for this queue - must not be set to a larger value + * than 5 x DBUF + */ + rlan_ctx.rxmax = min_t(u16, vsi->max_frame, + ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len); + + /* Rx queue threshold in units of 64 */ + rlan_ctx.lrxqthresh = 1; + + /* Enable Flexible Descriptors in the queue context which + * allows this driver to select a specific receive descriptor format + */ + if (vsi->type != ICE_VSI_VF) { + regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); + regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & + QRXFLXP_CNTXT_RXDID_IDX_M; + + /* increasing context priority to pick up profile ID; + * default is 0x01; setting to 0x03 to ensure profile + * is programming if prev context is of same priority + */ + regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & + QRXFLXP_CNTXT_RXDID_PRIO_M; + + wr32(hw, QRXFLXP_CNTXT(pf_q), regval); + } + + /* Absolute queue number out of 2K needs to be passed */ + err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); + if (err) { + dev_err(&vsi->back->pdev->dev, + "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n", + pf_q, err); + return -EIO; + } + + if (vsi->type == ICE_VSI_VF) + return 0; + + /* init queue specific tail register */ + ring->tail = hw->hw_addr + QRX_TAIL(pf_q); + writel(0, ring->tail); + ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); + + return 0; +} + +/** + * __ice_vsi_get_qs - helper function for assigning queues from PF to VSI + * @qs_cfg: gathered variables needed for pf->vsi queues assignment + * + * This function first tries to find contiguous space. If it is not successful, + * it tries with the scatter approach. + * + * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap + */ +int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg) +{ + int ret = 0; + + ret = __ice_vsi_get_qs_contig(qs_cfg); + if (ret) { + /* contig failed, so try with scatter approach */ + qs_cfg->mapping_mode = ICE_VSI_MAP_SCATTER; + qs_cfg->q_count = min_t(u16, qs_cfg->q_count, + qs_cfg->scatter_count); + ret = __ice_vsi_get_qs_sc(qs_cfg); + } + return ret; +} + +/** + * ice_vsi_ctrl_rx_ring - Start or stop a VSI's Rx ring + * @vsi: the VSI being configured + * @ena: start or stop the Rx rings + * @rxq_idx: Rx queue index + */ +int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) +{ + int pf_q = vsi->rxq_map[rxq_idx]; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + int ret = 0; + u32 rx_reg; + + rx_reg = rd32(hw, QRX_CTRL(pf_q)); + + /* Skip if the queue is already in the requested state */ + if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) + return 0; + + /* turn on/off the queue */ + if (ena) + rx_reg |= QRX_CTRL_QENA_REQ_M; + else + rx_reg &= ~QRX_CTRL_QENA_REQ_M; + wr32(hw, QRX_CTRL(pf_q), rx_reg); + + /* wait for the change to finish */ + ret = ice_pf_rxq_wait(pf, pf_q, ena); + if (ret) + dev_err(&pf->pdev->dev, + "VSI idx %d Rx ring %d %sable timeout\n", + vsi->idx, pf_q, (ena ? "en" : "dis")); + + return ret; +} + +/** + * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors + * @vsi: the VSI being configured + * + * We allocate one q_vector per queue interrupt. If allocation fails we + * return -ENOMEM. + */ +int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) +{ + struct ice_pf *pf = vsi->back; + int v_idx = 0, num_q_vectors; + int err; + + if (vsi->q_vectors[0]) { + dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", + vsi->vsi_num); + return -EEXIST; + } + + num_q_vectors = vsi->num_q_vectors; + + for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { + err = ice_vsi_alloc_q_vector(vsi, v_idx); + if (err) + goto err_out; + } + + return 0; + +err_out: + while (v_idx--) + ice_free_q_vector(vsi, v_idx); + + dev_err(&pf->pdev->dev, + "Failed to allocate %d q_vector for VSI %d, ret=%d\n", + vsi->num_q_vectors, vsi->vsi_num, err); + vsi->num_q_vectors = 0; + return err; +} + +/** + * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors + * @vsi: the VSI being configured + * + * This function maps descriptor rings to the queue-specific vectors allotted + * through the MSI-X enabling code. On a constrained vector budget, we map Tx + * and Rx rings to the vector as "efficiently" as possible. + */ +void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) +{ + int q_vectors = vsi->num_q_vectors; + int tx_rings_rem, rx_rings_rem; + int v_id; + + /* initially assigning remaining rings count to VSIs num queue value */ + tx_rings_rem = vsi->num_txq; + rx_rings_rem = vsi->num_rxq; + + for (v_id = 0; v_id < q_vectors; v_id++) { + struct ice_q_vector *q_vector = vsi->q_vectors[v_id]; + int tx_rings_per_v, rx_rings_per_v, q_id, q_base; + + /* Tx rings mapping to vector */ + tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); + q_vector->num_ring_tx = tx_rings_per_v; + q_vector->tx.ring = NULL; + q_vector->tx.itr_idx = ICE_TX_ITR; + q_base = vsi->num_txq - tx_rings_rem; + + for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { + struct ice_ring *tx_ring = vsi->tx_rings[q_id]; + + tx_ring->q_vector = q_vector; + tx_ring->next = q_vector->tx.ring; + q_vector->tx.ring = tx_ring; + } + tx_rings_rem -= tx_rings_per_v; + + /* Rx rings mapping to vector */ + rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); + q_vector->num_ring_rx = rx_rings_per_v; + q_vector->rx.ring = NULL; + q_vector->rx.itr_idx = ICE_RX_ITR; + q_base = vsi->num_rxq - rx_rings_rem; + + for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { + struct ice_ring *rx_ring = vsi->rx_rings[q_id]; + + rx_ring->q_vector = q_vector; + rx_ring->next = q_vector->rx.ring; + q_vector->rx.ring = rx_ring; + } + rx_rings_rem -= rx_rings_per_v; + } +} + +/** + * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors + * @vsi: the VSI having memory freed + */ +void ice_vsi_free_q_vectors(struct ice_vsi *vsi) +{ + int v_idx; + + ice_for_each_q_vector(vsi, v_idx) + ice_free_q_vector(vsi, v_idx); +} + +/** + * ice_vsi_cfg_txq - Configure single Tx queue + * @vsi: the VSI that queue belongs to + * @ring: Tx ring to be configured + * @tc_q_idx: queue index within given TC + * @qg_buf: queue group buffer + * @tc: TC that Tx ring belongs to + */ +int +ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, + struct ice_aqc_add_tx_qgrp *qg_buf, u8 tc) +{ + struct ice_tlan_ctx tlan_ctx = { 0 }; + struct ice_aqc_add_txqs_perq *txq; + struct ice_pf *pf = vsi->back; + u8 buf_len = sizeof(*qg_buf); + enum ice_status status; + u16 pf_q; + + pf_q = ring->reg_idx; + ice_setup_tx_ctx(ring, &tlan_ctx, pf_q); + /* copy context contents into the qg_buf */ + qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); + ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx, + ice_tlan_ctx_info); + + /* init queue specific tail reg. It is referred as + * transmit comm scheduler queue doorbell. + */ + ring->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); + + /* Add unique software queue handle of the Tx queue per + * TC into the VSI Tx ring + */ + ring->q_handle = tc_q_idx; + + status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, ring->q_handle, + 1, qg_buf, buf_len, NULL); + if (status) { + dev_err(&pf->pdev->dev, + "Failed to set LAN Tx queue context, error: %d\n", + status); + return -ENODEV; + } + + /* Add Tx Queue TEID into the VSI Tx ring from the + * response. This will complete configuring and + * enabling the queue. + */ + txq = &qg_buf->txqs[0]; + if (pf_q == le16_to_cpu(txq->txq_id)) + ring->txq_teid = le32_to_cpu(txq->q_teid); + + return 0; +} + +/** + * ice_cfg_itr - configure the initial interrupt throttle values + * @hw: pointer to the HW structure + * @q_vector: interrupt vector that's being configured + * + * Configure interrupt throttling values for the ring containers that are + * associated with the interrupt vector passed in. + */ +void ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector) +{ + ice_cfg_itr_gran(hw); + + if (q_vector->num_ring_rx) { + struct ice_ring_container *rc = &q_vector->rx; + + /* if this value is set then don't overwrite with default */ + if (!rc->itr_setting) + rc->itr_setting = ICE_DFLT_RX_ITR; + + rc->target_itr = ITR_TO_REG(rc->itr_setting); + rc->next_update = jiffies + 1; + rc->current_itr = rc->target_itr; + wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), + ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); + } + + if (q_vector->num_ring_tx) { + struct ice_ring_container *rc = &q_vector->tx; + + /* if this value is set then don't overwrite with default */ + if (!rc->itr_setting) + rc->itr_setting = ICE_DFLT_TX_ITR; + + rc->target_itr = ITR_TO_REG(rc->itr_setting); + rc->next_update = jiffies + 1; + rc->current_itr = rc->target_itr; + wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), + ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); + } +} + +/** + * ice_cfg_txq_interrupt - configure interrupt on Tx queue + * @vsi: the VSI being configured + * @txq: Tx queue being mapped to MSI-X vector + * @msix_idx: MSI-X vector index within the function + * @itr_idx: ITR index of the interrupt cause + * + * Configure interrupt on Tx queue by associating Tx queue to MSI-X vector + * within the function space. + */ +void +ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u32 val; + + itr_idx = (itr_idx << QINT_TQCTL_ITR_INDX_S) & QINT_TQCTL_ITR_INDX_M; + + val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | + ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M); + + wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); +} + +/** + * ice_cfg_rxq_interrupt - configure interrupt on Rx queue + * @vsi: the VSI being configured + * @rxq: Rx queue being mapped to MSI-X vector + * @msix_idx: MSI-X vector index within the function + * @itr_idx: ITR index of the interrupt cause + * + * Configure interrupt on Rx queue by associating Rx queue to MSI-X vector + * within the function space. + */ +void +ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + u32 val; + + itr_idx = (itr_idx << QINT_RQCTL_ITR_INDX_S) & QINT_RQCTL_ITR_INDX_M; + + val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | + ((msix_idx << QINT_RQCTL_MSIX_INDX_S) & QINT_RQCTL_MSIX_INDX_M); + + wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); + + ice_flush(hw); +} + +/** + * ice_trigger_sw_intr - trigger a software interrupt + * @hw: pointer to the HW structure + * @q_vector: interrupt vector to trigger the software interrupt for + */ +void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector) +{ + wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx), + (ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) | + GLINT_DYN_CTL_SWINT_TRIG_M | + GLINT_DYN_CTL_INTENA_M); +} + +/** + * ice_vsi_stop_tx_ring - Disable single Tx ring + * @vsi: the VSI being configured + * @rst_src: reset source + * @rel_vmvf_num: Relative ID of VF/VM + * @ring: Tx ring to be stopped + * @txq_meta: Meta data of Tx ring to be stopped + */ +int +ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, + u16 rel_vmvf_num, struct ice_ring *ring, + struct ice_txq_meta *txq_meta) +{ + struct ice_pf *pf = vsi->back; + struct ice_q_vector *q_vector; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + u32 val; + + /* clear cause_ena bit for disabled queues */ + val = rd32(hw, QINT_TQCTL(ring->reg_idx)); + val &= ~QINT_TQCTL_CAUSE_ENA_M; + wr32(hw, QINT_TQCTL(ring->reg_idx), val); + + /* software is expected to wait for 100 ns */ + ndelay(100); + + /* trigger a software interrupt for the vector + * associated to the queue to schedule NAPI handler + */ + q_vector = ring->q_vector; + if (q_vector) + ice_trigger_sw_intr(hw, q_vector); + + status = ice_dis_vsi_txq(vsi->port_info, txq_meta->vsi_idx, + txq_meta->tc, 1, &txq_meta->q_handle, + &txq_meta->q_id, &txq_meta->q_teid, rst_src, + rel_vmvf_num, NULL); + + /* if the disable queue command was exercised during an + * active reset flow, ICE_ERR_RESET_ONGOING is returned. + * This is not an error as the reset operation disables + * queues at the hardware level anyway. + */ + if (status == ICE_ERR_RESET_ONGOING) { + dev_dbg(&vsi->back->pdev->dev, + "Reset in progress. LAN Tx queues already disabled\n"); + } else if (status == ICE_ERR_DOES_NOT_EXIST) { + dev_dbg(&vsi->back->pdev->dev, + "LAN Tx queues do not exist, nothing to disable\n"); + } else if (status) { + dev_err(&vsi->back->pdev->dev, + "Failed to disable LAN Tx queues, error: %d\n", status); + return -ENODEV; + } + + return 0; +} + +/** + * ice_fill_txq_meta - Prepare the Tx queue's meta data + * @vsi: VSI that ring belongs to + * @ring: ring that txq_meta will be based on + * @txq_meta: a helper struct that wraps Tx queue's information + * + * Set up a helper struct that will contain all the necessary fields that + * are needed for stopping Tx queue + */ +void +ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_ring *ring, + struct ice_txq_meta *txq_meta) +{ + u8 tc; + + if (IS_ENABLED(CONFIG_DCB)) + tc = ring->dcb_tc; + else + tc = 0; + + txq_meta->q_id = ring->reg_idx; + txq_meta->q_teid = ring->txq_teid; + txq_meta->q_handle = ring->q_handle; + txq_meta->vsi_idx = vsi->idx; + txq_meta->tc = tc; +} diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h new file mode 100644 index 000000000000..db456862b35b --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Intel Corporation. */ + +#ifndef _ICE_BASE_H_ +#define _ICE_BASE_H_ + +#include "ice.h" + +int ice_setup_rx_ctx(struct ice_ring *ring); +int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg); +int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx); +int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); +void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); +void ice_vsi_free_q_vectors(struct ice_vsi *vsi); +int +ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, + struct ice_aqc_add_tx_qgrp *qg_buf, u8 tc); +void ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector); +void +ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx); +void +ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx); +void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector); +int +ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, + u16 rel_vmvf_num, struct ice_ring *ring, + struct ice_txq_meta *txq_meta); +void +ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_ring *ring, + struct ice_txq_meta *txq_meta); +#endif /* _ICE_BASE_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index 661a6f7bca64..d11a0aab01ac 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -5,6 +5,7 @@ #define _ICE_DCB_LIB_H_ #include "ice.h" +#include "ice_base.h" #include "ice_lib.h" #ifdef CONFIG_DCB diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index cc755382df25..b6bdf624c6e6 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2,234 +2,10 @@ /* Copyright (c) 2018, Intel Corporation. */ #include "ice.h" +#include "ice_base.h" #include "ice_lib.h" #include "ice_dcb_lib.h" -/** - * ice_setup_rx_ctx - Configure a receive ring context - * @ring: The Rx ring to configure - * - * Configure the Rx descriptor ring in RLAN context. - */ -static int ice_setup_rx_ctx(struct ice_ring *ring) -{ - struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; - u32 rxdid = ICE_RXDID_FLEX_NIC; - struct ice_rlan_ctx rlan_ctx; - u32 regval; - u16 pf_q; - int err; - - /* what is Rx queue number in global space of 2K Rx queues */ - pf_q = vsi->rxq_map[ring->q_index]; - - /* clear the context structure first */ - memset(&rlan_ctx, 0, sizeof(rlan_ctx)); - - rlan_ctx.base = ring->dma >> 7; - - rlan_ctx.qlen = ring->count; - - /* Receive Packet Data Buffer Size. - * The Packet Data Buffer Size is defined in 128 byte units. - */ - rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; - - /* use 32 byte descriptors */ - rlan_ctx.dsize = 1; - - /* Strip the Ethernet CRC bytes before the packet is posted to host - * memory. - */ - rlan_ctx.crcstrip = 1; - - /* L2TSEL flag defines the reported L2 Tags in the receive descriptor */ - rlan_ctx.l2tsel = 1; - - rlan_ctx.dtype = ICE_RX_DTYPE_NO_SPLIT; - rlan_ctx.hsplit_0 = ICE_RLAN_RX_HSPLIT_0_NO_SPLIT; - rlan_ctx.hsplit_1 = ICE_RLAN_RX_HSPLIT_1_NO_SPLIT; - - /* This controls whether VLAN is stripped from inner headers - * The VLAN in the inner L2 header is stripped to the receive - * descriptor if enabled by this flag. - */ - rlan_ctx.showiv = 0; - - /* Max packet size for this queue - must not be set to a larger value - * than 5 x DBUF - */ - rlan_ctx.rxmax = min_t(u16, vsi->max_frame, - ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len); - - /* Rx queue threshold in units of 64 */ - rlan_ctx.lrxqthresh = 1; - - /* Enable Flexible Descriptors in the queue context which - * allows this driver to select a specific receive descriptor format - */ - if (vsi->type != ICE_VSI_VF) { - regval = rd32(hw, QRXFLXP_CNTXT(pf_q)); - regval |= (rxdid << QRXFLXP_CNTXT_RXDID_IDX_S) & - QRXFLXP_CNTXT_RXDID_IDX_M; - - /* increasing context priority to pick up profile ID; - * default is 0x01; setting to 0x03 to ensure profile - * is programming if prev context is of same priority - */ - regval |= (0x03 << QRXFLXP_CNTXT_RXDID_PRIO_S) & - QRXFLXP_CNTXT_RXDID_PRIO_M; - - wr32(hw, QRXFLXP_CNTXT(pf_q), regval); - } - - /* Absolute queue number out of 2K needs to be passed */ - err = ice_write_rxq_ctx(hw, &rlan_ctx, pf_q); - if (err) { - dev_err(&vsi->back->pdev->dev, - "Failed to set LAN Rx queue context for absolute Rx queue %d error: %d\n", - pf_q, err); - return -EIO; - } - - if (vsi->type == ICE_VSI_VF) - return 0; - - /* init queue specific tail register */ - ring->tail = hw->hw_addr + QRX_TAIL(pf_q); - writel(0, ring->tail); - ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); - - return 0; -} - -/** - * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance - * @ring: The Tx ring to configure - * @tlan_ctx: Pointer to the Tx LAN queue context structure to be initialized - * @pf_q: queue index in the PF space - * - * Configure the Tx descriptor ring in TLAN context. - */ -static void -ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) -{ - struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; - - tlan_ctx->base = ring->dma >> ICE_TLAN_CTX_BASE_S; - - tlan_ctx->port_num = vsi->port_info->lport; - - /* Transmit Queue Length */ - tlan_ctx->qlen = ring->count; - - ice_set_cgd_num(tlan_ctx, ring); - - /* PF number */ - tlan_ctx->pf_num = hw->pf_id; - - /* queue belongs to a specific VSI type - * VF / VM index should be programmed per vmvf_type setting: - * for vmvf_type = VF, it is VF number between 0-256 - * for vmvf_type = VM, it is VM number between 0-767 - * for PF or EMP this field should be set to zero - */ - switch (vsi->type) { - case ICE_VSI_LB: - /* fall through */ - case ICE_VSI_PF: - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_PF; - break; - case ICE_VSI_VF: - /* Firmware expects vmvf_num to be absolute VF ID */ - tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_id; - tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF; - break; - default: - return; - } - - /* make sure the context is associated with the right VSI */ - tlan_ctx->src_vsi = ice_get_hw_vsi_num(hw, vsi->idx); - - tlan_ctx->tso_ena = ICE_TX_LEGACY; - tlan_ctx->tso_qnum = pf_q; - - /* Legacy or Advanced Host Interface: - * 0: Advanced Host Interface - * 1: Legacy Host Interface - */ - tlan_ctx->legacy_int = ICE_TX_LEGACY; -} - -/** - * ice_pf_rxq_wait - Wait for a PF's Rx queue to be enabled or disabled - * @pf: the PF being configured - * @pf_q: the PF queue - * @ena: enable or disable state of the queue - * - * This routine will wait for the given Rx queue of the PF to reach the - * enabled or disabled state. - * Returns -ETIMEDOUT in case of failing to reach the requested state after - * multiple retries; else will return 0 in case of success. - */ -static int ice_pf_rxq_wait(struct ice_pf *pf, int pf_q, bool ena) -{ - int i; - - for (i = 0; i < ICE_Q_WAIT_MAX_RETRY; i++) { - if (ena == !!(rd32(&pf->hw, QRX_CTRL(pf_q)) & - QRX_CTRL_QENA_STAT_M)) - return 0; - - usleep_range(20, 40); - } - - return -ETIMEDOUT; -} - -/** - * ice_vsi_ctrl_rx_ring - Start or stop a VSI's Rx ring - * @vsi: the VSI being configured - * @ena: start or stop the Rx rings - * @rxq_idx: Rx queue index - */ -#ifndef CONFIG_PCI_IOV -static -#endif /* !CONFIG_PCI_IOV */ -int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) -{ - int pf_q = vsi->rxq_map[rxq_idx]; - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - int ret = 0; - u32 rx_reg; - - rx_reg = rd32(hw, QRX_CTRL(pf_q)); - - /* Skip if the queue is already in the requested state */ - if (ena == !!(rx_reg & QRX_CTRL_QENA_STAT_M)) - return 0; - - /* turn on/off the queue */ - if (ena) - rx_reg |= QRX_CTRL_QENA_REQ_M; - else - rx_reg &= ~QRX_CTRL_QENA_REQ_M; - wr32(hw, QRX_CTRL(pf_q), rx_reg); - - /* wait for the change to finish */ - ret = ice_pf_rxq_wait(pf, pf_q, ena); - if (ret) - dev_err(&pf->pdev->dev, - "VSI idx %d Rx ring %d %sable timeout\n", - vsi->idx, pf_q, (ena ? "en" : "dis")); - - return ret; -} - /** * ice_vsi_ctrl_rx_rings - Start or stop a VSI's Rx rings * @vsi: the VSI being configured @@ -281,7 +57,6 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) if (!vsi->rxq_map) goto err_rxq_map; - /* There is no need to allocate q_vectors for a loopback VSI. */ if (vsi->type == ICE_VSI_LB) return 0; @@ -605,88 +380,6 @@ unlock_pf: return vsi; } -/** - * __ice_vsi_get_qs_contig - Assign a contiguous chunk of queues to VSI - * @qs_cfg: gathered variables needed for PF->VSI queues assignment - * - * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap - */ -static int __ice_vsi_get_qs_contig(struct ice_qs_cfg *qs_cfg) -{ - int offset, i; - - mutex_lock(qs_cfg->qs_mutex); - offset = bitmap_find_next_zero_area(qs_cfg->pf_map, qs_cfg->pf_map_size, - 0, qs_cfg->q_count, 0); - if (offset >= qs_cfg->pf_map_size) { - mutex_unlock(qs_cfg->qs_mutex); - return -ENOMEM; - } - - bitmap_set(qs_cfg->pf_map, offset, qs_cfg->q_count); - for (i = 0; i < qs_cfg->q_count; i++) - qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = i + offset; - mutex_unlock(qs_cfg->qs_mutex); - - return 0; -} - -/** - * __ice_vsi_get_qs_sc - Assign a scattered queues from PF to VSI - * @qs_cfg: gathered variables needed for pf->vsi queues assignment - * - * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap - */ -static int __ice_vsi_get_qs_sc(struct ice_qs_cfg *qs_cfg) -{ - int i, index = 0; - - mutex_lock(qs_cfg->qs_mutex); - for (i = 0; i < qs_cfg->q_count; i++) { - index = find_next_zero_bit(qs_cfg->pf_map, - qs_cfg->pf_map_size, index); - if (index >= qs_cfg->pf_map_size) - goto err_scatter; - set_bit(index, qs_cfg->pf_map); - qs_cfg->vsi_map[i + qs_cfg->vsi_map_offset] = index; - } - mutex_unlock(qs_cfg->qs_mutex); - - return 0; -err_scatter: - for (index = 0; index < i; index++) { - clear_bit(qs_cfg->vsi_map[index], qs_cfg->pf_map); - qs_cfg->vsi_map[index + qs_cfg->vsi_map_offset] = 0; - } - mutex_unlock(qs_cfg->qs_mutex); - - return -ENOMEM; -} - -/** - * __ice_vsi_get_qs - helper function for assigning queues from PF to VSI - * @qs_cfg: gathered variables needed for pf->vsi queues assignment - * - * This function first tries to find contiguous space. If it is not successful, - * it tries with the scatter approach. - * - * Return 0 on success and -ENOMEM in case of no left space in PF queue bitmap - */ -static int __ice_vsi_get_qs(struct ice_qs_cfg *qs_cfg) -{ - int ret = 0; - - ret = __ice_vsi_get_qs_contig(qs_cfg); - if (ret) { - /* contig failed, so try with scatter approach */ - qs_cfg->mapping_mode = ICE_VSI_MAP_SCATTER; - qs_cfg->q_count = min_t(u16, qs_cfg->q_count, - qs_cfg->scatter_count); - ret = __ice_vsi_get_qs_sc(qs_cfg); - } - return ret; -} - /** * ice_vsi_get_qs - Assign queues from PF to VSI * @vsi: the VSI to assign queues to @@ -1097,129 +790,6 @@ static int ice_vsi_init(struct ice_vsi *vsi) return ret; } -/** - * ice_free_q_vector - Free memory allocated for a specific interrupt vector - * @vsi: VSI having the memory freed - * @v_idx: index of the vector to be freed - */ -static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) -{ - struct ice_q_vector *q_vector; - struct ice_pf *pf = vsi->back; - struct ice_ring *ring; - - if (!vsi->q_vectors[v_idx]) { - dev_dbg(&pf->pdev->dev, "Queue vector at index %d not found\n", - v_idx); - return; - } - q_vector = vsi->q_vectors[v_idx]; - - ice_for_each_ring(ring, q_vector->tx) - ring->q_vector = NULL; - ice_for_each_ring(ring, q_vector->rx) - ring->q_vector = NULL; - - /* only VSI with an associated netdev is set up with NAPI */ - if (vsi->netdev) - netif_napi_del(&q_vector->napi); - - devm_kfree(&pf->pdev->dev, q_vector); - vsi->q_vectors[v_idx] = NULL; -} - -/** - * ice_vsi_free_q_vectors - Free memory allocated for interrupt vectors - * @vsi: the VSI having memory freed - */ -void ice_vsi_free_q_vectors(struct ice_vsi *vsi) -{ - int v_idx; - - ice_for_each_q_vector(vsi, v_idx) - ice_free_q_vector(vsi, v_idx); -} - -/** - * ice_vsi_alloc_q_vector - Allocate memory for a single interrupt vector - * @vsi: the VSI being configured - * @v_idx: index of the vector in the VSI struct - * - * We allocate one q_vector. If allocation fails we return -ENOMEM. - */ -static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) -{ - struct ice_pf *pf = vsi->back; - struct ice_q_vector *q_vector; - - /* allocate q_vector */ - q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); - if (!q_vector) - return -ENOMEM; - - q_vector->vsi = vsi; - q_vector->v_idx = v_idx; - if (vsi->type == ICE_VSI_VF) - goto out; - /* only set affinity_mask if the CPU is online */ - if (cpu_online(v_idx)) - cpumask_set_cpu(v_idx, &q_vector->affinity_mask); - - /* This will not be called in the driver load path because the netdev - * will not be created yet. All other cases with register the NAPI - * handler here (i.e. resume, reset/rebuild, etc.) - */ - if (vsi->netdev) - netif_napi_add(vsi->netdev, &q_vector->napi, ice_napi_poll, - NAPI_POLL_WEIGHT); - -out: - /* tie q_vector and VSI together */ - vsi->q_vectors[v_idx] = q_vector; - - return 0; -} - -/** - * ice_vsi_alloc_q_vectors - Allocate memory for interrupt vectors - * @vsi: the VSI being configured - * - * We allocate one q_vector per queue interrupt. If allocation fails we - * return -ENOMEM. - */ -static int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) -{ - struct ice_pf *pf = vsi->back; - int v_idx = 0, num_q_vectors; - int err; - - if (vsi->q_vectors[0]) { - dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", - vsi->vsi_num); - return -EEXIST; - } - - num_q_vectors = vsi->num_q_vectors; - - for (v_idx = 0; v_idx < num_q_vectors; v_idx++) { - err = ice_vsi_alloc_q_vector(vsi, v_idx); - if (err) - goto err_out; - } - - return 0; - -err_out: - while (v_idx--) - ice_free_q_vector(vsi, v_idx); - - dev_err(&pf->pdev->dev, - "Failed to allocate %d q_vector for VSI %d, ret=%d\n", - vsi->num_q_vectors, vsi->vsi_num, err); - vsi->num_q_vectors = 0; - return err; -} - /** * ice_vsi_setup_vector_base - Set up the base vector for the given VSI * @vsi: ptr to the VSI @@ -1340,66 +910,6 @@ err_out: return -ENOMEM; } -/** - * ice_vsi_map_rings_to_vectors - Map VSI rings to interrupt vectors - * @vsi: the VSI being configured - * - * This function maps descriptor rings to the queue-specific vectors allotted - * through the MSI-X enabling code. On a constrained vector budget, we map Tx - * and Rx rings to the vector as "efficiently" as possible. - */ -#ifdef CONFIG_DCB -void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) -#else -static void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi) -#endif /* CONFIG_DCB */ -{ - int q_vectors = vsi->num_q_vectors; - int tx_rings_rem, rx_rings_rem; - int v_id; - - /* initially assigning remaining rings count to VSIs num queue value */ - tx_rings_rem = vsi->num_txq; - rx_rings_rem = vsi->num_rxq; - - for (v_id = 0; v_id < q_vectors; v_id++) { - struct ice_q_vector *q_vector = vsi->q_vectors[v_id]; - int tx_rings_per_v, rx_rings_per_v, q_id, q_base; - - /* Tx rings mapping to vector */ - tx_rings_per_v = DIV_ROUND_UP(tx_rings_rem, q_vectors - v_id); - q_vector->num_ring_tx = tx_rings_per_v; - q_vector->tx.ring = NULL; - q_vector->tx.itr_idx = ICE_TX_ITR; - q_base = vsi->num_txq - tx_rings_rem; - - for (q_id = q_base; q_id < (q_base + tx_rings_per_v); q_id++) { - struct ice_ring *tx_ring = vsi->tx_rings[q_id]; - - tx_ring->q_vector = q_vector; - tx_ring->next = q_vector->tx.ring; - q_vector->tx.ring = tx_ring; - } - tx_rings_rem -= tx_rings_per_v; - - /* Rx rings mapping to vector */ - rx_rings_per_v = DIV_ROUND_UP(rx_rings_rem, q_vectors - v_id); - q_vector->num_ring_rx = rx_rings_per_v; - q_vector->rx.ring = NULL; - q_vector->rx.itr_idx = ICE_RX_ITR; - q_base = vsi->num_rxq - rx_rings_rem; - - for (q_id = q_base; q_id < (q_base + rx_rings_per_v); q_id++) { - struct ice_ring *rx_ring = vsi->rx_rings[q_id]; - - rx_ring->q_vector = q_vector; - rx_ring->next = q_vector->rx.ring; - q_vector->rx.ring = rx_ring; - } - rx_rings_rem -= rx_rings_per_v; - } -} - /** * ice_vsi_manage_rss_lut - disable/enable RSS * @vsi: the VSI being changed @@ -1711,62 +1221,6 @@ setup_rings: return 0; } -/** - * ice_vsi_cfg_txq - Configure single Tx queue - * @vsi: the VSI that queue belongs to - * @ring: Tx ring to be configured - * @tc_q_idx: queue index within given TC - * @qg_buf: queue group buffer - * @tc: TC that Tx ring belongs to - */ -static int -ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, - struct ice_aqc_add_tx_qgrp *qg_buf, u8 tc) -{ - struct ice_tlan_ctx tlan_ctx = { 0 }; - struct ice_aqc_add_txqs_perq *txq; - struct ice_pf *pf = vsi->back; - u8 buf_len = sizeof(*qg_buf); - enum ice_status status; - u16 pf_q; - - pf_q = ring->reg_idx; - ice_setup_tx_ctx(ring, &tlan_ctx, pf_q); - /* copy context contents into the qg_buf */ - qg_buf->txqs[0].txq_id = cpu_to_le16(pf_q); - ice_set_ctx((u8 *)&tlan_ctx, qg_buf->txqs[0].txq_ctx, - ice_tlan_ctx_info); - - /* init queue specific tail reg. It is referred as - * transmit comm scheduler queue doorbell. - */ - ring->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); - - /* Add unique software queue handle of the Tx queue per - * TC into the VSI Tx ring - */ - ring->q_handle = tc_q_idx; - - status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, ring->q_handle, - 1, qg_buf, buf_len, NULL); - if (status) { - dev_err(&pf->pdev->dev, - "Failed to set LAN Tx queue context, error: %d\n", - status); - return -ENODEV; - } - - /* Add Tx Queue TEID into the VSI Tx ring from the - * response. This will complete configuring and - * enabling the queue. - */ - txq = &qg_buf->txqs[0]; - if (pf_q == le16_to_cpu(txq->txq_id)) - ring->txq_teid = le32_to_cpu(txq->q_teid); - - return 0; -} - /** * ice_vsi_cfg_txqs - Configure the VSI for Tx * @vsi: the VSI being configured @@ -1839,141 +1293,6 @@ u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran) return 0; } -/** - * ice_cfg_itr_gran - set the ITR granularity to 2 usecs if not already set - * @hw: board specific structure - */ -static void ice_cfg_itr_gran(struct ice_hw *hw) -{ - u32 regval = rd32(hw, GLINT_CTL); - - /* no need to update global register if ITR gran is already set */ - if (!(regval & GLINT_CTL_DIS_AUTOMASK_M) && - (((regval & GLINT_CTL_ITR_GRAN_200_M) >> - GLINT_CTL_ITR_GRAN_200_S) == ICE_ITR_GRAN_US) && - (((regval & GLINT_CTL_ITR_GRAN_100_M) >> - GLINT_CTL_ITR_GRAN_100_S) == ICE_ITR_GRAN_US) && - (((regval & GLINT_CTL_ITR_GRAN_50_M) >> - GLINT_CTL_ITR_GRAN_50_S) == ICE_ITR_GRAN_US) && - (((regval & GLINT_CTL_ITR_GRAN_25_M) >> - GLINT_CTL_ITR_GRAN_25_S) == ICE_ITR_GRAN_US)) - return; - - regval = ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_200_S) & - GLINT_CTL_ITR_GRAN_200_M) | - ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_100_S) & - GLINT_CTL_ITR_GRAN_100_M) | - ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_50_S) & - GLINT_CTL_ITR_GRAN_50_M) | - ((ICE_ITR_GRAN_US << GLINT_CTL_ITR_GRAN_25_S) & - GLINT_CTL_ITR_GRAN_25_M); - wr32(hw, GLINT_CTL, regval); -} - -/** - * ice_cfg_itr - configure the initial interrupt throttle values - * @hw: pointer to the HW structure - * @q_vector: interrupt vector that's being configured - * - * Configure interrupt throttling values for the ring containers that are - * associated with the interrupt vector passed in. - */ -static void -ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector) -{ - ice_cfg_itr_gran(hw); - - if (q_vector->num_ring_rx) { - struct ice_ring_container *rc = &q_vector->rx; - - /* if this value is set then don't overwrite with default */ - if (!rc->itr_setting) - rc->itr_setting = ICE_DFLT_RX_ITR; - - rc->target_itr = ITR_TO_REG(rc->itr_setting); - rc->next_update = jiffies + 1; - rc->current_itr = rc->target_itr; - wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), - ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); - } - - if (q_vector->num_ring_tx) { - struct ice_ring_container *rc = &q_vector->tx; - - /* if this value is set then don't overwrite with default */ - if (!rc->itr_setting) - rc->itr_setting = ICE_DFLT_TX_ITR; - - rc->target_itr = ITR_TO_REG(rc->itr_setting); - rc->next_update = jiffies + 1; - rc->current_itr = rc->target_itr; - wr32(hw, GLINT_ITR(rc->itr_idx, q_vector->reg_idx), - ITR_REG_ALIGN(rc->current_itr) >> ICE_ITR_GRAN_S); - } -} - -/** - * ice_cfg_txq_interrupt - configure interrupt on Tx queue - * @vsi: the VSI being configured - * @txq: Tx queue being mapped to MSI-X vector - * @msix_idx: MSI-X vector index within the function - * @itr_idx: ITR index of the interrupt cause - * - * Configure interrupt on Tx queue by associating Tx queue to MSI-X vector - * within the function space. - */ -#ifdef CONFIG_PCI_IOV -void -ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) -#else -static void -ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) -#endif /* CONFIG_PCI_IOV */ -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - u32 val; - - itr_idx = (itr_idx << QINT_TQCTL_ITR_INDX_S) & QINT_TQCTL_ITR_INDX_M; - - val = QINT_TQCTL_CAUSE_ENA_M | itr_idx | - ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M); - - wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); -} - -/** - * ice_cfg_rxq_interrupt - configure interrupt on Rx queue - * @vsi: the VSI being configured - * @rxq: Rx queue being mapped to MSI-X vector - * @msix_idx: MSI-X vector index within the function - * @itr_idx: ITR index of the interrupt cause - * - * Configure interrupt on Rx queue by associating Rx queue to MSI-X vector - * within the function space. - */ -#ifdef CONFIG_PCI_IOV -void -ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx) -#else -static void -ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx) -#endif /* CONFIG_PCI_IOV */ -{ - struct ice_pf *pf = vsi->back; - struct ice_hw *hw = &pf->hw; - u32 val; - - itr_idx = (itr_idx << QINT_RQCTL_ITR_INDX_S) & QINT_RQCTL_ITR_INDX_M; - - val = QINT_RQCTL_CAUSE_ENA_M | itr_idx | - ((msix_idx << QINT_RQCTL_MSIX_INDX_S) & QINT_RQCTL_MSIX_INDX_M); - - wr32(hw, QINT_RQCTL(vsi->rxq_map[rxq]), val); - - ice_flush(hw); -} - /** * ice_vsi_cfg_msix - MSIX mode Interrupt Config in the HW * @vsi: the VSI being configured @@ -2133,109 +1452,6 @@ int ice_vsi_stop_rx_rings(struct ice_vsi *vsi) return ice_vsi_ctrl_rx_rings(vsi, false); } -/** - * ice_trigger_sw_intr - trigger a software interrupt - * @hw: pointer to the HW structure - * @q_vector: interrupt vector to trigger the software interrupt for - */ -void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector) -{ - wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx), - (ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) | - GLINT_DYN_CTL_SWINT_TRIG_M | - GLINT_DYN_CTL_INTENA_M); -} - -/** - * ice_vsi_stop_tx_ring - Disable single Tx ring - * @vsi: the VSI being configured - * @rst_src: reset source - * @rel_vmvf_num: Relative ID of VF/VM - * @ring: Tx ring to be stopped - * @txq_meta: Meta data of Tx ring to be stopped - */ -#ifndef CONFIG_PCI_IOV -static -#endif /* !CONFIG_PCI_IOV */ -int -ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, - u16 rel_vmvf_num, struct ice_ring *ring, - struct ice_txq_meta *txq_meta) -{ - struct ice_pf *pf = vsi->back; - struct ice_q_vector *q_vector; - struct ice_hw *hw = &pf->hw; - enum ice_status status; - u32 val; - - /* clear cause_ena bit for disabled queues */ - val = rd32(hw, QINT_TQCTL(ring->reg_idx)); - val &= ~QINT_TQCTL_CAUSE_ENA_M; - wr32(hw, QINT_TQCTL(ring->reg_idx), val); - - /* software is expected to wait for 100 ns */ - ndelay(100); - - /* trigger a software interrupt for the vector - * associated to the queue to schedule NAPI handler - */ - q_vector = ring->q_vector; - if (q_vector) - ice_trigger_sw_intr(hw, q_vector); - - status = ice_dis_vsi_txq(vsi->port_info, txq_meta->vsi_idx, - txq_meta->tc, 1, &txq_meta->q_handle, - &txq_meta->q_id, &txq_meta->q_teid, rst_src, - rel_vmvf_num, NULL); - - /* if the disable queue command was exercised during an - * active reset flow, ICE_ERR_RESET_ONGOING is returned. - * This is not an error as the reset operation disables - * queues at the hardware level anyway. - */ - if (status == ICE_ERR_RESET_ONGOING) { - dev_dbg(&vsi->back->pdev->dev, - "Reset in progress. LAN Tx queues already disabled\n"); - } else if (status == ICE_ERR_DOES_NOT_EXIST) { - dev_dbg(&vsi->back->pdev->dev, - "LAN Tx queues do not exist, nothing to disable\n"); - } else if (status) { - dev_err(&vsi->back->pdev->dev, - "Failed to disable LAN Tx queues, error: %d\n", status); - return -ENODEV; - } - - return 0; -} - -/** - * ice_fill_txq_meta - Prepare the Tx queue's meta data - * @vsi: VSI that ring belongs to - * @ring: ring that txq_meta will be based on - * @txq_meta: a helper struct that wraps Tx queue's information - * - * Set up a helper struct that will contain all the necessary fields that - * are needed for stopping Tx queue - */ -#ifndef CONFIG_PCI_IOV -static -#endif /* !CONFIG_PCI_IOV */ -void -ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_ring *ring, - struct ice_txq_meta *txq_meta) -{ - u8 tc = 0; - -#ifdef CONFIG_DCB - tc = ring->dcb_tc; -#endif /* CONFIG_DCB */ - txq_meta->q_id = ring->reg_idx; - txq_meta->q_teid = ring->txq_teid; - txq_meta->q_handle = ring->q_handle; - txq_meta->vsi_idx = vsi->idx; - txq_meta->tc = tc; -} - /** * ice_vsi_stop_tx_rings - Disable Tx rings * @vsi: the VSI being configured @@ -3085,7 +2301,6 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) if (ret < 0) goto err_vsi; - switch (vsi->type) { case ICE_VSI_PF: ret = ice_vsi_alloc_q_vectors(vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 47bc033fff20..2fd5da3d0275 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,19 +6,6 @@ #include "ice.h" -struct ice_txq_meta { - /* Tx-scheduler element identifier */ - u32 q_teid; - /* Entry in VSI's txq_map bitmap */ - u16 q_id; - /* Relative index of Tx queue within TC */ - u16 q_handle; - /* VSI index that Tx queue belongs to */ - u16 vsi_idx; - /* TC number that Tx queue belongs to */ - u8 tc; -}; - int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, const u8 *macaddr); @@ -33,24 +20,6 @@ int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi); void ice_vsi_cfg_msix(struct ice_vsi *vsi); -#ifdef CONFIG_PCI_IOV -void -ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx); - -void -ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx); - -int -ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, - u16 rel_vmvf_num, struct ice_ring *ring, - struct ice_txq_meta *txq_meta); - -void ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_ring *ring, - struct ice_txq_meta *txq_meta); - -int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx); -#endif /* CONFIG_PCI_IOV */ - int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid); int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid); @@ -98,16 +67,8 @@ int ice_vsi_rebuild(struct ice_vsi *vsi); bool ice_is_reset_in_progress(unsigned long *state); -void ice_vsi_free_q_vectors(struct ice_vsi *vsi); - -void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector); - void ice_vsi_put_qs(struct ice_vsi *vsi); -#ifdef CONFIG_DCB -void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); -#endif /* CONFIG_DCB */ - void ice_vsi_dis_irq(struct ice_vsi *vsi); void ice_vsi_free_irq(struct ice_vsi *vsi); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 214cd6eca405..bf9c4438cbfb 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "ice.h" +#include "ice_base.h" #include "ice_lib.h" #include "ice_dcb_lib.h" diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 94a9280193e2..a914e603b2ed 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -205,9 +205,7 @@ struct ice_ring { unsigned int size; /* length of descriptor ring in bytes */ u32 txq_teid; /* Added Tx queue TEID */ u16 rx_buf_len; -#ifdef CONFIG_DCB u8 dcb_tc; /* Traffic class of ring */ -#endif /* CONFIG_DCB */ } ____cacheline_internodealigned_in_smp; struct ice_ring_container { diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index b45797f39b2f..ad757412bb04 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -2,6 +2,7 @@ /* Copyright (c) 2018, Intel Corporation. */ #include "ice.h" +#include "ice_base.h" #include "ice_lib.h" /** -- cgit v1.2.3-59-g8ed1b From e75d1b2c37319998c9d9756ba4ea50c731f56e12 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 24 Oct 2019 01:11:18 -0700 Subject: ice: get rid of per-tc flow in Tx queue configuration routines There's no reason for treating DCB as first class citizen when configuring the Tx queues and going through TCs. Reverse the logic and base the configuration logic on rings, which is the object of interest anyway. Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_base.c | 29 +++++++++++--- drivers/net/ethernet/intel/ice/ice_base.h | 4 +- drivers/net/ethernet/intel/ice/ice_lib.c | 63 +++++++++++-------------------- 3 files changed, 47 insertions(+), 49 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 735922a4d632..df9f9bacbdf8 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -190,6 +190,21 @@ static void ice_cfg_itr_gran(struct ice_hw *hw) wr32(hw, GLINT_CTL, regval); } +/** + * ice_calc_q_handle - calculate the queue handle + * @vsi: VSI that ring belongs to + * @ring: ring to get the absolute queue index + * @tc: traffic class number + */ +static u16 ice_calc_q_handle(struct ice_vsi *vsi, struct ice_ring *ring, u8 tc) +{ + /* Idea here for calculation is that we subtract the number of queue + * count from TC that ring belongs to from it's absolute queue index + * and as a result we get the queue's index within TC. + */ + return ring->q_index - vsi->tc_cfg.tc_info[tc].qoffset; +} + /** * ice_setup_tx_ctx - setup a struct ice_tlan_ctx instance * @ring: The Tx ring to configure @@ -522,13 +537,11 @@ void ice_vsi_free_q_vectors(struct ice_vsi *vsi) * ice_vsi_cfg_txq - Configure single Tx queue * @vsi: the VSI that queue belongs to * @ring: Tx ring to be configured - * @tc_q_idx: queue index within given TC * @qg_buf: queue group buffer - * @tc: TC that Tx ring belongs to */ int -ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, - struct ice_aqc_add_tx_qgrp *qg_buf, u8 tc) +ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, + struct ice_aqc_add_tx_qgrp *qg_buf) { struct ice_tlan_ctx tlan_ctx = { 0 }; struct ice_aqc_add_txqs_perq *txq; @@ -536,6 +549,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, u8 buf_len = sizeof(*qg_buf); enum ice_status status; u16 pf_q; + u8 tc; pf_q = ring->reg_idx; ice_setup_tx_ctx(ring, &tlan_ctx, pf_q); @@ -549,10 +563,15 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, */ ring->tail = pf->hw.hw_addr + QTX_COMM_DBELL(pf_q); + if (IS_ENABLED(CONFIG_DCB)) + tc = ring->dcb_tc; + else + tc = 0; + /* Add unique software queue handle of the Tx queue per * TC into the VSI Tx ring */ - ring->q_handle = tc_q_idx; + ring->q_handle = ice_calc_q_handle(vsi, ring, tc); status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, ring->q_handle, 1, qg_buf, buf_len, NULL); diff --git a/drivers/net/ethernet/intel/ice/ice_base.h b/drivers/net/ethernet/intel/ice/ice_base.h index db456862b35b..407995e8e944 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.h +++ b/drivers/net/ethernet/intel/ice/ice_base.h @@ -13,8 +13,8 @@ int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi); void ice_vsi_map_rings_to_vectors(struct ice_vsi *vsi); void ice_vsi_free_q_vectors(struct ice_vsi *vsi); int -ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, u16 tc_q_idx, - struct ice_aqc_add_tx_qgrp *qg_buf, u8 tc); +ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, + struct ice_aqc_add_tx_qgrp *qg_buf); void ice_cfg_itr(struct ice_hw *hw, struct ice_q_vector *q_vector); void ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index b6bdf624c6e6..87f890363608 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1225,42 +1225,31 @@ setup_rings: * ice_vsi_cfg_txqs - Configure the VSI for Tx * @vsi: the VSI being configured * @rings: Tx ring array to be configured - * @offset: offset within vsi->txq_map * * Return 0 on success and a negative value on error * Configure the Tx VSI for operation. */ static int -ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings, int offset) +ice_vsi_cfg_txqs(struct ice_vsi *vsi, struct ice_ring **rings) { struct ice_aqc_add_tx_qgrp *qg_buf; - struct ice_pf *pf = vsi->back; - u16 q_idx = 0, i; + u16 q_idx = 0; int err = 0; - u8 tc; - qg_buf = devm_kzalloc(&pf->pdev->dev, sizeof(*qg_buf), GFP_KERNEL); + qg_buf = kzalloc(sizeof(*qg_buf), GFP_KERNEL); if (!qg_buf) return -ENOMEM; qg_buf->num_txqs = 1; - /* set up and configure the Tx queues for each enabled TC */ - ice_for_each_traffic_class(tc) { - if (!(vsi->tc_cfg.ena_tc & BIT(tc))) - break; - - for (i = 0; i < vsi->tc_cfg.tc_info[tc].qcount_tx; i++) { - err = ice_vsi_cfg_txq(vsi, rings[q_idx], i + offset, - qg_buf, tc); - if (err) - goto err_cfg_txqs; - - q_idx++; - } + for (q_idx = 0; q_idx < vsi->num_txq; q_idx++) { + err = ice_vsi_cfg_txq(vsi, rings[q_idx], qg_buf); + if (err) + goto err_cfg_txqs; } + err_cfg_txqs: - devm_kfree(&pf->pdev->dev, qg_buf); + kfree(qg_buf); return err; } @@ -1273,7 +1262,7 @@ err_cfg_txqs: */ int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) { - return ice_vsi_cfg_txqs(vsi, vsi->tx_rings, 0); + return ice_vsi_cfg_txqs(vsi, vsi->tx_rings); } /** @@ -1463,34 +1452,24 @@ static int ice_vsi_stop_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, u16 rel_vmvf_num, struct ice_ring **rings) { - u16 i, q_idx = 0; - int status; - u8 tc; + u16 q_idx; if (vsi->num_txq > ICE_LAN_TXQ_MAX_QDIS) return -EINVAL; - /* set up the Tx queue list to be disabled for each enabled TC */ - ice_for_each_traffic_class(tc) { - if (!(vsi->tc_cfg.ena_tc & BIT(tc))) - break; - - for (i = 0; i < vsi->tc_cfg.tc_info[tc].qcount_tx; i++) { - struct ice_txq_meta txq_meta = { }; + for (q_idx = 0; q_idx < vsi->num_txq; q_idx++) { + struct ice_txq_meta txq_meta = { }; + int status; - if (!rings || !rings[q_idx]) - return -EINVAL; + if (!rings || !rings[q_idx]) + return -EINVAL; - ice_fill_txq_meta(vsi, rings[q_idx], &txq_meta); - status = ice_vsi_stop_tx_ring(vsi, rst_src, - rel_vmvf_num, - rings[q_idx], &txq_meta); + ice_fill_txq_meta(vsi, rings[q_idx], &txq_meta); + status = ice_vsi_stop_tx_ring(vsi, rst_src, rel_vmvf_num, + rings[q_idx], &txq_meta); - if (status) - return status; - - q_idx++; - } + if (status) + return status; } return 0; -- cgit v1.2.3-59-g8ed1b From efc2214b6047b6f5b4ca53151eba62521b9452d6 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Mon, 4 Nov 2019 09:38:56 -0800 Subject: ice: Add support for XDP Add support for XDP. Implement ndo_bpf and ndo_xdp_xmit. Upon load of an XDP program, allocate additional Tx rings for dedicated XDP use. The following actions are supported: XDP_TX, XDP_DROP, XDP_REDIRECT, XDP_PASS, and XDP_ABORTED. Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 24 +- drivers/net/ethernet/intel/ice/ice_base.c | 28 ++- drivers/net/ethernet/intel/ice/ice_ethtool.c | 50 +++- drivers/net/ethernet/intel/ice/ice_lib.c | 68 +++++- drivers/net/ethernet/intel/ice/ice_lib.h | 6 + drivers/net/ethernet/intel/ice/ice_main.c | 326 +++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txrx.c | 346 +++++++++++++++++++++++---- drivers/net/ethernet/intel/ice/ice_txrx.h | 34 ++- 8 files changed, 825 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 0b5aa8feae26..b2451f768707 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -29,8 +29,10 @@ #include #include #include +#include #include #include +#include #include #include #include "ice_devids.h" @@ -78,8 +80,7 @@ extern const char ice_drv_ver[]; #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) -#define ICE_MAX_MTU (ICE_AQ_SET_MAC_FRAME_SIZE_MAX - \ - (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2))) +#define ICE_MAX_MTU (ICE_AQ_SET_MAC_FRAME_SIZE_MAX - ICE_ETH_PKT_HDR_PAD) #define ICE_UP_TABLE_TRANSLATE(val, i) \ (((val) << ICE_AQ_VSI_UP_TABLE_UP##i##_S) & \ @@ -282,6 +283,10 @@ struct ice_vsi { u16 num_rx_desc; u16 num_tx_desc; struct ice_tc_cfg tc_cfg; + struct bpf_prog *xdp_prog; + struct ice_ring **xdp_rings; /* XDP ring array */ + u16 num_xdp_txq; /* Used XDP queues */ + u8 xdp_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ } ____cacheline_internodealigned_in_smp; /* struct that defines an interrupt vector */ @@ -425,6 +430,16 @@ static inline struct ice_pf *ice_netdev_to_pf(struct net_device *netdev) return np->vsi->back; } +static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi) +{ + return !!vsi->xdp_prog; +} + +static inline void ice_set_ring_xdp(struct ice_ring *ring) +{ + ring->flags |= ICE_TX_FLAGS_RING_XDP; +} + /** * ice_get_main_vsi - Get the PF VSI * @pf: PF instance @@ -451,6 +466,11 @@ int ice_up(struct ice_vsi *vsi); int ice_down(struct ice_vsi *vsi); int ice_vsi_cfg(struct ice_vsi *vsi); struct ice_vsi *ice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi); +int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog); +int ice_destroy_xdp_rings(struct ice_vsi *vsi); +int +ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, + u32 flags); int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size); diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index df9f9bacbdf8..8721934fb4ea 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -198,6 +198,9 @@ static void ice_cfg_itr_gran(struct ice_hw *hw) */ static u16 ice_calc_q_handle(struct ice_vsi *vsi, struct ice_ring *ring, u8 tc) { + WARN_ONCE(ice_ring_is_xdp(ring) && tc, + "XDP ring can't belong to TC other than 0"); + /* Idea here for calculation is that we subtract the number of queue * count from TC that ring belongs to from it's absolute queue index * and as a result we get the queue's index within TC. @@ -287,6 +290,22 @@ int ice_setup_rx_ctx(struct ice_ring *ring) /* clear the context structure first */ memset(&rlan_ctx, 0, sizeof(rlan_ctx)); + ring->rx_buf_len = vsi->rx_buf_len; + + if (ring->vsi->type == ICE_VSI_PF) { + if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) + xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev, + ring->q_index); + + err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_PAGE_SHARED, NULL); + if (err) + return err; + } + /* Receive Queue Base Address. + * Indicates the starting address of the descriptor queue defined in + * 128 Byte units. + */ rlan_ctx.base = ring->dma >> 7; rlan_ctx.qlen = ring->count; @@ -294,7 +313,7 @@ int ice_setup_rx_ctx(struct ice_ring *ring) /* Receive Packet Data Buffer Size. * The Packet Data Buffer Size is defined in 128 byte units. */ - rlan_ctx.dbuf = vsi->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; + rlan_ctx.dbuf = ring->rx_buf_len >> ICE_RLAN_CTX_DBUF_S; /* use 32 byte descriptors */ rlan_ctx.dsize = 1; @@ -657,6 +676,13 @@ ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx) ((msix_idx << QINT_TQCTL_MSIX_INDX_S) & QINT_TQCTL_MSIX_INDX_M); wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), val); + if (ice_is_xdp_ena_vsi(vsi)) { + u32 xdp_txq = txq + vsi->num_xdp_txq; + + wr32(hw, QINT_TQCTL(vsi->txq_map[xdp_txq]), + val); + } + ice_flush(hw); } /** diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 7e23034df955..6cee99b5865b 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -2577,6 +2577,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct ice_ring *tx_rings = NULL, *rx_rings = NULL; struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_ring *xdp_rings = NULL; struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; int i, timeout = 50, err = 0; @@ -2624,6 +2625,11 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) vsi->tx_rings[i]->count = new_tx_cnt; for (i = 0; i < vsi->alloc_rxq; i++) vsi->rx_rings[i]->count = new_rx_cnt; + if (ice_is_xdp_ena_vsi(vsi)) + for (i = 0; i < vsi->num_xdp_txq; i++) + vsi->xdp_rings[i]->count = new_tx_cnt; + vsi->num_tx_desc = new_tx_cnt; + vsi->num_rx_desc = new_rx_cnt; netdev_dbg(netdev, "Link is down, descriptor count change happens when link is brought up\n"); goto done; } @@ -2650,15 +2656,43 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) tx_rings[i].tx_buf = NULL; err = ice_setup_tx_ring(&tx_rings[i]); if (err) { - while (i) { - i--; + while (i--) ice_clean_tx_ring(&tx_rings[i]); - } devm_kfree(&pf->pdev->dev, tx_rings); goto done; } } + if (!ice_is_xdp_ena_vsi(vsi)) + goto process_rx; + + /* alloc updated XDP resources */ + netdev_info(netdev, "Changing XDP descriptor count from %d to %d\n", + vsi->xdp_rings[0]->count, new_tx_cnt); + + xdp_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_xdp_txq, + sizeof(*xdp_rings), GFP_KERNEL); + if (!xdp_rings) { + err = -ENOMEM; + goto free_tx; + } + + for (i = 0; i < vsi->num_xdp_txq; i++) { + /* clone ring and setup updated count */ + xdp_rings[i] = *vsi->xdp_rings[i]; + xdp_rings[i].count = new_tx_cnt; + xdp_rings[i].desc = NULL; + xdp_rings[i].tx_buf = NULL; + err = ice_setup_tx_ring(&xdp_rings[i]); + if (err) { + while (i--) + ice_clean_tx_ring(&xdp_rings[i]); + devm_kfree(&pf->pdev->dev, xdp_rings); + goto free_tx; + } + ice_set_ring_xdp(&xdp_rings[i]); + } + process_rx: if (new_rx_cnt == vsi->rx_rings[0]->count) goto process_link; @@ -2737,6 +2771,16 @@ process_link: devm_kfree(&pf->pdev->dev, rx_rings); } + if (xdp_rings) { + for (i = 0; i < vsi->num_xdp_txq; i++) { + ice_free_tx_ring(vsi->xdp_rings[i]); + *vsi->xdp_rings[i] = xdp_rings[i]; + } + devm_kfree(&pf->pdev->dev, xdp_rings); + } + + vsi->num_tx_desc = new_tx_cnt; + vsi->num_rx_desc = new_rx_cnt; ice_up(vsi); } goto done; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 87f890363608..3794e42b1d69 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -46,7 +46,8 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) if (!vsi->rx_rings) goto err_rings; - vsi->txq_map = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, + /* XDP will have vsi->alloc_txq Tx queues as well, so double the size */ + vsi->txq_map = devm_kcalloc(&pf->pdev->dev, (2 * vsi->alloc_txq), sizeof(*vsi->txq_map), GFP_KERNEL); if (!vsi->txq_map) @@ -1183,6 +1184,20 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) return err; } +/** + * ice_vsi_cfg_frame_size - setup max frame size and Rx buffer length + * @vsi: VSI + */ +void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) +{ + if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) + vsi->max_frame = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD; + else + vsi->max_frame = ICE_RXBUF_2048; + + vsi->rx_buf_len = ICE_RXBUF_2048; +} + /** * ice_vsi_cfg_rxqs - Configure the VSI for Rx * @vsi: the VSI being configured @@ -1197,13 +1212,7 @@ int ice_vsi_cfg_rxqs(struct ice_vsi *vsi) if (vsi->type == ICE_VSI_VF) goto setup_rings; - if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) - vsi->max_frame = vsi->netdev->mtu + - ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; - else - vsi->max_frame = ICE_RXBUF_2048; - - vsi->rx_buf_len = ICE_RXBUF_2048; + ice_vsi_cfg_frame_size(vsi); setup_rings: /* set up individual rings */ for (i = 0; i < vsi->num_rxq; i++) { @@ -1265,6 +1274,18 @@ int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) return ice_vsi_cfg_txqs(vsi, vsi->tx_rings); } +/** + * ice_vsi_cfg_xdp_txqs - Configure Tx queues dedicated for XDP in given VSI + * @vsi: the VSI being configured + * + * Return 0 on success and a negative value on error + * Configure the Tx queues dedicated for XDP in given VSI for operation. + */ +int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) +{ + return ice_vsi_cfg_txqs(vsi, vsi->xdp_rings); +} + /** * ice_intrl_usec_to_reg - convert interrupt rate limit to register value * @intrl: interrupt rate limit in usecs @@ -1488,6 +1509,15 @@ ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, return ice_vsi_stop_tx_rings(vsi, rst_src, rel_vmvf_num, vsi->tx_rings); } +/** + * ice_vsi_stop_xdp_tx_rings - Disable XDP Tx rings + * @vsi: the VSI being configured + */ +int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi) +{ + return ice_vsi_stop_tx_rings(vsi, ICE_NO_RESET, 0, vsi->xdp_rings); +} + /** * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI * @vsi: VSI to enable or disable VLAN pruning on @@ -1885,6 +1915,11 @@ static void ice_vsi_release_msix(struct ice_vsi *vsi) wr32(hw, GLINT_ITR(ICE_IDX_ITR1, reg_idx), 0); for (q = 0; q < q_vector->num_ring_tx; q++) { wr32(hw, QINT_TQCTL(vsi->txq_map[txq]), 0); + if (ice_is_xdp_ena_vsi(vsi)) { + u32 xdp_txq = txq + vsi->num_xdp_txq; + + wr32(hw, QINT_TQCTL(vsi->txq_map[xdp_txq]), 0); + } txq++; } @@ -2259,6 +2294,11 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) vsi->base_vector = 0; } + if (ice_is_xdp_ena_vsi(vsi)) + /* return value check can be skipped here, it always returns + * 0 if reset is in progress + */ + ice_destroy_xdp_rings(vsi); ice_vsi_put_qs(vsi); ice_vsi_clear_rings(vsi); ice_vsi_free_arrays(vsi); @@ -2299,6 +2339,12 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) goto err_vectors; ice_vsi_map_rings_to_vectors(vsi); + if (ice_is_xdp_ena_vsi(vsi)) { + vsi->num_xdp_txq = vsi->alloc_txq; + ret = ice_prepare_xdp_rings(vsi, vsi->xdp_prog); + if (ret) + goto err_vectors; + } /* Do not exit if configuring RSS had an issue, at least * receive traffic on first queue. Hence no need to capture * return value @@ -2325,9 +2371,13 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) } /* configure VSI nodes based on number of queues and TC's */ - for (i = 0; i < vsi->tc_cfg.numtc; i++) + for (i = 0; i < vsi->tc_cfg.numtc; i++) { max_txqs[i] = vsi->alloc_txq; + if (ice_is_xdp_ena_vsi(vsi)) + max_txqs[i] += vsi->num_xdp_txq; + } + status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, max_txqs); if (status) { diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 2fd5da3d0275..8e92c37a0f21 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -36,6 +36,10 @@ int ice_vsi_stop_lan_tx_rings(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src, u16 rel_vmvf_num); +int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi); + +int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi); + int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc); void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create); @@ -79,6 +83,8 @@ void ice_vsi_free_tx_rings(struct ice_vsi *vsi); int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena); +void ice_vsi_cfg_frame_size(struct ice_vsi *vsi); + u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran); char *ice_nvm_version_str(struct ice_hw *hw); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index bf9c4438cbfb..3ee61ed21976 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1661,6 +1661,309 @@ free_q_irqs: return err; } +/** + * ice_xdp_alloc_setup_rings - Allocate and setup Tx rings for XDP + * @vsi: VSI to setup Tx rings used by XDP + * + * Return 0 on success and negative value on error + */ +static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi) +{ + struct device *dev = &vsi->back->pdev->dev; + int i; + + for (i = 0; i < vsi->num_xdp_txq; i++) { + u16 xdp_q_idx = vsi->alloc_txq + i; + struct ice_ring *xdp_ring; + + xdp_ring = kzalloc(sizeof(*xdp_ring), GFP_KERNEL); + + if (!xdp_ring) + goto free_xdp_rings; + + xdp_ring->q_index = xdp_q_idx; + xdp_ring->reg_idx = vsi->txq_map[xdp_q_idx]; + xdp_ring->ring_active = false; + xdp_ring->vsi = vsi; + xdp_ring->netdev = NULL; + xdp_ring->dev = dev; + xdp_ring->count = vsi->num_tx_desc; + vsi->xdp_rings[i] = xdp_ring; + if (ice_setup_tx_ring(xdp_ring)) + goto free_xdp_rings; + ice_set_ring_xdp(xdp_ring); + } + + return 0; + +free_xdp_rings: + for (; i >= 0; i--) + if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc) + ice_free_tx_ring(vsi->xdp_rings[i]); + return -ENOMEM; +} + +/** + * ice_vsi_assign_bpf_prog - set or clear bpf prog pointer on VSI + * @vsi: VSI to set the bpf prog on + * @prog: the bpf prog pointer + */ +static void ice_vsi_assign_bpf_prog(struct ice_vsi *vsi, struct bpf_prog *prog) +{ + struct bpf_prog *old_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); +} + +/** + * ice_prepare_xdp_rings - Allocate, configure and setup Tx rings for XDP + * @vsi: VSI to bring up Tx rings used by XDP + * @prog: bpf program that will be assigned to VSI + * + * Return 0 on success and negative value on error + */ +int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog) +{ + u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; + int xdp_rings_rem = vsi->num_xdp_txq; + struct ice_pf *pf = vsi->back; + struct ice_qs_cfg xdp_qs_cfg = { + .qs_mutex = &pf->avail_q_mutex, + .pf_map = pf->avail_txqs, + .pf_map_size = pf->max_pf_txqs, + .q_count = vsi->num_xdp_txq, + .scatter_count = ICE_MAX_SCATTER_TXQS, + .vsi_map = vsi->txq_map, + .vsi_map_offset = vsi->alloc_txq, + .mapping_mode = ICE_VSI_MAP_CONTIG + }; + enum ice_status status; + int i, v_idx; + + vsi->xdp_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_xdp_txq, + sizeof(*vsi->xdp_rings), GFP_KERNEL); + if (!vsi->xdp_rings) + return -ENOMEM; + + vsi->xdp_mapping_mode = xdp_qs_cfg.mapping_mode; + if (__ice_vsi_get_qs(&xdp_qs_cfg)) + goto err_map_xdp; + + if (ice_xdp_alloc_setup_rings(vsi)) + goto clear_xdp_rings; + + /* follow the logic from ice_vsi_map_rings_to_vectors */ + ice_for_each_q_vector(vsi, v_idx) { + struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; + int xdp_rings_per_v, q_id, q_base; + + xdp_rings_per_v = DIV_ROUND_UP(xdp_rings_rem, + vsi->num_q_vectors - v_idx); + q_base = vsi->num_xdp_txq - xdp_rings_rem; + + for (q_id = q_base; q_id < (q_base + xdp_rings_per_v); q_id++) { + struct ice_ring *xdp_ring = vsi->xdp_rings[q_id]; + + xdp_ring->q_vector = q_vector; + xdp_ring->next = q_vector->tx.ring; + q_vector->tx.ring = xdp_ring; + } + xdp_rings_rem -= xdp_rings_per_v; + } + + /* omit the scheduler update if in reset path; XDP queues will be + * taken into account at the end of ice_vsi_rebuild, where + * ice_cfg_vsi_lan is being called + */ + if (ice_is_reset_in_progress(pf->state)) + return 0; + + /* tell the Tx scheduler that right now we have + * additional queues + */ + for (i = 0; i < vsi->tc_cfg.numtc; i++) + max_txqs[i] = vsi->num_txq + vsi->num_xdp_txq; + + status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); + if (status) { + dev_err(&pf->pdev->dev, + "Failed VSI LAN queue config for XDP, error:%d\n", + status); + goto clear_xdp_rings; + } + ice_vsi_assign_bpf_prog(vsi, prog); + + return 0; +clear_xdp_rings: + for (i = 0; i < vsi->num_xdp_txq; i++) + if (vsi->xdp_rings[i]) { + kfree_rcu(vsi->xdp_rings[i], rcu); + vsi->xdp_rings[i] = NULL; + } + +err_map_xdp: + mutex_lock(&pf->avail_q_mutex); + for (i = 0; i < vsi->num_xdp_txq; i++) { + clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs); + vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX; + } + mutex_unlock(&pf->avail_q_mutex); + + devm_kfree(&pf->pdev->dev, vsi->xdp_rings); + return -ENOMEM; +} + +/** + * ice_destroy_xdp_rings - undo the configuration made by ice_prepare_xdp_rings + * @vsi: VSI to remove XDP rings + * + * Detach XDP rings from irq vectors, clean up the PF bitmap and free + * resources + */ +int ice_destroy_xdp_rings(struct ice_vsi *vsi) +{ + u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; + struct ice_pf *pf = vsi->back; + int i, v_idx; + + /* q_vectors are freed in reset path so there's no point in detaching + * rings; in case of rebuild being triggered not from reset reset bits + * in pf->state won't be set, so additionally check first q_vector + * against NULL + */ + if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0]) + goto free_qmap; + + ice_for_each_q_vector(vsi, v_idx) { + struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; + struct ice_ring *ring; + + ice_for_each_ring(ring, q_vector->tx) + if (!ring->tx_buf || !ice_ring_is_xdp(ring)) + break; + + /* restore the value of last node prior to XDP setup */ + q_vector->tx.ring = ring; + } + +free_qmap: + mutex_lock(&pf->avail_q_mutex); + for (i = 0; i < vsi->num_xdp_txq; i++) { + clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs); + vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX; + } + mutex_unlock(&pf->avail_q_mutex); + + for (i = 0; i < vsi->num_xdp_txq; i++) + if (vsi->xdp_rings[i]) { + if (vsi->xdp_rings[i]->desc) + ice_free_tx_ring(vsi->xdp_rings[i]); + kfree_rcu(vsi->xdp_rings[i], rcu); + vsi->xdp_rings[i] = NULL; + } + + devm_kfree(&pf->pdev->dev, vsi->xdp_rings); + vsi->xdp_rings = NULL; + + if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0]) + return 0; + + ice_vsi_assign_bpf_prog(vsi, NULL); + + /* notify Tx scheduler that we destroyed XDP queues and bring + * back the old number of child nodes + */ + for (i = 0; i < vsi->tc_cfg.numtc; i++) + max_txqs[i] = vsi->num_txq; + + return ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, + max_txqs); +} + +/** + * ice_xdp_setup_prog - Add or remove XDP eBPF program + * @vsi: VSI to setup XDP for + * @prog: XDP program + * @extack: netlink extended ack + */ +static int +ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + int frame_size = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD; + bool if_running = netif_running(vsi->netdev); + int ret = 0, xdp_ring_err = 0; + + if (frame_size > vsi->rx_buf_len) { + NL_SET_ERR_MSG_MOD(extack, "MTU too large for loading XDP"); + return -EOPNOTSUPP; + } + + /* need to stop netdev while setting up the program for Rx rings */ + if (if_running && !test_and_set_bit(__ICE_DOWN, vsi->state)) { + ret = ice_down(vsi); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, + "Preparing device for XDP attach failed"); + return ret; + } + } + + if (!ice_is_xdp_ena_vsi(vsi) && prog) { + vsi->num_xdp_txq = vsi->alloc_txq; + xdp_ring_err = ice_prepare_xdp_rings(vsi, prog); + if (xdp_ring_err) + NL_SET_ERR_MSG_MOD(extack, + "Setting up XDP Tx resources failed"); + } else if (ice_is_xdp_ena_vsi(vsi) && !prog) { + xdp_ring_err = ice_destroy_xdp_rings(vsi); + if (xdp_ring_err) + NL_SET_ERR_MSG_MOD(extack, + "Freeing XDP Tx resources failed"); + } else { + ice_vsi_assign_bpf_prog(vsi, prog); + } + + if (if_running) + ret = ice_up(vsi); + + return (ret || xdp_ring_err) ? -ENOMEM : 0; +} + +/** + * ice_xdp - implements XDP handler + * @dev: netdevice + * @xdp: XDP command + */ +static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_vsi *vsi = np->vsi; + + if (vsi->type != ICE_VSI_PF) { + NL_SET_ERR_MSG_MOD(xdp->extack, + "XDP can be loaded only on PF VSI"); + return -EINVAL; + } + + switch (xdp->command) { + case XDP_SETUP_PROG: + return ice_xdp_setup_prog(vsi, xdp->prog, xdp->extack); + case XDP_QUERY_PROG: + xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0; + return 0; + default: + return -EINVAL; + } +} + /** * ice_ena_misc_vector - enable the non-queue interrupts * @pf: board private structure @@ -2220,6 +2523,8 @@ static int ice_setup_pf_sw(struct ice_pf *pf) status = -ENODEV; goto unroll_vsi_setup; } + /* netdev has to be configured before setting frame size */ + ice_vsi_cfg_frame_size(vsi); /* registering the NAPI handler requires both the queues and * netdev to be created, which are done in ice_pf_vsi_setup() @@ -3506,6 +3811,8 @@ int ice_vsi_cfg(struct ice_vsi *vsi) ice_vsi_cfg_dcb_rings(vsi); err = ice_vsi_cfg_lan_txqs(vsi); + if (!err && ice_is_xdp_ena_vsi(vsi)) + err = ice_vsi_cfg_xdp_txqs(vsi); if (!err) err = ice_vsi_cfg_rxqs(vsi); @@ -3921,6 +4228,13 @@ int ice_down(struct ice_vsi *vsi) netdev_err(vsi->netdev, "Failed stop Tx rings, VSI %d error %d\n", vsi->vsi_num, tx_err); + if (!tx_err && ice_is_xdp_ena_vsi(vsi)) { + tx_err = ice_vsi_stop_xdp_tx_rings(vsi); + if (tx_err) + netdev_err(vsi->netdev, + "Failed stop XDP rings, VSI %d error %d\n", + vsi->vsi_num, tx_err); + } rx_err = ice_vsi_stop_rx_rings(vsi); if (rx_err) @@ -4348,6 +4662,16 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) return 0; } + if (ice_is_xdp_ena_vsi(vsi)) { + int frame_size = ICE_RXBUF_2048 - XDP_PACKET_HEADROOM; + + if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) { + netdev_err(netdev, "max MTU for XDP usage is %d\n", + frame_size); + return -EINVAL; + } + } + if (new_mtu < netdev->min_mtu) { netdev_err(netdev, "new MTU invalid. min_mtu is %d\n", netdev->min_mtu); @@ -4879,4 +5203,6 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_fdb_add = ice_fdb_add, .ndo_fdb_del = ice_fdb_del, .ndo_tx_timeout = ice_tx_timeout, + .ndo_bpf = ice_xdp, + .ndo_xdp_xmit = ice_xdp_xmit, }; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 33dd103035dc..f79a9376159b 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -5,6 +5,9 @@ #include #include +#include +#include +#include "ice_lib.h" #include "ice.h" #include "ice_dcb_lib.h" @@ -19,7 +22,10 @@ static void ice_unmap_and_free_tx_buf(struct ice_ring *ring, struct ice_tx_buf *tx_buf) { if (tx_buf->skb) { - dev_kfree_skb_any(tx_buf->skb); + if (ice_ring_is_xdp(ring)) + page_frag_free(tx_buf->raw_buf); + else + dev_kfree_skb_any(tx_buf->skb); if (dma_unmap_len(tx_buf, len)) dma_unmap_single(ring->dev, dma_unmap_addr(tx_buf, dma), @@ -136,8 +142,11 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget) total_bytes += tx_buf->bytecount; total_pkts += tx_buf->gso_segs; - /* free the skb */ - napi_consume_skb(tx_buf->skb, napi_budget); + if (ice_ring_is_xdp(tx_ring)) + page_frag_free(tx_buf->raw_buf); + else + /* free the skb */ + napi_consume_skb(tx_buf->skb, napi_budget); /* unmap skb header data */ dma_unmap_single(tx_ring->dev, @@ -195,6 +204,9 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget) tx_ring->q_vector->tx.total_bytes += total_bytes; tx_ring->q_vector->tx.total_pkts += total_pkts; + if (ice_ring_is_xdp(tx_ring)) + return !!budget; + netdev_tx_completed_queue(txring_txq(tx_ring), total_pkts, total_bytes); @@ -319,6 +331,10 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring) void ice_free_rx_ring(struct ice_ring *rx_ring) { ice_clean_rx_ring(rx_ring); + if (rx_ring->vsi->type == ICE_VSI_PF) + if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) + xdp_rxq_info_unreg(&rx_ring->xdp_rxq); + rx_ring->xdp_prog = NULL; devm_kfree(rx_ring->dev, rx_ring->rx_buf); rx_ring->rx_buf = NULL; @@ -363,6 +379,15 @@ int ice_setup_rx_ring(struct ice_ring *rx_ring) rx_ring->next_to_use = 0; rx_ring->next_to_clean = 0; + + if (ice_is_xdp_ena_vsi(rx_ring->vsi)) + WRITE_ONCE(rx_ring->xdp_prog, rx_ring->vsi->xdp_prog); + + if (rx_ring->vsi->type == ICE_VSI_PF && + !xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) + if (xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev, + rx_ring->q_index)) + goto err; return 0; err: @@ -402,6 +427,214 @@ static void ice_release_rx_desc(struct ice_ring *rx_ring, u32 val) } } +/** + * ice_rx_offset - Return expected offset into page to access data + * @rx_ring: Ring we are requesting offset of + * + * Returns the offset value for ring into the data buffer. + */ +static unsigned int ice_rx_offset(struct ice_ring *rx_ring) +{ + return ice_is_xdp_ena_vsi(rx_ring->vsi) ? XDP_PACKET_HEADROOM : 0; +} + +/** + * ice_xdp_ring_update_tail - Updates the XDP Tx ring tail register + * @xdp_ring: XDP Tx ring + * + * This function updates the XDP Tx ring tail register. + */ +static void ice_xdp_ring_update_tail(struct ice_ring *xdp_ring) +{ + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. + */ + wmb(); + writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); +} + +/** + * ice_xmit_xdp_ring - submit single packet to XDP ring for transmission + * @data: packet data pointer + * @size: packet data size + * @xdp_ring: XDP ring for transmission + */ +static int ice_xmit_xdp_ring(void *data, u16 size, struct ice_ring *xdp_ring) +{ + u16 i = xdp_ring->next_to_use; + struct ice_tx_desc *tx_desc; + struct ice_tx_buf *tx_buf; + dma_addr_t dma; + + if (!unlikely(ICE_DESC_UNUSED(xdp_ring))) { + xdp_ring->tx_stats.tx_busy++; + return ICE_XDP_CONSUMED; + } + + dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE); + if (dma_mapping_error(xdp_ring->dev, dma)) + return ICE_XDP_CONSUMED; + + tx_buf = &xdp_ring->tx_buf[i]; + tx_buf->bytecount = size; + tx_buf->gso_segs = 1; + tx_buf->raw_buf = data; + + /* record length, and DMA address */ + dma_unmap_len_set(tx_buf, len, size); + dma_unmap_addr_set(tx_buf, dma, dma); + + tx_desc = ICE_TX_DESC(xdp_ring, i); + tx_desc->buf_addr = cpu_to_le64(dma); + tx_desc->cmd_type_offset_bsz = build_ctob(ICE_TXD_LAST_DESC_CMD, 0, + size, 0); + + /* Make certain all of the status bits have been updated + * before next_to_watch is written. + */ + smp_wmb(); + + i++; + if (i == xdp_ring->count) + i = 0; + + tx_buf->next_to_watch = tx_desc; + xdp_ring->next_to_use = i; + + return ICE_XDP_TX; +} + +/** + * ice_xmit_xdp_buff - convert an XDP buffer to an XDP frame and send it + * @xdp: XDP buffer + * @xdp_ring: XDP Tx ring + * + * Returns negative on failure, 0 on success. + */ +static int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_ring *xdp_ring) +{ + struct xdp_frame *xdpf = convert_to_xdp_frame(xdp); + + if (unlikely(!xdpf)) + return ICE_XDP_CONSUMED; + + return ice_xmit_xdp_ring(xdpf->data, xdpf->len, xdp_ring); +} + +/** + * ice_run_xdp - Executes an XDP program on initialized xdp_buff + * @rx_ring: Rx ring + * @xdp: xdp_buff used as input to the XDP program + * @xdp_prog: XDP program to run + * + * Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR} + */ +static int +ice_run_xdp(struct ice_ring *rx_ring, struct xdp_buff *xdp, + struct bpf_prog *xdp_prog) +{ + int err, result = ICE_XDP_PASS; + struct ice_ring *xdp_ring; + u32 act; + + act = bpf_prog_run_xdp(xdp_prog, xdp); + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + xdp_ring = rx_ring->vsi->xdp_rings[smp_processor_id()]; + result = ice_xmit_xdp_buff(xdp, xdp_ring); + break; + case XDP_REDIRECT: + err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); + result = !err ? ICE_XDP_REDIR : ICE_XDP_CONSUMED; + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fallthrough -- not supported action */ + case XDP_ABORTED: + trace_xdp_exception(rx_ring->netdev, xdp_prog, act); + /* fallthrough -- handle aborts by dropping frame */ + case XDP_DROP: + result = ICE_XDP_CONSUMED; + break; + } + + return result; +} + +/** + * ice_xdp_xmit - submit packets to XDP ring for transmission + * @dev: netdev + * @n: number of XDP frames to be transmitted + * @frames: XDP frames to be transmitted + * @flags: transmit flags + * + * Returns number of frames successfully sent. Frames that fail are + * free'ed via XDP return API. + * For error cases, a negative errno code is returned and no-frames + * are transmitted (caller must handle freeing frames). + */ +int +ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, + u32 flags) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + unsigned int queue_index = smp_processor_id(); + struct ice_vsi *vsi = np->vsi; + struct ice_ring *xdp_ring; + int drops = 0, i; + + if (test_bit(__ICE_DOWN, vsi->state)) + return -ENETDOWN; + + if (!ice_is_xdp_ena_vsi(vsi) || queue_index >= vsi->num_xdp_txq) + return -ENXIO; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + xdp_ring = vsi->xdp_rings[queue_index]; + for (i = 0; i < n; i++) { + struct xdp_frame *xdpf = frames[i]; + int err; + + err = ice_xmit_xdp_ring(xdpf->data, xdpf->len, xdp_ring); + if (err != ICE_XDP_TX) { + xdp_return_frame_rx_napi(xdpf); + drops++; + } + } + + if (unlikely(flags & XDP_XMIT_FLUSH)) + ice_xdp_ring_update_tail(xdp_ring); + + return n - drops; +} + +/** + * ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map + * @rx_ring: Rx ring + * @xdp_res: Result of the receive batch + * + * This function bumps XDP Tx tail and/or flush redirect map, and + * should be called when a batch of packets has been processed in the + * napi loop. + */ +static void +ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res) +{ + if (xdp_res & ICE_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_res & ICE_XDP_TX) { + struct ice_ring *xdp_ring = + rx_ring->vsi->xdp_rings[rx_ring->q_index]; + + ice_xdp_ring_update_tail(xdp_ring); + } +} + /** * ice_alloc_mapped_page - recycle or make a new page * @rx_ring: ring to use @@ -444,7 +677,7 @@ ice_alloc_mapped_page(struct ice_ring *rx_ring, struct ice_rx_buf *bi) bi->dma = dma; bi->page = page; - bi->page_offset = 0; + bi->page_offset = ice_rx_offset(rx_ring); page_ref_add(page, USHRT_MAX - 1); bi->pagecnt_bias = USHRT_MAX; @@ -682,7 +915,7 @@ ice_get_rx_buf(struct ice_ring *rx_ring, struct sk_buff **skb, * ice_construct_skb - Allocate skb and populate it * @rx_ring: Rx descriptor ring to transact packets on * @rx_buf: Rx buffer to pull data from - * @size: the length of the packet + * @xdp: xdp_buff pointing to the data * * This function allocates an skb. It then populates it with the page * data from the current receive descriptor, taking care to set up the @@ -690,16 +923,16 @@ ice_get_rx_buf(struct ice_ring *rx_ring, struct sk_buff **skb, */ static struct sk_buff * ice_construct_skb(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, - unsigned int size) + struct xdp_buff *xdp) { - void *va = page_address(rx_buf->page) + rx_buf->page_offset; + unsigned int size = xdp->data_end - xdp->data; unsigned int headlen; struct sk_buff *skb; /* prefetch first cache line of first page */ - prefetch(va); + prefetch(xdp->data); #if L1_CACHE_BYTES < 128 - prefetch((u8 *)va + L1_CACHE_BYTES); + prefetch((void *)(xdp->data + L1_CACHE_BYTES)); #endif /* L1_CACHE_BYTES */ /* allocate a skb to store the frags */ @@ -712,10 +945,11 @@ ice_construct_skb(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, /* Determine available headroom for copy */ headlen = size; if (headlen > ICE_RX_HDR_SIZE) - headlen = eth_get_headlen(skb->dev, va, ICE_RX_HDR_SIZE); + headlen = eth_get_headlen(skb->dev, xdp->data, ICE_RX_HDR_SIZE); /* align pull length to size of long to optimize memcpy performance */ - memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long))); + memcpy(__skb_put(skb, headlen), xdp->data, ALIGN(headlen, + sizeof(long))); /* if we exhaust the linear part then add what is left as a frag */ size -= headlen; @@ -745,11 +979,18 @@ ice_construct_skb(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, * @rx_ring: Rx descriptor ring to transact packets on * @rx_buf: Rx buffer to pull data from * - * This function will clean up the contents of the rx_buf. It will - * either recycle the buffer or unmap it and free the associated resources. + * This function will update next_to_clean and then clean up the contents + * of the rx_buf. It will either recycle the buffer or unmap it and free + * the associated resources. */ static void ice_put_rx_buf(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) { + u32 ntc = rx_ring->next_to_clean + 1; + + /* fetch, update, and store next to clean */ + ntc = (ntc < rx_ring->count) ? ntc : 0; + rx_ring->next_to_clean = ntc; + if (!rx_buf) return; @@ -813,30 +1054,20 @@ ice_test_staterr(union ice_32b_rx_flex_desc *rx_desc, const u16 stat_err_bits) * @rx_desc: Rx descriptor for current buffer * @skb: Current socket buffer containing buffer in progress * - * This function updates next to clean. If the buffer is an EOP buffer - * this function exits returning false, otherwise it will place the - * sk_buff in the next buffer to be chained and return true indicating - * that this is in fact a non-EOP buffer. + * If the buffer is an EOP buffer, this function exits returning false, + * otherwise return true indicating that this is in fact a non-EOP buffer. */ static bool ice_is_non_eop(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb) { - u32 ntc = rx_ring->next_to_clean + 1; - - /* fetch, update, and store next to clean */ - ntc = (ntc < rx_ring->count) ? ntc : 0; - rx_ring->next_to_clean = ntc; - - prefetch(ICE_RX_DESC(rx_ring, ntc)); - /* if we are the last buffer then there is nothing else to do */ #define ICE_RXD_EOF BIT(ICE_RX_FLEX_DESC_STATUS0_EOF_S) if (likely(ice_test_staterr(rx_desc, ICE_RXD_EOF))) return false; /* place skb in next buffer to be received */ - rx_ring->rx_buf[ntc].skb = skb; + rx_ring->rx_buf[rx_ring->next_to_clean].skb = skb; rx_ring->rx_stats.non_eop_descs++; return true; @@ -1006,8 +1237,13 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) { unsigned int total_rx_bytes = 0, total_rx_pkts = 0; u16 cleaned_count = ICE_DESC_UNUSED(rx_ring); + unsigned int xdp_res, xdp_xmit = 0; + struct bpf_prog *xdp_prog = NULL; + struct xdp_buff xdp; bool failure; + xdp.rxq = &rx_ring->xdp_rxq; + /* start the loop to process Rx packets bounded by 'budget' */ while (likely(total_rx_pkts < (unsigned int)budget)) { union ice_32b_rx_flex_desc *rx_desc; @@ -1042,10 +1278,46 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) /* retrieve a buffer from the ring */ rx_buf = ice_get_rx_buf(rx_ring, &skb, size); + if (!size) { + xdp.data = NULL; + xdp.data_end = NULL; + goto construct_skb; + } + + xdp.data = page_address(rx_buf->page) + rx_buf->page_offset; + xdp.data_hard_start = xdp.data - ice_rx_offset(rx_ring); + xdp_set_data_meta_invalid(&xdp); + xdp.data_end = xdp.data + size; + + rcu_read_lock(); + xdp_prog = READ_ONCE(rx_ring->xdp_prog); + if (!xdp_prog) { + rcu_read_unlock(); + goto construct_skb; + } + + xdp_res = ice_run_xdp(rx_ring, &xdp, xdp_prog); + rcu_read_unlock(); + if (xdp_res) { + if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) { + xdp_xmit |= xdp_res; + ice_rx_buf_adjust_pg_offset(rx_buf, + ICE_RXBUF_2048); + } else { + rx_buf->pagecnt_bias++; + } + total_rx_bytes += size; + total_rx_pkts++; + + cleaned_count++; + ice_put_rx_buf(rx_ring, rx_buf); + continue; + } +construct_skb: if (skb) ice_add_rx_frag(rx_buf, skb, size); else - skb = ice_construct_skb(rx_ring, rx_buf, size); + skb = ice_construct_skb(rx_ring, rx_buf, &xdp); /* exit if we failed to retrieve a buffer */ if (!skb) { @@ -1099,6 +1371,9 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) /* return up to cleaned_count buffers to hardware */ failure = ice_alloc_rx_bufs(rx_ring, cleaned_count); + if (xdp_prog) + ice_finalize_xdp_rx(rx_ring, xdp_xmit); + /* update queue and vector specific stats */ u64_stats_update_begin(&rx_ring->syncp); rx_ring->stats.pkts += total_rx_pkts; @@ -1527,17 +1802,6 @@ int ice_napi_poll(struct napi_struct *napi, int budget) return min_t(int, work_done, budget - 1); } -/* helper function for building cmd/type/offset */ -static __le64 -build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag) -{ - return cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | - (td_cmd << ICE_TXD_QW1_CMD_S) | - (td_offset << ICE_TXD_QW1_OFFSET_S) | - ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | - (td_tag << ICE_TXD_QW1_L2TAG1_S)); -} - /** * __ice_maybe_stop_tx - 2nd level check for Tx stop conditions * @tx_ring: the ring to be checked @@ -1689,9 +1953,9 @@ ice_tx_map(struct ice_ring *tx_ring, struct ice_tx_buf *first, i = 0; /* write last descriptor with RS and EOP bits */ - td_cmd |= (u64)(ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS); - tx_desc->cmd_type_offset_bsz = - build_ctob(td_cmd, td_offset, size, td_tag); + td_cmd |= (u64)ICE_TXD_LAST_DESC_CMD; + tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset, size, + td_tag); /* Force memory writes to complete before letting h/w know there * are new descriptors to fetch. diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index a914e603b2ed..e40b4cb54ce3 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -22,6 +22,16 @@ #define ICE_RX_BUF_WRITE 16 /* Must be power of 2 */ #define ICE_MAX_TXQ_PER_TXQG 128 +static inline __le64 +build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag) +{ + return cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | + (td_cmd << ICE_TXD_QW1_CMD_S) | + (td_offset << ICE_TXD_QW1_OFFSET_S) | + ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | + (td_tag << ICE_TXD_QW1_L2TAG1_S)); +} + /* We are assuming that the cache line is always 64 Bytes here for ice. * In order to make sure that is a correct assumption there is a check in probe * to print a warning if the read from GLPCI_CNF2 tells us that the cache line @@ -49,12 +59,24 @@ #define ICE_TX_FLAGS_VLAN_PR_S 29 #define ICE_TX_FLAGS_VLAN_S 16 +#define ICE_XDP_PASS 0 +#define ICE_XDP_CONSUMED BIT(0) +#define ICE_XDP_TX BIT(1) +#define ICE_XDP_REDIR BIT(2) + #define ICE_RX_DMA_ATTR \ (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_WEAK_ORDERING) +#define ICE_ETH_PKT_HDR_PAD (ETH_HLEN + ETH_FCS_LEN + (VLAN_HLEN * 2)) + +#define ICE_TXD_LAST_DESC_CMD (ICE_TX_DESC_CMD_EOP | ICE_TX_DESC_CMD_RS) + struct ice_tx_buf { struct ice_tx_desc *next_to_watch; - struct sk_buff *skb; + union { + struct sk_buff *skb; + void *raw_buf; /* used for XDP */ + }; unsigned int bytecount; unsigned short gso_segs; u32 tx_flags; @@ -198,9 +220,14 @@ struct ice_ring { }; struct rcu_head rcu; /* to avoid race on free */ + struct bpf_prog *xdp_prog; + /* CL3 - 3rd cacheline starts here */ + struct xdp_rxq_info xdp_rxq; /* CLX - the below items are only accessed infrequently and should be * in their own cache line if possible */ +#define ICE_TX_FLAGS_RING_XDP BIT(0) + u8 flags; dma_addr_t dma; /* physical address of ring */ unsigned int size; /* length of descriptor ring in bytes */ u32 txq_teid; /* Added Tx queue TEID */ @@ -208,6 +235,11 @@ struct ice_ring { u8 dcb_tc; /* Traffic class of ring */ } ____cacheline_internodealigned_in_smp; +static inline bool ice_ring_is_xdp(struct ice_ring *ring) +{ + return !!(ring->flags & ICE_TX_FLAGS_RING_XDP); +} + struct ice_ring_container { /* head of linked-list of rings */ struct ice_ring *ring; -- cgit v1.2.3-59-g8ed1b From 0c65b2b90d13c1deaee6449304dd367c5d4eb8ae Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 4 Nov 2019 02:40:33 +0100 Subject: net: of_get_phy_mode: Change API to solve int/unit warnings Before this change of_get_phy_mode() returned an enum, phy_interface_t. On error, -ENODEV etc, is returned. If the result of the function is stored in a variable of type phy_interface_t, and the compiler has decided to represent this as an unsigned int, comparision with -ENODEV etc, is a signed vs unsigned comparision. Fix this problem by changing the API. Make the function return an error, or 0 on success, and pass a pointer, of type phy_interface_t, where the phy mode should be stored. v2: Return with *interface set to PHY_INTERFACE_MODE_NA on error. Add error checks to all users of of_get_phy_mode() Fixup a few reverse christmas tree errors Fixup a few slightly malformed reverse christmas trees v3: Fix 0-day reported errors. Reported-by: Dan Carpenter Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 7 ++++--- drivers/net/dsa/microchip/ksz_common.c | 7 ++++--- drivers/net/dsa/mt7530.c | 8 ++++++-- drivers/net/dsa/qca8k.c | 9 +++++---- drivers/net/dsa/sja1105/sja1105_main.c | 7 ++++--- drivers/net/ethernet/altera/altera_tse_main.c | 6 +++--- drivers/net/ethernet/arc/emac_arc.c | 15 ++++++++++----- drivers/net/ethernet/arc/emac_rockchip.c | 7 +++++-- drivers/net/ethernet/atheros/ag71xx.c | 5 ++--- drivers/net/ethernet/aurora/nb8800.c | 4 ++-- drivers/net/ethernet/aurora/nb8800.h | 2 +- drivers/net/ethernet/broadcom/bcmsysport.c | 4 ++-- drivers/net/ethernet/broadcom/genet/bcmmii.c | 8 ++++---- drivers/net/ethernet/cadence/macb_main.c | 7 ++++--- drivers/net/ethernet/faraday/ftgmac100.c | 6 +++--- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 7 ++++--- drivers/net/ethernet/freescale/enetc/enetc_pf.c | 4 ++-- drivers/net/ethernet/freescale/fec_main.c | 7 ++++--- drivers/net/ethernet/freescale/fman/mac.c | 6 +++--- drivers/net/ethernet/freescale/gianfar.c | 7 ++++--- drivers/net/ethernet/hisilicon/hip04_eth.c | 7 +++---- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 5 ++--- drivers/net/ethernet/ibm/emac/core.c | 5 +++-- drivers/net/ethernet/marvell/mv643xx_eth.c | 7 ++++--- drivers/net/ethernet/marvell/mvneta.c | 7 +++---- drivers/net/ethernet/marvell/pxa168_eth.c | 4 +++- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++---- drivers/net/ethernet/mscc/ocelot_board.c | 12 ++++++------ drivers/net/ethernet/ni/nixge.c | 5 ++--- drivers/net/ethernet/renesas/ravb_main.c | 4 +++- drivers/net/ethernet/renesas/sh_eth.c | 7 ++++--- drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c | 5 ++++- drivers/net/ethernet/socionext/sni_ave.c | 6 +++--- drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c | 10 +++++++--- drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c | 5 +++-- drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 9 +++++---- drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c | 5 ++--- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 4 ++-- drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c | 9 +++++++-- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 7 ++++--- drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c | 8 ++++++-- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 +++--- drivers/net/ethernet/ti/cpsw.c | 5 ++--- drivers/net/ethernet/ti/cpsw_priv.h | 2 +- drivers/net/ethernet/ti/netcp_ethss.c | 5 +++-- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 6 ++---- drivers/of/of_mdio.c | 4 ++-- drivers/of/of_net.c | 16 +++++++++++----- include/linux/of_net.h | 7 +++++-- include/linux/stmmac.h | 3 ++- include/linux/sxgbe_platform.h | 4 +++- net/dsa/port.c | 13 +++++++------ net/dsa/slave.c | 7 ++++--- 53 files changed, 201 insertions(+), 149 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 9add84c79dd6..67125a5487e1 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -381,8 +381,9 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, struct device_node *dn) { struct device_node *port; - int mode; unsigned int port_num; + phy_interface_t mode; + int err; priv->moca_port = -1; @@ -395,8 +396,8 @@ static void bcm_sf2_identify_ports(struct bcm_sf2_priv *priv, * has completed, since they might be turned off at that * time */ - mode = of_get_phy_mode(port); - if (mode < 0) + err = of_get_phy_mode(port, &mode); + if (err) continue; if (mode == PHY_INTERFACE_MODE_INTERNAL) diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 5d08e4430824..d8fda4a02640 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -422,6 +422,7 @@ EXPORT_SYMBOL(ksz_switch_alloc); int ksz_switch_register(struct ksz_device *dev, const struct ksz_dev_ops *ops) { + phy_interface_t interface; int ret; if (dev->pdata) @@ -456,9 +457,9 @@ int ksz_switch_register(struct ksz_device *dev, * device tree. */ if (dev->dev->of_node) { - ret = of_get_phy_mode(dev->dev->of_node); - if (ret >= 0) - dev->interface = ret; + ret = of_get_phy_mode(dev->dev->of_node, &interface); + if (ret == 0) + dev->interface = interface; dev->synclko_125 = of_property_read_bool(dev->dev->of_node, "microchip,synclko-125"); } diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index add9e4279176..ed1ec10ec62b 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -1340,7 +1340,9 @@ mt7530_setup(struct dsa_switch *ds) if (!dsa_is_unused_port(ds, 5)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5; - interface = of_get_phy_mode(dsa_to_port(ds, 5)->dn); + ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface); + if (ret && ret != -ENODEV) + return ret; } else { /* Scan the ethernet nodes. look for GMAC1, lookup used phy */ for_each_child_of_node(dn, mac_np) { @@ -1354,7 +1356,9 @@ mt7530_setup(struct dsa_switch *ds) phy_node = of_parse_phandle(mac_np, "phy-handle", 0); if (phy_node->parent == priv->dev->of_node->parent) { - interface = of_get_phy_mode(mac_np); + ret = of_get_phy_mode(mac_np, &interface); + if (ret && ret != -ENODEV) + return ret; id = of_mdio_parse_addr(ds->dev, phy_node); if (id == 0) priv->p5_intf_sel = P5_INTF_SEL_PHY_P0; diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 36c6ed98f8e7..e548289df31e 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -639,7 +639,8 @@ static int qca8k_setup(struct dsa_switch *ds) { struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; - int ret, i, phy_mode = -1; + phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA; + int ret, i; u32 mask; /* Make sure that port 0 is the cpu port */ @@ -661,10 +662,10 @@ qca8k_setup(struct dsa_switch *ds) return ret; /* Initialize CPU port pad mode (xMII type, delays...) */ - phy_mode = of_get_phy_mode(dsa_to_port(ds, QCA8K_CPU_PORT)->dn); - if (phy_mode < 0) { + ret = of_get_phy_mode(dsa_to_port(ds, QCA8K_CPU_PORT)->dn, &phy_mode); + if (ret) { pr_err("Can't find phy-mode for master device\n"); - return phy_mode; + return ret; } ret = qca8k_set_pad_ctrl(priv, QCA8K_CPU_PORT, phy_mode); if (ret < 0) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 2ae84a9dea59..d5dfda335aa1 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -584,8 +584,9 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, for_each_child_of_node(ports_node, child) { struct device_node *phy_node; - int phy_mode; + phy_interface_t phy_mode; u32 index; + int err; /* Get switch port number from DT */ if (of_property_read_u32(child, "reg", &index) < 0) { @@ -596,8 +597,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv, } /* Get PHY mode from DT */ - phy_mode = of_get_phy_mode(child); - if (phy_mode < 0) { + err = of_get_phy_mode(child, &phy_mode); + if (err) { dev_err(dev, "Failed to read phy-mode or " "phy-interface-type property for port %d\n", index); diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index bb032be7fe31..4cd53fc338b5 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -730,12 +730,12 @@ static int altera_tse_phy_get_addr_mdio_create(struct net_device *dev) { struct altera_tse_private *priv = netdev_priv(dev); struct device_node *np = priv->device->of_node; - int ret = 0; + int ret; - priv->phy_iface = of_get_phy_mode(np); + ret = of_get_phy_mode(np, &priv->phy_iface); /* Avoid get phy addr and create mdio if no phy is present */ - if (!priv->phy_iface) + if (ret) return 0; /* try to get PHY address from device tree, use PHY autodetection if diff --git a/drivers/net/ethernet/arc/emac_arc.c b/drivers/net/ethernet/arc/emac_arc.c index 78e52d217e56..539166112993 100644 --- a/drivers/net/ethernet/arc/emac_arc.c +++ b/drivers/net/ethernet/arc/emac_arc.c @@ -20,9 +20,10 @@ static int emac_arc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct net_device *ndev; struct arc_emac_priv *priv; - int interface, err; + phy_interface_t interface; + struct net_device *ndev; + int err; if (!dev->of_node) return -ENODEV; @@ -37,9 +38,13 @@ static int emac_arc_probe(struct platform_device *pdev) priv->drv_name = DRV_NAME; priv->drv_version = DRV_VERSION; - interface = of_get_phy_mode(dev->of_node); - if (interface < 0) - interface = PHY_INTERFACE_MODE_MII; + err = of_get_phy_mode(dev->of_node, &interface); + if (err) { + if (err == -ENODEV) + interface = PHY_INTERFACE_MODE_MII; + else + goto out_netdev; + } priv->clk = devm_clk_get(dev, "hclk"); if (IS_ERR(priv->clk)) { diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index 664d664e0925..aae231c5224f 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -97,8 +97,9 @@ static int emac_rockchip_probe(struct platform_device *pdev) struct net_device *ndev; struct rockchip_priv_data *priv; const struct of_device_id *match; + phy_interface_t interface; u32 data; - int err, interface; + int err; if (!pdev->dev.of_node) return -ENODEV; @@ -114,7 +115,9 @@ static int emac_rockchip_probe(struct platform_device *pdev) priv->emac.drv_version = DRV_VERSION; priv->emac.set_mac_speed = emac_rockchip_set_mac_speed; - interface = of_get_phy_mode(dev->of_node); + err = of_get_phy_mode(dev->of_node, &interface); + if (err) + goto out_netdev; /* RK3036/RK3066/RK3188 SoCs only support RMII */ if (interface != PHY_INTERFACE_MODE_RMII) { diff --git a/drivers/net/ethernet/atheros/ag71xx.c b/drivers/net/ethernet/atheros/ag71xx.c index 1b1a09095c0d..8f5021091eee 100644 --- a/drivers/net/ethernet/atheros/ag71xx.c +++ b/drivers/net/ethernet/atheros/ag71xx.c @@ -1744,10 +1744,9 @@ static int ag71xx_probe(struct platform_device *pdev) eth_random_addr(ndev->dev_addr); } - ag->phy_if_mode = of_get_phy_mode(np); - if (ag->phy_if_mode < 0) { + err = of_get_phy_mode(np, ag->phy_if_mode); + if (err) { netif_err(ag, probe, ndev, "missing phy-mode property in DT\n"); - err = ag->phy_if_mode; goto err_free; } diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c index 37752d9514e7..30b455013bf3 100644 --- a/drivers/net/ethernet/aurora/nb8800.c +++ b/drivers/net/ethernet/aurora/nb8800.c @@ -1371,8 +1371,8 @@ static int nb8800_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->base = base; - priv->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if (priv->phy_mode < 0) + ret = of_get_phy_mode(pdev->dev.of_node, &priv->phy_mode); + if (ret) priv->phy_mode = PHY_INTERFACE_MODE_RGMII; priv->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/net/ethernet/aurora/nb8800.h b/drivers/net/ethernet/aurora/nb8800.h index aacc3cce2cc0..40941fb6065b 100644 --- a/drivers/net/ethernet/aurora/nb8800.h +++ b/drivers/net/ethernet/aurora/nb8800.h @@ -287,7 +287,7 @@ struct nb8800_priv { struct device_node *phy_node; /* PHY connection type from DT */ - int phy_mode; + phy_interface_t phy_mode; /* Current link status */ int speed; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index a977a459bd20..825af709708e 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -2479,9 +2479,9 @@ static int bcm_sysport_probe(struct platform_device *pdev) priv->netdev = dev; priv->pdev = pdev; - priv->phy_interface = of_get_phy_mode(dn); + ret = of_get_phy_mode(dn, &priv->phy_interface); /* Default to GMII interface mode */ - if ((int)priv->phy_interface < 0) + if (ret) priv->phy_interface = PHY_INTERFACE_MODE_GMII; /* In the case of a fixed PHY, the DT node associated diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 17bb8d60a157..b797a7e59a53 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -436,7 +436,7 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; struct phy_device *phydev; - int phy_mode; + phy_interface_t phy_mode; int ret; /* Fetch the PHY phandle */ @@ -454,10 +454,10 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) } /* Get the link mode */ - phy_mode = of_get_phy_mode(dn); - if (phy_mode < 0) { + ret = of_get_phy_mode(dn, &phy_mode); + if (ret) { dev_err(kdev, "invalid PHY mode property\n"); - return phy_mode; + return ret; } priv->phy_interface = phy_mode; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 1e1b774e1953..b884cf7f339b 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4182,6 +4182,7 @@ static int macb_probe(struct platform_device *pdev) unsigned int queue_mask, num_queues; bool native_io; struct phy_device *phydev; + phy_interface_t interface; struct net_device *dev; struct resource *regs; void __iomem *mem; @@ -4308,12 +4309,12 @@ static int macb_probe(struct platform_device *pdev) macb_get_hwaddr(bp); } - err = of_get_phy_mode(np); - if (err < 0) + err = of_get_phy_mode(np, &interface); + if (err) /* not found in DT, MII by default */ bp->phy_interface = PHY_INTERFACE_MODE_MII; else - bp->phy_interface = err; + bp->phy_interface = interface; /* IP specific init */ err = init(pdev); diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index da0c506349d1..a6f2063f1475 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -1612,7 +1612,7 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) { struct ftgmac100 *priv = netdev_priv(netdev); struct platform_device *pdev = to_platform_device(priv->dev); - int phy_intf = PHY_INTERFACE_MODE_RGMII; + phy_interface_t phy_intf = PHY_INTERFACE_MODE_RGMII; struct device_node *np = pdev->dev.of_node; int i, err = 0; u32 reg; @@ -1637,8 +1637,8 @@ static int ftgmac100_setup_mdio(struct net_device *netdev) /* Get PHY mode from device-tree */ if (np) { /* Default to RGMII. It's a gigabit part after all */ - phy_intf = of_get_phy_mode(np); - if (phy_intf < 0) + err = of_get_phy_mode(np, &phy_intf); + if (err) phy_intf = PHY_INTERFACE_MODE_RGMII; /* Aspeed only supports these. I don't know about other IP diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index fea388d86f20..b713739f4804 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -44,10 +44,11 @@ static struct device_node *dpaa2_mac_get_node(u16 dpmac_id) static int dpaa2_mac_get_if_mode(struct device_node *node, struct dpmac_attr attr) { - int if_mode; + phy_interface_t if_mode; + int err; - if_mode = of_get_phy_mode(node); - if (if_mode >= 0) + err = of_get_phy_mode(node, &if_mode); + if (!err) return if_mode; if_mode = phy_mode(attr.eth_if); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index b73421c3e25b..7da79b816416 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -784,8 +784,8 @@ static int enetc_of_get_phy(struct enetc_ndev_priv *priv) } } - priv->if_mode = of_get_phy_mode(np); - if ((int)priv->if_mode < 0) { + err = of_get_phy_mode(np, &priv->if_mode); + if (err) { dev_err(priv->dev, "missing phy type\n"); of_node_put(priv->phy_node); if (of_phy_is_fixed_link(np)) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 7d37ba9f6819..d4d6c2e941f1 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3393,6 +3393,7 @@ fec_probe(struct platform_device *pdev) { struct fec_enet_private *fep; struct fec_platform_data *pdata; + phy_interface_t interface; struct net_device *ndev; int i, irq, ret = 0; const struct of_device_id *of_id; @@ -3465,15 +3466,15 @@ fec_probe(struct platform_device *pdev) } fep->phy_node = phy_node; - ret = of_get_phy_mode(pdev->dev.of_node); - if (ret < 0) { + ret = of_get_phy_mode(pdev->dev.of_node, &interface); + if (ret) { pdata = dev_get_platdata(&pdev->dev); if (pdata) fep->phy_interface = pdata->phy; else fep->phy_interface = PHY_INTERFACE_MODE_MII; } else { - fep->phy_interface = ret; + fep->phy_interface = interface; } fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 7ab8095db192..f0806ace1ae2 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -608,7 +608,7 @@ static int mac_probe(struct platform_device *_of_dev) const u8 *mac_addr; u32 val; u8 fman_id; - int phy_if; + phy_interface_t phy_if; dev = &_of_dev->dev; mac_node = dev->of_node; @@ -776,8 +776,8 @@ static int mac_probe(struct platform_device *_of_dev) } /* Get the PHY connection type */ - phy_if = of_get_phy_mode(mac_node); - if (phy_if < 0) { + err = of_get_phy_mode(mac_node, &phy_if); + if (err) { dev_warn(dev, "of_get_phy_mode() for %pOF failed. Defaulting to SGMII\n", mac_node); diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 51ad86417cb1..72868a28b621 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -641,6 +641,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) const char *model; const void *mac_addr; int err = 0, i; + phy_interface_t interface; struct net_device *dev = NULL; struct gfar_private *priv = NULL; struct device_node *np = ofdev->dev.of_node; @@ -805,9 +806,9 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) * rgmii-id really needs to be specified. Other types can be * detected by hardware */ - err = of_get_phy_mode(np); - if (err >= 0) - priv->interface = err; + err = of_get_phy_mode(np, &interface); + if (!err) + priv->interface = interface; else priv->interface = gfar_get_interface(dev); diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 4606a7e4a6d1..3e9b6d543c77 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -211,7 +211,7 @@ struct hip04_priv { #if defined(CONFIG_HI13X1_GMAC) void __iomem *sysctrl_base; #endif - int phy_mode; + phy_interface_t phy_mode; int chan; unsigned int port; unsigned int group; @@ -961,10 +961,9 @@ static int hip04_mac_probe(struct platform_device *pdev) goto init_fail; } - priv->phy_mode = of_get_phy_mode(node); - if (priv->phy_mode < 0) { + ret = of_get_phy_mode(node, &priv->phy_mode); + if (ret) { dev_warn(d, "not find phy-mode\n"); - ret = -EINVAL; goto init_fail; } diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index c41b19c760f8..247de9105d10 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1193,10 +1193,9 @@ static int hix5hd2_dev_probe(struct platform_device *pdev) if (ret) goto err_free_mdio; - priv->phy_mode = of_get_phy_mode(node); - if ((int)priv->phy_mode < 0) { + ret = of_get_phy_mode(node, &priv->phy_mode); + if (ret) { netdev_err(ndev, "not find phy-mode\n"); - ret = -EINVAL; goto err_mdiobus; } diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 9e43c9ace9c2..2e40425d8a34 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -2849,6 +2849,7 @@ static int emac_init_config(struct emac_instance *dev) { struct device_node *np = dev->ofdev->dev.of_node; const void *p; + int err; /* Read config from device-tree */ if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1)) @@ -2897,8 +2898,8 @@ static int emac_init_config(struct emac_instance *dev) dev->mal_burst_size = 256; /* PHY mode needs some decoding */ - dev->phy_mode = of_get_phy_mode(np); - if (dev->phy_mode < 0) + err = of_get_phy_mode(np, &dev->phy_mode); + if (err) dev->phy_mode = PHY_INTERFACE_MODE_NA; /* Check EMAC version */ diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 82ea55ae5053..d5b644131cff 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2959,15 +2959,16 @@ static void set_params(struct mv643xx_eth_private *mp, static int get_phy_mode(struct mv643xx_eth_private *mp) { struct device *dev = mp->dev->dev.parent; - int iface = -1; + phy_interface_t iface; + int err; if (dev->of_node) - iface = of_get_phy_mode(dev->of_node); + err = of_get_phy_mode(dev->of_node, &iface); /* Historical default if unspecified. We could also read/write * the interface state in the PSC1 */ - if (iface < 0) + if (!dev->of_node || err) iface = PHY_INTERFACE_MODE_GMII; return iface; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 8f9df6efda61..274ac39c0f0f 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -4797,9 +4797,9 @@ static int mvneta_probe(struct platform_device *pdev) struct phy *comphy; const char *dt_mac_addr; char hw_mac_addr[ETH_ALEN]; + phy_interface_t phy_mode; const char *mac_from; int tx_csum_limit; - int phy_mode; int err; int cpu; @@ -4812,10 +4812,9 @@ static int mvneta_probe(struct platform_device *pdev) if (dev->irq == 0) return -EINVAL; - phy_mode = of_get_phy_mode(dn); - if (phy_mode < 0) { + err = of_get_phy_mode(dn, &phy_mode); + if (err) { dev_err(&pdev->dev, "incorrect phy-mode\n"); - err = -EINVAL; goto err_free_irq; } diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c index 51b77c2de400..3fb7ee3d4d13 100644 --- a/drivers/net/ethernet/marvell/pxa168_eth.c +++ b/drivers/net/ethernet/marvell/pxa168_eth.c @@ -1489,8 +1489,10 @@ static int pxa168_eth_probe(struct platform_device *pdev) goto err_netdev; } of_property_read_u32(np, "reg", &pep->phy_addr); - pep->phy_intf = of_get_phy_mode(pdev->dev.of_node); of_node_put(np); + err = of_get_phy_mode(pdev->dev.of_node, &pep->phy_intf); + if (err && err != -ENODEV) + goto err_netdev; } /* Hardware supports only 3 ports */ diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 703adb96429e..385a4ab9ec99 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2758,9 +2758,10 @@ static const struct net_device_ops mtk_netdev_ops = { static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { const __be32 *_id = of_get_property(np, "reg", NULL); + phy_interface_t phy_mode; struct phylink *phylink; - int phy_mode, id, err; struct mtk_mac *mac; + int id, err; if (!_id) { dev_err(eth->dev, "missing mac id\n"); @@ -2805,10 +2806,9 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; /* phylink create */ - phy_mode = of_get_phy_mode(np); - if (phy_mode < 0) { + err = of_get_phy_mode(np, &phy_mode); + if (err) { dev_err(eth->dev, "incorrect phy-mode\n"); - err = -EINVAL; goto free_netdev; } diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index aac115136720..723724bdc139 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -364,12 +364,12 @@ static int mscc_ocelot_probe(struct platform_device *pdev) for_each_available_child_of_node(ports, portnp) { struct device_node *phy_node; + phy_interface_t phy_mode; struct phy_device *phy; struct resource *res; struct phy *serdes; void __iomem *regs; char res_name[8]; - int phy_mode; u32 port; if (of_property_read_u32(portnp, "reg", &port)) @@ -398,11 +398,11 @@ static int mscc_ocelot_probe(struct platform_device *pdev) goto out_put_ports; } - phy_mode = of_get_phy_mode(portnp); - if (phy_mode < 0) - ocelot->ports[port]->phy_mode = PHY_INTERFACE_MODE_NA; - else - ocelot->ports[port]->phy_mode = phy_mode; + err = of_get_phy_mode(portnp, &phy_mode); + if (err && err != -ENODEV) + goto out_put_ports; + + ocelot->ports[port]->phy_mode = phy_mode; switch (ocelot->ports[port]->phy_mode) { case PHY_INTERFACE_MODE_NA: diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c index 2761f3a3ae50..49c7987c2abd 100644 --- a/drivers/net/ethernet/ni/nixge.c +++ b/drivers/net/ethernet/ni/nixge.c @@ -1346,10 +1346,9 @@ static int nixge_probe(struct platform_device *pdev) } } - priv->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if ((int)priv->phy_mode < 0) { + err = of_get_phy_mode(pdev->dev.of_node, &priv->phy_mode); + if (err) { netdev_err(ndev, "not find \"phy-mode\" property\n"); - err = -EINVAL; goto unregister_mdio; } diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index de9aa8c47f1c..5ea14b5fbed8 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -2046,7 +2046,9 @@ static int ravb_probe(struct platform_device *pdev) spin_lock_init(&priv->lock); INIT_WORK(&priv->work, ravb_tx_timeout_work); - priv->phy_interface = of_get_phy_mode(np); + error = of_get_phy_mode(np, &priv->phy_interface); + if (error && error != -ENODEV) + goto out_release; priv->no_avb_link = of_property_read_bool(np, "renesas,no-ether-link"); priv->avb_link_active_low = diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 7ba35a0bdb29..e19b49c4013e 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3183,6 +3183,7 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) { struct device_node *np = dev->of_node; struct sh_eth_plat_data *pdata; + phy_interface_t interface; const char *mac_addr; int ret; @@ -3190,10 +3191,10 @@ static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) if (!pdata) return NULL; - ret = of_get_phy_mode(np); - if (ret < 0) + ret = of_get_phy_mode(np, &interface); + if (ret) return NULL; - pdata->phy_interface = ret; + pdata->phy_interface = interface; mac_addr = of_get_mac_address(np); if (!IS_ERR(mac_addr)) diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c index 2412c87561e0..33f79402850d 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c @@ -30,12 +30,15 @@ static int sxgbe_probe_config_dt(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct sxgbe_dma_cfg *dma_cfg; + int err; if (!np) return -ENODEV; *mac = of_get_mac_address(np); - plat->interface = of_get_phy_mode(np); + err = of_get_phy_mode(np, &plat->interface); + if (err && err != -ENODEV) + return err; plat->bus_id = of_alias_get_id(np, "ethernet"); if (plat->bus_id < 0) diff --git a/drivers/net/ethernet/socionext/sni_ave.c b/drivers/net/ethernet/socionext/sni_ave.c index 6e984d5a729f..f7e927ad67fa 100644 --- a/drivers/net/ethernet/socionext/sni_ave.c +++ b/drivers/net/ethernet/socionext/sni_ave.c @@ -1565,10 +1565,10 @@ static int ave_probe(struct platform_device *pdev) return -EINVAL; np = dev->of_node; - phy_mode = of_get_phy_mode(np); - if ((int)phy_mode < 0) { + ret = of_get_phy_mode(np, &phy_mode); + if (ret) { dev_err(dev, "phy-mode not found\n"); - return -EINVAL; + return ret; } irq = platform_get_irq(pdev, 0); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c index 527f93320a5a..d0d2d0fc5f0a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c @@ -61,9 +61,10 @@ static void anarion_gmac_exit(struct platform_device *pdev, void *priv) static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev) { - int phy_mode; - void __iomem *ctl_block; struct anarion_gmac *gmac; + phy_interface_t phy_mode; + void __iomem *ctl_block; + int err; ctl_block = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(ctl_block)) { @@ -78,7 +79,10 @@ static struct anarion_gmac *anarion_config_dt(struct platform_device *pdev) gmac->ctl_block = (uintptr_t)ctl_block; - phy_mode = of_get_phy_mode(pdev->dev.of_node); + err = of_get_phy_mode(pdev->dev.of_node, &phy_mode); + if (err) + return ERR_PTR(err); + switch (phy_mode) { case PHY_INTERFACE_MODE_RGMII: /* Fall through */ case PHY_INTERFACE_MODE_RGMII_ID /* Fall through */: diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index 0d21082ceb93..6ae13dc19510 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -189,9 +189,10 @@ static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed) static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) { struct device *dev = &gmac->pdev->dev; + int ret; - gmac->phy_mode = of_get_phy_mode(dev->of_node); - if ((int)gmac->phy_mode < 0) { + ret = of_get_phy_mode(dev->of_node, &gmac->phy_mode); + if (ret) { dev_err(dev, "missing phy mode property\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index cea7a0c7ce68..bdb80421acac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -54,7 +54,7 @@ struct mediatek_dwmac_plat_data { struct device_node *np; struct regmap *peri_regmap; struct device *dev; - int phy_mode; + phy_interface_t phy_mode; bool rmii_rxc; }; @@ -243,6 +243,7 @@ static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat) { struct mac_delay_struct *mac_delay = &plat->mac_delay; u32 tx_delay_ps, rx_delay_ps; + int err; plat->peri_regmap = syscon_regmap_lookup_by_phandle(plat->np, "mediatek,pericfg"); if (IS_ERR(plat->peri_regmap)) { @@ -250,10 +251,10 @@ static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat) return PTR_ERR(plat->peri_regmap); } - plat->phy_mode = of_get_phy_mode(plat->np); - if (plat->phy_mode < 0) { + err = of_get_phy_mode(plat->np, &plat->phy_mode); + if (err) { dev_err(plat->dev, "not find phy-mode\n"); - return -EINVAL; + return err; } if (!of_property_read_u32(plat->np, "mediatek,tx-delay-ps", &tx_delay_ps)) { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index 306da8f6b7d5..bd6c01004913 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -338,10 +338,9 @@ static int meson8b_dwmac_probe(struct platform_device *pdev) } dwmac->dev = &pdev->dev; - dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if ((int)dwmac->phy_mode < 0) { + ret = of_get_phy_mode(pdev->dev.of_node, &dwmac->phy_mode); + if (ret) { dev_err(&pdev->dev, "missing phy-mode property\n"); - ret = -EINVAL; goto err_remove_config_dt; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index e2e469c37a4d..dc50ba13a746 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -37,7 +37,7 @@ struct rk_gmac_ops { struct rk_priv_data { struct platform_device *pdev; - int phy_iface; + phy_interface_t phy_iface; struct regulator *regulator; bool suspended; const struct rk_gmac_ops *ops; @@ -1224,7 +1224,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, if (!bsp_priv) return ERR_PTR(-ENOMEM); - bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); + of_get_phy_mode(dev->of_node, &bsp_priv->phy_iface); bsp_priv->ops = ops; bsp_priv->regulator = devm_regulator_get_optional(dev, "phy"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index e9fd661f7995..e1b63df6f96f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -116,7 +116,7 @@ #define ETH_PHY_SEL_MII 0x0 struct sti_dwmac { - int interface; /* MII interface */ + phy_interface_t interface; /* MII interface */ bool ext_phyclk; /* Clock from external PHY */ u32 tx_retime_src; /* TXCLK Retiming*/ struct clk *clk; /* PHY clock */ @@ -269,7 +269,12 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, return err; } - dwmac->interface = of_get_phy_mode(np); + err = of_get_phy_mode(np, &dwmac->interface); + if (err && err != -ENODEV) { + dev_err(dev, "Can't get phy-mode\n"); + return err; + } + dwmac->regmap = regmap; dwmac->gmac_en = of_property_read_bool(np, "st,gmac_en"); dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index ddcc191febdb..eefb06d918c8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -1105,6 +1105,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) struct stmmac_resources stmmac_res; struct sunxi_priv_data *gmac; struct device *dev = &pdev->dev; + phy_interface_t interface; int ret; struct stmmac_priv *priv; struct net_device *ndev; @@ -1178,10 +1179,10 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) return ret; } - ret = of_get_phy_mode(dev->of_node); - if (ret < 0) + ret = of_get_phy_mode(dev->of_node, &interface); + if (ret) return -EINVAL; - plat_dat->interface = ret; + plat_dat->interface = interface; /* platform data specifying hardware features and callbacks. * hardware features were copied from Allwinner drivers. diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index a299da3971b4..26353ef616b8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -18,7 +18,7 @@ #include "stmmac_platform.h" struct sunxi_priv_data { - int interface; + phy_interface_t interface; int clk_enabled; struct clk *tx_clk; struct regulator *regulator; @@ -118,7 +118,11 @@ static int sun7i_gmac_probe(struct platform_device *pdev) goto err_remove_config_dt; } - gmac->interface = of_get_phy_mode(dev->of_node); + ret = of_get_phy_mode(dev->of_node, &gmac->interface); + if (ret && ret != -ENODEV) { + dev_err(dev, "Can't get phy-mode\n"); + goto err_remove_config_dt; + } gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); if (IS_ERR(gmac->tx_clk)) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 170c3a052b14..bedaff0c13bd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -412,9 +412,9 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) *mac = NULL; } - plat->phy_interface = of_get_phy_mode(np); - if (plat->phy_interface < 0) - return ERR_PTR(plat->phy_interface); + rc = of_get_phy_mode(np, &plat->phy_interface); + if (rc) + return ERR_PTR(rc); plat->interface = stmmac_of_get_mac_mode(np); if (plat->interface < 0) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index f298d714efd6..329671e66fe4 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -2619,11 +2619,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, i); goto no_phy_slave; } - slave_data->phy_if = of_get_phy_mode(slave_node); - if (slave_data->phy_if < 0) { + ret = of_get_phy_mode(slave_node, &slave_data->phy_if); + if (ret) { dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n", i); - ret = slave_data->phy_if; goto err_node_put; } diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 362c5a986869..8bfa761fa552 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -275,7 +275,7 @@ struct cpsw_slave_data { struct device_node *slave_node; struct device_node *phy_node; char phy_id[MII_BUS_ID_SIZE]; - int phy_if; + phy_interface_t phy_if; u8 mac_addr[ETH_ALEN]; u16 dual_emac_res_vlan; /* Reserved VLAN for DualEMAC */ struct phy *ifphy; diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 2c1fac33136c..86a3f42a3dcc 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2291,6 +2291,7 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) struct gbe_slave *slave = gbe_intf->slave; phy_interface_t phy_mode; bool has_phy = false; + int err; void (*hndlr)(struct net_device *) = gbe_adjust_link; @@ -2320,11 +2321,11 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) slave->phy_port_t = PORT_MII; } else if (slave->link_interface == RGMII_LINK_MAC_PHY) { has_phy = true; - phy_mode = of_get_phy_mode(slave->node); + err = of_get_phy_mode(slave->node, &phy_mode); /* if phy-mode is not present, default to * PHY_INTERFACE_MODE_RGMII */ - if (phy_mode < 0) + if (err) phy_mode = PHY_INTERFACE_MODE_RGMII; if (!phy_interface_mode_is_rgmii(phy_mode)) { diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 676006f32f91..867726d696e2 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1761,11 +1761,9 @@ static int axienet_probe(struct platform_device *pdev) goto free_netdev; } } else { - lp->phy_mode = of_get_phy_mode(pdev->dev.of_node); - if ((int)lp->phy_mode < 0) { - ret = -EINVAL; + ret = of_get_phy_mode(pdev->dev.of_node, &lp->phy_mode); + if (ret) goto free_netdev; - } } /* Find the DMA node, map the DMA registers, and decode the DMA IRQs */ diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index bd6129db6417..c6b87ce2b0cc 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -361,8 +361,8 @@ struct phy_device *of_phy_get_and_connect(struct net_device *dev, struct phy_device *phy; int ret; - iface = of_get_phy_mode(np); - if ((int)iface < 0) + ret = of_get_phy_mode(np, &iface); + if (ret) return NULL; if (of_phy_is_fixed_link(np)) { ret = of_phy_register_fixed_link(np); diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index b02734aff8c1..6e411821583e 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -15,16 +15,20 @@ /** * of_get_phy_mode - Get phy mode for given device_node * @np: Pointer to the given device_node + * @interface: Pointer to the result * * The function gets phy interface string from property 'phy-mode' or - * 'phy-connection-type', and return its index in phy_modes table, or errno in - * error case. + * 'phy-connection-type'. The index in phy_modes table is set in + * interface and 0 returned. In case of error interface is set to + * PHY_INTERFACE_MODE_NA and an errno is returned, e.g. -ENODEV. */ -int of_get_phy_mode(struct device_node *np) +int of_get_phy_mode(struct device_node *np, phy_interface_t *interface) { const char *pm; int err, i; + *interface = PHY_INTERFACE_MODE_NA; + err = of_property_read_string(np, "phy-mode", &pm); if (err < 0) err = of_property_read_string(np, "phy-connection-type", &pm); @@ -32,8 +36,10 @@ int of_get_phy_mode(struct device_node *np) return err; for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) - if (!strcasecmp(pm, phy_modes(i))) - return i; + if (!strcasecmp(pm, phy_modes(i))) { + *interface = i; + return 0; + } return -ENODEV; } diff --git a/include/linux/of_net.h b/include/linux/of_net.h index 6aeaea1775e6..71bbfcf3adcd 100644 --- a/include/linux/of_net.h +++ b/include/linux/of_net.h @@ -6,15 +6,18 @@ #ifndef __LINUX_OF_NET_H #define __LINUX_OF_NET_H +#include + #ifdef CONFIG_OF_NET #include struct net_device; -extern int of_get_phy_mode(struct device_node *np); +extern int of_get_phy_mode(struct device_node *np, phy_interface_t *interface); extern const void *of_get_mac_address(struct device_node *np); extern struct net_device *of_find_net_device_by_node(struct device_node *np); #else -static inline int of_get_phy_mode(struct device_node *np) +static inline int of_get_phy_mode(struct device_node *np, + phy_interface_t *interface) { return -ENODEV; } diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index 86f9464c3f5d..d4bcd9387136 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -13,6 +13,7 @@ #define __STMMAC_PLATFORM_DATA #include +#include #define MTL_MAX_RX_QUEUES 8 #define MTL_MAX_TX_QUEUES 8 @@ -132,7 +133,7 @@ struct plat_stmmacenet_data { int bus_id; int phy_addr; int interface; - int phy_interface; + phy_interface_t phy_interface; struct stmmac_mdio_bus_data *mdio_bus_data; struct device_node *phy_node; struct device_node *phylink_node; diff --git a/include/linux/sxgbe_platform.h b/include/linux/sxgbe_platform.h index 267369110584..85ec745767bd 100644 --- a/include/linux/sxgbe_platform.h +++ b/include/linux/sxgbe_platform.h @@ -10,6 +10,8 @@ #ifndef __SXGBE_PLATFORM_H__ #define __SXGBE_PLATFORM_H__ +#include + /* MDC Clock Selection define*/ #define SXGBE_CSR_100_150M 0x0 /* MDC = clk_scr_i/62 */ #define SXGBE_CSR_150_250M 0x1 /* MDC = clk_scr_i/102 */ @@ -38,7 +40,7 @@ struct sxgbe_plat_data { char *phy_bus_name; int bus_id; int phy_addr; - int interface; + phy_interface_t interface; struct sxgbe_mdio_bus_data *mdio_bus_data; struct sxgbe_dma_cfg *dma_cfg; int clk_csr; diff --git a/net/dsa/port.c b/net/dsa/port.c index 9b54e5a76297..6e93c36bf0c0 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -561,7 +561,7 @@ static int dsa_port_fixed_link_register_of(struct dsa_port *dp) struct dsa_switch *ds = dp->ds; struct phy_device *phydev; int port = dp->index; - int mode; + phy_interface_t mode; int err; err = of_phy_register_fixed_link(dn); @@ -574,8 +574,8 @@ static int dsa_port_fixed_link_register_of(struct dsa_port *dp) phydev = of_phy_find_device(dn); - mode = of_get_phy_mode(dn); - if (mode < 0) + err = of_get_phy_mode(dn, &mode); + if (err) mode = PHY_INTERFACE_MODE_NA; phydev->interface = mode; @@ -593,10 +593,11 @@ static int dsa_port_phylink_register(struct dsa_port *dp) { struct dsa_switch *ds = dp->ds; struct device_node *port_dn = dp->dn; - int mode, err; + phy_interface_t mode; + int err; - mode = of_get_phy_mode(port_dn); - if (mode < 0) + err = of_get_phy_mode(port_dn, &mode); + if (err) mode = PHY_INTERFACE_MODE_NA; dp->pl_config.dev = ds->dev; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index d18761649754..78ffc87dc25e 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1313,11 +1313,12 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev) struct dsa_port *dp = dsa_slave_to_port(slave_dev); struct device_node *port_dn = dp->dn; struct dsa_switch *ds = dp->ds; + phy_interface_t mode; u32 phy_flags = 0; - int mode, ret; + int ret; - mode = of_get_phy_mode(port_dn); - if (mode < 0) + ret = of_get_phy_mode(port_dn, &mode); + if (ret) mode = PHY_INTERFACE_MODE_NA; dp->pl_config.dev = &slave_dev->dev; -- cgit v1.2.3-59-g8ed1b From 4dd147471dae02e21db317fff02b7cf98694b22f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Nov 2019 11:45:11 +0100 Subject: net: sgi: ioc3-eth: don't abuse dma_direct_* calls dma_direct_ is a low-level API that must never be used by drivers directly. Switch to use the proper DMA API instead. Fixes: ed870f6a7aa2 ("net: sgi: ioc3-eth: use dma-direct for dma allocations") Signed-off-by: Christoph Hellwig Signed-off-by: Thomas Bogendoerfer Signed-off-by: David S. Miller --- drivers/net/ethernet/sgi/ioc3-eth.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index deb636d653f3..477af82bf8a9 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include @@ -1242,8 +1242,8 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ioc3_stop(ip); /* Allocate rx ring. 4kb = 512 entries, must be 4kb aligned */ - ip->rxr = dma_direct_alloc_pages(ip->dma_dev, RX_RING_SIZE, - &ip->rxr_dma, GFP_ATOMIC, 0); + ip->rxr = dma_alloc_coherent(ip->dma_dev, RX_RING_SIZE, &ip->rxr_dma, + GFP_ATOMIC); if (!ip->rxr) { pr_err("ioc3-eth: rx ring allocation failed\n"); err = -ENOMEM; @@ -1251,9 +1251,8 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Allocate tx rings. 16kb = 128 bufs, must be 16kb aligned */ - ip->txr = dma_direct_alloc_pages(ip->dma_dev, TX_RING_SIZE, - &ip->txr_dma, - GFP_KERNEL | __GFP_ZERO, 0); + ip->txr = dma_alloc_coherent(ip->dma_dev, TX_RING_SIZE, &ip->txr_dma, + GFP_KERNEL | __GFP_ZERO); if (!ip->txr) { pr_err("ioc3-eth: tx ring allocation failed\n"); err = -ENOMEM; @@ -1313,11 +1312,11 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) out_stop: del_timer_sync(&ip->ioc3_timer); if (ip->rxr) - dma_direct_free_pages(ip->dma_dev, RX_RING_SIZE, ip->rxr, - ip->rxr_dma, 0); + dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, + ip->rxr_dma); if (ip->txr) - dma_direct_free_pages(ip->dma_dev, TX_RING_SIZE, ip->txr, - ip->txr_dma, 0); + dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->txr, + ip->txr_dma); out_res: pci_release_regions(pdev); out_free: @@ -1335,10 +1334,8 @@ static void ioc3_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct ioc3_private *ip = netdev_priv(dev); - dma_direct_free_pages(ip->dma_dev, RX_RING_SIZE, ip->rxr, - ip->rxr_dma, 0); - dma_direct_free_pages(ip->dma_dev, TX_RING_SIZE, ip->txr, - ip->txr_dma, 0); + dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma); + dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->txr, ip->txr_dma); unregister_netdev(dev); del_timer_sync(&ip->ioc3_timer); -- cgit v1.2.3-59-g8ed1b From 59511bcf33f95e2bcf1100e8fde31e2d4a15f3a0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Nov 2019 11:45:12 +0100 Subject: net: sgi: ioc3-eth: fix usage of GFP_* flags dma_alloc_coherent always zeroes memory, there is no need for __GFP_ZERO. Also doing a GFP_ATOMIC allocation just before a GFP_KERNEL one is clearly bogus. Fixes: ed870f6a7aa2 ("net: sgi: ioc3-eth: use dma-direct for dma allocations") Signed-off-by: Christoph Hellwig Signed-off-by: Thomas Bogendoerfer Signed-off-by: David S. Miller --- drivers/net/ethernet/sgi/ioc3-eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 477af82bf8a9..8a684d882e63 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1243,7 +1243,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Allocate rx ring. 4kb = 512 entries, must be 4kb aligned */ ip->rxr = dma_alloc_coherent(ip->dma_dev, RX_RING_SIZE, &ip->rxr_dma, - GFP_ATOMIC); + GFP_KERNEL); if (!ip->rxr) { pr_err("ioc3-eth: rx ring allocation failed\n"); err = -ENOMEM; @@ -1252,7 +1252,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Allocate tx rings. 16kb = 128 bufs, must be 16kb aligned */ ip->txr = dma_alloc_coherent(ip->dma_dev, TX_RING_SIZE, &ip->txr_dma, - GFP_KERNEL | __GFP_ZERO); + GFP_KERNEL); if (!ip->txr) { pr_err("ioc3-eth: tx ring allocation failed\n"); err = -ENOMEM; -- cgit v1.2.3-59-g8ed1b From 051a07ec7a3def775c599547e5ce69bd59c43794 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Nov 2019 11:45:13 +0100 Subject: net: sgi: ioc3-eth: simplify setting the DMA mask There is no need to fall back to a lower mask these days, the DMA mask just communicates the hardware supported features. Signed-off-by: Christoph Hellwig Signed-off-by: Thomas Bogendoerfer Signed-off-by: David S. Miller --- drivers/net/ethernet/sgi/ioc3-eth.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 8a684d882e63..dc2e22652b55 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1173,26 +1173,14 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct ioc3 *ioc3; unsigned long ioc3_base, ioc3_size; u32 vendor, model, rev; - int err, pci_using_dac; + int err; /* Configure DMA attributes. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (!err) { - pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err < 0) { - pr_err("%s: Unable to obtain 64 bit DMA for consistent allocations\n", - pci_name(pdev)); - goto out; - } - } else { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - pr_err("%s: No usable DMA configuration, aborting.\n", - pci_name(pdev)); - goto out; - } - pci_using_dac = 0; + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + pr_err("%s: No usable DMA configuration, aborting.\n", + pci_name(pdev)); + goto out; } if (pci_enable_device(pdev)) @@ -1204,8 +1192,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable; } - if (pci_using_dac) - dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_HIGHDMA; err = pci_request_regions(pdev, "ioc3"); if (err) -- cgit v1.2.3-59-g8ed1b From 7ca2c4c2ca9e09d6be888baca61a10891ea93bda Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Nov 2019 11:45:14 +0100 Subject: net: sgi: ioc3-eth: fix setting NETIF_F_HIGHDMA Set NETIF_F_HIGHDMA together with the NETIF_F_IP_CSUM flag instead of letting the second assignment overwrite it. Probably doesn't matter in practice as none of the systems an IOC3 is usually found in has highmem to start with. Signed-off-by: Christoph Hellwig Signed-off-by: Thomas Bogendoerfer Signed-off-by: David S. Miller --- drivers/net/ethernet/sgi/ioc3-eth.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index dc2e22652b55..1af68826810a 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -1192,8 +1192,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_disable; } - dev->features |= NETIF_F_HIGHDMA; - err = pci_request_regions(pdev, "ioc3"); if (err) goto out_free; @@ -1274,7 +1272,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev->netdev_ops = &ioc3_netdev_ops; dev->ethtool_ops = &ioc3_ethtool_ops; dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM; - dev->features = NETIF_F_IP_CSUM; + dev->features = NETIF_F_IP_CSUM | NETIF_F_HIGHDMA; sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1); sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2); -- cgit v1.2.3-59-g8ed1b From 369a782af0f1a9acf81d6fe8de44c8ee02be0f3a Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Mon, 4 Nov 2019 11:45:15 +0100 Subject: net: sgi: ioc3-eth: ensure tx ring is 16k aligned. IOC3 hardware needs a 16k aligned TX ring. Signed-off-by: Thomas Bogendoerfer Signed-off-by: David S. Miller --- drivers/net/ethernet/sgi/ioc3-eth.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 1af68826810a..d242906ae233 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -89,6 +89,7 @@ struct ioc3_private { struct device *dma_dev; u32 *ssram; unsigned long *rxr; /* pointer to receiver ring */ + void *tx_ring; struct ioc3_etxd *txr; dma_addr_t rxr_dma; dma_addr_t txr_dma; @@ -1236,13 +1237,16 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Allocate tx rings. 16kb = 128 bufs, must be 16kb aligned */ - ip->txr = dma_alloc_coherent(ip->dma_dev, TX_RING_SIZE, &ip->txr_dma, - GFP_KERNEL); - if (!ip->txr) { + ip->tx_ring = dma_alloc_coherent(ip->dma_dev, TX_RING_SIZE + SZ_16K - 1, + &ip->txr_dma, GFP_KERNEL); + if (!ip->tx_ring) { pr_err("ioc3-eth: tx ring allocation failed\n"); err = -ENOMEM; goto out_stop; } + /* Align TX ring */ + ip->txr = PTR_ALIGN(ip->tx_ring, SZ_16K); + ip->txr_dma = ALIGN(ip->txr_dma, SZ_16K); ioc3_init(dev); @@ -1299,8 +1303,8 @@ out_stop: if (ip->rxr) dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma); - if (ip->txr) - dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->txr, + if (ip->tx_ring) + dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->tx_ring, ip->txr_dma); out_res: pci_release_regions(pdev); @@ -1320,7 +1324,7 @@ static void ioc3_remove_one(struct pci_dev *pdev) struct ioc3_private *ip = netdev_priv(dev); dma_free_coherent(ip->dma_dev, RX_RING_SIZE, ip->rxr, ip->rxr_dma); - dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->txr, ip->txr_dma); + dma_free_coherent(ip->dma_dev, TX_RING_SIZE, ip->tx_ring, ip->txr_dma); unregister_netdev(dev); del_timer_sync(&ip->ioc3_timer); -- cgit v1.2.3-59-g8ed1b From 54e0602d796ceb20b292e9d364046b6b2724f735 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Mon, 4 Nov 2019 11:51:00 +0100 Subject: net: ethernet: stmmac: drop unused variable in stm32mp1_set_mode() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building with W=1 (cf.scripts/Makefile.extrawarn) outputs: warning: variable ‘ret’ set but not used [-Wunused-but-set-variable] Drop the unused 'ret' variable. Signed-off-by: Christophe Roullier Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 4ef041bdf6a1..595af2ec89fb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -175,7 +175,7 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; u32 reg = dwmac->mode_reg; - int val, ret; + int val; switch (plat_dat->interface) { case PHY_INTERFACE_MODE_MII: @@ -211,8 +211,8 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) } /* Need to update PMCCLRR (clear register) */ - ret = regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, - dwmac->ops->syscfg_eth_mask); + regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, + dwmac->ops->syscfg_eth_mask); /* Update PMCSETR (set register) */ return regmap_update_bits(dwmac->regmap, reg, -- cgit v1.2.3-59-g8ed1b From 0891d6d4b1fe1becf1a77353b03449955820084b Mon Sep 17 00:00:00 2001 From: Krzysztof Kazimierczak Date: Mon, 4 Nov 2019 09:38:56 -0800 Subject: ice: Move common functions to ice_txrx_lib.c In preparation of AF XDP, move functions that will be used both by skb and zero-copy paths to a new file called ice_txrx_lib.c. This allows us to avoid using ifdefs to control the staticness of said functions. Move other functions (ice_rx_csum, ice_rx_hash and ice_ptype_to_htype) called only by the moved ones to the new file as well. Signed-off-by: Krzysztof Kazimierczak Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice_txrx.c | 303 +------------------------- drivers/net/ethernet/intel/ice/ice_txrx.h | 10 - drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 273 +++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 59 +++++ 5 files changed, 334 insertions(+), 312 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_txrx_lib.c create mode 100644 drivers/net/ethernet/intel/ice/ice_txrx_lib.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 101313e55a11..9a7d6c02bcc6 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -15,6 +15,7 @@ ice-y := ice_main.o \ ice_sched.o \ ice_base.o \ ice_lib.o \ + ice_txrx_lib.o \ ice_txrx.o \ ice_flex_pipe.o \ ice_ethtool.o diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index f79a9376159b..279e5ec7d15f 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -7,6 +7,7 @@ #include #include #include +#include "ice_txrx_lib.h" #include "ice_lib.h" #include "ice.h" #include "ice_dcb_lib.h" @@ -396,37 +397,6 @@ err: return -ENOMEM; } -/** - * ice_release_rx_desc - Store the new tail and head values - * @rx_ring: ring to bump - * @val: new head index - */ -static void ice_release_rx_desc(struct ice_ring *rx_ring, u32 val) -{ - u16 prev_ntu = rx_ring->next_to_use; - - rx_ring->next_to_use = val; - - /* update next to alloc since we have filled the ring */ - rx_ring->next_to_alloc = val; - - /* QRX_TAIL will be updated with any tail value, but hardware ignores - * the lower 3 bits. This makes it so we only bump tail on meaningful - * boundaries. Also, this allows us to bump tail on intervals of 8 up to - * the budget depending on the current traffic load. - */ - val &= ~0x7; - if (prev_ntu != val) { - /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. (Only - * applicable for weak-ordered memory model archs, - * such as IA-64). - */ - wmb(); - writel(val, rx_ring->tail); - } -} - /** * ice_rx_offset - Return expected offset into page to access data * @rx_ring: Ring we are requesting offset of @@ -438,89 +408,6 @@ static unsigned int ice_rx_offset(struct ice_ring *rx_ring) return ice_is_xdp_ena_vsi(rx_ring->vsi) ? XDP_PACKET_HEADROOM : 0; } -/** - * ice_xdp_ring_update_tail - Updates the XDP Tx ring tail register - * @xdp_ring: XDP Tx ring - * - * This function updates the XDP Tx ring tail register. - */ -static void ice_xdp_ring_update_tail(struct ice_ring *xdp_ring) -{ - /* Force memory writes to complete before letting h/w - * know there are new descriptors to fetch. - */ - wmb(); - writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); -} - -/** - * ice_xmit_xdp_ring - submit single packet to XDP ring for transmission - * @data: packet data pointer - * @size: packet data size - * @xdp_ring: XDP ring for transmission - */ -static int ice_xmit_xdp_ring(void *data, u16 size, struct ice_ring *xdp_ring) -{ - u16 i = xdp_ring->next_to_use; - struct ice_tx_desc *tx_desc; - struct ice_tx_buf *tx_buf; - dma_addr_t dma; - - if (!unlikely(ICE_DESC_UNUSED(xdp_ring))) { - xdp_ring->tx_stats.tx_busy++; - return ICE_XDP_CONSUMED; - } - - dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE); - if (dma_mapping_error(xdp_ring->dev, dma)) - return ICE_XDP_CONSUMED; - - tx_buf = &xdp_ring->tx_buf[i]; - tx_buf->bytecount = size; - tx_buf->gso_segs = 1; - tx_buf->raw_buf = data; - - /* record length, and DMA address */ - dma_unmap_len_set(tx_buf, len, size); - dma_unmap_addr_set(tx_buf, dma, dma); - - tx_desc = ICE_TX_DESC(xdp_ring, i); - tx_desc->buf_addr = cpu_to_le64(dma); - tx_desc->cmd_type_offset_bsz = build_ctob(ICE_TXD_LAST_DESC_CMD, 0, - size, 0); - - /* Make certain all of the status bits have been updated - * before next_to_watch is written. - */ - smp_wmb(); - - i++; - if (i == xdp_ring->count) - i = 0; - - tx_buf->next_to_watch = tx_desc; - xdp_ring->next_to_use = i; - - return ICE_XDP_TX; -} - -/** - * ice_xmit_xdp_buff - convert an XDP buffer to an XDP frame and send it - * @xdp: XDP buffer - * @xdp_ring: XDP Tx ring - * - * Returns negative on failure, 0 on success. - */ -static int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_ring *xdp_ring) -{ - struct xdp_frame *xdpf = convert_to_xdp_frame(xdp); - - if (unlikely(!xdpf)) - return ICE_XDP_CONSUMED; - - return ice_xmit_xdp_ring(xdpf->data, xdpf->len, xdp_ring); -} - /** * ice_run_xdp - Executes an XDP program on initialized xdp_buff * @rx_ring: Rx ring @@ -612,29 +499,6 @@ ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, return n - drops; } -/** - * ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map - * @rx_ring: Rx ring - * @xdp_res: Result of the receive batch - * - * This function bumps XDP Tx tail and/or flush redirect map, and - * should be called when a batch of packets has been processed in the - * napi loop. - */ -static void -ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res) -{ - if (xdp_res & ICE_XDP_REDIR) - xdp_do_flush_map(); - - if (xdp_res & ICE_XDP_TX) { - struct ice_ring *xdp_ring = - rx_ring->vsi->xdp_rings[rx_ring->q_index]; - - ice_xdp_ring_update_tail(xdp_ring); - } -} - /** * ice_alloc_mapped_page - recycle or make a new page * @rx_ring: ring to use @@ -1031,23 +895,6 @@ static bool ice_cleanup_headers(struct sk_buff *skb) return false; } -/** - * ice_test_staterr - tests bits in Rx descriptor status and error fields - * @rx_desc: pointer to receive descriptor (in le64 format) - * @stat_err_bits: value to mask - * - * This function does some fast chicanery in order to return the - * value of the mask which is really only used for boolean tests. - * The status_error_len doesn't need to be shifted because it begins - * at offset zero. - */ -static bool -ice_test_staterr(union ice_32b_rx_flex_desc *rx_desc, const u16 stat_err_bits) -{ - return !!(rx_desc->wb.status_error0 & - cpu_to_le16(stat_err_bits)); -} - /** * ice_is_non_eop - process handling of non-EOP buffers * @rx_ring: Rx ring being processed @@ -1073,154 +920,6 @@ ice_is_non_eop(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, return true; } -/** - * ice_ptype_to_htype - get a hash type - * @ptype: the ptype value from the descriptor - * - * Returns a hash type to be used by skb_set_hash - */ -static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype) -{ - return PKT_HASH_TYPE_NONE; -} - -/** - * ice_rx_hash - set the hash value in the skb - * @rx_ring: descriptor ring - * @rx_desc: specific descriptor - * @skb: pointer to current skb - * @rx_ptype: the ptype value from the descriptor - */ -static void -ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, - struct sk_buff *skb, u8 rx_ptype) -{ - struct ice_32b_rx_flex_desc_nic *nic_mdid; - u32 hash; - - if (!(rx_ring->netdev->features & NETIF_F_RXHASH)) - return; - - if (rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC) - return; - - nic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc; - hash = le32_to_cpu(nic_mdid->rss_hash); - skb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype)); -} - -/** - * ice_rx_csum - Indicate in skb if checksum is good - * @ring: the ring we care about - * @skb: skb currently being received and modified - * @rx_desc: the receive descriptor - * @ptype: the packet type decoded by hardware - * - * skb->protocol must be set before this function is called - */ -static void -ice_rx_csum(struct ice_ring *ring, struct sk_buff *skb, - union ice_32b_rx_flex_desc *rx_desc, u8 ptype) -{ - struct ice_rx_ptype_decoded decoded; - u32 rx_error, rx_status; - bool ipv4, ipv6; - - rx_status = le16_to_cpu(rx_desc->wb.status_error0); - rx_error = rx_status; - - decoded = ice_decode_rx_desc_ptype(ptype); - - /* Start with CHECKSUM_NONE and by default csum_level = 0 */ - skb->ip_summed = CHECKSUM_NONE; - skb_checksum_none_assert(skb); - - /* check if Rx checksum is enabled */ - if (!(ring->netdev->features & NETIF_F_RXCSUM)) - return; - - /* check if HW has decoded the packet and checksum */ - if (!(rx_status & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S))) - return; - - if (!(decoded.known && decoded.outer_ip)) - return; - - ipv4 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && - (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4); - ipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && - (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6); - - if (ipv4 && (rx_error & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) | - BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)))) - goto checksum_fail; - else if (ipv6 && (rx_status & - (BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S)))) - goto checksum_fail; - - /* check for L4 errors and handle packets that were not able to be - * checksummed due to arrival speed - */ - if (rx_error & BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_L4E_S)) - goto checksum_fail; - - /* Only report checksum unnecessary for TCP, UDP, or SCTP */ - switch (decoded.inner_prot) { - case ICE_RX_PTYPE_INNER_PROT_TCP: - case ICE_RX_PTYPE_INNER_PROT_UDP: - case ICE_RX_PTYPE_INNER_PROT_SCTP: - skb->ip_summed = CHECKSUM_UNNECESSARY; - default: - break; - } - return; - -checksum_fail: - ring->vsi->back->hw_csum_rx_error++; -} - -/** - * ice_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 - * @ptype: the packet type decoded by hardware - * - * This function checks the ring, descriptor, and packet information in - * order to populate the hash, checksum, VLAN, protocol, and - * other fields within the skb. - */ -static void -ice_process_skb_fields(struct ice_ring *rx_ring, - union ice_32b_rx_flex_desc *rx_desc, - struct sk_buff *skb, u8 ptype) -{ - ice_rx_hash(rx_ring, rx_desc, skb, ptype); - - /* modifies the skb - consumes the enet header */ - skb->protocol = eth_type_trans(skb, rx_ring->netdev); - - ice_rx_csum(rx_ring, skb, rx_desc, ptype); -} - -/** - * ice_receive_skb - Send a completed packet up the stack - * @rx_ring: Rx ring in play - * @skb: packet to send up - * @vlan_tag: VLAN tag for packet - * - * This function sends the completed packet (via. skb) up the stack using - * gro receive functions (with/without VLAN tag) - */ -static void -ice_receive_skb(struct ice_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag) -{ - if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && - (vlan_tag & VLAN_VID_MASK)) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); - napi_gro_receive(&rx_ring->q_vector->napi, skb); -} - /** * ice_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf * @rx_ring: Rx descriptor ring to transact packets on diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index e40b4cb54ce3..a07101b13226 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -22,16 +22,6 @@ #define ICE_RX_BUF_WRITE 16 /* Must be power of 2 */ #define ICE_MAX_TXQ_PER_TXQG 128 -static inline __le64 -build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag) -{ - return cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | - (td_cmd << ICE_TXD_QW1_CMD_S) | - (td_offset << ICE_TXD_QW1_OFFSET_S) | - ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | - (td_tag << ICE_TXD_QW1_L2TAG1_S)); -} - /* We are assuming that the cache line is always 64 Bytes here for ice. * In order to make sure that is a correct assumption there is a check in probe * to print a warning if the read from GLPCI_CNF2 tells us that the cache line diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.c b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c new file mode 100644 index 000000000000..35bbc4ff603c --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Intel Corporation. */ + +#include "ice_txrx_lib.h" + +/** + * ice_release_rx_desc - Store the new tail and head values + * @rx_ring: ring to bump + * @val: new head index + */ +void ice_release_rx_desc(struct ice_ring *rx_ring, u32 val) +{ + u16 prev_ntu = rx_ring->next_to_use; + + rx_ring->next_to_use = val; + + /* update next to alloc since we have filled the ring */ + rx_ring->next_to_alloc = val; + + /* QRX_TAIL will be updated with any tail value, but hardware ignores + * the lower 3 bits. This makes it so we only bump tail on meaningful + * boundaries. Also, this allows us to bump tail on intervals of 8 up to + * the budget depending on the current traffic load. + */ + val &= ~0x7; + if (prev_ntu != val) { + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). + */ + wmb(); + writel(val, rx_ring->tail); + } +} + +/** + * ice_ptype_to_htype - get a hash type + * @ptype: the ptype value from the descriptor + * + * Returns a hash type to be used by skb_set_hash + */ +static enum pkt_hash_types ice_ptype_to_htype(u8 __always_unused ptype) +{ + return PKT_HASH_TYPE_NONE; +} + +/** + * ice_rx_hash - set the hash value in the skb + * @rx_ring: descriptor ring + * @rx_desc: specific descriptor + * @skb: pointer to current skb + * @rx_ptype: the ptype value from the descriptor + */ +static void +ice_rx_hash(struct ice_ring *rx_ring, union ice_32b_rx_flex_desc *rx_desc, + struct sk_buff *skb, u8 rx_ptype) +{ + struct ice_32b_rx_flex_desc_nic *nic_mdid; + u32 hash; + + if (!(rx_ring->netdev->features & NETIF_F_RXHASH)) + return; + + if (rx_desc->wb.rxdid != ICE_RXDID_FLEX_NIC) + return; + + nic_mdid = (struct ice_32b_rx_flex_desc_nic *)rx_desc; + hash = le32_to_cpu(nic_mdid->rss_hash); + skb_set_hash(skb, hash, ice_ptype_to_htype(rx_ptype)); +} + +/** + * ice_rx_csum - Indicate in skb if checksum is good + * @ring: the ring we care about + * @skb: skb currently being received and modified + * @rx_desc: the receive descriptor + * @ptype: the packet type decoded by hardware + * + * skb->protocol must be set before this function is called + */ +static void +ice_rx_csum(struct ice_ring *ring, struct sk_buff *skb, + union ice_32b_rx_flex_desc *rx_desc, u8 ptype) +{ + struct ice_rx_ptype_decoded decoded; + u32 rx_error, rx_status; + bool ipv4, ipv6; + + rx_status = le16_to_cpu(rx_desc->wb.status_error0); + rx_error = rx_status; + + decoded = ice_decode_rx_desc_ptype(ptype); + + /* Start with CHECKSUM_NONE and by default csum_level = 0 */ + skb->ip_summed = CHECKSUM_NONE; + skb_checksum_none_assert(skb); + + /* check if Rx checksum is enabled */ + if (!(ring->netdev->features & NETIF_F_RXCSUM)) + return; + + /* check if HW has decoded the packet and checksum */ + if (!(rx_status & BIT(ICE_RX_FLEX_DESC_STATUS0_L3L4P_S))) + return; + + if (!(decoded.known && decoded.outer_ip)) + return; + + ipv4 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && + (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV4); + ipv6 = (decoded.outer_ip == ICE_RX_PTYPE_OUTER_IP) && + (decoded.outer_ip_ver == ICE_RX_PTYPE_OUTER_IPV6); + + if (ipv4 && (rx_error & (BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_IPE_S) | + BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_EIPE_S)))) + goto checksum_fail; + else if (ipv6 && (rx_status & + (BIT(ICE_RX_FLEX_DESC_STATUS0_IPV6EXADD_S)))) + goto checksum_fail; + + /* check for L4 errors and handle packets that were not able to be + * checksummed due to arrival speed + */ + if (rx_error & BIT(ICE_RX_FLEX_DESC_STATUS0_XSUM_L4E_S)) + goto checksum_fail; + + /* Only report checksum unnecessary for TCP, UDP, or SCTP */ + switch (decoded.inner_prot) { + case ICE_RX_PTYPE_INNER_PROT_TCP: + case ICE_RX_PTYPE_INNER_PROT_UDP: + case ICE_RX_PTYPE_INNER_PROT_SCTP: + skb->ip_summed = CHECKSUM_UNNECESSARY; + default: + break; + } + return; + +checksum_fail: + ring->vsi->back->hw_csum_rx_error++; +} + +/** + * ice_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 + * @ptype: the packet type decoded by hardware + * + * This function checks the ring, descriptor, and packet information in + * order to populate the hash, checksum, VLAN, protocol, and + * other fields within the skb. + */ +void +ice_process_skb_fields(struct ice_ring *rx_ring, + union ice_32b_rx_flex_desc *rx_desc, + struct sk_buff *skb, u8 ptype) +{ + ice_rx_hash(rx_ring, rx_desc, skb, ptype); + + /* modifies the skb - consumes the enet header */ + skb->protocol = eth_type_trans(skb, rx_ring->netdev); + + ice_rx_csum(rx_ring, skb, rx_desc, ptype); +} + +/** + * ice_receive_skb - Send a completed packet up the stack + * @rx_ring: Rx ring in play + * @skb: packet to send up + * @vlan_tag: VLAN tag for packet + * + * This function sends the completed packet (via. skb) up the stack using + * gro receive functions (with/without VLAN tag) + */ +void +ice_receive_skb(struct ice_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag) +{ + if ((rx_ring->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) && + (vlan_tag & VLAN_VID_MASK)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); + napi_gro_receive(&rx_ring->q_vector->napi, skb); +} + +/** + * ice_xmit_xdp_ring - submit single packet to XDP ring for transmission + * @data: packet data pointer + * @size: packet data size + * @xdp_ring: XDP ring for transmission + */ +int ice_xmit_xdp_ring(void *data, u16 size, struct ice_ring *xdp_ring) +{ + u16 i = xdp_ring->next_to_use; + struct ice_tx_desc *tx_desc; + struct ice_tx_buf *tx_buf; + dma_addr_t dma; + + if (!unlikely(ICE_DESC_UNUSED(xdp_ring))) { + xdp_ring->tx_stats.tx_busy++; + return ICE_XDP_CONSUMED; + } + + dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE); + if (dma_mapping_error(xdp_ring->dev, dma)) + return ICE_XDP_CONSUMED; + + tx_buf = &xdp_ring->tx_buf[i]; + tx_buf->bytecount = size; + tx_buf->gso_segs = 1; + tx_buf->raw_buf = data; + + /* record length, and DMA address */ + dma_unmap_len_set(tx_buf, len, size); + dma_unmap_addr_set(tx_buf, dma, dma); + + tx_desc = ICE_TX_DESC(xdp_ring, i); + tx_desc->buf_addr = cpu_to_le64(dma); + tx_desc->cmd_type_offset_bsz = build_ctob(ICE_TXD_LAST_DESC_CMD, 0, + size, 0); + + /* Make certain all of the status bits have been updated + * before next_to_watch is written. + */ + smp_wmb(); + + i++; + if (i == xdp_ring->count) + i = 0; + + tx_buf->next_to_watch = tx_desc; + xdp_ring->next_to_use = i; + + return ICE_XDP_TX; +} + +/** + * ice_xmit_xdp_buff - convert an XDP buffer to an XDP frame and send it + * @xdp: XDP buffer + * @xdp_ring: XDP Tx ring + * + * Returns negative on failure, 0 on success. + */ +int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_ring *xdp_ring) +{ + struct xdp_frame *xdpf = convert_to_xdp_frame(xdp); + + if (unlikely(!xdpf)) + return ICE_XDP_CONSUMED; + + return ice_xmit_xdp_ring(xdpf->data, xdpf->len, xdp_ring); +} + +/** + * ice_finalize_xdp_rx - Bump XDP Tx tail and/or flush redirect map + * @rx_ring: Rx ring + * @xdp_res: Result of the receive batch + * + * This function bumps XDP Tx tail and/or flush redirect map, and + * should be called when a batch of packets has been processed in the + * napi loop. + */ +void ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res) +{ + if (xdp_res & ICE_XDP_REDIR) + xdp_do_flush_map(); + + if (xdp_res & ICE_XDP_TX) { + struct ice_ring *xdp_ring = + rx_ring->vsi->xdp_rings[rx_ring->q_index]; + + ice_xdp_ring_update_tail(xdp_ring); + } +} diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h new file mode 100644 index 000000000000..ba9164dad9ae --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Intel Corporation. */ + +#ifndef _ICE_TXRX_LIB_H_ +#define _ICE_TXRX_LIB_H_ +#include "ice.h" + +/** + * ice_test_staterr - tests bits in Rx descriptor status and error fields + * @rx_desc: pointer to receive descriptor (in le64 format) + * @stat_err_bits: value to mask + * + * This function does some fast chicanery in order to return the + * value of the mask which is really only used for boolean tests. + * The status_error_len doesn't need to be shifted because it begins + * at offset zero. + */ +static inline bool +ice_test_staterr(union ice_32b_rx_flex_desc *rx_desc, const u16 stat_err_bits) +{ + return !!(rx_desc->wb.status_error0 & cpu_to_le16(stat_err_bits)); +} + +static inline __le64 +build_ctob(u64 td_cmd, u64 td_offset, unsigned int size, u64 td_tag) +{ + return cpu_to_le64(ICE_TX_DESC_DTYPE_DATA | + (td_cmd << ICE_TXD_QW1_CMD_S) | + (td_offset << ICE_TXD_QW1_OFFSET_S) | + ((u64)size << ICE_TXD_QW1_TX_BUF_SZ_S) | + (td_tag << ICE_TXD_QW1_L2TAG1_S)); +} + +/** + * ice_xdp_ring_update_tail - Updates the XDP Tx ring tail register + * @xdp_ring: XDP Tx ring + * + * This function updates the XDP Tx ring tail register. + */ +static inline void ice_xdp_ring_update_tail(struct ice_ring *xdp_ring) +{ + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. + */ + wmb(); + writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); +} + +void ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res); +int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_ring *xdp_ring); +int ice_xmit_xdp_ring(void *data, u16 size, struct ice_ring *xdp_ring); +void ice_release_rx_desc(struct ice_ring *rx_ring, u32 val); +void +ice_process_skb_fields(struct ice_ring *rx_ring, + union ice_32b_rx_flex_desc *rx_desc, + struct sk_buff *skb, u8 ptype); +void +ice_receive_skb(struct ice_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag); +#endif /* !_ICE_TXRX_LIB_H_ */ -- cgit v1.2.3-59-g8ed1b From 2d4238f5569722197612656163d824098208519c Mon Sep 17 00:00:00 2001 From: Krzysztof Kazimierczak Date: Mon, 4 Nov 2019 09:38:56 -0800 Subject: ice: Add support for AF_XDP Add zero copy AF_XDP support. This patch adds zero copy support for Tx and Rx; code for zero copy is added to ice_xsk.h and ice_xsk.c. For Tx, implement ndo_xsk_wakeup. As with other drivers, reuse existing XDP Tx queues for this task, since XDP_REDIRECT guarantees mutual exclusion between different NAPI contexts based on CPU ID. In turn, a netdev can XDP_REDIRECT to another netdev with a different NAPI context, since the operation is bound to a specific core and each core has its own hardware ring. For Rx, allocate frames as MEM_TYPE_ZERO_COPY on queues that AF_XDP is enabled. Signed-off-by: Krzysztof Kazimierczak Co-developed-by: Maciej Fijalkowski Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 1 + drivers/net/ethernet/intel/ice/ice.h | 26 + drivers/net/ethernet/intel/ice/ice_base.c | 53 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 7 + drivers/net/ethernet/intel/ice/ice_lib.c | 57 +- drivers/net/ethernet/intel/ice/ice_lib.h | 4 + drivers/net/ethernet/intel/ice/ice_main.c | 16 + drivers/net/ethernet/intel/ice/ice_txrx.c | 46 +- drivers/net/ethernet/intel/ice/ice_txrx.h | 20 +- drivers/net/ethernet/intel/ice/ice_xsk.c | 1181 ++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_xsk.h | 72 ++ 11 files changed, 1456 insertions(+), 27 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_xsk.c create mode 100644 drivers/net/ethernet/intel/ice/ice_xsk.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index 9a7d6c02bcc6..df5a9699276a 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -21,3 +21,4 @@ ice-y := ice_main.o \ ice_ethtool.o ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_lib.o +ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index b2451f768707..1df18fda83e5 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -35,6 +35,7 @@ #include #include #include +#include #include "ice_devids.h" #include "ice_type.h" #include "ice_txrx.h" @@ -44,6 +45,7 @@ #include "ice_sched.h" #include "ice_virtchnl_pf.h" #include "ice_sriov.h" +#include "ice_xsk.h" extern const char ice_drv_ver[]; #define ICE_BAR0 0 @@ -287,6 +289,9 @@ struct ice_vsi { struct ice_ring **xdp_rings; /* XDP ring array */ u16 num_xdp_txq; /* Used XDP queues */ u8 xdp_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ + struct xdp_umem **xsk_umems; + u16 num_xsk_umems_used; + u16 num_xsk_umems; } ____cacheline_internodealigned_in_smp; /* struct that defines an interrupt vector */ @@ -440,6 +445,27 @@ static inline void ice_set_ring_xdp(struct ice_ring *ring) ring->flags |= ICE_TX_FLAGS_RING_XDP; } +/** + * ice_xsk_umem - get XDP UMEM bound to a ring + * @ring - ring to use + * + * Returns a pointer to xdp_umem structure if there is an UMEM present, + * NULL otherwise. + */ +static inline struct xdp_umem *ice_xsk_umem(struct ice_ring *ring) +{ + struct xdp_umem **umems = ring->vsi->xsk_umems; + int qid = ring->q_index; + + if (ice_ring_is_xdp(ring)) + qid -= ring->vsi->num_xdp_txq; + + if (!umems || !umems[qid] || !ice_is_xdp_ena_vsi(ring->vsi)) + return NULL; + + return umems[qid]; +} + /** * ice_get_main_vsi - Get the PF VSI * @pf: PF instance diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 8721934fb4ea..2904de054c10 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -276,14 +276,17 @@ ice_setup_tx_ctx(struct ice_ring *ring, struct ice_tlan_ctx *tlan_ctx, u16 pf_q) */ int ice_setup_rx_ctx(struct ice_ring *ring) { + int chain_len = ICE_MAX_CHAINED_RX_BUFS; struct ice_vsi *vsi = ring->vsi; - struct ice_hw *hw = &vsi->back->hw; u32 rxdid = ICE_RXDID_FLEX_NIC; struct ice_rlan_ctx rlan_ctx; + struct ice_hw *hw; u32 regval; u16 pf_q; int err; + hw = &vsi->back->hw; + /* what is Rx queue number in global space of 2K Rx queues */ pf_q = vsi->rxq_map[ring->q_index]; @@ -297,10 +300,38 @@ int ice_setup_rx_ctx(struct ice_ring *ring) xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev, ring->q_index); - err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, - MEM_TYPE_PAGE_SHARED, NULL); - if (err) - return err; + ring->xsk_umem = ice_xsk_umem(ring); + if (ring->xsk_umem) { + xdp_rxq_info_unreg_mem_model(&ring->xdp_rxq); + + ring->rx_buf_len = ring->xsk_umem->chunk_size_nohr - + XDP_PACKET_HEADROOM; + /* For AF_XDP ZC, we disallow packets to span on + * multiple buffers, thus letting us skip that + * handling in the fast-path. + */ + chain_len = 1; + ring->zca.free = ice_zca_free; + err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_ZERO_COPY, + &ring->zca); + if (err) + return err; + + dev_info(&vsi->back->pdev->dev, "Registered XDP mem model MEM_TYPE_ZERO_COPY on Rx ring %d\n", + ring->q_index); + } else { + if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) + xdp_rxq_info_reg(&ring->xdp_rxq, + ring->netdev, + ring->q_index); + + err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, + MEM_TYPE_PAGE_SHARED, + NULL); + if (err) + return err; + } } /* Receive Queue Base Address. * Indicates the starting address of the descriptor queue defined in @@ -340,7 +371,7 @@ int ice_setup_rx_ctx(struct ice_ring *ring) * than 5 x DBUF */ rlan_ctx.rxmax = min_t(u16, vsi->max_frame, - ICE_MAX_CHAINED_RX_BUFS * vsi->rx_buf_len); + chain_len * ring->rx_buf_len); /* Rx queue threshold in units of 64 */ rlan_ctx.lrxqthresh = 1; @@ -378,7 +409,15 @@ int ice_setup_rx_ctx(struct ice_ring *ring) /* init queue specific tail register */ ring->tail = hw->hw_addr + QRX_TAIL(pf_q); writel(0, ring->tail); - ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); + + err = ring->xsk_umem ? + ice_alloc_rx_bufs_slow_zc(ring, ICE_DESC_UNUSED(ring)) : + ice_alloc_rx_bufs(ring, ICE_DESC_UNUSED(ring)); + if (err) + dev_info(&vsi->back->pdev->dev, + "Failed allocate some buffers on %sRx ring %d (pf_q %d)\n", + ring->xsk_umem ? "UMEM enabled " : "", + ring->q_index, pf_q); return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 6cee99b5865b..42b032620f66 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -2612,6 +2612,13 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) return 0; } + /* If there is a AF_XDP UMEM attached to any of Rx rings, + * disallow changing the number of descriptors -- regardless + * if the netdev is running or not. + */ + if (ice_xsk_any_rx_ring_ena(vsi)) + return -EBUSY; + while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { timeout--; if (!timeout) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 3794e42b1d69..48319d8b0f54 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1283,7 +1283,17 @@ int ice_vsi_cfg_lan_txqs(struct ice_vsi *vsi) */ int ice_vsi_cfg_xdp_txqs(struct ice_vsi *vsi) { - return ice_vsi_cfg_txqs(vsi, vsi->xdp_rings); + int ret; + int i; + + ret = ice_vsi_cfg_txqs(vsi, vsi->xdp_rings); + if (ret) + return ret; + + for (i = 0; i < vsi->num_xdp_txq; i++) + vsi->xdp_rings[i]->xsk_umem = ice_xsk_umem(vsi->xdp_rings[i]); + + return ret; } /** @@ -2514,6 +2524,51 @@ char *ice_nvm_version_str(struct ice_hw *hw) return buf; } +/** + * ice_update_ring_stats - Update ring statistics + * @ring: ring to update + * @cont: used to increment per-vector counters + * @pkts: number of processed packets + * @bytes: number of processed bytes + * + * This function assumes that caller has acquired a u64_stats_sync lock. + */ +static void +ice_update_ring_stats(struct ice_ring *ring, struct ice_ring_container *cont, + u64 pkts, u64 bytes) +{ + ring->stats.bytes += bytes; + ring->stats.pkts += pkts; + cont->total_bytes += bytes; + cont->total_pkts += pkts; +} + +/** + * ice_update_tx_ring_stats - Update Tx ring specific counters + * @tx_ring: ring to update + * @pkts: number of processed packets + * @bytes: number of processed bytes + */ +void ice_update_tx_ring_stats(struct ice_ring *tx_ring, u64 pkts, u64 bytes) +{ + u64_stats_update_begin(&tx_ring->syncp); + ice_update_ring_stats(tx_ring, &tx_ring->q_vector->tx, pkts, bytes); + u64_stats_update_end(&tx_ring->syncp); +} + +/** + * ice_update_rx_ring_stats - Update Rx ring specific counters + * @rx_ring: ring to update + * @pkts: number of processed packets + * @bytes: number of processed bytes + */ +void ice_update_rx_ring_stats(struct ice_ring *rx_ring, u64 pkts, u64 bytes) +{ + u64_stats_update_begin(&rx_ring->syncp); + ice_update_ring_stats(rx_ring, &rx_ring->q_vector->rx, pkts, bytes); + u64_stats_update_end(&rx_ring->syncp); +} + /** * ice_vsi_cfg_mac_fltr - Add or remove a MAC address filter for a VSI * @vsi: the VSI being configured MAC filter diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 8e92c37a0f21..8d5a7978e066 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -83,6 +83,10 @@ void ice_vsi_free_tx_rings(struct ice_vsi *vsi); int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena); +void ice_update_tx_ring_stats(struct ice_ring *ring, u64 pkts, u64 bytes); + +void ice_update_rx_ring_stats(struct ice_ring *ring, u64 pkts, u64 bytes); + void ice_vsi_cfg_frame_size(struct ice_vsi *vsi); u32 ice_intrl_usec_to_reg(u8 intrl, u8 gran); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 3ee61ed21976..29eea08807fd 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -1692,6 +1692,7 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi) if (ice_setup_tx_ring(xdp_ring)) goto free_xdp_rings; ice_set_ring_xdp(xdp_ring); + xdp_ring->xsk_umem = ice_xsk_umem(xdp_ring); } return 0; @@ -1934,6 +1935,17 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, if (if_running) ret = ice_up(vsi); + if (!ret && prog && vsi->xsk_umems) { + int i; + + ice_for_each_rxq(vsi, i) { + struct ice_ring *rx_ring = vsi->rx_rings[i]; + + if (rx_ring->xsk_umem) + napi_schedule(&rx_ring->q_vector->napi); + } + } + return (ret || xdp_ring_err) ? -ENOMEM : 0; } @@ -1959,6 +1971,9 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) case XDP_QUERY_PROG: xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0; return 0; + case XDP_SETUP_XSK_UMEM: + return ice_xsk_umem_setup(vsi, xdp->xsk.umem, + xdp->xsk.queue_id); default: return -EINVAL; } @@ -5205,4 +5220,5 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_tx_timeout = ice_tx_timeout, .ndo_bpf = ice_xdp, .ndo_xdp_xmit = ice_xdp_xmit, + .ndo_xsk_wakeup = ice_xsk_wakeup, }; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 279e5ec7d15f..86a23036f420 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -11,6 +11,7 @@ #include "ice_lib.h" #include "ice.h" #include "ice_dcb_lib.h" +#include "ice_xsk.h" #define ICE_RX_HDR_SIZE 256 @@ -58,6 +59,11 @@ void ice_clean_tx_ring(struct ice_ring *tx_ring) { u16 i; + if (ice_ring_is_xdp(tx_ring) && tx_ring->xsk_umem) { + ice_xsk_clean_xdp_ring(tx_ring); + goto tx_skip_free; + } + /* ring already cleared, nothing to do */ if (!tx_ring->tx_buf) return; @@ -66,6 +72,7 @@ void ice_clean_tx_ring(struct ice_ring *tx_ring) for (i = 0; i < tx_ring->count; i++) ice_unmap_and_free_tx_buf(tx_ring, &tx_ring->tx_buf[i]); +tx_skip_free: memset(tx_ring->tx_buf, 0, sizeof(*tx_ring->tx_buf) * tx_ring->count); /* Zero out the descriptor ring */ @@ -198,12 +205,8 @@ static bool ice_clean_tx_irq(struct ice_ring *tx_ring, int napi_budget) i += tx_ring->count; tx_ring->next_to_clean = i; - u64_stats_update_begin(&tx_ring->syncp); - tx_ring->stats.bytes += total_bytes; - tx_ring->stats.pkts += total_pkts; - u64_stats_update_end(&tx_ring->syncp); - tx_ring->q_vector->tx.total_bytes += total_bytes; - tx_ring->q_vector->tx.total_pkts += total_pkts; + + ice_update_tx_ring_stats(tx_ring, total_pkts, total_bytes); if (ice_ring_is_xdp(tx_ring)) return !!budget; @@ -286,6 +289,11 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring) if (!rx_ring->rx_buf) return; + if (rx_ring->xsk_umem) { + ice_xsk_clean_rx_ring(rx_ring); + goto rx_skip_free; + } + /* Free all the Rx ring sk_buffs */ for (i = 0; i < rx_ring->count; i++) { struct ice_rx_buf *rx_buf = &rx_ring->rx_buf[i]; @@ -313,6 +321,7 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring) rx_buf->page_offset = 0; } +rx_skip_free: memset(rx_ring->rx_buf, 0, sizeof(*rx_ring->rx_buf) * rx_ring->count); /* Zero out the descriptor ring */ @@ -1073,13 +1082,7 @@ construct_skb: if (xdp_prog) ice_finalize_xdp_rx(rx_ring, xdp_xmit); - /* update queue and vector specific stats */ - u64_stats_update_begin(&rx_ring->syncp); - rx_ring->stats.pkts += total_rx_pkts; - rx_ring->stats.bytes += total_rx_bytes; - u64_stats_update_end(&rx_ring->syncp); - rx_ring->q_vector->rx.total_pkts += total_rx_pkts; - rx_ring->q_vector->rx.total_bytes += total_rx_bytes; + ice_update_rx_ring_stats(rx_ring, total_rx_pkts, total_rx_bytes); /* guarantee a trip back through this routine if there was a failure */ return failure ? budget : (int)total_rx_pkts; @@ -1457,9 +1460,14 @@ int ice_napi_poll(struct napi_struct *napi, int budget) /* Since the actual Tx work is minimal, we can give the Tx a larger * budget and be more aggressive about cleaning up the Tx descriptors. */ - ice_for_each_ring(ring, q_vector->tx) - if (!ice_clean_tx_irq(ring, budget)) + ice_for_each_ring(ring, q_vector->tx) { + bool wd = ring->xsk_umem ? + ice_clean_tx_irq_zc(ring, budget) : + ice_clean_tx_irq(ring, budget); + + if (!wd) clean_complete = false; + } /* Handle case where we are called by netpoll with a budget of 0 */ if (unlikely(budget <= 0)) @@ -1479,7 +1487,13 @@ int ice_napi_poll(struct napi_struct *napi, int budget) ice_for_each_ring(ring, q_vector->rx) { int cleaned; - cleaned = ice_clean_rx_irq(ring, budget_per_ring); + /* A dedicated path for zero-copy allows making a single + * comparison in the irq context instead of many inside the + * ice_clean_rx_irq function and makes the codebase cleaner. + */ + cleaned = ring->xsk_umem ? + ice_clean_rx_irq_zc(ring, budget_per_ring) : + ice_clean_rx_irq(ring, budget_per_ring); work_done += cleaned; /* if we clean as many as budgeted, we must not be done */ if (cleaned >= budget_per_ring) diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index a07101b13226..d5d243b8e69f 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -4,6 +4,8 @@ #ifndef _ICE_TXRX_H_ #define _ICE_TXRX_H_ +#include "ice_type.h" + #define ICE_DFLT_IRQ_WORK 256 #define ICE_RXBUF_2048 2048 #define ICE_MAX_CHAINED_RX_BUFS 5 @@ -88,9 +90,17 @@ struct ice_tx_offload_params { struct ice_rx_buf { struct sk_buff *skb; dma_addr_t dma; - struct page *page; - unsigned int page_offset; - u16 pagecnt_bias; + union { + struct { + struct page *page; + unsigned int page_offset; + u16 pagecnt_bias; + }; + struct { + void *addr; + u64 handle; + }; + }; }; struct ice_q_stats { @@ -211,6 +221,8 @@ struct ice_ring { struct rcu_head rcu; /* to avoid race on free */ struct bpf_prog *xdp_prog; + struct xdp_umem *xsk_umem; + struct zero_copy_allocator zca; /* CL3 - 3rd cacheline starts here */ struct xdp_rxq_info xdp_rxq; /* CLX - the below items are only accessed infrequently and should be @@ -250,6 +262,8 @@ struct ice_ring_container { #define ice_for_each_ring(pos, head) \ for (pos = (head).ring; pos; pos = pos->next) +union ice_32b_rx_flex_desc; + bool ice_alloc_rx_bufs(struct ice_ring *rxr, u16 cleaned_count); netdev_tx_t ice_start_xmit(struct sk_buff *skb, struct net_device *netdev); void ice_clean_tx_ring(struct ice_ring *tx_ring); diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c new file mode 100644 index 000000000000..fcffad0069d6 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -0,0 +1,1181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Intel Corporation. */ + +#include +#include +#include +#include "ice.h" +#include "ice_base.h" +#include "ice_type.h" +#include "ice_xsk.h" +#include "ice_txrx.h" +#include "ice_txrx_lib.h" +#include "ice_lib.h" + +/** + * ice_qp_reset_stats - Resets all stats for rings of given index + * @vsi: VSI that contains rings of interest + * @q_idx: ring index in array + */ +static void ice_qp_reset_stats(struct ice_vsi *vsi, u16 q_idx) +{ + memset(&vsi->rx_rings[q_idx]->rx_stats, 0, + sizeof(vsi->rx_rings[q_idx]->rx_stats)); + memset(&vsi->tx_rings[q_idx]->stats, 0, + sizeof(vsi->tx_rings[q_idx]->stats)); + if (ice_is_xdp_ena_vsi(vsi)) + memset(&vsi->xdp_rings[q_idx]->stats, 0, + sizeof(vsi->xdp_rings[q_idx]->stats)); +} + +/** + * ice_qp_clean_rings - Cleans all the rings of a given index + * @vsi: VSI that contains rings of interest + * @q_idx: ring index in array + */ +static void ice_qp_clean_rings(struct ice_vsi *vsi, u16 q_idx) +{ + ice_clean_tx_ring(vsi->tx_rings[q_idx]); + if (ice_is_xdp_ena_vsi(vsi)) + ice_clean_tx_ring(vsi->xdp_rings[q_idx]); + ice_clean_rx_ring(vsi->rx_rings[q_idx]); +} + +/** + * ice_qvec_toggle_napi - Enables/disables NAPI for a given q_vector + * @vsi: VSI that has netdev + * @q_vector: q_vector that has NAPI context + * @enable: true for enable, false for disable + */ +static void +ice_qvec_toggle_napi(struct ice_vsi *vsi, struct ice_q_vector *q_vector, + bool enable) +{ + if (!vsi->netdev || !q_vector) + return; + + if (enable) + napi_enable(&q_vector->napi); + else + napi_disable(&q_vector->napi); +} + +/** + * ice_qvec_dis_irq - Mask off queue interrupt generation on given ring + * @vsi: the VSI that contains queue vector being un-configured + * @rx_ring: Rx ring that will have its IRQ disabled + * @q_vector: queue vector + */ +static void +ice_qvec_dis_irq(struct ice_vsi *vsi, struct ice_ring *rx_ring, + struct ice_q_vector *q_vector) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + int base = vsi->base_vector; + u16 reg; + u32 val; + + /* QINT_TQCTL is being cleared in ice_vsi_stop_tx_ring, so handle + * here only QINT_RQCTL + */ + reg = rx_ring->reg_idx; + val = rd32(hw, QINT_RQCTL(reg)); + val &= ~QINT_RQCTL_CAUSE_ENA_M; + 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(pf->msix_entries[v_idx + base].vector); + } +} + +/** + * ice_qvec_cfg_msix - Enable IRQ for given queue vector + * @vsi: the VSI that contains queue vector + * @q_vector: queue vector + */ +static void +ice_qvec_cfg_msix(struct ice_vsi *vsi, struct ice_q_vector *q_vector) +{ + u16 reg_idx = q_vector->reg_idx; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + struct ice_ring *ring; + + ice_cfg_itr(hw, q_vector); + + wr32(hw, GLINT_RATE(reg_idx), + ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); + + ice_for_each_ring(ring, q_vector->tx) + ice_cfg_txq_interrupt(vsi, ring->reg_idx, reg_idx, + q_vector->tx.itr_idx); + + ice_for_each_ring(ring, q_vector->rx) + ice_cfg_rxq_interrupt(vsi, ring->reg_idx, reg_idx, + q_vector->rx.itr_idx); + + ice_flush(hw); +} + +/** + * ice_qvec_ena_irq - Enable IRQ for given queue vector + * @vsi: the VSI that contains queue vector + * @q_vector: queue vector + */ +static void ice_qvec_ena_irq(struct ice_vsi *vsi, struct ice_q_vector *q_vector) +{ + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + + ice_irq_dynamic_ena(hw, vsi, q_vector); + + ice_flush(hw); +} + +/** + * ice_qp_dis - Disables a queue pair + * @vsi: VSI of interest + * @q_idx: ring index in array + * + * Returns 0 on success, negative on failure. + */ +static int ice_qp_dis(struct ice_vsi *vsi, u16 q_idx) +{ + struct ice_txq_meta txq_meta = { }; + struct ice_ring *tx_ring, *rx_ring; + struct ice_q_vector *q_vector; + int timeout = 50; + int err; + + if (q_idx >= vsi->num_rxq || q_idx >= vsi->num_txq) + return -EINVAL; + + tx_ring = vsi->tx_rings[q_idx]; + rx_ring = vsi->rx_rings[q_idx]; + q_vector = rx_ring->q_vector; + + while (test_and_set_bit(__ICE_CFG_BUSY, vsi->state)) { + timeout--; + if (!timeout) + return -EBUSY; + usleep_range(1000, 2000); + } + netif_tx_stop_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); + + ice_qvec_dis_irq(vsi, rx_ring, q_vector); + + ice_fill_txq_meta(vsi, tx_ring, &txq_meta); + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, tx_ring, &txq_meta); + if (err) + return err; + if (ice_is_xdp_ena_vsi(vsi)) { + struct ice_ring *xdp_ring = vsi->xdp_rings[q_idx]; + + memset(&txq_meta, 0, sizeof(txq_meta)); + ice_fill_txq_meta(vsi, xdp_ring, &txq_meta); + err = ice_vsi_stop_tx_ring(vsi, ICE_NO_RESET, 0, xdp_ring, + &txq_meta); + if (err) + return err; + } + err = ice_vsi_ctrl_rx_ring(vsi, false, q_idx); + if (err) + return err; + + ice_qvec_toggle_napi(vsi, q_vector, false); + ice_qp_clean_rings(vsi, q_idx); + ice_qp_reset_stats(vsi, q_idx); + + return 0; +} + +/** + * ice_qp_ena - Enables a queue pair + * @vsi: VSI of interest + * @q_idx: ring index in array + * + * Returns 0 on success, negative on failure. + */ +static int ice_qp_ena(struct ice_vsi *vsi, u16 q_idx) +{ + struct ice_aqc_add_tx_qgrp *qg_buf; + struct ice_ring *tx_ring, *rx_ring; + struct ice_q_vector *q_vector; + int err; + + if (q_idx >= vsi->num_rxq || q_idx >= vsi->num_txq) + return -EINVAL; + + qg_buf = kzalloc(sizeof(*qg_buf), GFP_KERNEL); + if (!qg_buf) + return -ENOMEM; + + qg_buf->num_txqs = 1; + + tx_ring = vsi->tx_rings[q_idx]; + rx_ring = vsi->rx_rings[q_idx]; + q_vector = rx_ring->q_vector; + + err = ice_vsi_cfg_txq(vsi, tx_ring, qg_buf); + if (err) + goto free_buf; + + if (ice_is_xdp_ena_vsi(vsi)) { + struct ice_ring *xdp_ring = vsi->xdp_rings[q_idx]; + + memset(qg_buf, 0, sizeof(*qg_buf)); + qg_buf->num_txqs = 1; + err = ice_vsi_cfg_txq(vsi, xdp_ring, qg_buf); + if (err) + goto free_buf; + ice_set_ring_xdp(xdp_ring); + xdp_ring->xsk_umem = ice_xsk_umem(xdp_ring); + } + + err = ice_setup_rx_ctx(rx_ring); + if (err) + goto free_buf; + + ice_qvec_cfg_msix(vsi, q_vector); + + err = ice_vsi_ctrl_rx_ring(vsi, true, q_idx); + if (err) + goto free_buf; + + clear_bit(__ICE_CFG_BUSY, vsi->state); + ice_qvec_toggle_napi(vsi, q_vector, true); + ice_qvec_ena_irq(vsi, q_vector); + + netif_tx_start_queue(netdev_get_tx_queue(vsi->netdev, q_idx)); +free_buf: + kfree(qg_buf); + return err; +} + +/** + * ice_xsk_alloc_umems - allocate a UMEM region for an XDP socket + * @vsi: VSI to allocate the UMEM on + * + * Returns 0 on success, negative on error + */ +static int ice_xsk_alloc_umems(struct ice_vsi *vsi) +{ + if (vsi->xsk_umems) + return 0; + + vsi->xsk_umems = kcalloc(vsi->num_xsk_umems, sizeof(*vsi->xsk_umems), + GFP_KERNEL); + + if (!vsi->xsk_umems) { + vsi->num_xsk_umems = 0; + return -ENOMEM; + } + + return 0; +} + +/** + * ice_xsk_add_umem - add a UMEM region for XDP sockets + * @vsi: VSI to which the UMEM will be added + * @umem: pointer to a requested UMEM region + * @qid: queue ID + * + * Returns 0 on success, negative on error + */ +static int ice_xsk_add_umem(struct ice_vsi *vsi, struct xdp_umem *umem, u16 qid) +{ + int err; + + err = ice_xsk_alloc_umems(vsi); + if (err) + return err; + + vsi->xsk_umems[qid] = umem; + vsi->num_xsk_umems_used++; + + return 0; +} + +/** + * ice_xsk_remove_umem - Remove an UMEM for a certain ring/qid + * @vsi: VSI from which the VSI will be removed + * @qid: Ring/qid associated with the UMEM + */ +static void ice_xsk_remove_umem(struct ice_vsi *vsi, u16 qid) +{ + vsi->xsk_umems[qid] = NULL; + vsi->num_xsk_umems_used--; + + if (vsi->num_xsk_umems_used == 0) { + kfree(vsi->xsk_umems); + vsi->xsk_umems = NULL; + vsi->num_xsk_umems = 0; + } +} + +/** + * ice_xsk_umem_dma_map - DMA map UMEM region for XDP sockets + * @vsi: VSI to map the UMEM region + * @umem: UMEM to map + * + * Returns 0 on success, negative on error + */ +static int ice_xsk_umem_dma_map(struct ice_vsi *vsi, struct xdp_umem *umem) +{ + struct ice_pf *pf = vsi->back; + struct device *dev; + unsigned int i; + + dev = &pf->pdev->dev; + for (i = 0; i < umem->npgs; i++) { + dma_addr_t dma = dma_map_page_attrs(dev, umem->pgs[i], 0, + PAGE_SIZE, + DMA_BIDIRECTIONAL, + ICE_RX_DMA_ATTR); + if (dma_mapping_error(dev, dma)) { + dev_dbg(dev, + "XSK UMEM DMA mapping error on page num %d", i); + goto out_unmap; + } + + umem->pages[i].dma = dma; + } + + return 0; + +out_unmap: + for (; i > 0; i--) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, ICE_RX_DMA_ATTR); + umem->pages[i].dma = 0; + } + + return -EFAULT; +} + +/** + * ice_xsk_umem_dma_unmap - DMA unmap UMEM region for XDP sockets + * @vsi: VSI from which the UMEM will be unmapped + * @umem: UMEM to unmap + */ +static void ice_xsk_umem_dma_unmap(struct ice_vsi *vsi, struct xdp_umem *umem) +{ + struct ice_pf *pf = vsi->back; + struct device *dev; + unsigned int i; + + dev = &pf->pdev->dev; + for (i = 0; i < umem->npgs; i++) { + dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, + DMA_BIDIRECTIONAL, ICE_RX_DMA_ATTR); + + umem->pages[i].dma = 0; + } +} + +/** + * ice_xsk_umem_disable - disable a UMEM region + * @vsi: Current VSI + * @qid: queue ID + * + * Returns 0 on success, negative on failure + */ +static int ice_xsk_umem_disable(struct ice_vsi *vsi, u16 qid) +{ + if (!vsi->xsk_umems || qid >= vsi->num_xsk_umems || + !vsi->xsk_umems[qid]) + return -EINVAL; + + ice_xsk_umem_dma_unmap(vsi, vsi->xsk_umems[qid]); + ice_xsk_remove_umem(vsi, qid); + + return 0; +} + +/** + * ice_xsk_umem_enable - enable a UMEM region + * @vsi: Current VSI + * @umem: pointer to a requested UMEM region + * @qid: queue ID + * + * Returns 0 on success, negative on failure + */ +static int +ice_xsk_umem_enable(struct ice_vsi *vsi, struct xdp_umem *umem, u16 qid) +{ + struct xdp_umem_fq_reuse *reuseq; + int err; + + if (vsi->type != ICE_VSI_PF) + return -EINVAL; + + vsi->num_xsk_umems = min_t(u16, vsi->num_rxq, vsi->num_txq); + if (qid >= vsi->num_xsk_umems) + return -EINVAL; + + if (vsi->xsk_umems && vsi->xsk_umems[qid]) + return -EBUSY; + + reuseq = xsk_reuseq_prepare(vsi->rx_rings[0]->count); + if (!reuseq) + return -ENOMEM; + + xsk_reuseq_free(xsk_reuseq_swap(umem, reuseq)); + + err = ice_xsk_umem_dma_map(vsi, umem); + if (err) + return err; + + err = ice_xsk_add_umem(vsi, umem, qid); + if (err) + return err; + + return 0; +} + +/** + * ice_xsk_umem_setup - enable/disable a UMEM region depending on its state + * @vsi: Current VSI + * @umem: UMEM to enable/associate to a ring, NULL to disable + * @qid: queue ID + * + * Returns 0 on success, negative on failure + */ +int ice_xsk_umem_setup(struct ice_vsi *vsi, struct xdp_umem *umem, u16 qid) +{ + bool if_running, umem_present = !!umem; + int ret = 0, umem_failure = 0; + + if_running = netif_running(vsi->netdev) && ice_is_xdp_ena_vsi(vsi); + + if (if_running) { + ret = ice_qp_dis(vsi, qid); + if (ret) { + netdev_err(vsi->netdev, "ice_qp_dis error = %d", ret); + goto xsk_umem_if_up; + } + } + + umem_failure = umem_present ? ice_xsk_umem_enable(vsi, umem, qid) : + ice_xsk_umem_disable(vsi, qid); + +xsk_umem_if_up: + if (if_running) { + ret = ice_qp_ena(vsi, qid); + if (!ret && umem_present) + napi_schedule(&vsi->xdp_rings[qid]->q_vector->napi); + else if (ret) + netdev_err(vsi->netdev, "ice_qp_ena error = %d", ret); + } + + if (umem_failure) { + netdev_err(vsi->netdev, "Could not %sable UMEM, error = %d", + umem_present ? "en" : "dis", umem_failure); + return umem_failure; + } + + return ret; +} + +/** + * ice_zca_free - Callback for MEM_TYPE_ZERO_COPY allocations + * @zca: zero-cpoy allocator + * @handle: Buffer handle + */ +void ice_zca_free(struct zero_copy_allocator *zca, unsigned long handle) +{ + struct ice_rx_buf *rx_buf; + struct ice_ring *rx_ring; + struct xdp_umem *umem; + u64 hr, mask; + u16 nta; + + rx_ring = container_of(zca, struct ice_ring, zca); + umem = rx_ring->xsk_umem; + hr = umem->headroom + XDP_PACKET_HEADROOM; + + mask = umem->chunk_mask; + + nta = rx_ring->next_to_alloc; + rx_buf = &rx_ring->rx_buf[nta]; + + nta++; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + handle &= mask; + + rx_buf->dma = xdp_umem_get_dma(umem, handle); + rx_buf->dma += hr; + + rx_buf->addr = xdp_umem_get_data(umem, handle); + rx_buf->addr += hr; + + rx_buf->handle = (u64)handle + umem->headroom; +} + +/** + * ice_alloc_buf_fast_zc - Retrieve buffer address from XDP umem + * @rx_ring: ring with an xdp_umem bound to it + * @rx_buf: buffer to which xsk page address will be assigned + * + * This function allocates an Rx buffer in the hot path. + * The buffer can come from fill queue or recycle queue. + * + * Returns true if an assignment was successful, false if not. + */ +static __always_inline bool +ice_alloc_buf_fast_zc(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + void *addr = rx_buf->addr; + u64 handle, hr; + + if (addr) { + rx_ring->rx_stats.page_reuse_count++; + return true; + } + + if (!xsk_umem_peek_addr(umem, &handle)) { + rx_ring->rx_stats.alloc_page_failed++; + return false; + } + + hr = umem->headroom + XDP_PACKET_HEADROOM; + + rx_buf->dma = xdp_umem_get_dma(umem, handle); + rx_buf->dma += hr; + + rx_buf->addr = xdp_umem_get_data(umem, handle); + rx_buf->addr += hr; + + rx_buf->handle = handle + umem->headroom; + + xsk_umem_discard_addr(umem); + return true; +} + +/** + * ice_alloc_buf_slow_zc - Retrieve buffer address from XDP umem + * @rx_ring: ring with an xdp_umem bound to it + * @rx_buf: buffer to which xsk page address will be assigned + * + * This function allocates an Rx buffer in the slow path. + * The buffer can come from fill queue or recycle queue. + * + * Returns true if an assignment was successful, false if not. + */ +static __always_inline bool +ice_alloc_buf_slow_zc(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) +{ + struct xdp_umem *umem = rx_ring->xsk_umem; + u64 handle, headroom; + + if (!xsk_umem_peek_addr_rq(umem, &handle)) { + rx_ring->rx_stats.alloc_page_failed++; + return false; + } + + handle &= umem->chunk_mask; + headroom = umem->headroom + XDP_PACKET_HEADROOM; + + rx_buf->dma = xdp_umem_get_dma(umem, handle); + rx_buf->dma += headroom; + + rx_buf->addr = xdp_umem_get_data(umem, handle); + rx_buf->addr += headroom; + + rx_buf->handle = handle + umem->headroom; + + xsk_umem_discard_addr_rq(umem); + return true; +} + +/** + * ice_alloc_rx_bufs_zc - allocate a number of Rx buffers + * @rx_ring: Rx ring + * @count: The number of buffers to allocate + * @alloc: the function pointer to call for allocation + * + * This function allocates a number of Rx buffers from the fill ring + * or the internal recycle mechanism and places them on the Rx ring. + * + * Returns false if all allocations were successful, true if any fail. + */ +static bool +ice_alloc_rx_bufs_zc(struct ice_ring *rx_ring, int count, + bool alloc(struct ice_ring *, struct ice_rx_buf *)) +{ + union ice_32b_rx_flex_desc *rx_desc; + u16 ntu = rx_ring->next_to_use; + struct ice_rx_buf *rx_buf; + bool ret = false; + + if (!count) + return false; + + rx_desc = ICE_RX_DESC(rx_ring, ntu); + rx_buf = &rx_ring->rx_buf[ntu]; + + do { + if (!alloc(rx_ring, rx_buf)) { + ret = true; + break; + } + + dma_sync_single_range_for_device(rx_ring->dev, rx_buf->dma, 0, + rx_ring->rx_buf_len, + DMA_BIDIRECTIONAL); + + rx_desc->read.pkt_addr = cpu_to_le64(rx_buf->dma); + rx_desc->wb.status_error0 = 0; + + rx_desc++; + rx_buf++; + ntu++; + + if (unlikely(ntu == rx_ring->count)) { + rx_desc = ICE_RX_DESC(rx_ring, 0); + rx_buf = rx_ring->rx_buf; + ntu = 0; + } + } while (--count); + + if (rx_ring->next_to_use != ntu) + ice_release_rx_desc(rx_ring, ntu); + + return ret; +} + +/** + * ice_alloc_rx_bufs_fast_zc - allocate zero copy bufs in the hot path + * @rx_ring: Rx ring + * @count: number of bufs to allocate + * + * Returns false on success, true on failure. + */ +static bool ice_alloc_rx_bufs_fast_zc(struct ice_ring *rx_ring, u16 count) +{ + return ice_alloc_rx_bufs_zc(rx_ring, count, + ice_alloc_buf_fast_zc); +} + +/** + * ice_alloc_rx_bufs_slow_zc - allocate zero copy bufs in the slow path + * @rx_ring: Rx ring + * @count: number of bufs to allocate + * + * Returns false on success, true on failure. + */ +bool ice_alloc_rx_bufs_slow_zc(struct ice_ring *rx_ring, u16 count) +{ + return ice_alloc_rx_bufs_zc(rx_ring, count, + ice_alloc_buf_slow_zc); +} + +/** + * ice_bump_ntc - Bump the next_to_clean counter of an Rx ring + * @rx_ring: Rx ring + */ +static void ice_bump_ntc(struct ice_ring *rx_ring) +{ + int ntc = rx_ring->next_to_clean + 1; + + ntc = (ntc < rx_ring->count) ? ntc : 0; + rx_ring->next_to_clean = ntc; + prefetch(ICE_RX_DESC(rx_ring, ntc)); +} + +/** + * ice_get_rx_buf_zc - Fetch the current Rx buffer + * @rx_ring: Rx ring + * @size: size of a buffer + * + * This function returns the current, received Rx buffer and does + * DMA synchronization. + * + * Returns a pointer to the received Rx buffer. + */ +static struct ice_rx_buf *ice_get_rx_buf_zc(struct ice_ring *rx_ring, int size) +{ + struct ice_rx_buf *rx_buf; + + rx_buf = &rx_ring->rx_buf[rx_ring->next_to_clean]; + + dma_sync_single_range_for_cpu(rx_ring->dev, rx_buf->dma, 0, + size, DMA_BIDIRECTIONAL); + + return rx_buf; +} + +/** + * ice_reuse_rx_buf_zc - reuse an Rx buffer + * @rx_ring: Rx ring + * @old_buf: The buffer to recycle + * + * This function recycles a finished Rx buffer, and places it on the recycle + * queue (next_to_alloc). + */ +static void +ice_reuse_rx_buf_zc(struct ice_ring *rx_ring, struct ice_rx_buf *old_buf) +{ + unsigned long mask = (unsigned long)rx_ring->xsk_umem->chunk_mask; + u64 hr = rx_ring->xsk_umem->headroom + XDP_PACKET_HEADROOM; + u16 nta = rx_ring->next_to_alloc; + struct ice_rx_buf *new_buf; + + new_buf = &rx_ring->rx_buf[nta++]; + rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0; + + new_buf->dma = old_buf->dma & mask; + new_buf->dma += hr; + + new_buf->addr = (void *)((unsigned long)old_buf->addr & mask); + new_buf->addr += hr; + + new_buf->handle = old_buf->handle & mask; + new_buf->handle += rx_ring->xsk_umem->headroom; + + old_buf->addr = NULL; +} + +/** + * ice_construct_skb_zc - Create an sk_buff from zero-copy buffer + * @rx_ring: Rx ring + * @rx_buf: zero-copy Rx buffer + * @xdp: XDP buffer + * + * This function allocates a new skb from a zero-copy Rx buffer. + * + * Returns the skb on success, NULL on failure. + */ +static struct sk_buff * +ice_construct_skb_zc(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, + struct xdp_buff *xdp) +{ + unsigned int metasize = xdp->data - xdp->data_meta; + unsigned int datasize = xdp->data_end - xdp->data; + unsigned int datasize_hard = xdp->data_end - + xdp->data_hard_start; + struct sk_buff *skb; + + skb = __napi_alloc_skb(&rx_ring->q_vector->napi, datasize_hard, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(!skb)) + return NULL; + + skb_reserve(skb, xdp->data - xdp->data_hard_start); + memcpy(__skb_put(skb, datasize), xdp->data, datasize); + if (metasize) + skb_metadata_set(skb, metasize); + + ice_reuse_rx_buf_zc(rx_ring, rx_buf); + + return skb; +} + +/** + * ice_run_xdp_zc - Executes an XDP program in zero-copy path + * @rx_ring: Rx ring + * @xdp: xdp_buff used as input to the XDP program + * + * Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR} + */ +static int +ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp) +{ + int err, result = ICE_XDP_PASS; + struct bpf_prog *xdp_prog; + struct ice_ring *xdp_ring; + u32 act; + + rcu_read_lock(); + xdp_prog = READ_ONCE(rx_ring->xdp_prog); + if (!xdp_prog) { + rcu_read_unlock(); + return ICE_XDP_PASS; + } + + act = bpf_prog_run_xdp(xdp_prog, xdp); + xdp->handle += xdp->data - xdp->data_hard_start; + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->q_index]; + result = ice_xmit_xdp_buff(xdp, xdp_ring); + break; + case XDP_REDIRECT: + err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog); + result = !err ? ICE_XDP_REDIR : ICE_XDP_CONSUMED; + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fallthrough -- not supported action */ + case XDP_ABORTED: + trace_xdp_exception(rx_ring->netdev, xdp_prog, act); + /* fallthrough -- handle aborts by dropping frame */ + case XDP_DROP: + result = ICE_XDP_CONSUMED; + break; + } + + rcu_read_unlock(); + return result; +} + +/** + * ice_clean_rx_irq_zc - consumes packets from the hardware ring + * @rx_ring: AF_XDP Rx ring + * @budget: NAPI budget + * + * Returns number of processed packets on success, remaining budget on failure. + */ +int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget) +{ + unsigned int total_rx_bytes = 0, total_rx_packets = 0; + u16 cleaned_count = ICE_DESC_UNUSED(rx_ring); + unsigned int xdp_xmit = 0; + struct xdp_buff xdp; + bool failure = 0; + + xdp.rxq = &rx_ring->xdp_rxq; + + while (likely(total_rx_packets < (unsigned int)budget)) { + union ice_32b_rx_flex_desc *rx_desc; + unsigned int size, xdp_res = 0; + struct ice_rx_buf *rx_buf; + struct sk_buff *skb; + u16 stat_err_bits; + u16 vlan_tag = 0; + u8 rx_ptype; + + if (cleaned_count >= ICE_RX_BUF_WRITE) { + failure |= ice_alloc_rx_bufs_fast_zc(rx_ring, + cleaned_count); + cleaned_count = 0; + } + + rx_desc = ICE_RX_DESC(rx_ring, rx_ring->next_to_clean); + + stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_DD_S); + if (!ice_test_staterr(rx_desc, stat_err_bits)) + break; + + /* This memory barrier is needed to keep us from reading + * any other fields out of the rx_desc until we have + * verified the descriptor has been written back. + */ + dma_rmb(); + + size = le16_to_cpu(rx_desc->wb.pkt_len) & + ICE_RX_FLX_DESC_PKT_LEN_M; + if (!size) + break; + + rx_buf = ice_get_rx_buf_zc(rx_ring, size); + if (!rx_buf->addr) + break; + + xdp.data = rx_buf->addr; + xdp.data_meta = xdp.data; + xdp.data_hard_start = xdp.data - XDP_PACKET_HEADROOM; + xdp.data_end = xdp.data + size; + xdp.handle = rx_buf->handle; + + xdp_res = ice_run_xdp_zc(rx_ring, &xdp); + if (xdp_res) { + if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) { + xdp_xmit |= xdp_res; + rx_buf->addr = NULL; + } else { + ice_reuse_rx_buf_zc(rx_ring, rx_buf); + } + + total_rx_bytes += size; + total_rx_packets++; + cleaned_count++; + + ice_bump_ntc(rx_ring); + continue; + } + + /* XDP_PASS path */ + skb = ice_construct_skb_zc(rx_ring, rx_buf, &xdp); + if (!skb) { + rx_ring->rx_stats.alloc_buf_failed++; + break; + } + + cleaned_count++; + ice_bump_ntc(rx_ring); + + if (eth_skb_pad(skb)) { + skb = NULL; + continue; + } + + total_rx_bytes += skb->len; + total_rx_packets++; + + stat_err_bits = BIT(ICE_RX_FLEX_DESC_STATUS0_L2TAG1P_S); + if (ice_test_staterr(rx_desc, stat_err_bits)) + vlan_tag = le16_to_cpu(rx_desc->wb.l2tag1); + + rx_ptype = le16_to_cpu(rx_desc->wb.ptype_flex_flags0) & + ICE_RX_FLEX_DESC_PTYPE_M; + + ice_process_skb_fields(rx_ring, rx_desc, skb, rx_ptype); + ice_receive_skb(rx_ring, skb, vlan_tag); + } + + ice_finalize_xdp_rx(rx_ring, xdp_xmit); + ice_update_rx_ring_stats(rx_ring, total_rx_packets, total_rx_bytes); + + return failure ? budget : (int)total_rx_packets; +} + +/** + * ice_xmit_zc - Completes AF_XDP entries, and cleans XDP entries + * @xdp_ring: XDP Tx ring + * @budget: max number of frames to xmit + * + * Returns true if cleanup/transmission is done. + */ +static bool ice_xmit_zc(struct ice_ring *xdp_ring, int budget) +{ + struct ice_tx_desc *tx_desc = NULL; + bool work_done = true; + struct xdp_desc desc; + dma_addr_t dma; + + while (likely(budget-- > 0)) { + struct ice_tx_buf *tx_buf; + + if (unlikely(!ICE_DESC_UNUSED(xdp_ring))) { + xdp_ring->tx_stats.tx_busy++; + work_done = false; + break; + } + + tx_buf = &xdp_ring->tx_buf[xdp_ring->next_to_use]; + + if (!xsk_umem_consume_tx(xdp_ring->xsk_umem, &desc)) + break; + + dma = xdp_umem_get_dma(xdp_ring->xsk_umem, desc.addr); + + dma_sync_single_for_device(xdp_ring->dev, dma, desc.len, + DMA_BIDIRECTIONAL); + + tx_buf->bytecount = desc.len; + + tx_desc = ICE_TX_DESC(xdp_ring, xdp_ring->next_to_use); + tx_desc->buf_addr = cpu_to_le64(dma); + tx_desc->cmd_type_offset_bsz = build_ctob(ICE_TXD_LAST_DESC_CMD, + 0, desc.len, 0); + + xdp_ring->next_to_use++; + if (xdp_ring->next_to_use == xdp_ring->count) + xdp_ring->next_to_use = 0; + } + + if (tx_desc) { + ice_xdp_ring_update_tail(xdp_ring); + xsk_umem_consume_tx_done(xdp_ring->xsk_umem); + } + + return budget > 0 && work_done; +} + +/** + * ice_clean_xdp_tx_buf - Free and unmap XDP Tx buffer + * @xdp_ring: XDP Tx ring + * @tx_buf: Tx buffer to clean + */ +static void +ice_clean_xdp_tx_buf(struct ice_ring *xdp_ring, struct ice_tx_buf *tx_buf) +{ + xdp_return_frame((struct xdp_frame *)tx_buf->raw_buf); + dma_unmap_single(xdp_ring->dev, dma_unmap_addr(tx_buf, dma), + dma_unmap_len(tx_buf, len), DMA_TO_DEVICE); + dma_unmap_len_set(tx_buf, len, 0); +} + +/** + * ice_clean_tx_irq_zc - Completes AF_XDP entries, and cleans XDP entries + * @xdp_ring: XDP Tx ring + * @budget: NAPI budget + * + * Returns true if cleanup/tranmission is done. + */ +bool ice_clean_tx_irq_zc(struct ice_ring *xdp_ring, int budget) +{ + int total_packets = 0, total_bytes = 0; + s16 ntc = xdp_ring->next_to_clean; + struct ice_tx_desc *tx_desc; + struct ice_tx_buf *tx_buf; + bool xmit_done = true; + u32 xsk_frames = 0; + + tx_desc = ICE_TX_DESC(xdp_ring, ntc); + tx_buf = &xdp_ring->tx_buf[ntc]; + ntc -= xdp_ring->count; + + do { + if (!(tx_desc->cmd_type_offset_bsz & + cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE))) + break; + + total_bytes += tx_buf->bytecount; + total_packets++; + + if (tx_buf->raw_buf) { + ice_clean_xdp_tx_buf(xdp_ring, tx_buf); + tx_buf->raw_buf = NULL; + } else { + xsk_frames++; + } + + tx_desc->cmd_type_offset_bsz = 0; + tx_buf++; + tx_desc++; + ntc++; + + if (unlikely(!ntc)) { + ntc -= xdp_ring->count; + tx_buf = xdp_ring->tx_buf; + tx_desc = ICE_TX_DESC(xdp_ring, 0); + } + + prefetch(tx_desc); + + } while (likely(--budget)); + + ntc += xdp_ring->count; + xdp_ring->next_to_clean = ntc; + + if (xsk_frames) + xsk_umem_complete_tx(xdp_ring->xsk_umem, xsk_frames); + + ice_update_tx_ring_stats(xdp_ring, total_packets, total_bytes); + xmit_done = ice_xmit_zc(xdp_ring, ICE_DFLT_IRQ_WORK); + + return budget > 0 && xmit_done; +} + +/** + * ice_xsk_wakeup - Implements ndo_xsk_wakeup + * @netdev: net_device + * @queue_id: queue to wake up + * @flags: ignored in our case, since we have Rx and Tx in the same NAPI + * + * Returns negative on error, zero otherwise. + */ +int +ice_xsk_wakeup(struct net_device *netdev, u32 queue_id, + u32 __always_unused flags) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_q_vector *q_vector; + struct ice_vsi *vsi = np->vsi; + struct ice_ring *ring; + + if (test_bit(__ICE_DOWN, vsi->state)) + return -ENETDOWN; + + if (!ice_is_xdp_ena_vsi(vsi)) + return -ENXIO; + + if (queue_id >= vsi->num_txq) + return -ENXIO; + + if (!vsi->xdp_rings[queue_id]->xsk_umem) + return -ENXIO; + + ring = vsi->xdp_rings[queue_id]; + + /* The idea here is that if NAPI is running, mark a miss, so + * it will run again. If not, trigger an interrupt and + * schedule the NAPI from interrupt context. If NAPI would be + * scheduled here, the interrupt affinity would not be + * honored. + */ + q_vector = ring->q_vector; + if (!napi_if_scheduled_mark_missed(&q_vector->napi)) + ice_trigger_sw_intr(&vsi->back->hw, q_vector); + + return 0; +} + +/** + * ice_xsk_any_rx_ring_ena - Checks if Rx rings have AF_XDP UMEM attached + * @vsi: VSI to be checked + * + * Returns true if any of the Rx rings has an AF_XDP UMEM attached + */ +bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi) +{ + int i; + + if (!vsi->xsk_umems) + return false; + + for (i = 0; i < vsi->num_xsk_umems; i++) { + if (vsi->xsk_umems[i]) + return true; + } + + return false; +} + +/** + * ice_xsk_clean_rx_ring - clean UMEM queues connected to a given Rx ring + * @rx_ring: ring to be cleaned + */ +void ice_xsk_clean_rx_ring(struct ice_ring *rx_ring) +{ + u16 i; + + for (i = 0; i < rx_ring->count; i++) { + struct ice_rx_buf *rx_buf = &rx_ring->rx_buf[i]; + + if (!rx_buf->addr) + continue; + + xsk_umem_fq_reuse(rx_ring->xsk_umem, rx_buf->handle); + rx_buf->addr = NULL; + } +} + +/** + * ice_xsk_clean_xdp_ring - Clean the XDP Tx ring and its UMEM queues + * @xdp_ring: XDP_Tx ring + */ +void ice_xsk_clean_xdp_ring(struct ice_ring *xdp_ring) +{ + u16 ntc = xdp_ring->next_to_clean, ntu = xdp_ring->next_to_use; + u32 xsk_frames = 0; + + while (ntc != ntu) { + struct ice_tx_buf *tx_buf = &xdp_ring->tx_buf[ntc]; + + if (tx_buf->raw_buf) + ice_clean_xdp_tx_buf(xdp_ring, tx_buf); + else + xsk_frames++; + + tx_buf->raw_buf = NULL; + + ntc++; + if (ntc >= xdp_ring->count) + ntc = 0; + } + + if (xsk_frames) + xsk_umem_complete_tx(xdp_ring->xsk_umem, xsk_frames); +} diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.h b/drivers/net/ethernet/intel/ice/ice_xsk.h new file mode 100644 index 000000000000..3479e1de98fe --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_xsk.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Intel Corporation. */ + +#ifndef _ICE_XSK_H_ +#define _ICE_XSK_H_ +#include "ice_txrx.h" +#include "ice.h" + +struct ice_vsi; + +#ifdef CONFIG_XDP_SOCKETS +int ice_xsk_umem_setup(struct ice_vsi *vsi, struct xdp_umem *umem, u16 qid); +void ice_zca_free(struct zero_copy_allocator *zca, unsigned long handle); +int ice_clean_rx_irq_zc(struct ice_ring *rx_ring, int budget); +bool ice_clean_tx_irq_zc(struct ice_ring *xdp_ring, int budget); +int ice_xsk_wakeup(struct net_device *netdev, u32 queue_id, u32 flags); +bool ice_alloc_rx_bufs_slow_zc(struct ice_ring *rx_ring, u16 count); +bool ice_xsk_any_rx_ring_ena(struct ice_vsi *vsi); +void ice_xsk_clean_rx_ring(struct ice_ring *rx_ring); +void ice_xsk_clean_xdp_ring(struct ice_ring *xdp_ring); +#else +static inline int +ice_xsk_umem_setup(struct ice_vsi __always_unused *vsi, + struct xdp_umem __always_unused *umem, + u16 __always_unused qid) +{ + return -ENOTSUPP; +} + +static inline void +ice_zca_free(struct zero_copy_allocator __always_unused *zca, + unsigned long __always_unused handle) +{ +} + +static inline int +ice_clean_rx_irq_zc(struct ice_ring __always_unused *rx_ring, + int __always_unused budget) +{ + return 0; +} + +static inline bool +ice_clean_tx_irq_zc(struct ice_ring __always_unused *xdp_ring, + int __always_unused budget) +{ + return false; +} + +static inline bool +ice_alloc_rx_bufs_slow_zc(struct ice_ring __always_unused *rx_ring, + u16 __always_unused count) +{ + return false; +} + +static inline bool ice_xsk_any_rx_ring_ena(struct ice_vsi __always_unused *vsi) +{ + return false; +} + +static inline int +ice_xsk_wakeup(struct net_device __always_unused *netdev, + u32 __always_unused queue_id, u32 __always_unused flags) +{ + return -ENOTSUPP; +} + +#define ice_xsk_clean_rx_ring(rx_ring) do {} while (0) +#define ice_xsk_clean_xdp_ring(xdp_ring) do {} while (0) +#endif /* CONFIG_XDP_SOCKETS */ +#endif /* !_ICE_XSK_H_ */ -- cgit v1.2.3-59-g8ed1b From 7237f5b0dba443756e190bdbecd83f9b1377a912 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 24 Oct 2019 01:11:22 -0700 Subject: ice: introduce legacy Rx flag Add an ethtool "legacy-rx" priv flag for toggling the Rx path. This control knob will be mainly used for build_skb usage as well as buffer size/MTU manipulation. In preparation for adding build_skb support in a way that it takes care of how we set the values of max_frame and rx_buf_len fields of struct ice_vsi. Specifically, in this patch mentioned fields are set to values that will allow us to provide headroom and tailroom in-place. This can be mostly broken down onto following: - for legacy-rx "on" ethtool control knob, old behaviour is kept; - for standard 1500 MTU size configure the buffer of size 1536, as network stack is expecting the NET_SKB_PAD to be provided and NET_IP_ALIGN can have a non-zero value (these can be typically equal to 32 and 2, respectively); - for larger MTUs go with max_frame set to 9k and configure the 3k buffer in case when PAGE_SIZE of underlying arch is less than 8k; 3k buffer is implying the need for order 1 page, so that our page recycling scheme can still be applied; With that said, substitute the hardcoded ICE_RXBUF_2048 and PAGE_SIZE values in DMA API that we're making use of with rx_ring->rx_buf_len and ice_rx_pg_size(rx_ring). The latter is an introduced helper for determining the page size based on its order (which was figured out via ice_rx_pg_order). Last but not least, take care of truesize calculation. In the followup patch the headroom/tailroom computation logic will be introduced. This change aligns the buffer and frame configuration with other Intel drivers, most importantly with iavf. Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 1 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 6 ++++ drivers/net/ethernet/intel/ice/ice_lib.c | 22 +++++++++---- drivers/net/ethernet/intel/ice/ice_txrx.c | 46 ++++++++++++++++------------ drivers/net/ethernet/intel/ice/ice_txrx.h | 13 ++++++++ 5 files changed, 63 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 1df18fda83e5..f552a67467aa 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -331,6 +331,7 @@ enum ice_pf_flags { ICE_FLAG_NO_MEDIA, ICE_FLAG_FW_LLDP_AGENT, ICE_FLAG_ETHTOOL_CTXT, /* set when ethtool holds RTNL lock */ + ICE_FLAG_LEGACY_RX, ICE_PF_FLAGS_NBITS /* must be last */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 42b032620f66..c1737625bbc2 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -156,6 +156,7 @@ struct ice_priv_flag { static const struct ice_priv_flag ice_gstrings_priv_flags[] = { ICE_PRIV_FLAG("link-down-on-close", ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA), ICE_PRIV_FLAG("fw-lldp-agent", ICE_FLAG_FW_LLDP_AGENT), + ICE_PRIV_FLAG("legacy-rx", ICE_FLAG_LEGACY_RX), }; #define ICE_PRIV_FLAG_ARRAY_SIZE ARRAY_SIZE(ice_gstrings_priv_flags) @@ -1256,6 +1257,11 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) "Fail to enable MIB change events\n"); } } + if (test_bit(ICE_FLAG_LEGACY_RX, change_flags)) { + /* down and up VSI so that changes of Rx cfg are reflected. */ + ice_down(vsi); + ice_up(vsi); + } clear_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); return ret; } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 48319d8b0f54..76569caec469 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1190,12 +1190,22 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) */ void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) { - if (vsi->netdev && vsi->netdev->mtu > ETH_DATA_LEN) - vsi->max_frame = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD; - else - vsi->max_frame = ICE_RXBUF_2048; - - vsi->rx_buf_len = ICE_RXBUF_2048; + if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) { + vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; + vsi->rx_buf_len = ICE_RXBUF_2048; +#if (PAGE_SIZE < 8192) + } else if (vsi->netdev->mtu <= ETH_DATA_LEN) { + vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; + vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; +#endif + } else { + vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; +#if (PAGE_SIZE < 8192) + vsi->rx_buf_len = ICE_RXBUF_3072; +#else + vsi->rx_buf_len = ICE_RXBUF_2048; +#endif + } } /** diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 86a23036f420..9528bd69d6b4 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -310,10 +310,11 @@ void ice_clean_rx_ring(struct ice_ring *rx_ring) */ dma_sync_single_range_for_cpu(dev, rx_buf->dma, rx_buf->page_offset, - ICE_RXBUF_2048, DMA_FROM_DEVICE); + rx_ring->rx_buf_len, + DMA_FROM_DEVICE); /* free resources associated with mapping */ - dma_unmap_page_attrs(dev, rx_buf->dma, PAGE_SIZE, + dma_unmap_page_attrs(dev, rx_buf->dma, ice_rx_pg_size(rx_ring), DMA_FROM_DEVICE, ICE_RX_DMA_ATTR); __page_frag_cache_drain(rx_buf->page, rx_buf->pagecnt_bias); @@ -529,21 +530,21 @@ ice_alloc_mapped_page(struct ice_ring *rx_ring, struct ice_rx_buf *bi) } /* alloc new page for storage */ - page = alloc_page(GFP_ATOMIC | __GFP_NOWARN); + page = dev_alloc_pages(ice_rx_pg_order(rx_ring)); if (unlikely(!page)) { rx_ring->rx_stats.alloc_page_failed++; return false; } /* map page for use */ - dma = dma_map_page_attrs(rx_ring->dev, page, 0, PAGE_SIZE, + dma = dma_map_page_attrs(rx_ring->dev, page, 0, ice_rx_pg_size(rx_ring), DMA_FROM_DEVICE, ICE_RX_DMA_ATTR); /* if mapping failed free memory back to system since * there isn't much point in holding memory we can't use */ if (dma_mapping_error(rx_ring->dev, dma)) { - __free_pages(page, 0); + __free_pages(page, ice_rx_pg_order(rx_ring)); rx_ring->rx_stats.alloc_page_failed++; return false; } @@ -592,7 +593,7 @@ bool ice_alloc_rx_bufs(struct ice_ring *rx_ring, u16 cleaned_count) /* sync the buffer for use by the device */ dma_sync_single_range_for_device(rx_ring->dev, bi->dma, bi->page_offset, - ICE_RXBUF_2048, + rx_ring->rx_buf_len, DMA_FROM_DEVICE); /* Refresh the desc even if buffer_addrs didn't change @@ -663,9 +664,6 @@ ice_rx_buf_adjust_pg_offset(struct ice_rx_buf *rx_buf, unsigned int size) */ static bool ice_can_reuse_rx_page(struct ice_rx_buf *rx_buf) { -#if (PAGE_SIZE >= 8192) - unsigned int last_offset = PAGE_SIZE - ICE_RXBUF_2048; -#endif unsigned int pagecnt_bias = rx_buf->pagecnt_bias; struct page *page = rx_buf->page; @@ -678,7 +676,9 @@ static bool ice_can_reuse_rx_page(struct ice_rx_buf *rx_buf) if (unlikely((page_count(page) - pagecnt_bias) > 1)) return false; #else - if (rx_buf->page_offset > last_offset) +#define ICE_LAST_OFFSET \ + (SKB_WITH_OVERHEAD(PAGE_SIZE) - ICE_RXBUF_2048) + if (rx_buf->page_offset > ICE_LAST_OFFSET) return false; #endif /* PAGE_SIZE < 8192) */ @@ -696,6 +696,7 @@ static bool ice_can_reuse_rx_page(struct ice_rx_buf *rx_buf) /** * ice_add_rx_frag - Add contents of Rx buffer to sk_buff as a frag + * @rx_ring: Rx descriptor ring to transact packets on * @rx_buf: buffer containing page to add * @skb: sk_buff to place the data into * @size: packet length from rx_desc @@ -705,13 +706,13 @@ static bool ice_can_reuse_rx_page(struct ice_rx_buf *rx_buf) * The function will then update the page offset. */ static void -ice_add_rx_frag(struct ice_rx_buf *rx_buf, struct sk_buff *skb, - unsigned int size) +ice_add_rx_frag(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, + struct sk_buff *skb, unsigned int size) { #if (PAGE_SIZE >= 8192) unsigned int truesize = SKB_DATA_ALIGN(size); #else - unsigned int truesize = ICE_RXBUF_2048; + unsigned int truesize = ice_rx_pg_size(rx_ring) / 2; #endif if (!size) @@ -830,7 +831,7 @@ ice_construct_skb(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, #if (PAGE_SIZE >= 8192) unsigned int truesize = SKB_DATA_ALIGN(size); #else - unsigned int truesize = ICE_RXBUF_2048; + unsigned int truesize = ice_rx_pg_size(rx_ring) / 2; #endif skb_add_rx_frag(skb, 0, rx_buf->page, rx_buf->page_offset + headlen, size, truesize); @@ -873,8 +874,9 @@ static void ice_put_rx_buf(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) rx_ring->rx_stats.page_reuse_count++; } else { /* we are not reusing the buffer so unmap it */ - dma_unmap_page_attrs(rx_ring->dev, rx_buf->dma, PAGE_SIZE, - DMA_FROM_DEVICE, ICE_RX_DMA_ATTR); + dma_unmap_page_attrs(rx_ring->dev, rx_buf->dma, + ice_rx_pg_size(rx_ring), DMA_FROM_DEVICE, + ICE_RX_DMA_ATTR); __page_frag_cache_drain(rx_buf->page, rx_buf->pagecnt_bias); } @@ -1008,9 +1010,15 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) rcu_read_unlock(); if (xdp_res) { if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) { + unsigned int truesize; + +#if (PAGE_SIZE < 8192) + truesize = ice_rx_pg_size(rx_ring) / 2; +#else + truesize = SKB_DATA_ALIGN(size); +#endif xdp_xmit |= xdp_res; - ice_rx_buf_adjust_pg_offset(rx_buf, - ICE_RXBUF_2048); + ice_rx_buf_adjust_pg_offset(rx_buf, truesize); } else { rx_buf->pagecnt_bias++; } @@ -1023,7 +1031,7 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) } construct_skb: if (skb) - ice_add_rx_frag(rx_buf, skb, size); + ice_add_rx_frag(rx_ring, rx_buf, skb, size); else skb = ice_construct_skb(rx_ring, rx_buf, &xdp); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index d5d243b8e69f..6a6e3d2339ba 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -7,7 +7,9 @@ #include "ice_type.h" #define ICE_DFLT_IRQ_WORK 256 +#define ICE_RXBUF_3072 3072 #define ICE_RXBUF_2048 2048 +#define ICE_RXBUF_1536 1536 #define ICE_MAX_CHAINED_RX_BUFS 5 #define ICE_MAX_BUF_TXD 8 #define ICE_MIN_TX_LEN 17 @@ -262,6 +264,17 @@ struct ice_ring_container { #define ice_for_each_ring(pos, head) \ for (pos = (head).ring; pos; pos = pos->next) +static inline unsigned int ice_rx_pg_order(struct ice_ring *ring) +{ +#if (PAGE_SIZE < 8192) + if (ring->rx_buf_len > (PAGE_SIZE / 2)) + return 1; +#endif + return 0; +} + +#define ice_rx_pg_size(_ring) (PAGE_SIZE << ice_rx_pg_order(_ring)) + union ice_32b_rx_flex_desc; bool ice_alloc_rx_bufs(struct ice_ring *rxr, u16 cleaned_count); -- cgit v1.2.3-59-g8ed1b From 59bb08080557589aaf577a99d329ccea38b55c95 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 24 Oct 2019 01:11:23 -0700 Subject: ice: introduce frame padding computation logic Take into account the underlying architecture specific settings and based on that calculate the possible padding that can be supplied. Typically, for x86 and standard MTU size we will end up with 192 bytes of headroom. This is the same behavior as our other drivers have and we can dedicate it for XDP purposes. Furthermore, introduce the Rx ring flag for indicating whether build_skb is used on particular. Based on that invoke the routines for padding calculation. Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_base.c | 6 +++ drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_lib.c | 3 +- drivers/net/ethernet/intel/ice/ice_txrx.c | 42 ++++++++------- drivers/net/ethernet/intel/ice/ice_txrx.h | 81 ++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 2904de054c10..69d2da14fe5c 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -406,6 +406,12 @@ int ice_setup_rx_ctx(struct ice_ring *ring) if (vsi->type == ICE_VSI_VF) return 0; + /* configure Rx buffer alignment */ + if (!vsi->netdev || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) + ice_clear_ring_build_skb_ena(ring); + else + ice_set_ring_build_skb_ena(ring); + /* init queue specific tail register */ ring->tail = hw->hw_addr + QRX_TAIL(pf_q); writel(0, ring->tail); diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index c1737625bbc2..7e779060069c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -624,7 +624,7 @@ static int ice_lbtest_receive_frames(struct ice_ring *rx_ring) continue; rx_buf = &rx_ring->rx_buf[i]; - received_buf = page_address(rx_buf->page); + received_buf = page_address(rx_buf->page) + rx_buf->page_offset; if (ice_lbtest_check_frame(received_buf)) valid_frames++; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index 76569caec469..b1e96cac5b1f 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1194,7 +1194,8 @@ void ice_vsi_cfg_frame_size(struct ice_vsi *vsi) vsi->max_frame = ICE_AQ_SET_MAC_FRAME_SIZE_MAX; vsi->rx_buf_len = ICE_RXBUF_2048; #if (PAGE_SIZE < 8192) - } else if (vsi->netdev->mtu <= ETH_DATA_LEN) { + } else if (!ICE_2K_TOO_SMALL_WITH_PADDING && + (vsi->netdev->mtu <= ETH_DATA_LEN)) { vsi->max_frame = ICE_RXBUF_1536 - NET_IP_ALIGN; vsi->rx_buf_len = ICE_RXBUF_1536 - NET_IP_ALIGN; #endif diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 9528bd69d6b4..bd1f73af468c 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -415,7 +415,12 @@ err: */ static unsigned int ice_rx_offset(struct ice_ring *rx_ring) { - return ice_is_xdp_ena_vsi(rx_ring->vsi) ? XDP_PACKET_HEADROOM : 0; + if (ice_ring_uses_build_skb(rx_ring)) + return ICE_SKB_PAD; + else if (ice_is_xdp_ena_vsi(rx_ring->vsi)) + return XDP_PACKET_HEADROOM; + + return 0; } /** @@ -710,7 +715,7 @@ ice_add_rx_frag(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, struct sk_buff *skb, unsigned int size) { #if (PAGE_SIZE >= 8192) - unsigned int truesize = SKB_DATA_ALIGN(size); + unsigned int truesize = SKB_DATA_ALIGN(size + ice_rx_offset(rx_ring)); #else unsigned int truesize = ice_rx_pg_size(rx_ring) / 2; #endif @@ -1008,27 +1013,28 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) xdp_res = ice_run_xdp(rx_ring, &xdp, xdp_prog); rcu_read_unlock(); - if (xdp_res) { - if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) { - unsigned int truesize; + if (!xdp_res) + goto construct_skb; + if (xdp_res & (ICE_XDP_TX | ICE_XDP_REDIR)) { + unsigned int truesize; #if (PAGE_SIZE < 8192) - truesize = ice_rx_pg_size(rx_ring) / 2; + truesize = ice_rx_pg_size(rx_ring) / 2; #else - truesize = SKB_DATA_ALIGN(size); + truesize = SKB_DATA_ALIGN(ice_rx_offset(rx_ring) + + size); #endif - xdp_xmit |= xdp_res; - ice_rx_buf_adjust_pg_offset(rx_buf, truesize); - } else { - rx_buf->pagecnt_bias++; - } - total_rx_bytes += size; - total_rx_pkts++; - - cleaned_count++; - ice_put_rx_buf(rx_ring, rx_buf); - continue; + xdp_xmit |= xdp_res; + ice_rx_buf_adjust_pg_offset(rx_buf, truesize); + } else { + rx_buf->pagecnt_bias++; } + total_rx_bytes += size; + total_rx_pkts++; + + cleaned_count++; + ice_put_rx_buf(rx_ring, rx_buf); + continue; construct_skb: if (skb) ice_add_rx_frag(rx_ring, rx_buf, skb, size); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 6a6e3d2339ba..a84cc0e6dd27 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -26,6 +26,71 @@ #define ICE_RX_BUF_WRITE 16 /* Must be power of 2 */ #define ICE_MAX_TXQ_PER_TXQG 128 +/* Attempt to maximize the headroom available for incoming frames. We use a 2K + * buffer for MTUs <= 1500 and need 1536/1534 to store the data for the frame. + * This leaves us with 512 bytes of room. From that we need to deduct the + * space needed for the shared info and the padding needed to IP align the + * frame. + * + * Note: For cache line sizes 256 or larger this value is going to end + * up negative. In these cases we should fall back to the legacy + * receive path. + */ +#if (PAGE_SIZE < 8192) +#define ICE_2K_TOO_SMALL_WITH_PADDING \ +((NET_SKB_PAD + ICE_RXBUF_1536) > SKB_WITH_OVERHEAD(ICE_RXBUF_2048)) + +/** + * ice_compute_pad - compute the padding + * rx_buf_len: buffer length + * + * Figure out the size of half page based on given buffer length and + * then subtract the skb_shared_info followed by subtraction of the + * actual buffer length; this in turn results in the actual space that + * is left for padding usage + */ +static inline int ice_compute_pad(int rx_buf_len) +{ + int half_page_size; + + half_page_size = ALIGN(rx_buf_len, PAGE_SIZE / 2); + return SKB_WITH_OVERHEAD(half_page_size) - rx_buf_len; +} + +/** + * ice_skb_pad - determine the padding that we can supply + * + * Figure out the right Rx buffer size and based on that calculate the + * padding + */ +static inline int ice_skb_pad(void) +{ + int rx_buf_len; + + /* If a 2K buffer cannot handle a standard Ethernet frame then + * optimize padding for a 3K buffer instead of a 1.5K buffer. + * + * For a 3K buffer we need to add enough padding to allow for + * tailroom due to NET_IP_ALIGN possibly shifting us out of + * cache-line alignment. + */ + if (ICE_2K_TOO_SMALL_WITH_PADDING) + rx_buf_len = ICE_RXBUF_3072 + SKB_DATA_ALIGN(NET_IP_ALIGN); + else + rx_buf_len = ICE_RXBUF_1536; + + /* if needed make room for NET_IP_ALIGN */ + rx_buf_len -= NET_IP_ALIGN; + + return ice_compute_pad(rx_buf_len); +} + +#define ICE_SKB_PAD ice_skb_pad() +#else +#define ICE_2K_TOO_SMALL_WITH_PADDING false +#define ICE_SKB_PAD (NET_SKB_PAD + NET_IP_ALIGN) +#endif + /* We are assuming that the cache line is always 64 Bytes here for ice. * In order to make sure that is a correct assumption there is a check in probe * to print a warning if the read from GLPCI_CNF2 tells us that the cache line @@ -231,6 +296,7 @@ struct ice_ring { * in their own cache line if possible */ #define ICE_TX_FLAGS_RING_XDP BIT(0) +#define ICE_RX_FLAGS_RING_BUILD_SKB BIT(1) u8 flags; dma_addr_t dma; /* physical address of ring */ unsigned int size; /* length of descriptor ring in bytes */ @@ -239,6 +305,21 @@ struct ice_ring { u8 dcb_tc; /* Traffic class of ring */ } ____cacheline_internodealigned_in_smp; +static inline bool ice_ring_uses_build_skb(struct ice_ring *ring) +{ + return !!(ring->flags & ICE_RX_FLAGS_RING_BUILD_SKB); +} + +static inline void ice_set_ring_build_skb_ena(struct ice_ring *ring) +{ + ring->flags |= ICE_RX_FLAGS_RING_BUILD_SKB; +} + +static inline void ice_clear_ring_build_skb_ena(struct ice_ring *ring) +{ + ring->flags &= ~ICE_RX_FLAGS_RING_BUILD_SKB; +} + static inline bool ice_ring_is_xdp(struct ice_ring *ring) { return !!(ring->flags & ICE_TX_FLAGS_RING_XDP); -- cgit v1.2.3-59-g8ed1b From aaf27254fdf9054c00cf2a9c479a52a16204d768 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 24 Oct 2019 01:11:24 -0700 Subject: ice: add build_skb() support Driver is now prepared for building the skb around the existing Rx buffer, so introduce the ice_build_skb responsible for it. Make use of XDP's data_meta as well. I've observed around 30% less CPU consumption with build_skb Rx path, in comparison to legacy Rx. What stands behind such result is the avoidance of flow_dissector (which we were diving into via eth_get_headlen) and no memcpy calls. Signed-off-by: Maciej Fijalkowski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_txrx.c | 60 ++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index bd1f73af468c..40a29b9d3034 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -790,6 +790,60 @@ ice_get_rx_buf(struct ice_ring *rx_ring, struct sk_buff **skb, return rx_buf; } +/** + * ice_build_skb - Build skb around an existing buffer + * @rx_ring: Rx descriptor ring to transact packets on + * @rx_buf: Rx buffer to pull data from + * @xdp: xdp_buff pointing to the data + * + * This function builds an skb around an existing Rx buffer, taking care + * to set up the skb correctly and avoid any memcpy overhead. + */ +static struct sk_buff * +ice_build_skb(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf, + struct xdp_buff *xdp) +{ + unsigned int metasize = xdp->data - xdp->data_meta; +#if (PAGE_SIZE < 8192) + unsigned int truesize = ice_rx_pg_size(rx_ring) / 2; +#else + unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) + + SKB_DATA_ALIGN(xdp->data_end - + xdp->data_hard_start); +#endif + struct sk_buff *skb; + + /* Prefetch first cache line of first page. If xdp->data_meta + * is unused, this points exactly as xdp->data, otherwise we + * likely have a consumer accessing first few bytes of meta + * data, and then actual data. + */ + prefetch(xdp->data_meta); +#if L1_CACHE_BYTES < 128 + prefetch((void *)(xdp->data + L1_CACHE_BYTES)); +#endif + /* build an skb around the page buffer */ + skb = build_skb(xdp->data_hard_start, truesize); + if (unlikely(!skb)) + return NULL; + + /* must to record Rx queue, otherwise OS features such as + * symmetric queue won't work + */ + skb_record_rx_queue(skb, rx_ring->q_index); + + /* update pointers within the skb to store the data */ + skb_reserve(skb, xdp->data - xdp->data_hard_start); + __skb_put(skb, xdp->data_end - xdp->data); + if (metasize) + skb_metadata_set(skb, metasize); + + /* buffer is used by skb, update page_offset */ + ice_rx_buf_adjust_pg_offset(rx_buf, truesize); + + return skb; +} + /** * ice_construct_skb - Allocate skb and populate it * @rx_ring: Rx descriptor ring to transact packets on @@ -996,12 +1050,14 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) if (!size) { xdp.data = NULL; xdp.data_end = NULL; + xdp.data_hard_start = NULL; + xdp.data_meta = NULL; goto construct_skb; } xdp.data = page_address(rx_buf->page) + rx_buf->page_offset; xdp.data_hard_start = xdp.data - ice_rx_offset(rx_ring); - xdp_set_data_meta_invalid(&xdp); + xdp.data_meta = xdp.data; xdp.data_end = xdp.data + size; rcu_read_lock(); @@ -1038,6 +1094,8 @@ static int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) construct_skb: if (skb) ice_add_rx_frag(rx_ring, rx_buf, skb, size); + else if (ice_ring_uses_build_skb(rx_ring)) + skb = ice_build_skb(rx_ring, rx_buf, &xdp); else skb = ice_construct_skb(rx_ring, rx_buf, &xdp); -- cgit v1.2.3-59-g8ed1b From 23b44513c3e6f999fb9ddc2874979317d8329e96 Mon Sep 17 00:00:00 2001 From: Maciej Fijalkowski Date: Thu, 24 Oct 2019 01:11:25 -0700 Subject: ice: allow 3k MTU for XDP At this point ice driver is able to work on order 1 pages that are split onto two 3k buffers. Let's reflect that when user is setting new MTU size and XDP is present on interface. Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 29eea08807fd..363b284e8aa1 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4658,6 +4658,18 @@ clear_recovery: dev_err(dev, "Rebuild failed, unload and reload driver\n"); } +/** + * ice_max_xdp_frame_size - returns the maximum allowed frame size for XDP + * @vsi: Pointer to VSI structure + */ +static int ice_max_xdp_frame_size(struct ice_vsi *vsi) +{ + if (PAGE_SIZE >= 8192 || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) + return ICE_RXBUF_2048 - XDP_PACKET_HEADROOM; + else + return ICE_RXBUF_3072; +} + /** * ice_change_mtu - NDO callback to change the MTU * @netdev: network interface device structure @@ -4678,11 +4690,11 @@ static int ice_change_mtu(struct net_device *netdev, int new_mtu) } if (ice_is_xdp_ena_vsi(vsi)) { - int frame_size = ICE_RXBUF_2048 - XDP_PACKET_HEADROOM; + int frame_size = ice_max_xdp_frame_size(vsi); if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) { netdev_err(netdev, "max MTU for XDP usage is %d\n", - frame_size); + frame_size - ICE_ETH_PKT_HDR_PAD); return -EINVAL; } } -- cgit v1.2.3-59-g8ed1b From 1df96ca7e001f08cb347a022e0a6a3e45869dd21 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 19 Feb 2019 14:26:27 -0800 Subject: fm10k: add missing field initializers to TLV attributes) Add the missing field initializers for a couple of the TLV attribute macros. This resolves the last few -Wmissing-field-initializers warnings for the fm10k Linux driver. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_tlv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h b/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h index 160bc5b78f99..ceb9b791f799 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_tlv.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright(c) 2013 - 2018 Intel Corporation. */ +/* Copyright(c) 2013 - 2019 Intel Corporation. */ #ifndef _FM10K_TLV_H_ #define _FM10K_TLV_H_ @@ -76,8 +76,8 @@ struct fm10k_tlv_attr { #define FM10K_TLV_ATTR_S32(id) { id, FM10K_TLV_SIGNED, 4 } #define FM10K_TLV_ATTR_S64(id) { id, FM10K_TLV_SIGNED, 8 } #define FM10K_TLV_ATTR_LE_STRUCT(id, len) { id, FM10K_TLV_LE_STRUCT, len } -#define FM10K_TLV_ATTR_NESTED(id) { id, FM10K_TLV_NESTED } -#define FM10K_TLV_ATTR_LAST { FM10K_TLV_ERROR } +#define FM10K_TLV_ATTR_NESTED(id) { id, FM10K_TLV_NESTED, 0 } +#define FM10K_TLV_ATTR_LAST { FM10K_TLV_ERROR, 0, 0 } struct fm10k_msg_data { unsigned int id; -- cgit v1.2.3-59-g8ed1b From 0e100440e24b365ea3ba81777666ee9030ecfd00 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Tue, 20 Aug 2019 14:19:21 -0700 Subject: fm10k: add support for ndo_get_vf_stats operation Support capturing and reporting statistics for all of the VFs associated with a given PF device via the ndo_get_vf_stats callback. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k.h | 3 ++ drivers/net/ethernet/intel/fm10k/fm10k_iov.c | 48 +++++++++++++++++++++++++ drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 1 + drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 3 ++ drivers/net/ethernet/intel/fm10k/fm10k_type.h | 1 + 5 files changed, 56 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index b14441944b4b..f306084ca12c 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h @@ -534,6 +534,7 @@ void fm10k_iov_suspend(struct pci_dev *pdev); int fm10k_iov_resume(struct pci_dev *pdev); void fm10k_iov_disable(struct pci_dev *pdev); int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs); +void fm10k_iov_update_stats(struct fm10k_intfc *interface); s32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid); int fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac); int fm10k_ndo_set_vf_vlan(struct net_device *netdev, @@ -542,6 +543,8 @@ int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int __always_unused min_rate, int max_rate); int fm10k_ndo_get_vf_config(struct net_device *netdev, int vf_idx, struct ifla_vf_info *ivi); +int fm10k_ndo_get_vf_stats(struct net_device *netdev, + int vf_idx, struct ifla_vf_stats *stats); /* DebugFS */ #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c index afe1fafd2447..8c50a128df29 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c @@ -520,6 +520,27 @@ int fm10k_iov_configure(struct pci_dev *pdev, int num_vfs) return num_vfs; } +/** + * fm10k_iov_update_stats - Update stats for all VFs + * @interface: device private structure + * + * Updates the VF statistics for all enabled VFs. Expects to be called by + * fm10k_update_stats and assumes that locking via the __FM10K_UPDATING_STATS + * bit is already handled. + */ +void fm10k_iov_update_stats(struct fm10k_intfc *interface) +{ + struct fm10k_iov_data *iov_data = interface->iov_data; + struct fm10k_hw *hw = &interface->hw; + int i; + + if (!iov_data) + return; + + for (i = 0; i < iov_data->num_vfs; i++) + hw->iov.ops.update_stats(hw, iov_data->vf_info[i].stats, i); +} + static inline void fm10k_reset_vf_info(struct fm10k_intfc *interface, struct fm10k_vf_info *vf_info) { @@ -650,3 +671,30 @@ int fm10k_ndo_get_vf_config(struct net_device *netdev, return 0; } + +int fm10k_ndo_get_vf_stats(struct net_device *netdev, + int vf_idx, struct ifla_vf_stats *stats) +{ + struct fm10k_intfc *interface = netdev_priv(netdev); + struct fm10k_iov_data *iov_data = interface->iov_data; + struct fm10k_hw *hw = &interface->hw; + struct fm10k_hw_stats_q *hw_stats; + u32 idx, qpp; + + /* verify SR-IOV is active and that vf idx is valid */ + if (!iov_data || vf_idx >= iov_data->num_vfs) + return -EINVAL; + + qpp = fm10k_queues_per_pool(hw); + hw_stats = iov_data->vf_info[vf_idx].stats; + + for (idx = 0; idx < qpp; idx++) { + stats->rx_packets += hw_stats[idx].rx_packets.count; + stats->tx_packets += hw_stats[idx].tx_packets.count; + stats->rx_bytes += hw_stats[idx].rx_bytes.count; + stats->tx_bytes += hw_stats[idx].tx_bytes.count; + stats->rx_dropped += hw_stats[idx].rx_drops.count; + } + + return 0; +} diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 09f7a246e134..68baee04dc58 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -1643,6 +1643,7 @@ static const struct net_device_ops fm10k_netdev_ops = { .ndo_set_vf_vlan = fm10k_ndo_set_vf_vlan, .ndo_set_vf_rate = fm10k_ndo_set_vf_bw, .ndo_get_vf_config = fm10k_ndo_get_vf_config, + .ndo_get_vf_stats = fm10k_ndo_get_vf_stats, .ndo_udp_tunnel_add = fm10k_udp_tunnel_add, .ndo_udp_tunnel_del = fm10k_udp_tunnel_del, .ndo_dfwd_add_station = fm10k_dfwd_add_station, diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index bb236fa44048..d122d0087191 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -630,6 +630,9 @@ void fm10k_update_stats(struct fm10k_intfc *interface) net_stats->rx_errors = rx_errors; net_stats->rx_dropped = interface->stats.nodesc_drop.count; + /* Update VF statistics */ + fm10k_iov_update_stats(interface); + clear_bit(__FM10K_UPDATING_STATS, interface->state); } diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h index 15ac1c7885bc..63968c5d7c5d 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h @@ -581,6 +581,7 @@ struct fm10k_vf_info { * at the same offset as the mailbox */ struct fm10k_mbx_info mbx; /* PF side of VF mailbox */ + struct fm10k_hw_stats_q stats[FM10K_MAX_QUEUES_POOL]; int rate; /* Tx BW cap as defined by OS */ u16 glort; /* resource tag for this VF */ u16 sw_vid; /* Switch API assigned VLAN */ -- cgit v1.2.3-59-g8ed1b From 780e354dcdb911351c624e11a86e9b3155d4e7ab Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 20 Sep 2019 17:18:50 -0700 Subject: ixgbe: Make use of cpumask_local_spread to improve RSS locality This patch is meant to address locality issues present in the ixgbe driver when it is loaded on a system supporting multiple NUMA nodes and more CPUs then the device can map in a 1:1 fashion. Instead of just arbitrarily mapping itself to CPUs 0-62 it would make much more sense to map itself to the local CPUs first, and then map itself to any remaining CPUs that might be used. The first effect of this is that queue 0 should always be allocated on the local CPU/NUMA node. This is important as it is the default destination if a packet doesn't match any existing flow director filter or RSS rule and as such having it local should help to reduce QPI cross-talk in the event of an unrecognized traffic type. In addition this should increase the likelihood of the RSS queues being allocated and used on CPUs local to the device while the ATR/Flow Director queues would be able to route traffic directly to the CPU that is likely to be processing it. Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index cc3196ae5aea..fd9f5d41b594 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -832,9 +832,9 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, int xdp_count, int xdp_idx, int rxr_count, int rxr_idx) { + int node = dev_to_node(&adapter->pdev->dev); struct ixgbe_q_vector *q_vector; struct ixgbe_ring *ring; - int node = NUMA_NO_NODE; int cpu = -1; int ring_count; u8 tcs = adapter->hw_tcs; @@ -845,10 +845,8 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, if ((tcs <= 1) && !(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) { u16 rss_i = adapter->ring_feature[RING_F_RSS].indices; if (rss_i > 1 && adapter->atr_sample_rate) { - if (cpu_online(v_idx)) { - cpu = v_idx; - node = cpu_to_node(cpu); - } + cpu = cpumask_local_spread(v_idx, node); + node = cpu_to_node(cpu); } } -- cgit v1.2.3-59-g8ed1b From 739e6b4a837485f21900c97f2ec0e0ddfaa6aea5 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Thu, 26 Sep 2019 14:29:04 -0700 Subject: fm10k: update driver version to match out-of-tree An upcoming out-of-tree release will be occurring which will include the recent functionality to support virtual function statistics. Update the kernel driver version to match this. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 2be9222510e7..17738b0a9873 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -11,7 +11,7 @@ #include "fm10k.h" -#define DRV_VERSION "0.26.1-k" +#define DRV_VERSION "0.27.1-k" #define DRV_SUMMARY "Intel(R) Ethernet Switch Host Interface Driver" const char fm10k_driver_version[] = DRV_VERSION; char fm10k_driver_name[] = "fm10k"; -- cgit v1.2.3-59-g8ed1b From 07066d9dc3d2326fbad8f7b0cb0120cff7b7dedb Mon Sep 17 00:00:00 2001 From: Manjunath Patil Date: Sat, 5 Oct 2019 08:20:03 -0700 Subject: ixgbe: protect TX timestamping from API misuse HW timestamping can only be requested for a packet if the NIC is first setup via ioctl(SIOCSHWTSTAMP). If this step was skipped, then the ixgbe driver still allowed TX packets to request HW timestamping. In this situation, we see 'clearing Tx Timestamp hang' noise in the log. Fix this by checking that the NIC is configured for HW TX timestamping before accepting a HW TX timestamping request. Similar-to: commit 26bd4e2db06b ("igb: protect TX timestamping from API misuse") commit 0a6f2f05a2f5 ("igb: Fix a test with HWTSTAMP_TX_ON") Signed-off-by: Manjunath Patil Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index b22baea9d39b..1129ae70d5fb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8649,7 +8649,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && adapter->ptp_clock) { - if (!test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, + if (adapter->tstamp_config.tx_type == HWTSTAMP_TX_ON && + !test_and_set_bit_lock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state)) { skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_flags |= IXGBE_TX_FLAGS_TSTAMP; -- cgit v1.2.3-59-g8ed1b From 3df5b9a6a9ec3c1e4431bf1db3426b54dc92dd91 Mon Sep 17 00:00:00 2001 From: Alice Michael Date: Wed, 23 Oct 2019 03:19:57 -0700 Subject: i40e: enable X710 support The I40E_DEV_ID_10G_BASE_T_BC device id was added previously, but was not enabled in all the appropriate places. Adding it to enable it's use. Signed-off-by: Alice Michael Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 8b25a6d9c81d..a0791447849a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -29,6 +29,7 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) case I40E_DEV_ID_QSFP_C: case I40E_DEV_ID_10G_BASE_T: case I40E_DEV_ID_10G_BASE_T4: + case I40E_DEV_ID_10G_BASE_T_BC: case I40E_DEV_ID_10G_B: case I40E_DEV_ID_10G_SFP: case I40E_DEV_ID_20G_KR2: @@ -4910,6 +4911,7 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw, break; case I40E_DEV_ID_10G_BASE_T: case I40E_DEV_ID_10G_BASE_T4: + case I40E_DEV_ID_10G_BASE_T_BC: case I40E_DEV_ID_10G_BASE_T_X722: case I40E_DEV_ID_25G_B: case I40E_DEV_ID_25G_SFP28: -- cgit v1.2.3-59-g8ed1b From dc645daef9af5bcbd9c5c73370dc7f96761ff186 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 28 Oct 2019 17:37:07 -0700 Subject: i40e: implement VF stats NDO Implement the VF stats gathering via the kernel via ndo_get_vf_stats(). The driver will show per-VF stats in the output of the command: ip -s link show dev Testing Hints: ip -s link show dev eth0 will return non-zero VF stats. ... vf 0 MAC 00:55:aa:00:55:aa, spoof checking on, link-state enable, trust off RX: bytes packets mcast bcast 128000 1000 104 104 TX: bytes packets 128000 1000 Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 48 ++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 2 + 3 files changed, 51 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b3d7edbb1389..9fac1cea6fa5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -12870,6 +12870,7 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_set_features = i40e_set_features, .ndo_set_vf_mac = i40e_ndo_set_vf_mac, .ndo_set_vf_vlan = i40e_ndo_set_vf_port_vlan, + .ndo_get_vf_stats = i40e_get_vf_stats, .ndo_set_vf_rate = i40e_ndo_set_vf_bw, .ndo_get_vf_config = i40e_ndo_get_vf_config, .ndo_set_vf_link_state = i40e_ndo_set_vf_link_state, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index a2710664d653..6a3f0fc56c3b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -4524,3 +4524,51 @@ out: clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state); return ret; } + +/** + * i40e_get_vf_stats - populate some stats for the VF + * @netdev: the netdev of the PF + * @vf_id: the host OS identifier (0-127) + * @vf_stats: pointer to the OS memory to be initialized + */ +int i40e_get_vf_stats(struct net_device *netdev, int vf_id, + struct ifla_vf_stats *vf_stats) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_eth_stats *stats; + struct i40e_vsi *vsi; + struct i40e_vf *vf; + + /* validate the request */ + if (i40e_validate_vf(pf, vf_id)) + return -EINVAL; + + vf = &pf->vf[vf_id]; + if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) { + dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); + return -EBUSY; + } + + vsi = pf->vsi[vf->lan_vsi_idx]; + if (!vsi) + return -EINVAL; + + i40e_update_eth_stats(vsi); + stats = &vsi->eth_stats; + + memset(vf_stats, 0, sizeof(*vf_stats)); + + vf_stats->rx_packets = stats->rx_unicast + stats->rx_broadcast + + stats->rx_multicast; + vf_stats->tx_packets = stats->tx_unicast + stats->tx_broadcast + + stats->tx_multicast; + vf_stats->rx_bytes = stats->rx_bytes; + vf_stats->tx_bytes = stats->tx_bytes; + vf_stats->broadcast = stats->rx_broadcast; + vf_stats->multicast = stats->rx_multicast; + vf_stats->rx_dropped = stats->rx_discards; + vf_stats->tx_dropped = stats->tx_discards; + + return 0; +} diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 1ce06240a702..631248c0981a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -138,5 +138,7 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable); void i40e_vc_notify_link_state(struct i40e_pf *pf); void i40e_vc_notify_reset(struct i40e_pf *pf); +int i40e_get_vf_stats(struct net_device *netdev, int vf_id, + struct ifla_vf_stats *vf_stats); #endif /* _I40E_VIRTCHNL_PF_H_ */ -- cgit v1.2.3-59-g8ed1b From df9f540ca74297a84bafacfa197e9347b20beea5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 1 Nov 2019 16:42:37 -0700 Subject: hv_netvsc: flag software created hash value When the driver needs to create a hash value because it was not done at higher level, then the hash should be marked as a software not hardware hash. Fixes: f72860afa2e3 ("hv_netvsc: Exclude non-TCP port numbers from vRSS hashing") Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 963509add611..e5e43db4acf2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -285,9 +285,9 @@ static inline u32 netvsc_get_hash( else if (flow.basic.n_proto == htons(ETH_P_IPV6)) hash = jhash2((u32 *)&flow.addrs.v6addrs, 8, hashrnd); else - hash = 0; + return 0; - skb_set_hash(skb, hash, PKT_HASH_TYPE_L3); + __skb_set_sw_hash(skb, hash, false); } return hash; @@ -795,8 +795,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, skb->protocol == htons(ETH_P_IP)) netvsc_comp_ipcsum(skb); - /* Do L4 checksum offload if enabled and present. - */ + /* Do L4 checksum offload if enabled and present. */ if (csum_info && (net->features & NETIF_F_RXCSUM)) { if (csum_info->receive.tcp_checksum_succeeded || csum_info->receive.udp_checksum_succeeded) -- cgit v1.2.3-59-g8ed1b From 1fac7ca4e63bf935780cc632ccb6ba8de5f22321 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 1 Nov 2019 16:42:38 -0700 Subject: hv_netvsc: record hardware hash in skb Since RSS hash is available from the host, record it in the skb. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc_drv.c | 4 ++++ drivers/net/hyperv/rndis_filter.c | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 670ef682f268..4209d1cf57f6 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -853,6 +853,7 @@ struct multi_recv_comp { struct nvsc_rsc { const struct ndis_pkt_8021q_info *vlan; const struct ndis_tcp_ip_checksum_info *csum_info; + const u32 *hash_info; u8 is_last; /* last RNDIS msg in a vmtransfer_page */ u32 cnt; /* #fragments in an RSC packet */ u32 pktlen; /* Full packet length */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index e5e43db4acf2..5fa5c49e481b 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -766,6 +766,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, const struct ndis_pkt_8021q_info *vlan = nvchan->rsc.vlan; const struct ndis_tcp_ip_checksum_info *csum_info = nvchan->rsc.csum_info; + const u32 *hash_info = nvchan->rsc.hash_info; struct sk_buff *skb; int i; @@ -802,6 +803,9 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, skb->ip_summed = CHECKSUM_UNNECESSARY; } + if (hash_info) + skb_set_hash(skb, *hash_info, PKT_HASH_TYPE_L4); + if (vlan) { u16 vlan_tci = vlan->vlanid | (vlan->pri << VLAN_PRIO_SHIFT) | (vlan->cfi ? VLAN_CFI_MASK : 0); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index abaf8156d19d..c06178380ac8 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -358,6 +358,7 @@ static inline void rsc_add_data(struct netvsc_channel *nvchan, const struct ndis_pkt_8021q_info *vlan, const struct ndis_tcp_ip_checksum_info *csum_info, + const u32 *hash_info, void *data, u32 len) { u32 cnt = nvchan->rsc.cnt; @@ -368,6 +369,7 @@ void rsc_add_data(struct netvsc_channel *nvchan, nvchan->rsc.vlan = vlan; nvchan->rsc.csum_info = csum_info; nvchan->rsc.pktlen = len; + nvchan->rsc.hash_info = hash_info; } nvchan->rsc.data[cnt] = data; @@ -385,6 +387,7 @@ static int rndis_filter_receive_data(struct net_device *ndev, const struct ndis_tcp_ip_checksum_info *csum_info; const struct ndis_pkt_8021q_info *vlan; const struct rndis_pktinfo_id *pktinfo_id; + const u32 *hash_info; u32 data_offset; void *data; bool rsc_more = false; @@ -411,6 +414,8 @@ static int rndis_filter_receive_data(struct net_device *ndev, csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO, 0); + hash_info = rndis_get_ppi(rndis_pkt, NBL_HASH_VALUE, 0); + pktinfo_id = rndis_get_ppi(rndis_pkt, RNDIS_PKTINFO_ID, 1); data = (void *)msg + data_offset; @@ -441,7 +446,8 @@ static int rndis_filter_receive_data(struct net_device *ndev, * rndis_pkt->data_len tell us the real data length, we only copy * the data packet to the stack, without the rndis trailer padding */ - rsc_add_data(nvchan, vlan, csum_info, data, rndis_pkt->data_len); + rsc_add_data(nvchan, vlan, csum_info, hash_info, + data, rndis_pkt->data_len); if (rsc_more) return NVSP_STAT_SUCCESS; -- cgit v1.2.3-59-g8ed1b From a5ec65169c6000bb525b45cb5615dd98356dbf73 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 3 Nov 2019 13:15:38 +0000 Subject: net: hns3: remove unused macros The macros HCLGE_MPF_ENBALE and HCLGEVF_MPF_ENBALE are defined but never used. I was going to fix the spelling mistake "ENBALE" -> "ENABLE" but found these macros are not used, so they can be removed. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 -- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 599f76a05f41..1c0f6dfb95fc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -225,8 +225,6 @@ enum hclge_evt_cause { HCLGE_VECTOR0_EVENT_OTHER, }; -#define HCLGE_MPF_ENBALE 1 - enum HCLGE_MAC_SPEED { HCLGE_MAC_SPEED_UNKNOWN = 0, /* unknown */ HCLGE_MAC_SPEED_10M = 10, /* 10 Mbps */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index ef86155de9e0..2f4c81bf4169 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -150,8 +150,6 @@ enum hclgevf_states { HCLGEVF_STATE_CMD_DISABLE, }; -#define HCLGEVF_MPF_ENBALE 1 - struct hclgevf_mac { u8 media_type; u8 module_type; -- cgit v1.2.3-59-g8ed1b From eee87e4377a4b86dc2eea0ade162b0dc33f40576 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 4 Nov 2019 13:51:39 -0800 Subject: net: dsa: bcm_sf2: Add support for optional reset controller line Grab an optional and exclusive reset controller line for the switch and manage it during probe/remove functions accordingly. For 7278 devices we change bcm_sf2_sw_rst() to use the reset controller line since the WATCHDOG_CTRL register does not reset the switch contrary to stated documentation. Signed-off-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 19 +++++++++++++++++++ drivers/net/dsa/bcm_sf2.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 67125a5487e1..9ce5a0dbcde1 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -350,6 +350,18 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) { unsigned int timeout = 1000; u32 reg; + int ret; + + /* The watchdog reset does not work on 7278, we need to hit the + * "external" reset line through the reset controller. + */ + if (priv->type == BCM7278_DEVICE_ID && !IS_ERR(priv->rcdev)) { + ret = reset_control_assert(priv->rcdev); + if (ret) + return ret; + + return reset_control_deassert(priv->rcdev); + } reg = core_readl(priv, CORE_WATCHDOG_CTRL); reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET; @@ -1092,6 +1104,11 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) priv->core_reg_align = data->core_reg_align; priv->num_cfp_rules = data->num_cfp_rules; + priv->rcdev = devm_reset_control_get_optional_exclusive(&pdev->dev, + "switch"); + if (PTR_ERR(priv->rcdev) == -EPROBE_DEFER) + return PTR_ERR(priv->rcdev); + /* Auto-detection using standard registers will not work, so * provide an indication of what kind of device we are for * b53_common to work with @@ -1224,6 +1241,8 @@ static int bcm_sf2_sw_remove(struct platform_device *pdev) /* Disable all ports and interrupts */ bcm_sf2_sw_suspend(priv->dev->ds); bcm_sf2_mdio_unregister(priv); + if (priv->type == BCM7278_DEVICE_ID && !IS_ERR(priv->rcdev)) + reset_control_assert(priv->rcdev); return 0; } diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h index 1df30ccec42d..de386dd96d66 100644 --- a/drivers/net/dsa/bcm_sf2.h +++ b/drivers/net/dsa/bcm_sf2.h @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -64,6 +65,8 @@ struct bcm_sf2_priv { void __iomem *fcb; void __iomem *acb; + struct reset_control *rcdev; + /* Register offsets indirection tables */ u32 type; const u16 *reg_offsets; -- cgit v1.2.3-59-g8ed1b From d9ea56206c4df77175321874544eb4ca48c0bac8 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 5 Nov 2019 01:12:58 +0100 Subject: net: dsa: mv88e6xxx: Add number of MACs in the ATU For each supported switch, add an entry to the info structure for the number of MACs which can be stored in the ATU. This will later be used to export the ATU as a devlink resource, and indicate its occupancy, how full the ATU is. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 25 +++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 6 ++++++ 2 files changed, 31 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 66de492117ad..3540ca2e3b6f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4299,6 +4299,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6097, .name = "Marvell 88E6085", .num_databases = 4096, + .num_macs = 8192, .num_ports = 10, .num_internal_phys = 5, .max_vid = 4095, @@ -4321,6 +4322,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6095, .name = "Marvell 88E6095/88E6095F", .num_databases = 256, + .num_macs = 8192, .num_ports = 11, .num_internal_phys = 0, .max_vid = 4095, @@ -4341,6 +4343,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6097, .name = "Marvell 88E6097/88E6097F", .num_databases = 4096, + .num_macs = 8192, .num_ports = 11, .num_internal_phys = 8, .max_vid = 4095, @@ -4363,6 +4366,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6123", .num_databases = 4096, + .num_macs = 1024, .num_ports = 3, .num_internal_phys = 5, .max_vid = 4095, @@ -4385,6 +4389,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6185, .name = "Marvell 88E6131", .num_databases = 256, + .num_macs = 8192, .num_ports = 8, .num_internal_phys = 0, .max_vid = 4095, @@ -4405,6 +4410,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6341, .name = "Marvell 88E6141", .num_databases = 4096, + .num_macs = 2048, .num_ports = 6, .num_internal_phys = 5, .num_gpio = 11, @@ -4428,6 +4434,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6161", .num_databases = 4096, + .num_macs = 1024, .num_ports = 6, .num_internal_phys = 5, .max_vid = 4095, @@ -4451,6 +4458,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6165, .name = "Marvell 88E6165", .num_databases = 4096, + .num_macs = 8192, .num_ports = 6, .num_internal_phys = 0, .max_vid = 4095, @@ -4474,6 +4482,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6171", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .max_vid = 4095, @@ -4496,6 +4505,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6172", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4519,6 +4529,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6175", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .max_vid = 4095, @@ -4541,6 +4552,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6176", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4564,6 +4576,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6185, .name = "Marvell 88E6185", .num_databases = 256, + .num_macs = 8192, .num_ports = 10, .num_internal_phys = 0, .max_vid = 4095, @@ -4584,6 +4597,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6190", .num_databases = 4096, + .num_macs = 16384, .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .num_gpio = 16, @@ -4607,6 +4621,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6190X", .num_databases = 4096, + .num_macs = 16384, .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .num_gpio = 16, @@ -4630,6 +4645,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6191", .num_databases = 4096, + .num_macs = 16384, .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .max_vid = 8191, @@ -4680,6 +4696,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6240", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4750,6 +4767,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6320, .name = "Marvell 88E6320", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4774,6 +4792,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6320, .name = "Marvell 88E6321", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4797,6 +4816,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6341, .name = "Marvell 88E6341", .num_databases = 4096, + .num_macs = 2048, .num_internal_phys = 5, .num_ports = 6, .num_gpio = 11, @@ -4821,6 +4841,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6350", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .max_vid = 4095, @@ -4843,6 +4864,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6351, .name = "Marvell 88E6351", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .max_vid = 4095, @@ -4865,6 +4887,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6352, .name = "Marvell 88E6352", .num_databases = 4096, + .num_macs = 8192, .num_ports = 7, .num_internal_phys = 5, .num_gpio = 15, @@ -4888,6 +4911,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6390", .num_databases = 4096, + .num_macs = 16384, .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .num_gpio = 16, @@ -4911,6 +4935,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .family = MV88E6XXX_FAMILY_6390, .name = "Marvell 88E6390X", .num_databases = 4096, + .num_macs = 16384, .num_ports = 11, /* 10 + Z80 */ .num_internal_phys = 9, .num_gpio = 16, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 52f7726cc099..65ce09bdcbcf 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -94,6 +94,7 @@ struct mv88e6xxx_info { u16 prod_num; const char *name; unsigned int num_databases; + unsigned int num_macs; unsigned int num_ports; unsigned int num_internal_phys; unsigned int num_gpio; @@ -613,6 +614,11 @@ static inline unsigned int mv88e6xxx_num_databases(struct mv88e6xxx_chip *chip) return chip->info->num_databases; } +static inline unsigned int mv88e6xxx_num_macs(struct mv88e6xxx_chip *chip) +{ + return chip->info->num_macs; +} + static inline unsigned int mv88e6xxx_num_ports(struct mv88e6xxx_chip *chip) { return chip->info->num_ports; -- cgit v1.2.3-59-g8ed1b From 6239a386e784aed13c3ead54c3992ebcb0512d5f Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 5 Nov 2019 01:12:59 +0100 Subject: net: dsa: mv88e6xxx: global2: Expose ATU stats register Add helpers to set/get the ATU statistics register. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.c | 20 ++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/global2.h | 24 +++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index bdbb72fc20ed..14954d92c564 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -280,6 +280,26 @@ int mv88e6xxx_g2_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) return err; } +/* Offset 0x0E: ATU Statistics */ + +int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin) +{ + return mv88e6xxx_g2_write(chip, MV88E6XXX_G2_ATU_STATS, + kind | bin); +} + +int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip) +{ + int err; + u16 val; + + err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, &val); + if (err) + return err; + + return val & MV88E6XXX_G2_ATU_STATS_MASK; +} + /* Offset 0x0F: Priority Override Table */ static int mv88e6xxx_g2_pot_write(struct mv88e6xxx_chip *chip, int pointer, diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index 42da4bca73e8..a308ca7a7da6 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -113,7 +113,16 @@ #define MV88E6XXX_G2_SWITCH_MAC_DATA_MASK 0x00ff /* Offset 0x0E: ATU Stats Register */ -#define MV88E6XXX_G2_ATU_STATS 0x0e +#define MV88E6XXX_G2_ATU_STATS 0x0e +#define MV88E6XXX_G2_ATU_STATS_BIN_0 (0x0 << 14) +#define MV88E6XXX_G2_ATU_STATS_BIN_1 (0x1 << 14) +#define MV88E6XXX_G2_ATU_STATS_BIN_2 (0x2 << 14) +#define MV88E6XXX_G2_ATU_STATS_BIN_3 (0x3 << 14) +#define MV88E6XXX_G2_ATU_STATS_MODE_ALL (0x0 << 12) +#define MV88E6XXX_G2_ATU_STATS_MODE_ALL_DYNAMIC (0x1 << 12) +#define MV88E6XXX_G2_ATU_STATS_MODE_FID_ALL (0x2 << 12) +#define MV88E6XXX_G2_ATU_STATS_MODE_FID_ALL_DYNAMIC (0x3 << 12) +#define MV88E6XXX_G2_ATU_STATS_MASK 0x0fff /* Offset 0x0F: Priority Override Table */ #define MV88E6XXX_G2_PRIO_OVERRIDE 0x0f @@ -353,6 +362,8 @@ extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops; int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external); +int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin); +int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip); #else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */ @@ -515,6 +526,17 @@ static inline int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, return -EOPNOTSUPP; } +static inline int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, + u16 kind, u16 bin) +{ + return -EOPNOTSUPP; +} + +static inline int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */ #endif /* _MV88E6XXX_GLOBAL2_H */ -- cgit v1.2.3-59-g8ed1b From c5f299d592617847124900d75e5765cb0368ffae Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 5 Nov 2019 01:13:00 +0100 Subject: net: dsa: mv88e6xxx: global1_atu: Add helper for get next When retrieving the ATU statistics, and ATU get next has to be performed to trigger the ATU to collect the statistics. Export a helper from global1_atu to perform this. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global1.h | 1 + drivers/net/dsa/mv88e6xxx/global1_atu.c | 5 +++++ drivers/net/dsa/mv88e6xxx/global2.c | 11 ++--------- drivers/net/dsa/mv88e6xxx/global2.h | 2 +- 4 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 40fc0e13fc45..342172275841 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -341,5 +341,6 @@ int mv88e6390_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip, int mv88e6xxx_g1_vtu_flush(struct mv88e6xxx_chip *chip); int mv88e6xxx_g1_vtu_prob_irq_setup(struct mv88e6xxx_chip *chip); void mv88e6xxx_g1_vtu_prob_irq_free(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid); #endif /* _MV88E6XXX_GLOBAL1_H */ diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c index d8a03bbba83c..bdcd25560dd2 100644 --- a/drivers/net/dsa/mv88e6xxx/global1_atu.c +++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c @@ -154,6 +154,11 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op) return mv88e6xxx_g1_atu_op_wait(chip); } +int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid) +{ + return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB); +} + /* Offset 0x0C: ATU Data Register */ static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip, diff --git a/drivers/net/dsa/mv88e6xxx/global2.c b/drivers/net/dsa/mv88e6xxx/global2.c index 14954d92c564..87bfe7c8c9cd 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.c +++ b/drivers/net/dsa/mv88e6xxx/global2.c @@ -288,16 +288,9 @@ int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin) kind | bin); } -int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip) +int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats) { - int err; - u16 val; - - err = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, &val); - if (err) - return err; - - return val & MV88E6XXX_G2_ATU_STATS_MASK; + return mv88e6xxx_g2_read(chip, MV88E6XXX_G2_ATU_STATS, stats); } /* Offset 0x0F: Priority Override Table */ diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index a308ca7a7da6..d80ad203d126 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -363,7 +363,7 @@ extern const struct mv88e6xxx_gpio_ops mv88e6352_gpio_ops; int mv88e6xxx_g2_scratch_gpio_set_smi(struct mv88e6xxx_chip *chip, bool external); int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, u16 kind, u16 bin); -int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip); +int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, u16 *stats); #else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */ -- cgit v1.2.3-59-g8ed1b From e0c69ca7dfbbaaa6f9167c65f5cde740557aaed9 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 5 Nov 2019 01:13:01 +0100 Subject: net: dsa: mv88e6xxx: Add ATU occupancy via devlink resources The ATU can report how many entries it contains. It does this per bin, there being 4 bins in total. Export the ATU as a devlink resource, and provide a method the needed callback to get the resource occupancy. Signed-off-by: Andrew Lunn Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 190 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 3540ca2e3b6f..0dbe6c8b9dc0 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2720,9 +2720,179 @@ static void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds) ARRAY_SIZE(mv88e6xxx_devlink_params)); } +enum mv88e6xxx_devlink_resource_id { + MV88E6XXX_RESOURCE_ID_ATU, + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, +}; + +static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip, + u16 bin) +{ + u16 occupancy = 0; + int err; + + mv88e6xxx_reg_lock(chip); + + err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL, + bin); + if (err) { + dev_err(chip->dev, "failed to set ATU stats kind/bin\n"); + goto unlock; + } + + err = mv88e6xxx_g1_atu_get_next(chip, 0); + if (err) { + dev_err(chip->dev, "failed to perform ATU get next\n"); + goto unlock; + } + + err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy); + if (err) { + dev_err(chip->dev, "failed to get ATU stats\n"); + goto unlock; + } + +unlock: + mv88e6xxx_reg_unlock(chip); + + return occupancy; +} + +static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv) +{ + struct mv88e6xxx_chip *chip = priv; + + return mv88e6xxx_devlink_atu_bin_get(chip, + MV88E6XXX_G2_ATU_STATS_BIN_0); +} + +static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv) +{ + struct mv88e6xxx_chip *chip = priv; + + return mv88e6xxx_devlink_atu_bin_get(chip, + MV88E6XXX_G2_ATU_STATS_BIN_1); +} + +static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv) +{ + struct mv88e6xxx_chip *chip = priv; + + return mv88e6xxx_devlink_atu_bin_get(chip, + MV88E6XXX_G2_ATU_STATS_BIN_2); +} + +static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv) +{ + struct mv88e6xxx_chip *chip = priv; + + return mv88e6xxx_devlink_atu_bin_get(chip, + MV88E6XXX_G2_ATU_STATS_BIN_3); +} + +static u64 mv88e6xxx_devlink_atu_get(void *priv) +{ + return mv88e6xxx_devlink_atu_bin_0_get(priv) + + mv88e6xxx_devlink_atu_bin_1_get(priv) + + mv88e6xxx_devlink_atu_bin_2_get(priv) + + mv88e6xxx_devlink_atu_bin_3_get(priv); +} + +static int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds) +{ + struct devlink_resource_size_params size_params; + struct mv88e6xxx_chip *chip = ds->priv; + int err; + + devlink_resource_size_params_init(&size_params, + mv88e6xxx_num_macs(chip), + mv88e6xxx_num_macs(chip), + 1, DEVLINK_RESOURCE_UNIT_ENTRY); + + err = dsa_devlink_resource_register(ds, "ATU", + mv88e6xxx_num_macs(chip), + MV88E6XXX_RESOURCE_ID_ATU, + DEVLINK_RESOURCE_ID_PARENT_TOP, + &size_params); + if (err) + goto out; + + devlink_resource_size_params_init(&size_params, + mv88e6xxx_num_macs(chip) / 4, + mv88e6xxx_num_macs(chip) / 4, + 1, DEVLINK_RESOURCE_UNIT_ENTRY); + + err = dsa_devlink_resource_register(ds, "ATU_bin_0", + mv88e6xxx_num_macs(chip) / 4, + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, + MV88E6XXX_RESOURCE_ID_ATU, + &size_params); + if (err) + goto out; + + err = dsa_devlink_resource_register(ds, "ATU_bin_1", + mv88e6xxx_num_macs(chip) / 4, + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, + MV88E6XXX_RESOURCE_ID_ATU, + &size_params); + if (err) + goto out; + + err = dsa_devlink_resource_register(ds, "ATU_bin_2", + mv88e6xxx_num_macs(chip) / 4, + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, + MV88E6XXX_RESOURCE_ID_ATU, + &size_params); + if (err) + goto out; + + err = dsa_devlink_resource_register(ds, "ATU_bin_3", + mv88e6xxx_num_macs(chip) / 4, + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, + MV88E6XXX_RESOURCE_ID_ATU, + &size_params); + if (err) + goto out; + + dsa_devlink_resource_occ_get_register(ds, + MV88E6XXX_RESOURCE_ID_ATU, + mv88e6xxx_devlink_atu_get, + chip); + + dsa_devlink_resource_occ_get_register(ds, + MV88E6XXX_RESOURCE_ID_ATU_BIN_0, + mv88e6xxx_devlink_atu_bin_0_get, + chip); + + dsa_devlink_resource_occ_get_register(ds, + MV88E6XXX_RESOURCE_ID_ATU_BIN_1, + mv88e6xxx_devlink_atu_bin_1_get, + chip); + + dsa_devlink_resource_occ_get_register(ds, + MV88E6XXX_RESOURCE_ID_ATU_BIN_2, + mv88e6xxx_devlink_atu_bin_2_get, + chip); + + dsa_devlink_resource_occ_get_register(ds, + MV88E6XXX_RESOURCE_ID_ATU_BIN_3, + mv88e6xxx_devlink_atu_bin_3_get, + chip); + + return 0; + +out: + dsa_devlink_resources_unregister(ds); + return err; +} + static void mv88e6xxx_teardown(struct dsa_switch *ds) { mv88e6xxx_teardown_devlink_params(ds); + dsa_devlink_resources_unregister(ds); } static int mv88e6xxx_setup(struct dsa_switch *ds) @@ -2841,11 +3011,23 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) unlock: mv88e6xxx_reg_unlock(chip); - /* Has to be called without holding the register lock, since - * it takes the devlink lock, and we later take the locks in - * the reverse order when getting/setting parameters. + if (err) + return err; + + /* Have to be called without holding the register lock, since + * they take the devlink lock, and we later take the locks in + * the reverse order when getting/setting parameters or + * resource occupancy. */ - return mv88e6xxx_setup_devlink_params(ds); + err = mv88e6xxx_setup_devlink_resources(ds); + if (err) + return err; + + err = mv88e6xxx_setup_devlink_params(ds); + if (err) + dsa_devlink_resources_unregister(ds); + + return err; } static int mv88e6xxx_mdio_read(struct mii_bus *bus, int phy, int reg) -- cgit v1.2.3-59-g8ed1b From f92186177620c9bcc4fc314d5c3ec79f32153348 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Tue, 5 Nov 2019 18:53:23 +0100 Subject: net: ethernet: emac: Fix phy mode type Pass a phy_interface_t to of_get_phy_mode(), by changing the type of phy_mode in the device structure. This then requires that zmii_attach() is also changes, since it takes a pointer to phy_mode. Fixes: 0c65b2b90d13 ("net: of_get_phy_mode: Change API to solve int/unit warnings") Reported-by: kbuild test robot Reported-by: Stephen Rothwell Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/emac/core.h | 2 +- drivers/net/ethernet/ibm/emac/zmii.c | 3 ++- drivers/net/ethernet/ibm/emac/zmii.h | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h index e9cda024cbf6..89a1b0fea158 100644 --- a/drivers/net/ethernet/ibm/emac/core.h +++ b/drivers/net/ethernet/ibm/emac/core.h @@ -171,7 +171,7 @@ struct emac_instance { struct mal_commac commac; /* PHY infos */ - int phy_mode; + phy_interface_t phy_mode; u32 phy_map; u32 phy_address; u32 phy_feat_exc; diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c index b9e821de2ac6..57a25c7a9e70 100644 --- a/drivers/net/ethernet/ibm/emac/zmii.c +++ b/drivers/net/ethernet/ibm/emac/zmii.c @@ -78,7 +78,8 @@ static inline u32 zmii_mode_mask(int mode, int input) } } -int zmii_attach(struct platform_device *ofdev, int input, int *mode) +int zmii_attach(struct platform_device *ofdev, int input, + phy_interface_t *mode) { struct zmii_instance *dev = platform_get_drvdata(ofdev); struct zmii_regs __iomem *p = dev->base; diff --git a/drivers/net/ethernet/ibm/emac/zmii.h b/drivers/net/ethernet/ibm/emac/zmii.h index 41d46e9b87ba..65daedc78594 100644 --- a/drivers/net/ethernet/ibm/emac/zmii.h +++ b/drivers/net/ethernet/ibm/emac/zmii.h @@ -50,7 +50,8 @@ struct zmii_instance { int zmii_init(void); void zmii_exit(void); -int zmii_attach(struct platform_device *ofdev, int input, int *mode); +int zmii_attach(struct platform_device *ofdev, int input, + phy_interface_t *mode); void zmii_detach(struct platform_device *ofdev, int input); void zmii_get_mdio(struct platform_device *ofdev, int input); void zmii_put_mdio(struct platform_device *ofdev, int input); -- cgit v1.2.3-59-g8ed1b From 0a6890b9b4df89a83678eba0bee3541bcca8753c Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Mon, 4 Nov 2019 21:51:09 -0800 Subject: bnx2x: Utilize FW 7.13.15.0. Commit 97a27d6d6e8d "bnx2x: Add FW 7.13.15.0" added said .bin FW to linux-firmware tree. This FW addresses few important issues in the earlier FW release. This patch incorporates FW 7.13.15.0 in the bnx2x driver. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 132 ++++++++++----------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 2 +- 2 files changed, 67 insertions(+), 67 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index 226ab29f4cb6..3f8435208bf4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -32,31 +32,31 @@ * IRO[142].m2) + ((sbId) * IRO[142].m3)) #define CSTORM_IGU_MODE_OFFSET (IRO[161].base) #define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ - (IRO[323].base + ((pfId) * IRO[323].m1)) -#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ (IRO[324].base + ((pfId) * IRO[324].m1)) +#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[325].base + ((pfId) * IRO[325].m1)) #define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \ - (IRO[316].base + ((pfId) * IRO[316].m1) + ((iscsiEqId) * IRO[316].m2)) + (IRO[317].base + ((pfId) * IRO[317].m1) + ((iscsiEqId) * IRO[317].m2)) #define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \ - (IRO[318].base + ((pfId) * IRO[318].m1) + ((iscsiEqId) * IRO[318].m2)) + (IRO[319].base + ((pfId) * IRO[319].m1) + ((iscsiEqId) * IRO[319].m2)) #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \ - (IRO[317].base + ((pfId) * IRO[317].m1) + ((iscsiEqId) * IRO[317].m2)) + (IRO[318].base + ((pfId) * IRO[318].m1) + ((iscsiEqId) * IRO[318].m2)) #define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \ - (IRO[319].base + ((pfId) * IRO[319].m1) + ((iscsiEqId) * IRO[319].m2)) + (IRO[320].base + ((pfId) * IRO[320].m1) + ((iscsiEqId) * IRO[320].m2)) #define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \ - (IRO[315].base + ((pfId) * IRO[315].m1) + ((iscsiEqId) * IRO[315].m2)) + (IRO[316].base + ((pfId) * IRO[316].m1) + ((iscsiEqId) * IRO[316].m2)) #define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \ - (IRO[321].base + ((pfId) * IRO[321].m1) + ((iscsiEqId) * IRO[321].m2)) + (IRO[322].base + ((pfId) * IRO[322].m1) + ((iscsiEqId) * IRO[322].m2)) #define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \ - (IRO[320].base + ((pfId) * IRO[320].m1) + ((iscsiEqId) * IRO[320].m2)) + (IRO[321].base + ((pfId) * IRO[321].m1) + ((iscsiEqId) * IRO[321].m2)) #define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ - (IRO[322].base + ((pfId) * IRO[322].m1)) + (IRO[323].base + ((pfId) * IRO[323].m1)) #define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[314].base + ((pfId) * IRO[314].m1)) + (IRO[315].base + ((pfId) * IRO[315].m1)) #define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[313].base + ((pfId) * IRO[313].m1)) + (IRO[314].base + ((pfId) * IRO[314].m1)) #define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[312].base + ((pfId) * IRO[312].m1)) + (IRO[313].base + ((pfId) * IRO[313].m1)) #define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ (IRO[155].base + ((funcId) * IRO[155].m1)) #define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \ @@ -99,81 +99,81 @@ #define TSTORM_FUNC_EN_OFFSET(funcId) \ (IRO[107].base + ((funcId) * IRO[107].m1)) #define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ - (IRO[278].base + ((pfId) * IRO[278].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \ (IRO[279].base + ((pfId) * IRO[279].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \ +#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \ (IRO[280].base + ((pfId) * IRO[280].m1)) -#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \ +#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \ (IRO[281].base + ((pfId) * IRO[281].m1)) +#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \ + (IRO[282].base + ((pfId) * IRO[282].m1)) #define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[277].base + ((pfId) * IRO[277].m1)) + (IRO[278].base + ((pfId) * IRO[278].m1)) #define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[276].base + ((pfId) * IRO[276].m1)) + (IRO[277].base + ((pfId) * IRO[277].m1)) #define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[275].base + ((pfId) * IRO[275].m1)) + (IRO[276].base + ((pfId) * IRO[276].m1)) #define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ - (IRO[274].base + ((pfId) * IRO[274].m1)) + (IRO[275].base + ((pfId) * IRO[275].m1)) #define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \ - (IRO[284].base + ((pfId) * IRO[284].m1)) + (IRO[285].base + ((pfId) * IRO[285].m1)) #define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ - (IRO[270].base + ((pfId) * IRO[270].m1)) -#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[271].base + ((pfId) * IRO[271].m1)) -#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \ +#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[272].base + ((pfId) * IRO[272].m1)) -#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ +#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \ (IRO[273].base + ((pfId) * IRO[273].m1)) +#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ + (IRO[274].base + ((pfId) * IRO[274].m1)) #define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \ (IRO[206].base + ((pfId) * IRO[206].m1)) #define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ (IRO[109].base + ((funcId) * IRO[109].m1)) #define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \ - (IRO[223].base + ((pfId) * IRO[223].m1)) + (IRO[224].base + ((pfId) * IRO[224].m1)) #define TSTORM_VF_TO_PF_OFFSET(funcId) \ (IRO[108].base + ((funcId) * IRO[108].m1)) -#define USTORM_AGG_DATA_OFFSET (IRO[212].base) -#define USTORM_AGG_DATA_SIZE (IRO[212].size) +#define USTORM_AGG_DATA_OFFSET (IRO[213].base) +#define USTORM_AGG_DATA_SIZE (IRO[213].size) #define USTORM_ASSERT_LIST_INDEX_OFFSET (IRO[181].base) #define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \ (IRO[180].base + ((assertListEntry) * IRO[180].m1)) #define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \ (IRO[187].base + ((portId) * IRO[187].m1)) #define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \ - (IRO[325].base + ((pfId) * IRO[325].m1)) + (IRO[326].base + ((pfId) * IRO[326].m1)) #define USTORM_FUNC_EN_OFFSET(funcId) \ (IRO[182].base + ((funcId) * IRO[182].m1)) #define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ - (IRO[289].base + ((pfId) * IRO[289].m1)) -#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ (IRO[290].base + ((pfId) * IRO[290].m1)) +#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[291].base + ((pfId) * IRO[291].m1)) #define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ - (IRO[294].base + ((pfId) * IRO[294].m1)) + (IRO[295].base + ((pfId) * IRO[295].m1)) #define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \ - (IRO[291].base + ((pfId) * IRO[291].m1)) + (IRO[292].base + ((pfId) * IRO[292].m1)) #define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[287].base + ((pfId) * IRO[287].m1)) + (IRO[288].base + ((pfId) * IRO[288].m1)) #define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[286].base + ((pfId) * IRO[286].m1)) + (IRO[287].base + ((pfId) * IRO[287].m1)) #define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[285].base + ((pfId) * IRO[285].m1)) + (IRO[286].base + ((pfId) * IRO[286].m1)) #define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ - (IRO[288].base + ((pfId) * IRO[288].m1)) + (IRO[289].base + ((pfId) * IRO[289].m1)) #define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \ - (IRO[292].base + ((pfId) * IRO[292].m1)) -#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ (IRO[293].base + ((pfId) * IRO[293].m1)) +#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ + (IRO[294].base + ((pfId) * IRO[294].m1)) #define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \ (IRO[186].base + ((pfId) * IRO[186].m1)) #define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ (IRO[184].base + ((funcId) * IRO[184].m1)) #define USTORM_RX_PRODS_E1X_OFFSET(portId, clientId) \ - (IRO[215].base + ((portId) * IRO[215].m1) + ((clientId) * \ - IRO[215].m2)) + (IRO[216].base + ((portId) * IRO[216].m1) + ((clientId) * \ + IRO[216].m2)) #define USTORM_RX_PRODS_E2_OFFSET(qzoneId) \ - (IRO[216].base + ((qzoneId) * IRO[216].m1)) -#define USTORM_TPA_BTR_OFFSET (IRO[213].base) -#define USTORM_TPA_BTR_SIZE (IRO[213].size) + (IRO[217].base + ((qzoneId) * IRO[217].m1)) +#define USTORM_TPA_BTR_OFFSET (IRO[214].base) +#define USTORM_TPA_BTR_SIZE (IRO[214].size) #define USTORM_VF_TO_PF_OFFSET(funcId) \ (IRO[183].base + ((funcId) * IRO[183].m1)) #define XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE (IRO[67].base) @@ -188,39 +188,39 @@ #define XSTORM_FUNC_EN_OFFSET(funcId) \ (IRO[47].base + ((funcId) * IRO[47].m1)) #define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ - (IRO[302].base + ((pfId) * IRO[302].m1)) + (IRO[303].base + ((pfId) * IRO[303].m1)) #define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \ - (IRO[305].base + ((pfId) * IRO[305].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \ (IRO[306].base + ((pfId) * IRO[306].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \ (IRO[307].base + ((pfId) * IRO[307].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \ (IRO[308].base + ((pfId) * IRO[308].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \ (IRO[309].base + ((pfId) * IRO[309].m1)) -#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \ (IRO[310].base + ((pfId) * IRO[310].m1)) -#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \ +#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \ (IRO[311].base + ((pfId) * IRO[311].m1)) +#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \ + (IRO[312].base + ((pfId) * IRO[312].m1)) #define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ - (IRO[301].base + ((pfId) * IRO[301].m1)) + (IRO[302].base + ((pfId) * IRO[302].m1)) #define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ - (IRO[300].base + ((pfId) * IRO[300].m1)) + (IRO[301].base + ((pfId) * IRO[301].m1)) #define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ - (IRO[299].base + ((pfId) * IRO[299].m1)) + (IRO[300].base + ((pfId) * IRO[300].m1)) #define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ - (IRO[304].base + ((pfId) * IRO[304].m1)) + (IRO[305].base + ((pfId) * IRO[305].m1)) #define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \ - (IRO[303].base + ((pfId) * IRO[303].m1)) + (IRO[304].base + ((pfId) * IRO[304].m1)) #define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \ - (IRO[298].base + ((pfId) * IRO[298].m1)) + (IRO[299].base + ((pfId) * IRO[299].m1)) #define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ - (IRO[297].base + ((pfId) * IRO[297].m1)) + (IRO[298].base + ((pfId) * IRO[298].m1)) #define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \ - (IRO[296].base + ((pfId) * IRO[296].m1)) + (IRO[297].base + ((pfId) * IRO[297].m1)) #define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \ - (IRO[295].base + ((pfId) * IRO[295].m1)) + (IRO[296].base + ((pfId) * IRO[296].m1)) #define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \ (IRO[44].base + ((pfId) * IRO[44].m1)) #define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ @@ -233,12 +233,12 @@ #define XSTORM_SPQ_PROD_OFFSET(funcId) \ (IRO[31].base + ((funcId) * IRO[31].m1)) #define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(portId) \ - (IRO[217].base + ((portId) * IRO[217].m1)) -#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \ (IRO[218].base + ((portId) * IRO[218].m1)) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \ + (IRO[219].base + ((portId) * IRO[219].m1)) #define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfId) \ - (IRO[220].base + (((pfId)>>1) * IRO[220].m1) + (((pfId)&1) * \ - IRO[220].m2)) + (IRO[221].base + (((pfId)>>1) * IRO[221].m1) + (((pfId)&1) * \ + IRO[221].m2)) #define XSTORM_VF_TO_PF_OFFSET(funcId) \ (IRO[48].base + ((funcId) * IRO[48].m1)) #define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 78326a6c0aba..622fadc50316 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -3024,7 +3024,7 @@ struct afex_stats { #define BCM_5710_FW_MAJOR_VERSION 7 #define BCM_5710_FW_MINOR_VERSION 13 -#define BCM_5710_FW_REVISION_VERSION 11 +#define BCM_5710_FW_REVISION_VERSION 15 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 -- cgit v1.2.3-59-g8ed1b From 069e47823fff2c634b2d46a328b5096fdc8c2a0c Mon Sep 17 00:00:00 2001 From: Sudarsana Reddy Kalluru Date: Mon, 4 Nov 2019 21:51:10 -0800 Subject: bnx2x: Enable Multi-Cos feature. FW version 7.13.15 addresses the issue in Multi-cos implementation. This patch re-enables the Multi-Cos support in the driver. Fixes: d1f0b5dce8fd ("bnx2x: Disable multi-cos feature.") Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index d10b421ed1f1..5e037a305b83 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1934,7 +1934,8 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, } /* select a non-FCoE queue */ - return netdev_pick_tx(dev, skb, NULL) % (BNX2X_NUM_ETH_QUEUES(bp)); + return netdev_pick_tx(dev, skb, NULL) % + (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos); } void bnx2x_set_num_queues(struct bnx2x *bp) -- cgit v1.2.3-59-g8ed1b From dc5a3d79c345871439ffe72550b604fcde9770e1 Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Mon, 4 Nov 2019 21:51:11 -0800 Subject: bnx2x: Fix PF-VF communication over multi-cos queues. PF driver doesn't enable tx-switching for all cos queues/clients, which causes packets drop from PF to VF. Fix this by enabling tx-switching on all cos queues/clients. Signed-off-by: Manish Chopra Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 0edbb0a76847..5097a44686b3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -2397,15 +2397,21 @@ static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable) /* send the ramrod on all the queues of the PF */ for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; + int tx_idx; /* Set the appropriate Queue object */ q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj; - /* Update the Queue state */ - rc = bnx2x_queue_state_change(bp, &q_params); - if (rc) { - BNX2X_ERR("Failed to configure Tx switching\n"); - return rc; + for (tx_idx = FIRST_TX_COS_INDEX; + tx_idx < fp->max_cos; tx_idx++) { + q_params.params.update.cid_index = tx_idx; + + /* Update the Queue state */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Failed to configure Tx switching\n"); + return rc; + } } } -- cgit v1.2.3-59-g8ed1b From 888f43e5da61100b967445220123378da3426711 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Mon, 4 Nov 2019 21:51:12 -0800 Subject: cnic: Set fp_hsi_ver as part of CLIENT_SETUP ramrod The new FW has added extra validation for HSI version to make FW backward compatible with older VF drivers. Hence set fp_hsi_ver to Fast Path HSI version of the FW in use. Signed-off-by: Manish Rangankar Signed-off-by: Nilesh Javali Signed-off-by: Manish Chopra Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/cnic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c index 155599dcee76..61ab7d21f6bd 100644 --- a/drivers/net/ethernet/broadcom/cnic.c +++ b/drivers/net/ethernet/broadcom/cnic.c @@ -5208,6 +5208,8 @@ static void cnic_init_rings(struct cnic_dev *dev) cnic_init_bnx2x_tx_ring(dev, data); cnic_init_bnx2x_rx_ring(dev, data); + data->general.fp_hsi_ver = ETH_FP_HSI_VERSION; + l5_data.phy_address.lo = udev->l2_buf_map & 0xffffffff; l5_data.phy_address.hi = (u64) udev->l2_buf_map >> 32; -- cgit v1.2.3-59-g8ed1b From 86e8f2988786cb7ccf4833e6d32bc91a28a989b2 Mon Sep 17 00:00:00 2001 From: Vishal Kulkarni Date: Tue, 5 Nov 2019 11:49:15 +0530 Subject: cxgb4: Add pci reset handler This patch implements reset_prepare and reset_done, which are used for handling FLR. Signed-off-by: Vishal Kulkarni Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 105 ++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 38024877751c..33a923cfd82e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -184,6 +184,8 @@ static struct dentry *cxgb4_debugfs_root; LIST_HEAD(adapter_list); DEFINE_MUTEX(uld_mutex); +static int cfg_queues(struct adapter *adap); + static void link_report(struct net_device *dev) { if (!netif_carrier_ok(dev)) @@ -4286,14 +4288,14 @@ static struct fw_info *find_fw_info(int chip) /* * Phase 0 of initialization: contact FW, obtain config, perform basic init. */ -static int adap_init0(struct adapter *adap) +static int adap_init0(struct adapter *adap, int vpd_skip) { - int ret; - u32 v, port_vec; - enum dev_state state; - u32 params[7], val[7]; struct fw_caps_config_cmd caps_cmd; + u32 params[7], val[7]; + enum dev_state state; + u32 v, port_vec; int reset = 1; + int ret; /* Grab Firmware Device Log parameters as early as possible so we have * access to it for debugging, etc. @@ -4448,9 +4450,11 @@ static int adap_init0(struct adapter *adap) * could have FLASHed a new VPD which won't be read by the firmware * until we do the RESET ... */ - ret = t4_get_vpd_params(adap, &adap->params.vpd); - if (ret < 0) - goto bye; + if (!vpd_skip) { + ret = t4_get_vpd_params(adap, &adap->params.vpd); + if (ret < 0) + goto bye; + } /* Find out what ports are available to us. Note that we need to do * this before calling adap_init0_no_config() since it needs nports @@ -5050,10 +5054,93 @@ static void eeh_resume(struct pci_dev *pdev) rtnl_unlock(); } +static void eeh_reset_prepare(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + int i; + + if (adapter->pf != 4) + return; + + adapter->flags &= ~CXGB4_FW_OK; + + notify_ulds(adapter, CXGB4_STATE_DOWN); + + for_each_port(adapter, i) + if (adapter->port[i]->reg_state == NETREG_REGISTERED) + cxgb_close(adapter->port[i]); + + disable_interrupts(adapter); + cxgb4_free_mps_ref_entries(adapter); + + adap_free_hma_mem(adapter); + + if (adapter->flags & CXGB4_FULL_INIT_DONE) + cxgb_down(adapter); +} + +static void eeh_reset_done(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + int err, i; + + if (adapter->pf != 4) + return; + + err = t4_wait_dev_ready(adapter->regs); + if (err < 0) { + dev_err(adapter->pdev_dev, + "Device not ready, err %d", err); + return; + } + + setup_memwin(adapter); + + err = adap_init0(adapter, 1); + if (err) { + dev_err(adapter->pdev_dev, + "Adapter init failed, err %d", err); + return; + } + + setup_memwin_rdma(adapter); + + if (adapter->flags & CXGB4_FW_OK) { + err = t4_port_init(adapter, adapter->pf, adapter->pf, 0); + if (err) { + dev_err(adapter->pdev_dev, + "Port init failed, err %d", err); + return; + } + } + + err = cfg_queues(adapter); + if (err) { + dev_err(adapter->pdev_dev, + "Config queues failed, err %d", err); + return; + } + + cxgb4_init_mps_ref_entries(adapter); + + err = setup_fw_sge_queues(adapter); + if (err) { + dev_err(adapter->pdev_dev, + "FW sge queue allocation failed, err %d", err); + return; + } + + for_each_port(adapter, i) + if (adapter->port[i]->reg_state == NETREG_REGISTERED) + cxgb_open(adapter->port[i]); +} + static const struct pci_error_handlers cxgb4_eeh = { .error_detected = eeh_err_detected, .slot_reset = eeh_slot_reset, .resume = eeh_resume, + .reset_prepare = eeh_reset_prepare, + .reset_done = eeh_reset_done, }; /* Return true if the Link Configuration supports "High Speeds" (those greater @@ -5837,7 +5924,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } setup_memwin(adapter); - err = adap_init0(adapter); + err = adap_init0(adapter, 0); #ifdef CONFIG_DEBUG_FS bitmap_zero(adapter->sge.blocked_fl, adapter->sge.egr_sz); #endif -- cgit v1.2.3-59-g8ed1b From 9647722befbedcd6735e00655ffec392c05f0c56 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 5 Nov 2019 19:24:52 +0800 Subject: r8152: Add macpassthru support for ThinkPad Thunderbolt 3 Dock Gen 2 ThinkPad Thunderbolt 3 Dock Gen 2 is another docking station that uses RTL8153 based USB ethernet. The device supports macpassthru, but it failed to pass the test of -AD, -BND and -BD. Simply bypass these tests since the device supports this feature just fine. Also the ACPI objects have some differences between Dell's and Lenovo's, so make those ACPI infos no longer hardcoded. BugLink: https://bugs.launchpad.net/bugs/1827961 Signed-off-by: Kai-Heng Feng Acked-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 7 ++++++ drivers/net/usb/r8152.c | 58 ++++++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index fe630438f67b..0cdb2ce47645 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -766,6 +766,13 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* ThinkPad Thunderbolt 3 Dock Gen 2 (based on Realtek RTL8153) */ +{ + USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x3082, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* Lenovo Thinkpad USB 3.0 Ethernet Adapters (based on Realtek RTL8153) */ { USB_DEVICE_AND_INTERFACE_INFO(LENOVO_VENDOR_ID, 0x7205, USB_CLASS_COMM, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index b9f526ed0d30..ac079395c8d4 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -670,6 +670,7 @@ enum rtl8152_flags { SCHEDULE_TASKLET, GREEN_ETHERNET, DELL_TB_RX_AGG_BUG, + LENOVO_MACPASSTHRU, }; /* Define these values to match your device */ @@ -1408,38 +1409,52 @@ static int vendor_mac_passthru_addr_read(struct r8152 *tp, struct sockaddr *sa) int ret = -EINVAL; u32 ocp_data; unsigned char buf[6]; - - /* test for -AD variant of RTL8153 */ - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); - if ((ocp_data & AD_MASK) == 0x1000) { - /* test for MAC address pass-through bit */ - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); - if ((ocp_data & PASS_THRU_MASK) != 1) { - netif_dbg(tp, probe, tp->netdev, - "No efuse for RTL8153-AD MAC pass through\n"); - return -ENODEV; - } + char *mac_obj_name; + acpi_object_type mac_obj_type; + int mac_strlen; + + if (test_bit(LENOVO_MACPASSTHRU, &tp->flags)) { + mac_obj_name = "\\MACA"; + mac_obj_type = ACPI_TYPE_STRING; + mac_strlen = 0x16; } else { - /* test for RTL8153-BND and RTL8153-BD */ - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); - if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) { - netif_dbg(tp, probe, tp->netdev, - "Invalid variant for MAC pass through\n"); - return -ENODEV; + /* test for -AD variant of RTL8153 */ + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); + if ((ocp_data & AD_MASK) == 0x1000) { + /* test for MAC address pass-through bit */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, EFUSE); + if ((ocp_data & PASS_THRU_MASK) != 1) { + netif_dbg(tp, probe, tp->netdev, + "No efuse for RTL8153-AD MAC pass through\n"); + return -ENODEV; + } + } else { + /* test for RTL8153-BND and RTL8153-BD */ + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_MISC_1); + if ((ocp_data & BND_MASK) == 0 && (ocp_data & BD_MASK) == 0) { + netif_dbg(tp, probe, tp->netdev, + "Invalid variant for MAC pass through\n"); + return -ENODEV; + } } + + mac_obj_name = "\\_SB.AMAC"; + mac_obj_type = ACPI_TYPE_BUFFER; + mac_strlen = 0x17; } /* returns _AUXMAC_#AABBCCDDEEFF# */ - status = acpi_evaluate_object(NULL, "\\_SB.AMAC", NULL, &buffer); + status = acpi_evaluate_object(NULL, mac_obj_name, NULL, &buffer); obj = (union acpi_object *)buffer.pointer; if (!ACPI_SUCCESS(status)) return -ENODEV; - if (obj->type != ACPI_TYPE_BUFFER || obj->string.length != 0x17) { + if (obj->type != mac_obj_type || obj->string.length != mac_strlen) { netif_warn(tp, probe, tp->netdev, "Invalid buffer for pass-thru MAC addr: (%d, %d)\n", obj->type, obj->string.length); goto amacout; } + if (strncmp(obj->string.pointer, "_AUXMAC_#", 9) != 0 || strncmp(obj->string.pointer + 0x15, "#", 1) != 0) { netif_warn(tp, probe, tp->netdev, @@ -6629,6 +6644,10 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->hw_features &= ~NETIF_F_RXCSUM; } + if (le16_to_cpu(udev->descriptor.idVendor) == VENDOR_ID_LENOVO && + le16_to_cpu(udev->descriptor.idProduct) == 0x3082) + set_bit(LENOVO_MACPASSTHRU, &tp->flags); + if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x3011 && udev->serial && (!strcmp(udev->serial, "000001000000") || !strcmp(udev->serial, "000002000000"))) { @@ -6755,6 +6774,7 @@ static const struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3062)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3069)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x3082)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x720c)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7214)}, -- cgit v1.2.3-59-g8ed1b From 8b3f2eb038d3098b37715afced1e62bbc72da90f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Nov 2019 18:27:40 +0000 Subject: net/mlx5: fix kvfree of uninitialized pointer spec Currently when a call to esw_vport_create_legacy_ingress_acl_group fails the error exit path to label 'out' will cause a kvfree on the uninitialized pointer spec. Fix this by ensuring pointer spec is initialized to NULL to avoid this issue. Addresses-Coverity: ("Uninitialized pointer read") Fixes: 10652f39943e ("net/mlx5: Refactor ingress acl configuration") Signed-off-by: Colin Ian King Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index 24c2217a4ce8..48627472a691 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1253,7 +1253,7 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw, struct mlx5_flow_destination drop_ctr_dst = {0}; struct mlx5_flow_destination *dst = NULL; struct mlx5_flow_act flow_act = {0}; - struct mlx5_flow_spec *spec; + struct mlx5_flow_spec *spec = NULL; int dest_num = 0; int err = 0; u8 *smac_v; -- cgit v1.2.3-59-g8ed1b From 9ea7f01f470a25bb795224cc0ecc57c91a1519c6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Nov 2019 14:54:16 +0000 Subject: net/mlx5: fix spelling mistake "metdata" -> "metadata" There is a spelling mistake in a esw_warn warning message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Parav Pandit Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 59eebcae5df6..d8e25416a15d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -1878,7 +1878,7 @@ static int esw_vport_create_ingress_acl_group(struct mlx5_eswitch *esw, if (IS_ERR(g)) { ret = PTR_ERR(g); esw_warn(esw->dev, - "Failed to create vport[%d] ingress metdata group, err(%d)\n", + "Failed to create vport[%d] ingress metadata group, err(%d)\n", vport->vport, ret); goto grp_err; } -- cgit v1.2.3-59-g8ed1b From e310813279b7ea0f5401384675de818f852445c6 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 2 Nov 2019 16:55:21 +0800 Subject: ipw2x00: Remove redundant variable "rc" local variable "rc" is not used. It is safe to remove and There is only one caller of libipw_qos_convert_ac_to_parameters(). hence make it void Signed-off-by: zhong jiang Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 34cfd8162855..0cb36d1b983a 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -999,13 +999,12 @@ static int libipw_read_qos_info_element(struct /* * Write QoS parameters from the ac parameters. */ -static int libipw_qos_convert_ac_to_parameters(struct +static void libipw_qos_convert_ac_to_parameters(struct libipw_qos_parameter_info *param_elm, struct libipw_qos_parameters *qos_param) { - int rc = 0; int i; struct libipw_qos_ac_parameter *ac_params; u32 txop; @@ -1030,7 +1029,6 @@ static int libipw_qos_convert_ac_to_parameters(struct txop = le16_to_cpu(ac_params->tx_op_limit) * 32; qos_param->tx_op_limit[i] = cpu_to_le16(txop); } - return rc; } /* -- cgit v1.2.3-59-g8ed1b From ea7ad5f12ca2e1b067d6177ee0141a96ae8f1c53 Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Sat, 2 Nov 2019 16:55:22 +0800 Subject: iwlegacy: Remove redundant variable "ret" local variable "ret" is not used. hence it is safe to remove and just return 0. Signed-off-by: zhong jiang Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlegacy/4965-mac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 51fdd7ce30af..3664f56f8cbd 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -3331,7 +3331,6 @@ il4965_set_tkip_dynamic_key_info(struct il_priv *il, struct ieee80211_key_conf *keyconf, u8 sta_id) { unsigned long flags; - int ret = 0; __le16 key_flags = 0; key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); @@ -3368,7 +3367,7 @@ il4965_set_tkip_dynamic_key_info(struct il_priv *il, spin_unlock_irqrestore(&il->sta_lock, flags); - return ret; + return 0; } void -- cgit v1.2.3-59-g8ed1b From bf9840ccf8efbdac755772501bd05f6662e1d799 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Fri, 1 Nov 2019 13:19:42 +0800 Subject: rtw88: raise LPS threshold to 50, for less power consumption The LPS threshold was set to 2, means driver will leave LPS mode if there is more than 2 frames TX/RX for every 2 seconds. This makes driver enter/leave LPS frequently even if we just "ping -i1" to the others. Apparently we do not want to leave LPS mode if there is only some background traffics or web surfing. By experiment, set this to 50 is a more reasonable value to lower the over all power consumption. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.h b/drivers/net/wireless/realtek/rtw88/ps.h index 25925eedbad4..19afceca7d0e 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.h +++ b/drivers/net/wireless/realtek/rtw88/ps.h @@ -5,7 +5,7 @@ #ifndef __RTW_PS_H_ #define __RTW_PS_H_ -#define RTW_LPS_THRESHOLD 2 +#define RTW_LPS_THRESHOLD 50 #define POWER_MODE_ACK BIT(6) #define POWER_MODE_PG BIT(4) -- cgit v1.2.3-59-g8ed1b From 5565331152ee0d5a46aced51c35df637465bb5e1 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 1 Nov 2019 21:50:35 +0800 Subject: brcmsmac: remove set but not used variables drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c:841:7: warning: variable free_pdu set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c:842:30: warning: variable tx_rts_count set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c:842:6: warning: variable tx_rts set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c:843:7: warning: variable totlen set but not used [-Wunused-but-set-variable] They are never used, so can be removed. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index 6bb34a12a94b..ff39773333db 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -838,9 +838,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) struct dma_pub *dma = NULL; struct d11txh *txh = NULL; struct scb *scb = NULL; - bool free_pdu; - int tx_rts, tx_frame_count, tx_rts_count; - uint totlen, supr_status; + int tx_frame_count; + uint supr_status; bool lastframe; struct ieee80211_hdr *h; u16 mcl; @@ -917,11 +916,8 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) CHSPEC_CHANNEL(wlc->default_bss->chanspec)); } - tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS; tx_frame_count = (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT; - tx_rts_count = - (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT; lastframe = !ieee80211_has_morefrags(h->frame_control); @@ -989,9 +985,6 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) tx_info->flags |= IEEE80211_TX_STAT_ACK; } - totlen = p->len; - free_pdu = true; - if (lastframe) { /* remove PLCP & Broadcom tx descriptor header */ skb_pull(p, D11_PHY_HDR_LEN); -- cgit v1.2.3-59-g8ed1b From a3a03716196fa32991ecda5667595f78c61cbd95 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 2 Nov 2019 15:46:03 +0800 Subject: rtlwifi: rtl8225se: remove some unused const variables drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:83:17: warning: 'rtl8225sez2_tx_power_cck' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:79:17: warning: 'rtl8225sez2_tx_power_cck_A' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:75:17: warning: 'rtl8225sez2_tx_power_cck_B' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:71:17: warning: 'rtl8225sez2_tx_power_cck_ch14' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:62:17: warning: 'rtl8225se_tx_power_ofdm' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:53:17: warning: 'rtl8225se_tx_power_cck_ch14' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:44:17: warning: 'rtl8225se_tx_power_cck' defined but not used [-Wunused-const-variable=] drivers/net/wireless//realtek/rtl818x/rtl8180/rtl8225se.c:40:17: warning: 'rtl8225se_tx_gain_cck_ofdm' defined but not used [-Wunused-const-variable=] They are never used, so can be removed. Signed-off-by: YueHaibing Signed-off-by: Kalle Valo --- .../wireless/realtek/rtl818x/rtl8180/rtl8225se.c | 42 ---------------------- 1 file changed, 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c index 23cd4ff78e54..e1bf41c278a5 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/rtl8225se.c @@ -37,53 +37,11 @@ static const u8 cck_ofdm_gain_settings[] = { 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, }; -static const u8 rtl8225se_tx_gain_cck_ofdm[] = { - 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e -}; - -static const u8 rtl8225se_tx_power_cck[] = { - 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, - 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, - 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, - 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, - 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, - 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 -}; - -static const u8 rtl8225se_tx_power_cck_ch14[] = { - 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, - 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225se_tx_power_ofdm[] = { - 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 -}; - static const u32 rtl8225se_chan[] = { 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A, }; -static const u8 rtl8225sez2_tx_power_cck_ch14[] = { - 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 -}; - -static const u8 rtl8225sez2_tx_power_cck_B[] = { - 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 -}; - -static const u8 rtl8225sez2_tx_power_cck_A[] = { - 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 -}; - -static const u8 rtl8225sez2_tx_power_cck[] = { - 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 -}; - static const u8 ZEBRA_AGC[] = { 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, -- cgit v1.2.3-59-g8ed1b From a1f7c2cabf701a17b1a05d6526bbdadc3d05e05c Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 2 Nov 2019 18:47:01 +0100 Subject: rt2800: remove errornous duplicate condition On 2019-10-28 06:07, wbob wrote: > Hello Roman, > > while reading around drivers/net/wireless/ralink/rt2x00/rt2800lib.c > I stumbled on what I think is an edit of yours made in error in march > 2017: > > https://github.com/torvalds/linux/commit/41977e86#diff-dae5dc10da180f3b055809a48118e18aR5281 > > RT6352 in line 5281 should not have been introduced as the "else if" > below line 5291 can then not take effect for a RT6352 device. Another > possibility is for line 5291 to be not for RT6352, but this seems > very unlikely. Are you able to clarify still after this substantial time? > > 5277: static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) > ... > 5279: } else if (rt2x00_rt(rt2x00dev, RT5390) || > 5280: rt2x00_rt(rt2x00dev, RT5392) || > 5281: rt2x00_rt(rt2x00dev, RT6352)) { > ... > 5291: } else if (rt2x00_rt(rt2x00dev, RT6352)) { > ... Hence remove errornous line 5281 to make the driver actually execute the correct initialization routine for MT7620 chips. As it was requested by Stanislaw Gruszka remove setting values of MIMO_PS_CFG and TX_PIN_CFG. MIMO_PS_CFG is responsible for MIMO power-safe mode (which is disabled), hence we can drop setting it. TX_PIN_CFG is set correctly in other functions, and as setting this value breaks some devices, rather don't set it here during init, but only modify it later on. Fixes: 41977e86c984 ("rt2x00: add support for MT7620") Reported-by: wbob Reported-by: Roman Yeryomin Signed-off-by: Daniel Golle Acked-by: Stanislaw Gruszka Signed-off-by: Kalle Valo --- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index 25466454b73e..a36c3fea7495 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -5839,8 +5839,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_TXBF_CFG_0, 0x8000fc21); rt2800_register_write(rt2x00dev, TX_TXBF_CFG_3, 0x00009c40); } else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392) || - rt2x00_rt(rt2x00dev, RT6352)) { + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); @@ -5854,8 +5853,6 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000); rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); - rt2800_register_write(rt2x00dev, MIMO_PS_CFG, 0x00000002); - rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0x00150F0F); rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0); -- cgit v1.2.3-59-g8ed1b From 5174f1e41074b5186608badc2e89441d021e8c08 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Tue, 5 Nov 2019 10:18:38 +0800 Subject: rtlwifi: fix memory leak in rtl92c_set_fw_rsvdpagepkt() This leak was found by testing the EDIMAX EW-7612 on Raspberry Pi 3B+ with Linux 5.4-rc5 (multi_v7_defconfig + rtlwifi + kmemleak) and noticed a single memory leak during probe: unreferenced object 0xec13ee40 (size 176): comm "kworker/u8:1", pid 36, jiffies 4294939321 (age 5580.790s) hex dump (first 32 bytes): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] __netdev_alloc_skb+0x9c/0x164 [<863dfa6e>] rtl92c_set_fw_rsvdpagepkt+0x254/0x340 [rtl8192c_common] [<9572be0d>] rtl92cu_set_hw_reg+0xf48/0xfa4 [rtl8192cu] [<116df4d8>] rtl_op_bss_info_changed+0x234/0x96c [rtlwifi] [<8933575f>] ieee80211_bss_info_change_notify+0xb8/0x264 [mac80211] [] ieee80211_assoc_success+0x934/0x1798 [mac80211] [] ieee80211_rx_mgmt_assoc_resp+0x174/0x314 [mac80211] [<5974629e>] ieee80211_sta_rx_queued_mgmt+0x3f4/0x7f0 [mac80211] [] ieee80211_iface_work+0x208/0x318 [mac80211] [] process_one_work+0x22c/0x564 [] worker_thread+0x44/0x5d8 [<82c7b073>] kthread+0x150/0x154 [] ret_from_fork+0x14/0x2c [<794dff30>] 0x0 It is because 8192cu doesn't implement usb_cmd_send_packet(), and this patch just frees the skb within the function to resolve memleak problem by now. Since 8192cu doesn't turn on fwctrl_lps that needs to download command packet for firmware via the function, applying this patch doesn't affect driver behavior. Reported-by: Stefan Wahren Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 56cc3bc30860..f070f25bb735 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -1540,6 +1540,8 @@ static bool usb_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) * This is maybe necessary: * rtlpriv->cfg->ops->fill_tx_cmddesc(hw, buffer, 1, 1, skb); */ + dev_kfree_skb(skb); + return true; } -- cgit v1.2.3-59-g8ed1b From f530c1961af27f68a009b5fa532a4ed14f9c0e8c Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Tue, 5 Nov 2019 17:04:42 +0800 Subject: rtw88: fix potential NULL pointer access for firmware Driver could access a NULL firmware pointer if we don't return here. Fixes: 5195b90426409 ("rtw88: avoid FW info flood") Reported-by: kbuild test robot Reported-by: Dan Carpenter Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index 021668f1b74f..de82d08ea29e 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1024,8 +1024,10 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context) struct rtw_fw_state *fw = &rtwdev->fw; const struct rtw_fw_hdr *fw_hdr; - if (!firmware) + if (!firmware || !firmware->data) { rtw_err(rtwdev, "failed to request firmware\n"); + return; + } fw_hdr = (const struct rtw_fw_hdr *)firmware->data; fw->h2c_version = le16_to_cpu(fw_hdr->h2c_fmt_ver); -- cgit v1.2.3-59-g8ed1b From bfcccfe78b361f5f6ef48554aed5bcd30c72f67f Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 5 Nov 2019 13:26:11 -0800 Subject: netdevsim: drop code duplicated by a merge Looks like the port adding loop makes a re-appearance on net-next after net was merged back into it (even though it doesn't feature in the merge diff). The ports are already added in nsim_dev_create() so when we try to add them again get EEXIST, and see: netdevsim: probe of netdevsim0 failed with error -17 in the logs. When we remove the loop again the nsim_dev_probe() and nsim_dev_remove() become a wrapper of nsim_dev_create() and nsim_dev_destroy(). Remove this layer of indirection. Fixes: d31e95585ca6 ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net") Signed-off-by: Jakub Kicinski Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/dev.c | 47 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index e59a8826f36d..3da96c7e8265 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -753,7 +753,7 @@ err_fib_destroy: return err; } -static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) +int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) { struct nsim_dev *nsim_dev; struct devlink *devlink; @@ -761,7 +761,7 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev)); if (!devlink) - return ERR_PTR(-ENOMEM); + return -ENOMEM; devlink_net_set(devlink, nsim_bus_dev->initial_net); nsim_dev = devlink_priv(devlink); nsim_dev->nsim_bus_dev = nsim_bus_dev; @@ -773,6 +773,8 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) nsim_dev->max_macs = NSIM_DEV_MAX_MACS_DEFAULT; nsim_dev->test1 = NSIM_DEV_TEST1_DEFAULT; + dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); + err = nsim_dev_resources_register(devlink); if (err) goto err_devlink_free; @@ -818,7 +820,7 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) goto err_bpf_dev_exit; devlink_params_publish(devlink); - return nsim_dev; + return 0; err_bpf_dev_exit: nsim_bpf_dev_exit(nsim_dev); @@ -841,7 +843,7 @@ err_resources_unregister: devlink_resources_unregister(devlink, NULL); err_devlink_free: devlink_free(devlink); - return ERR_PTR(err); + return err; } static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) @@ -858,8 +860,9 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) nsim_fib_destroy(devlink, nsim_dev->fib_data); } -static void nsim_dev_destroy(struct nsim_dev *nsim_dev) +void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) { + struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); struct devlink *devlink = priv_to_devlink(nsim_dev); nsim_dev_reload_destroy(nsim_dev); @@ -873,40 +876,6 @@ static void nsim_dev_destroy(struct nsim_dev *nsim_dev) devlink_free(devlink); } -int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) -{ - struct nsim_dev *nsim_dev; - int i; - int err; - - nsim_dev = nsim_dev_create(nsim_bus_dev); - if (IS_ERR(nsim_dev)) - return PTR_ERR(nsim_dev); - dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); - - mutex_lock(&nsim_dev->port_list_lock); - for (i = 0; i < nsim_bus_dev->port_count; i++) { - err = __nsim_dev_port_add(nsim_dev, i); - if (err) - goto err_port_del_all; - } - mutex_unlock(&nsim_dev->port_list_lock); - return 0; - -err_port_del_all: - mutex_unlock(&nsim_dev->port_list_lock); - nsim_dev_port_del_all(nsim_dev); - nsim_dev_destroy(nsim_dev); - return err; -} - -void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) -{ - struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); - - nsim_dev_destroy(nsim_dev); -} - static struct nsim_dev_port * __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index) { -- cgit v1.2.3-59-g8ed1b From 5d8876e2c2517e8f0b035f5566b1775f99d785ea Mon Sep 17 00:00:00 2001 From: Zhu Yanjun Date: Wed, 6 Nov 2019 01:01:11 -0500 Subject: net: forcedeth: add xmit_more support This change adds support for xmit_more based on the igb commit 6f19e12f6230 ("igb: flush when in xmit_more mode and under descriptor pressure") and commit 6b16f9ee89b8 ("net: move skb->xmit_more hint to softnet data") that were made to igb to support this feature. The function netif_xmit_stopped is called to check whether transmit queue on device is currently unable to send to determine whether we must write the tail because we can add no further buffers. When normal packets and/or xmit_more packets fill up tx_desc, it is necessary to trigger NIC tx reg. Following the advice from David Miller and Jakub Kicinski, after the xmit_more feature is added, the following scenario will occur. | xmit_more packets | DMA_MAPPING | DMA_MAPPING error check | xmit_more packets already in HW xmit queue | In the above scenario, if DMA_MAPPING error occurrs, the xmit_more packets already in HW xmit queue will also be dropped. This is different from the behavior before xmit_more feature. So it is necessary to trigger NIC HW tx reg in the above scenario. To the non-xmit_more packets, the above scenario will not occur. Tested: - pktgen (xmit_more packets) SMP x86_64 -> Test command: ./pktgen_sample03_burst_single_flow.sh ... -b 8 -n 1000000 Test results: Params: ... burst: 8 ... Result: OK: 12194004(c12188996+d5007) usec, 1000001 (1500byte,0frags) 82007pps 984Mb/sec (984084000bps) errors: 0 - iperf (normal packets) SMP x86_64 -> Test command: Server: iperf -s Client: iperf -c serverip Result: TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 1.10 GBytes 942 Mbits/sec CC: Joe Jin CC: JUNXIAO_BI Reported-and-tested-by: Nan san Signed-off-by: Zhu Yanjun Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/nvidia/forcedeth.c | 59 +++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 05d2b478c99b..6b54cb3b681d 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -2225,6 +2225,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) struct nv_skb_map *prev_tx_ctx; struct nv_skb_map *tmp_tx_ctx = NULL, *start_tx_ctx = NULL; unsigned long flags; + netdev_tx_t ret = NETDEV_TX_OK; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -2240,7 +2241,12 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); np->tx_stop = 1; spin_unlock_irqrestore(&np->lock, flags); - return NETDEV_TX_BUSY; + + /* When normal packets and/or xmit_more packets fill up + * tx_desc, it is necessary to trigger NIC tx reg. + */ + ret = NETDEV_TX_BUSY; + goto txkick; } spin_unlock_irqrestore(&np->lock, flags); @@ -2259,7 +2265,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) u64_stats_update_begin(&np->swstats_tx_syncp); nv_txrx_stats_inc(stat_tx_dropped); u64_stats_update_end(&np->swstats_tx_syncp); - return NETDEV_TX_OK; + + ret = NETDEV_TX_OK; + + goto dma_error; } np->put_tx_ctx->dma_len = bcnt; np->put_tx_ctx->dma_single = 1; @@ -2305,7 +2314,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) u64_stats_update_begin(&np->swstats_tx_syncp); nv_txrx_stats_inc(stat_tx_dropped); u64_stats_update_end(&np->swstats_tx_syncp); - return NETDEV_TX_OK; + + ret = NETDEV_TX_OK; + + goto dma_error; } np->put_tx_ctx->dma_len = bcnt; @@ -2357,8 +2369,15 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&np->lock, flags); - writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - return NETDEV_TX_OK; +txkick: + if (netif_queue_stopped(dev) || !netdev_xmit_more()) { + u32 txrxctl_kick; +dma_error: + txrxctl_kick = NVREG_TXRXCTL_KICK | np->txrxctl_bits; + writel(txrxctl_kick, get_hwbase(dev) + NvRegTxRxControl); + } + + return ret; } static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, @@ -2381,6 +2400,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, struct nv_skb_map *start_tx_ctx = NULL; struct nv_skb_map *tmp_tx_ctx = NULL; unsigned long flags; + netdev_tx_t ret = NETDEV_TX_OK; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -2396,7 +2416,13 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, netif_stop_queue(dev); np->tx_stop = 1; spin_unlock_irqrestore(&np->lock, flags); - return NETDEV_TX_BUSY; + + /* When normal packets and/or xmit_more packets fill up + * tx_desc, it is necessary to trigger NIC tx reg. + */ + ret = NETDEV_TX_BUSY; + + goto txkick; } spin_unlock_irqrestore(&np->lock, flags); @@ -2416,7 +2442,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, u64_stats_update_begin(&np->swstats_tx_syncp); nv_txrx_stats_inc(stat_tx_dropped); u64_stats_update_end(&np->swstats_tx_syncp); - return NETDEV_TX_OK; + + ret = NETDEV_TX_OK; + + goto dma_error; } np->put_tx_ctx->dma_len = bcnt; np->put_tx_ctx->dma_single = 1; @@ -2463,7 +2492,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, u64_stats_update_begin(&np->swstats_tx_syncp); nv_txrx_stats_inc(stat_tx_dropped); u64_stats_update_end(&np->swstats_tx_syncp); - return NETDEV_TX_OK; + + ret = NETDEV_TX_OK; + + goto dma_error; } np->put_tx_ctx->dma_len = bcnt; np->put_tx_ctx->dma_single = 0; @@ -2542,8 +2574,15 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, spin_unlock_irqrestore(&np->lock, flags); - writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); - return NETDEV_TX_OK; +txkick: + if (netif_queue_stopped(dev) || !netdev_xmit_more()) { + u32 txrxctl_kick; +dma_error: + txrxctl_kick = NVREG_TXRXCTL_KICK | np->txrxctl_bits; + writel(txrxctl_kick, get_hwbase(dev) + NvRegTxRxControl); + } + + return ret; } static inline void nv_tx_flip_ownership(struct net_device *dev) -- cgit v1.2.3-59-g8ed1b From 9439bb0f3656003308a479a9a785ec2e79cfeb39 Mon Sep 17 00:00:00 2001 From: Yunfeng Ye Date: Tue, 5 Nov 2019 19:30:45 +0800 Subject: ehea: replace with page_shift() in ehea_is_hugepage() The function page_shift() is supported after the commit 94ad9338109f ("mm: introduce page_shift()"). So replace with page_shift() in ehea_is_hugepage() for readability. Signed-off-by: Yunfeng Ye Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ehea/ehea_qmr.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c index 6e70658d50c4..db45373ea31c 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_qmr.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_qmr.c @@ -670,13 +670,10 @@ int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages) static int ehea_is_hugepage(unsigned long pfn) { - int page_order; - if (pfn & EHEA_HUGEPAGE_PFN_MASK) return 0; - page_order = compound_order(pfn_to_page(pfn)); - if (page_order + PAGE_SHIFT != EHEA_HUGEPAGESHIFT) + if (page_shift(pfn_to_page(pfn)) != EHEA_HUGEPAGESHIFT) return 0; return 1; -- cgit v1.2.3-59-g8ed1b From a9b97286fec1a87976ac7852ad65f2013faad9f6 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Tue, 5 Nov 2019 20:18:21 +0200 Subject: gianfar: Maximize Rx buffer size Until now the size of a Rx buffer was artificially limited to 1536B (which happens to be the default, after reset, hardware value for a Rx buffer). This approach however leaves unused memory space for Rx packets, since the driver uses a paged allocation scheme that reserves half a page for each Rx skb. There's also the inconvenience that frames around 1536 bytes can get scattered if the limit is slightly exceeded. This limit can be exceeded even for standard MTU of 1500B traffic, for common cases like stacked VLANs, or DSA tags. To address these issues, let's just compute the buffer size starting from the upper limit of 2KB (half a page) and subtract the skb overhead and alignment restrictions. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index f472a6dbbe6f..432c6a818ae5 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -90,11 +90,11 @@ extern const char gfar_driver_version[]; #define DEFAULT_RX_LFC_THR 16 #define DEFAULT_LFC_PTVVAL 4 -/* prevent fragmenation by HW in DSA environments */ -#define GFAR_RXB_SIZE roundup(1536 + 8, 64) -#define GFAR_SKBFRAG_SIZE (RXBUF_ALIGNMENT + GFAR_RXB_SIZE \ - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) #define GFAR_RXB_TRUESIZE 2048 +#define GFAR_SKBFRAG_OVR (RXBUF_ALIGNMENT \ + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define GFAR_RXB_SIZE rounddown(GFAR_RXB_TRUESIZE - GFAR_SKBFRAG_OVR, 64) +#define GFAR_SKBFRAG_SIZE (GFAR_RXB_SIZE + GFAR_SKBFRAG_OVR) #define TX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1) -- cgit v1.2.3-59-g8ed1b From a012dca9f7a2bc44b6680c20bec06fe9b2e55d37 Mon Sep 17 00:00:00 2001 From: Scott W Taylor Date: Wed, 9 Oct 2019 07:09:40 -0700 Subject: ice: add ethtool -m support for reading i2c eeprom modules Implement ethtool -m support to read eeprom data from SFP/QSFP modules. Signed-off-by: Scott W Taylor Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 29 +++++ drivers/net/ethernet/intel/ice/ice_common.c | 46 ++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 4 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 147 ++++++++++++++++++++++++ 4 files changed, 226 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 023e3d2fee5f..9b32aac66444 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1147,6 +1147,33 @@ struct ice_aqc_set_port_id_led { u8 rsvd[13]; }; +/* Read/Write SFF EEPROM command (indirect 0x06EE) */ +struct ice_aqc_sff_eeprom { + u8 lport_num; + u8 lport_num_valid; +#define ICE_AQC_SFF_PORT_NUM_VALID BIT(0) + __le16 i2c_bus_addr; +#define ICE_AQC_SFF_I2CBUS_7BIT_M 0x7F +#define ICE_AQC_SFF_I2CBUS_10BIT_M 0x3FF +#define ICE_AQC_SFF_I2CBUS_TYPE_M BIT(10) +#define ICE_AQC_SFF_I2CBUS_TYPE_7BIT 0 +#define ICE_AQC_SFF_I2CBUS_TYPE_10BIT ICE_AQC_SFF_I2CBUS_TYPE_M +#define ICE_AQC_SFF_SET_EEPROM_PAGE_S 11 +#define ICE_AQC_SFF_SET_EEPROM_PAGE_M (0x3 << ICE_AQC_SFF_SET_EEPROM_PAGE_S) +#define ICE_AQC_SFF_NO_PAGE_CHANGE 0 +#define ICE_AQC_SFF_SET_23_ON_MISMATCH 1 +#define ICE_AQC_SFF_SET_22_ON_MISMATCH 2 +#define ICE_AQC_SFF_IS_WRITE BIT(15) + __le16 i2c_mem_addr; + __le16 eeprom_page; +#define ICE_AQC_SFF_EEPROM_BANK_S 0 +#define ICE_AQC_SFF_EEPROM_BANK_M (0xFF << ICE_AQC_SFF_EEPROM_BANK_S) +#define ICE_AQC_SFF_EEPROM_PAGE_S 8 +#define ICE_AQC_SFF_EEPROM_PAGE_M (0xFF << ICE_AQC_SFF_EEPROM_PAGE_S) + __le32 addr_high; + __le32 addr_low; +}; + /* NVM Read command (indirect 0x0701) * NVM Erase commands (direct 0x0702) * NVM Update commands (indirect 0x0703) @@ -1618,6 +1645,7 @@ struct ice_aq_desc { struct ice_aqc_get_phy_caps get_phy; struct ice_aqc_set_phy_cfg set_phy; struct ice_aqc_restart_an restart_an; + struct ice_aqc_sff_eeprom read_write_sff_param; struct ice_aqc_set_port_id_led set_port_id_led; struct ice_aqc_get_sw_cfg get_sw_conf; struct ice_aqc_sw_rules sw_rules; @@ -1741,6 +1769,7 @@ enum ice_adminq_opc { ice_aqc_opc_set_event_mask = 0x0613, ice_aqc_opc_set_mac_lb = 0x0620, ice_aqc_opc_set_port_id_led = 0x06E9, + ice_aqc_opc_sff_eeprom = 0x06EE, /* NVM commands */ ice_aqc_opc_nvm_read = 0x0701, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 3a6b3950eb0e..b41bf475b36f 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -2555,6 +2555,52 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode, return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); } +/** + * ice_aq_sff_eeprom + * @hw: pointer to the HW struct + * @lport: bits [7:0] = logical port, bit [8] = logical port valid + * @bus_addr: I2C bus address of the eeprom (typically 0xA0, 0=topo default) + * @mem_addr: I2C offset. lower 8 bits for address, 8 upper bits zero padding. + * @page: QSFP page + * @set_page: set or ignore the page + * @data: pointer to data buffer to be read/written to the I2C device. + * @length: 1-16 for read, 1 for write. + * @write: 0 read, 1 for write. + * @cd: pointer to command details structure or NULL + * + * Read/Write SFF EEPROM (0x06EE) + */ +enum ice_status +ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr, + u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length, + bool write, struct ice_sq_cd *cd) +{ + struct ice_aqc_sff_eeprom *cmd; + struct ice_aq_desc desc; + enum ice_status status; + + if (!data || (mem_addr & 0xff00)) + return ICE_ERR_PARAM; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_sff_eeprom); + cmd = &desc.params.read_write_sff_param; + desc.flags = cpu_to_le16(ICE_AQ_FLAG_RD | ICE_AQ_FLAG_BUF); + cmd->lport_num = (u8)(lport & 0xff); + cmd->lport_num_valid = (u8)((lport >> 8) & 0x01); + cmd->i2c_bus_addr = cpu_to_le16(((bus_addr >> 1) & + ICE_AQC_SFF_I2CBUS_7BIT_M) | + ((set_page << + ICE_AQC_SFF_SET_EEPROM_PAGE_S) & + ICE_AQC_SFF_SET_EEPROM_PAGE_M)); + cmd->i2c_mem_addr = cpu_to_le16(mem_addr & 0xff); + cmd->eeprom_page = cpu_to_le16((u16)page << ICE_AQC_SFF_EEPROM_PAGE_S); + if (write) + cmd->i2c_bus_addr |= cpu_to_le16(ICE_AQC_SFF_IS_WRITE); + + status = ice_aq_send_cmd(hw, &desc, data, length, cd); + return status; +} + /** * __ice_aq_get_set_rss_lut * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index c3df92f57777..4d5aa0a0d27a 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -117,6 +117,10 @@ ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd); enum ice_status ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode, struct ice_sq_cd *cd); +enum ice_status +ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr, + u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length, + bool write, struct ice_sq_cd *cd); enum ice_status ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues, diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 7e779060069c..a8e51bc95198 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3455,6 +3455,151 @@ ice_set_per_q_coalesce(struct net_device *netdev, u32 q_num, return __ice_set_coalesce(netdev, ec, q_num); } +#define ICE_I2C_EEPROM_DEV_ADDR 0xA0 +#define ICE_I2C_EEPROM_DEV_ADDR2 0xA2 +#define ICE_MODULE_TYPE_SFP 0x03 +#define ICE_MODULE_TYPE_QSFP_PLUS 0x0D +#define ICE_MODULE_TYPE_QSFP28 0x11 +#define ICE_MODULE_SFF_ADDR_MODE 0x04 +#define ICE_MODULE_SFF_DIAG_CAPAB 0x40 +#define ICE_MODULE_REVISION_ADDR 0x01 +#define ICE_MODULE_SFF_8472_COMP 0x5E +#define ICE_MODULE_SFF_8472_SWAP 0x5C +#define ICE_MODULE_QSFP_MAX_LEN 640 + +/** + * ice_get_module_info - get SFF module type and revision information + * @netdev: network interface device structure + * @modinfo: module EEPROM size and layout information structure + */ +static int +ice_get_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + u8 sff8472_comp = 0; + u8 sff8472_swap = 0; + u8 sff8636_rev = 0; + u8 value = 0; + + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, 0x00, 0x00, + 0, &value, 1, 0, NULL); + if (status) + return -EIO; + + switch (value) { + case ICE_MODULE_TYPE_SFP: + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_SFF_8472_COMP, 0x00, 0, + &sff8472_comp, 1, 0, NULL); + if (status) + return -EIO; + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_SFF_8472_SWAP, 0x00, 0, + &sff8472_swap, 1, 0, NULL); + if (status) + return -EIO; + + if (sff8472_swap & ICE_MODULE_SFF_ADDR_MODE) { + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + } else if (sff8472_comp && + (sff8472_swap & ICE_MODULE_SFF_DIAG_CAPAB)) { + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8079; + modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN; + } + break; + case ICE_MODULE_TYPE_QSFP_PLUS: + case ICE_MODULE_TYPE_QSFP28: + status = ice_aq_sff_eeprom(hw, 0, ICE_I2C_EEPROM_DEV_ADDR, + ICE_MODULE_REVISION_ADDR, 0x00, 0, + &sff8636_rev, 1, 0, NULL); + if (status) + return -EIO; + /* Check revision compliance */ + if (sff8636_rev > 0x02) { + /* Module is SFF-8636 compliant */ + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ICE_MODULE_QSFP_MAX_LEN; + } + break; + default: + netdev_warn(netdev, + "SFF Module Type not recognized.\n"); + return -EINVAL; + } + return 0; +} + +/** + * ice_get_module_eeprom - fill buffer with SFF EEPROM contents + * @netdev: network interface device structure + * @ee: EEPROM dump request structure + * @data: buffer to be filled with EEPROM contents + */ +static int +ice_get_module_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + u8 addr = ICE_I2C_EEPROM_DEV_ADDR; + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + struct ice_hw *hw = &pf->hw; + enum ice_status status; + bool is_sfp = false; + u16 offset = 0; + u8 value = 0; + u8 page = 0; + int i; + + status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, 0, + &value, 1, 0, NULL); + if (status) + return -EIO; + + if (!ee || !ee->len || !data) + return -EINVAL; + + if (value == ICE_MODULE_TYPE_SFP) + is_sfp = true; + + for (i = 0; i < ee->len; i++) { + offset = i + ee->offset; + + /* Check if we need to access the other memory page */ + if (is_sfp) { + if (offset >= ETH_MODULE_SFF_8079_LEN) { + offset -= ETH_MODULE_SFF_8079_LEN; + addr = ICE_I2C_EEPROM_DEV_ADDR2; + } + } else { + while (offset >= ETH_MODULE_SFF_8436_LEN) { + /* Compute memory page number and offset. */ + offset -= ETH_MODULE_SFF_8436_LEN / 2; + page++; + } + } + + status = ice_aq_sff_eeprom(hw, 0, addr, offset, page, !is_sfp, + &value, 1, 0, NULL); + if (status) + value = 0; + data[i] = value; + } + return 0; +} + static const struct ethtool_ops ice_ethtool_ops = { .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings, @@ -3490,6 +3635,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .set_per_queue_coalesce = ice_set_per_q_coalesce, .get_fecparam = ice_get_fecparam, .set_fecparam = ice_set_fecparam, + .get_module_info = ice_get_module_info, + .get_module_eeprom = ice_get_module_eeprom, }; static const struct ethtool_ops ice_ethtool_safe_mode_ops = { -- cgit v1.2.3-59-g8ed1b From 031f21475297042d86534246c1b2948fc58172b6 Mon Sep 17 00:00:00 2001 From: Md Fahad Iqbal Polash Date: Wed, 9 Oct 2019 07:09:42 -0700 Subject: ice: Update Boot Configuration Section read of NVM The Boot Configuration Section Block has been moved to the Preserved Field Area (PFA) of NVM. Update the NVM reads that involves Boot Configuration Section. Signed-off-by: Md Fahad Iqbal Polash Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 66 +++++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_common.h | 4 ++ drivers/net/ethernet/intel/ice/ice_nvm.c | 51 ++++++++++++++++++---- drivers/net/ethernet/intel/ice/ice_nvm.h | 8 ++++ drivers/net/ethernet/intel/ice/ice_type.h | 3 ++ 5 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_nvm.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index b41bf475b36f..9972929053aa 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1066,6 +1066,72 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req) return ice_check_reset(hw); } +/** + * ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA + * @hw: pointer to hardware structure + * @module_tlv: pointer to module TLV to return + * @module_tlv_len: pointer to module TLV length to return + * @module_type: module type requested + * + * Finds the requested sub module TLV type from the Preserved Field + * Area (PFA) and returns the TLV pointer and length. The caller can + * use these to read the variable length TLV value. + */ +enum ice_status +ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len, + u16 module_type) +{ + enum ice_status status; + u16 pfa_len, pfa_ptr; + u16 next_tlv; + + status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n"); + return status; + } + status = ice_read_sr_word(hw, pfa_ptr, &pfa_len); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n"); + return status; + } + /* Starting with first TLV after PFA length, iterate through the list + * of TLVs to find the requested one. + */ + next_tlv = pfa_ptr + 1; + while (next_tlv < pfa_ptr + pfa_len) { + u16 tlv_sub_module_type; + u16 tlv_len; + + /* Read TLV type */ + status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n"); + break; + } + /* Read TLV length */ + status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n"); + break; + } + if (tlv_sub_module_type == module_type) { + if (tlv_len) { + *module_tlv = next_tlv; + *module_tlv_len = tlv_len; + return 0; + } + return ICE_ERR_INVAL_SIZE; + } + /* Check next TLV, i.e. current TLV pointer + length + 2 words + * (for current TLV's type and length) + */ + next_tlv = next_tlv + tlv_len + 2; + } + /* Module does not exist */ + return ICE_ERR_DOES_NOT_EXIST; +} + /** * ice_copy_rxq_ctx_to_hw * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 4d5aa0a0d27a..db9a2d48202f 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -6,6 +6,7 @@ #include "ice.h" #include "ice_type.h" +#include "ice_nvm.h" #include "ice_flex_pipe.h" #include "ice_switch.h" #include @@ -16,6 +17,9 @@ void ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf, u16 buf_len); enum ice_status ice_init_hw(struct ice_hw *hw); void ice_deinit_hw(struct ice_hw *hw); +enum ice_status +ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len, + u16 module_type); enum ice_status ice_check_reset(struct ice_hw *hw); enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req); enum ice_status ice_create_all_ctrlq(struct ice_hw *hw); diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c index bcb431f1bd92..57c73f613f32 100644 --- a/drivers/net/ethernet/intel/ice/ice_nvm.c +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c @@ -219,8 +219,7 @@ static void ice_release_nvm(struct ice_hw *hw) * * Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq. */ -static enum ice_status -ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) +enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) { enum ice_status status; @@ -242,9 +241,10 @@ ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data) */ enum ice_status ice_init_nvm(struct ice_hw *hw) { + u16 oem_hi, oem_lo, boot_cfg_tlv, boot_cfg_tlv_len; struct ice_nvm_info *nvm = &hw->nvm; u16 eetrack_lo, eetrack_hi; - enum ice_status status = 0; + enum ice_status status; u32 fla, gens_stat; u8 sr_size; @@ -261,15 +261,15 @@ enum ice_status ice_init_nvm(struct ice_hw *hw) fla = rd32(hw, GLNVM_FLA); if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */ nvm->blank_nvm_mode = false; - } else { /* Blank programming mode */ + } else { + /* Blank programming mode */ nvm->blank_nvm_mode = true; - status = ICE_ERR_NVM_BLANK_MODE; ice_debug(hw, ICE_DBG_NVM, "NVM init error: unsupported blank mode.\n"); - return status; + return ICE_ERR_NVM_BLANK_MODE; } - status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &hw->nvm.ver); + status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &nvm->ver); if (status) { ice_debug(hw, ICE_DBG_INIT, "Failed to read DEV starter version.\n"); @@ -287,9 +287,42 @@ enum ice_status ice_init_nvm(struct ice_hw *hw) return status; } - hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo; + nvm->eetrack = (eetrack_hi << 16) | eetrack_lo; - return status; + status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len, + ICE_SR_BOOT_CFG_PTR); + if (status) { + ice_debug(hw, ICE_DBG_INIT, + "Failed to read Boot Configuration Block TLV.\n"); + return status; + } + + /* Boot Configuration Block must have length at least 2 words + * (Combo Image Version High and Combo Image Version Low) + */ + if (boot_cfg_tlv_len < 2) { + ice_debug(hw, ICE_DBG_INIT, + "Invalid Boot Configuration Block TLV size.\n"); + return ICE_ERR_INVAL_SIZE; + } + + status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF), + &oem_hi); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER hi.\n"); + return status; + } + + status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OEM_VER_OFF + 1), + &oem_lo); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to read OEM_VER lo.\n"); + return status; + } + + nvm->oem_ver = ((u32)oem_hi << 16) | oem_lo; + + return 0; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.h b/drivers/net/ethernet/intel/ice/ice_nvm.h new file mode 100644 index 000000000000..a9fa011c22c6 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_nvm.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Intel Corporation. */ + +#ifndef _ICE_NVM_H_ +#define _ICE_NVM_H_ + +enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data); +#endif /* _ICE_NVM_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 6667d17a4206..08fe3e5e72d4 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -555,6 +555,8 @@ struct ice_hw_port_stats { }; /* Checksum and Shadow RAM pointers */ +#define ICE_SR_BOOT_CFG_PTR 0x132 +#define ICE_NVM_OEM_VER_OFF 0x02 #define ICE_SR_NVM_DEV_STARTER_VER 0x18 #define ICE_SR_NVM_EETRACK_LO 0x2D #define ICE_SR_NVM_EETRACK_HI 0x2E @@ -568,6 +570,7 @@ struct ice_hw_port_stats { #define ICE_OEM_VER_BUILD_MASK (0xffff << ICE_OEM_VER_BUILD_SHIFT) #define ICE_OEM_VER_SHIFT 24 #define ICE_OEM_VER_MASK (0xff << ICE_OEM_VER_SHIFT) +#define ICE_SR_PFA_PTR 0x40 #define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800 #define ICE_SR_WORDS_IN_1KB 512 -- cgit v1.2.3-59-g8ed1b From cfbf13674be4ecb9a38048cd228c382825807b12 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 9 Oct 2019 07:09:43 -0700 Subject: ice: handle DCBx non-contiguous TC request If DCBx request non-contiguous TCs, then the driver will configure default traffic class (TC0). This is done to prevent Tx hang since the driver currently does not support non-contiguous TC. Signed-off-by: Paul Greenwalt Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 141 +++++++++++++++++++-------- 1 file changed, 102 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index dd47869c4ad4..13da89e22123 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -3,6 +3,8 @@ #include "ice_dcb_lib.h" +static void ice_pf_dcb_recfg(struct ice_pf *pf); + /** * ice_vsi_cfg_netdev_tc - Setup the netdev TC configuration * @vsi: the VSI being configured @@ -137,42 +139,6 @@ void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) } } -/** - * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs - * @pf: pointer to the PF struct - * - * Assumed caller has already disabled all VSIs before - * calling this function. Reconfiguring DCB based on - * local_dcbx_cfg. - */ -static void ice_pf_dcb_recfg(struct ice_pf *pf) -{ - struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; - u8 tc_map = 0; - int v, ret; - - /* Update each VSI */ - ice_for_each_vsi(pf, v) { - if (!pf->vsi[v]) - continue; - - if (pf->vsi[v]->type == ICE_VSI_PF) - tc_map = ice_dcb_get_ena_tc(dcbcfg); - else - tc_map = ICE_DFLT_TRAFFIC_CLASS; - - ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map); - if (ret) { - dev_err(&pf->pdev->dev, - "Failed to config TC for VSI index: %d\n", - pf->vsi[v]->idx); - continue; - } - - ice_vsi_map_rings_to_vectors(pf->vsi[v]); - } -} - /** * ice_pf_dcb_cfg - Apply new DCB configuration * @pf: pointer to the PF struct @@ -437,9 +403,10 @@ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked) /** * ice_dcb_sw_default_config - Apply a default DCB config * @pf: PF to apply config to + * @ets_willing: configure ets willing * @locked: was this function called with RTNL held */ -static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked) +static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool ets_willing, bool locked) { struct ice_aqc_port_ets_elem buf = { 0 }; struct ice_dcbx_cfg *dcbcfg; @@ -454,7 +421,7 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked) memset(dcbcfg, 0, sizeof(*dcbcfg)); memset(&pi->local_dcbx_cfg, 0, sizeof(*dcbcfg)); - dcbcfg->etscfg.willing = 1; + dcbcfg->etscfg.willing = ets_willing ? 1 : 0; dcbcfg->etscfg.maxtcs = hw->func_caps.common_cap.maxtc; dcbcfg->etscfg.tcbwtable[0] = 100; dcbcfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS; @@ -479,6 +446,102 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked) return ice_query_port_ets(pi, &buf, sizeof(buf), NULL); } +/** + * ice_dcb_tc_contig - Check that TCs are contiguous + * @prio_table: pointer to priority table + * + * Check if TCs begin with TC0 and are contiguous + */ +static bool ice_dcb_tc_contig(u8 *prio_table) +{ + u8 max_tc = 0; + int i; + + for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) { + u8 cur_tc = prio_table[i]; + + if (cur_tc > max_tc) + return false; + else if (cur_tc == max_tc) + max_tc++; + } + + return true; +} + +/** + * ice_dcb_noncontig_cfg - Configure DCB for non-contiguous TCs + * @pf: pointer to the PF struct + * + * If non-contiguous TCs, then configure SW DCB with TC0 and ETS non-willing + */ +static int ice_dcb_noncontig_cfg(struct ice_pf *pf) +{ + struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; + int ret; + + /* Configure SW DCB default with ETS non-willing */ + ret = ice_dcb_sw_dflt_cfg(pf, false, true); + if (ret) { + dev_err(&pf->pdev->dev, + "Failed to set local DCB config %d\n", ret); + return ret; + } + + /* Reconfigure with ETS willing so that FW will send LLDP MIB event */ + dcbcfg->etscfg.willing = 1; + ret = ice_set_dcb_cfg(pf->hw.port_info); + if (ret) + dev_err(&pf->pdev->dev, "Failed to set DCB to unwilling\n"); + + return ret; +} + +/** + * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs + * @pf: pointer to the PF struct + * + * Assumed caller has already disabled all VSIs before + * calling this function. Reconfiguring DCB based on + * local_dcbx_cfg. + */ +static void ice_pf_dcb_recfg(struct ice_pf *pf) +{ + struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; + u8 tc_map = 0; + int v, ret; + + /* Update each VSI */ + ice_for_each_vsi(pf, v) { + if (!pf->vsi[v]) + continue; + + if (pf->vsi[v]->type == ICE_VSI_PF) { + tc_map = ice_dcb_get_ena_tc(dcbcfg); + + /* If DCBX request non-contiguous TC, then configure + * default TC + */ + if (!ice_dcb_tc_contig(dcbcfg->etscfg.prio_table)) { + tc_map = ICE_DFLT_TRAFFIC_CLASS; + ice_dcb_noncontig_cfg(pf); + } + } else { + tc_map = ICE_DFLT_TRAFFIC_CLASS; + } + + ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map); + if (ret) { + dev_err(&pf->pdev->dev, + "Failed to config TC for VSI index: %d\n", + pf->vsi[v]->idx); + continue; + } + + ice_vsi_map_rings_to_vectors(pf->vsi[v]); + } +} + /** * ice_init_pf_dcb - initialize DCB for a PF * @pf: PF to initialize DCB for @@ -507,7 +570,7 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) dev_info(&pf->pdev->dev, "FW LLDP is disabled, DCBx/LLDP in SW mode.\n"); clear_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags); - err = ice_dcb_sw_dflt_cfg(pf, locked); + err = ice_dcb_sw_dflt_cfg(pf, true, locked); if (err) { dev_err(&pf->pdev->dev, "Failed to set local DCB config %d\n", err); -- cgit v1.2.3-59-g8ed1b From c6012ac1c35bc49fba0f133dffe233ae7d04a881 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 9 Oct 2019 07:09:44 -0700 Subject: ice: fix driver unload flow As part of the driver unload flow, a PF reset is issued which may still cause an interrupt to be generated by the device. Do not clear the interrupt scheme until the reset is complete and there are no pending transactions otherwise a hardware error may occur. Signed-off-by: Bruce Allan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 363b284e8aa1..f29f5753f977 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3348,12 +3348,13 @@ static void ice_remove(struct pci_dev *pdev) } ice_deinit_pf(pf); ice_deinit_hw(&pf->hw); - ice_clear_interrupt_scheme(pf); /* Issue a PFR as part of the prescribed driver unload flow. Do not * do it via ice_schedule_reset() since there is no need to rebuild * and the service task is already stopped. */ ice_reset(&pf->hw, ICE_RESET_PFR); + pci_wait_for_pending_transaction(pdev); + ice_clear_interrupt_scheme(pf); pci_disable_pcie_error_reporting(pdev); } -- cgit v1.2.3-59-g8ed1b From b2883dfe1ffce63364ee8ba7476bcd0cf8a63009 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 9 Oct 2019 07:09:45 -0700 Subject: ice: Adjust DCB INIT for SW mode Adjust ice_init_dcb to set the is_sw_lldp boolean in the case where the FW has been detected to be in an untenable state such that the driver should forcibly make sure it is off. This will ensure that the FW is in a known state. Signed-off-by: Dave Ertman Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_dcb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_dcb.c b/drivers/net/ethernet/intel/ice/ice_dcb.c index dd7efff121bd..713e8a892e14 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb.c @@ -965,9 +965,9 @@ enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change) pi->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) { /* Get current DCBX configuration */ ret = ice_get_dcb_cfg(pi); - pi->is_sw_lldp = (hw->adminq.sq_last_status == ICE_AQ_RC_EPERM); if (ret) return ret; + pi->is_sw_lldp = false; } else if (pi->dcbx_status == ICE_DCBX_STATUS_DIS) { return ICE_ERR_NOT_READY; } @@ -975,8 +975,8 @@ enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change) /* Configure the LLDP MIB change event */ if (enable_mib_change) { ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL); - if (!ret) - pi->is_sw_lldp = false; + if (ret) + pi->is_sw_lldp = true; } return ret; -- cgit v1.2.3-59-g8ed1b From 4e56802e0ef3ed92cb28196ebd91d8fa6455c45f Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Wed, 9 Oct 2019 07:09:46 -0700 Subject: ice: save PCI state in probe Save state to correct recovery memory and I/O BARs address after PCI bus reset. Without this after reset kernel can't read device registers. Signed-off-by: Michal Swiatkowski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index f29f5753f977..76c5324268c5 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3152,6 +3152,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) hw = &pf->hw; hw->hw_addr = pcim_iomap_table(pdev)[ICE_BAR0]; + pci_save_state(pdev); + hw->back = pf; hw->vendor_id = pdev->vendor; hw->device_id = pdev->device; -- cgit v1.2.3-59-g8ed1b From eb0ee8abfeb9ff4b98e8e40217b8667bfb08587a Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Wed, 9 Oct 2019 07:09:47 -0700 Subject: ice: Check for null pointer dereference when setting rings Without this check rebuild vsi can lead to kernel panic. Signed-off-by: Michal Swiatkowski Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 76c5324268c5..d061e9fd6f2c 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4303,8 +4303,13 @@ int ice_vsi_setup_tx_rings(struct ice_vsi *vsi) } ice_for_each_txq(vsi, i) { - vsi->tx_rings[i]->netdev = vsi->netdev; - err = ice_setup_tx_ring(vsi->tx_rings[i]); + struct ice_ring *ring = vsi->tx_rings[i]; + + if (!ring) + return -EINVAL; + + ring->netdev = vsi->netdev; + err = ice_setup_tx_ring(ring); if (err) break; } @@ -4329,8 +4334,13 @@ int ice_vsi_setup_rx_rings(struct ice_vsi *vsi) } ice_for_each_rxq(vsi, i) { - vsi->rx_rings[i]->netdev = vsi->netdev; - err = ice_setup_rx_ring(vsi->rx_rings[i]); + struct ice_ring *ring = vsi->rx_rings[i]; + + if (!ring) + return -EINVAL; + + ring->netdev = vsi->netdev; + err = ice_setup_rx_ring(ring); if (err) break; } -- cgit v1.2.3-59-g8ed1b From 395594563b29fbcd8d9a4f0a642484e5d3bb6db1 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 9 Oct 2019 07:09:48 -0700 Subject: ice: write register with correct offset The VF_MBX_ARQLEN register array is per-PF, not global, so we should not use the absolute VF ID as an index. Instead, use the per-PF VF ID. This fixes an issue with VFs on PFs other than 0 not seeing reset. Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index ad757412bb04..3d8c231b0614 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -390,7 +390,7 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr) * by the time we get here. */ if (!is_pfr) - wr32(hw, VF_MBX_ARQLEN(vf_abs_id), 0); + wr32(hw, VF_MBX_ARQLEN(vf->vf_id), 0); /* In the case of a VFLR, the HW has already reset the VF and we * just need to clean up, so don't hit the VFRTRIG register. -- cgit v1.2.3-59-g8ed1b From 5878589dc3182795c9a7f04aec4ae5e0a7636d35 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 9 Oct 2019 07:09:49 -0700 Subject: ice: print unsupported module message Print message to inform user if unsupported module is inserted, and extend the topology / configuration detection. Signed-off-by: Paul Greenwalt Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 4 ++++ drivers/net/ethernet/intel/ice/ice_main.c | 6 ++++++ 2 files changed, 10 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 9b32aac66444..622c666399fd 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1044,6 +1044,10 @@ struct ice_aqc_get_link_status_data { #define ICE_AQ_LINK_TOPO_CONFLICT BIT(0) #define ICE_AQ_LINK_MEDIA_CONFLICT BIT(1) #define ICE_AQ_LINK_TOPO_CORRUPT BIT(2) +#define ICE_AQ_LINK_TOPO_UNREACH_PRT BIT(4) +#define ICE_AQ_LINK_TOPO_UNDRUTIL_PRT BIT(5) +#define ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA BIT(6) +#define ICE_AQ_LINK_TOPO_UNSUPP_MEDIA BIT(7) u8 reserved1; u8 link_info; #define ICE_AQ_LINK_UP BIT(0) /* Link Status */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d061e9fd6f2c..7a90243198eb 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -637,8 +637,14 @@ static void ice_print_topo_conflict(struct ice_vsi *vsi) switch (vsi->port_info->phy.link_info.topo_media_conflict) { case ICE_AQ_LINK_TOPO_CONFLICT: case ICE_AQ_LINK_MEDIA_CONFLICT: + case ICE_AQ_LINK_TOPO_UNREACH_PRT: + case ICE_AQ_LINK_TOPO_UNDRUTIL_PRT: + case ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA: netdev_info(vsi->netdev, "Possible mis-configuration of the Ethernet port detected, please use the Intel(R) Ethernet Port Configuration Tool application to address the issue.\n"); break; + case ICE_AQ_LINK_TOPO_UNSUPP_MEDIA: + netdev_info(vsi->netdev, "Rx/Tx is disabled on this device because an unsupported module type was detected. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n"); + break; default: break; } -- cgit v1.2.3-59-g8ed1b From e18ff118181bca507a9e52effc8dd587224925f5 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 9 Oct 2019 07:09:50 -0700 Subject: ice: print PCI link speed and width Print message to inform user of PCI link speed and width. Signed-off-by: Paul Greenwalt Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 7a90243198eb..32684fce7de6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3305,6 +3305,9 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) ice_cfg_lldp_mib_change(&pf->hw, true); } + /* print PCI link speed and width */ + pcie_print_link_status(pf->pdev); + return 0; err_alloc_sw_unroll: -- cgit v1.2.3-59-g8ed1b From 133f4883f9066822a684252f7850cf06db7c10de Mon Sep 17 00:00:00 2001 From: Krzysztof Kazimierczak Date: Wed, 9 Oct 2019 07:09:51 -0700 Subject: ice: Get rid of ice_cleanup_header ice_cleanup_hdrs() has been stripped of most of its content, it only serves as a wrapper for eth_skb_pad(). We can get rid of it altogether and simplify the codebase. Signed-off-by: Krzysztof Kazimierczak Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_txrx.c | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 40a29b9d3034..2c212f64d99f 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -944,27 +944,6 @@ static void ice_put_rx_buf(struct ice_ring *rx_ring, struct ice_rx_buf *rx_buf) rx_buf->skb = NULL; } -/** - * ice_cleanup_headers - Correct empty headers - * @skb: pointer to current skb being fixed - * - * Also address the case where we are pulling data in on pages only - * and as such no data is present in the skb header. - * - * In addition if skb is not at least 60 bytes we need to pad it so that - * it is large enough to qualify as a valid Ethernet frame. - * - * Returns true if an error was encountered and skb was freed. - */ -static bool ice_cleanup_headers(struct sk_buff *skb) -{ - /* if eth_skb_pad returns an error the skb was freed */ - if (eth_skb_pad(skb)) - return true; - - return false; -} - /** * ice_is_non_eop - process handling of non-EOP buffers * @rx_ring: Rx ring being processed @@ -1124,10 +1103,8 @@ construct_skb: if (ice_test_staterr(rx_desc, stat_err_bits)) vlan_tag = le16_to_cpu(rx_desc->wb.l2tag1); - /* correct empty headers and pad skb if needed (to make valid - * ethernet frame - */ - if (ice_cleanup_headers(skb)) { + /* pad the skb if needed, to make a valid ethernet frame */ + if (eth_skb_pad(skb)) { skb = NULL; continue; } -- cgit v1.2.3-59-g8ed1b From ff010eca05fae91e23a88a3b6604b88dd9bef7dc Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 9 Oct 2019 07:09:52 -0700 Subject: ice: Rename VF function ice_vc_dis_vf to match its behavior ice_vc_dis_vf() tells iavf that it's going to perform a reset and then performs a software reset. This is misleading based on the function name because the VF does not get disabled. So fix this by changing the name to ice_vc_reset_vf(). Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 3d8c231b0614..7ef2cc739587 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1496,12 +1496,10 @@ void ice_process_vflr_event(struct ice_pf *pf) } /** - * ice_vc_dis_vf - Disable a given VF via SW reset + * ice_vc_reset_vf - Perform software reset on the VF after informing the AVF * @vf: pointer to the VF info - * - * Disable the VF through a SW reset */ -static void ice_vc_dis_vf(struct ice_vf *vf) +static void ice_vc_reset_vf(struct ice_vf *vf) { ice_vc_notify_vf_reset(vf); ice_reset_vf(vf, false); @@ -2541,7 +2539,7 @@ static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) } else { /* request is successful, then reset VF */ vf->num_req_qs = req_queues; - ice_vc_dis_vf(vf); + ice_vc_reset_vf(vf); dev_info(&pf->pdev->dev, "VF %d granted request of %u queues.\n", vf->vf_id, req_queues); @@ -3168,7 +3166,7 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) "MAC on VF %d set to %pM. VF driver will be reinitialized\n", vf_id, mac); - ice_vc_dis_vf(vf); + ice_vc_reset_vf(vf); return ret; } @@ -3204,7 +3202,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) return 0; vf->trusted = trusted; - ice_vc_dis_vf(vf); + ice_vc_reset_vf(vf); dev_info(&pf->pdev->dev, "VF %u is now %strusted\n", vf_id, trusted ? "" : "un"); -- cgit v1.2.3-59-g8ed1b From 039c60c5970ff7dcf8ff3033397a77f3a283cb3e Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 9 Oct 2019 07:09:53 -0700 Subject: ice: Fix return value when SR-IOV is not supported When the device is not capable of supporting SR-IOV -ENODEV is being returned; -EOPNOTSUPP is more appropriate. Signed-off-by: Anirudh Venkataramanan Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 7ef2cc739587..b4813ccc467d 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1408,7 +1408,7 @@ static int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs) if (!test_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags)) { dev_err(dev, "This device is not capable of SR-IOV\n"); - return -ENODEV; + return -EOPNOTSUPP; } if (pre_existing_vfs && pre_existing_vfs != num_vfs) -- cgit v1.2.3-59-g8ed1b From 1dcff44a9d2b74b3de2c854bbf11a5f765e7ba77 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 6 Nov 2019 14:59:21 +0000 Subject: net: aquantia: fix return value check in aq_ptp_init() Function ptp_clock_register() returns ERR_PTR() and never returns NULL. The NULL test should be removed. Signed-off-by: Wei Yongjun Acked-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 8175513e48c9..1f9eab74453e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -1207,7 +1207,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec) aq_ptp->ptp_info = aq_ptp_clock; aq_ptp_gpio_init(&aq_ptp->ptp_info, &mbox.info); clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev); - if (!clock || IS_ERR(clock)) { + if (IS_ERR(clock)) { netdev_err(aq_nic->ndev, "ptp_clock_register failed\n"); err = PTR_ERR(clock); goto err_exit; -- cgit v1.2.3-59-g8ed1b From eb34e98baf4ce269423948dacefea6747e963b48 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 6 Nov 2019 15:54:49 +0000 Subject: net: axienet: Fix error return code in axienet_probe() In the DMA memory resource get failed case, the error is not set and 0 will be returned. Fix it by removing redundant check since devm_ioremap_resource() will handle it. Fixes: 28ef9ebdb64c ("net: axienet: make use of axistream-connected attribute optional") Signed-off-by: Wei Yongjun Reviewed-by: Radhey Shyam Pandey Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 867726d696e2..8f32db6d2c45 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1788,10 +1788,6 @@ static int axienet_probe(struct platform_device *pdev) /* Check for these resources directly on the Ethernet node. */ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(&pdev->dev, "unable to get DMA memory resource\n"); - goto free_netdev; - } lp->dma_regs = devm_ioremap_resource(&pdev->dev, res); lp->rx_irq = platform_get_irq(pdev, 1); lp->tx_irq = platform_get_irq(pdev, 0); -- cgit v1.2.3-59-g8ed1b From 226df3ef1c02a99e7303d91dc27267fae529a820 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Wed, 6 Nov 2019 19:06:50 +0200 Subject: dpaa2-eth: fix an always true condition in dpaa2_mac_get_if_mode Convert the phy_mode() function to return the if_mode through an argument, similar to the new form of of_get_phy_mode(). This will help with handling errors in a common manner and also will fix an always true condition. Fixes: 0c65b2b90d13 ("net: of_get_phy_mode: Change API to solve int/unit warnings") Reported-by: Dan Carpenter Signed-off-by: Ioana Ciornei Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index b713739f4804..d322123ed373 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -7,14 +7,19 @@ #define phylink_to_dpaa2_mac(config) \ container_of((config), struct dpaa2_mac, phylink_config) -static phy_interface_t phy_mode(enum dpmac_eth_if eth_if) +static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode) { + *if_mode = PHY_INTERFACE_MODE_NA; + switch (eth_if) { case DPMAC_ETH_IF_RGMII: - return PHY_INTERFACE_MODE_RGMII; + *if_mode = PHY_INTERFACE_MODE_RGMII; + break; default: return -EINVAL; } + + return 0; } /* Caller must call of_node_put on the returned value */ @@ -51,11 +56,11 @@ static int dpaa2_mac_get_if_mode(struct device_node *node, if (!err) return if_mode; - if_mode = phy_mode(attr.eth_if); - if (if_mode >= 0) + err = phy_mode(attr.eth_if, &if_mode); + if (!err) return if_mode; - return -ENODEV; + return err; } static bool dpaa2_mac_phy_mode_mismatch(struct dpaa2_mac *mac, -- cgit v1.2.3-59-g8ed1b From 4985dffced1471385af234b7d4aab4830df78121 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 6 Nov 2019 23:36:12 +0100 Subject: net: phy: at803x: fix Kconfig description The name of the PHY is actually AR803x not AT803x. Additionally, add the name of the vendor and mention the AR8031 support. Signed-off-by: Michael Walle Reviewed-by: Florian Fainelli Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index fe602648b99f..1b884ebb4e48 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -282,11 +282,6 @@ config AX88796B_PHY Currently supports the Asix Electronics PHY found in the X-Surf 100 AX88796B package. -config AT803X_PHY - tristate "AT803X PHYs" - ---help--- - Currently supports the AT8030 and AT8035 model - config BCM63XX_PHY tristate "Broadcom 63xx SOCs internal PHY" depends on BCM63XX || COMPILE_TEST @@ -444,6 +439,11 @@ config NXP_TJA11XX_PHY ---help--- Currently supports the NXP TJA1100 and TJA1101 PHY. +config AT803X_PHY + tristate "Qualcomm Atheros AR803X PHYs" + help + Currently supports the AR8030, AR8031 and AR8035 model + config QSEMI_PHY tristate "Quality Semiconductor PHYs" ---help--- -- cgit v1.2.3-59-g8ed1b From 2f664823a47021ae029fe91272adbf0a223e477f Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 6 Nov 2019 23:36:14 +0100 Subject: net: phy: at803x: add device tree binding Add support for configuring the CLK_25M pin as well as the RGMII I/O voltage by the device tree. Signed-off-by: Michael Walle Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 300 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 8e30db28fd7d..aa782b28615b 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -13,7 +13,12 @@ #include #include #include +#include #include +#include +#include +#include +#include #define AT803X_SPECIFIC_STATUS 0x11 #define AT803X_SS_SPEED_MASK (3 << 14) @@ -62,6 +67,42 @@ #define AT803X_DEBUG_REG_5 0x05 #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) +#define AT803X_DEBUG_REG_1F 0x1F +#define AT803X_DEBUG_PLL_ON BIT(2) +#define AT803X_DEBUG_RGMII_1V8 BIT(3) + +/* AT803x supports either the XTAL input pad, an internal PLL or the + * DSP as clock reference for the clock output pad. The XTAL reference + * is only used for 25 MHz output, all other frequencies need the PLL. + * The DSP as a clock reference is used in synchronous ethernet + * applications. + * + * By default the PLL is only enabled if there is a link. Otherwise + * the PHY will go into low power state and disabled the PLL. You can + * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always + * enabled. + */ +#define AT803X_MMD7_CLK25M 0x8016 +#define AT803X_CLK_OUT_MASK GENMASK(4, 2) +#define AT803X_CLK_OUT_25MHZ_XTAL 0 +#define AT803X_CLK_OUT_25MHZ_DSP 1 +#define AT803X_CLK_OUT_50MHZ_PLL 2 +#define AT803X_CLK_OUT_50MHZ_DSP 3 +#define AT803X_CLK_OUT_62_5MHZ_PLL 4 +#define AT803X_CLK_OUT_62_5MHZ_DSP 5 +#define AT803X_CLK_OUT_125MHZ_PLL 6 +#define AT803X_CLK_OUT_125MHZ_DSP 7 + +/* The AR8035 has another mask which is compatible with the AR8031 mask but + * doesn't support choosing between XTAL/PLL and DSP. + */ +#define AT8035_CLK_OUT_MASK GENMASK(4, 3) + +#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) +#define AT803X_CLK_OUT_STRENGTH_FULL 0 +#define AT803X_CLK_OUT_STRENGTH_HALF 1 +#define AT803X_CLK_OUT_STRENGTH_QUARTER 2 + #define ATH9331_PHY_ID 0x004dd041 #define ATH8030_PHY_ID 0x004dd076 #define ATH8031_PHY_ID 0x004dd074 @@ -72,6 +113,16 @@ MODULE_DESCRIPTION("Atheros 803x PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); +struct at803x_priv { + int flags; +#define AT803X_KEEP_PLL_ENABLED BIT(0) /* don't turn off internal PLL */ + u16 clk_25m_reg; + u16 clk_25m_mask; + struct regulator_dev *vddio_rdev; + struct regulator_dev *vddh_rdev; + struct regulator *vddio; +}; + struct at803x_context { u16 bmcr; u16 advertise; @@ -237,6 +288,238 @@ static int at803x_resume(struct phy_device *phydev) return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); } +static int at803x_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + + if (selector) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_RGMII_1V8); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_RGMII_1V8, 0); +} + +static int at803x_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + int val; + + val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); + if (val < 0) + return val; + + return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; +} + +static struct regulator_ops vddio_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = at803x_rgmii_reg_set_voltage_sel, + .get_voltage_sel = at803x_rgmii_reg_get_voltage_sel, +}; + +static const unsigned int vddio_voltage_table[] = { + 1500000, + 1800000, +}; + +static const struct regulator_desc vddio_desc = { + .name = "vddio", + .of_match = of_match_ptr("vddio-regulator"), + .n_voltages = ARRAY_SIZE(vddio_voltage_table), + .volt_table = vddio_voltage_table, + .ops = &vddio_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static struct regulator_ops vddh_regulator_ops = { +}; + +static const struct regulator_desc vddh_desc = { + .name = "vddh", + .of_match = of_match_ptr("vddh-regulator"), + .n_voltages = 1, + .fixed_uV = 2500000, + .ops = &vddh_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int at8031_register_regulators(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct regulator_config config = { }; + + config.dev = dev; + config.driver_data = phydev; + + priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); + if (IS_ERR(priv->vddio_rdev)) { + phydev_err(phydev, "failed to register VDDIO regulator\n"); + return PTR_ERR(priv->vddio_rdev); + } + + priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); + if (IS_ERR(priv->vddh_rdev)) { + phydev_err(phydev, "failed to register VDDH regulator\n"); + return PTR_ERR(priv->vddh_rdev); + } + + return 0; +} + +static bool at803x_match_phy_id(struct phy_device *phydev, u32 phy_id) +{ + return (phydev->phy_id & phydev->drv->phy_id_mask) + == (phy_id & phydev->drv->phy_id_mask); +} + +static int at803x_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct at803x_priv *priv = phydev->priv; + unsigned int sel, mask; + u32 freq, strength; + int ret; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) + return 0; + + ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); + if (!ret) { + mask = AT803X_CLK_OUT_MASK; + switch (freq) { + case 25000000: + sel = AT803X_CLK_OUT_25MHZ_XTAL; + break; + case 50000000: + sel = AT803X_CLK_OUT_50MHZ_PLL; + break; + case 62500000: + sel = AT803X_CLK_OUT_62_5MHZ_PLL; + break; + case 125000000: + sel = AT803X_CLK_OUT_125MHZ_PLL; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-frequency\n"); + return -EINVAL; + } + + priv->clk_25m_reg |= FIELD_PREP(mask, sel); + priv->clk_25m_mask |= mask; + + /* Fixup for the AR8030/AR8035. This chip has another mask and + * doesn't support the DSP reference. Eg. the lowest bit of the + * mask. The upper two bits select the same frequencies. Mask + * the lowest bit here. + * + * Warning: + * There was no datasheet for the AR8030 available so this is + * just a guess. But the AR8035 is listed as pin compatible + * to the AR8030 so there might be a good chance it works on + * the AR8030 too. + */ + if (at803x_match_phy_id(phydev, ATH8030_PHY_ID) || + at803x_match_phy_id(phydev, ATH8035_PHY_ID)) { + priv->clk_25m_reg &= ~AT8035_CLK_OUT_MASK; + priv->clk_25m_mask &= ~AT8035_CLK_OUT_MASK; + } + } + + ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); + if (!ret) { + priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; + switch (strength) { + case AR803X_STRENGTH_FULL: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; + break; + case AR803X_STRENGTH_HALF: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; + break; + case AR803X_STRENGTH_QUARTER: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-strength\n"); + return -EINVAL; + } + } + + /* Only supported on AR8031, the AR8030/AR8035 use strapping options */ + if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { + if (of_property_read_bool(node, "qca,keep-pll-enabled")) + priv->flags |= AT803X_KEEP_PLL_ENABLED; + + ret = at8031_register_regulators(phydev); + if (ret < 0) + return ret; + + priv->vddio = devm_regulator_get_optional(&phydev->mdio.dev, + "vddio"); + if (IS_ERR(priv->vddio)) { + phydev_err(phydev, "failed to get VDDIO regulator\n"); + return PTR_ERR(priv->vddio); + } + + ret = regulator_enable(priv->vddio); + if (ret < 0) + return ret; + } + + return 0; +} + +static int at803x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct at803x_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return at803x_parse_dt(phydev); +} + +static int at803x_clk_out_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int val; + + if (!priv->clk_25m_mask) + return 0; + + val = phy_read_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M); + if (val < 0) + return val; + + val &= ~priv->clk_25m_mask; + val |= priv->clk_25m_reg; + + return phy_write_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, val); +} + +static int at8031_pll_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is PLL OFF. After a soft reset, the + * values are retained. + */ + if (priv->flags & AT803X_KEEP_PLL_ENABLED) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_PLL_ON); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_PLL_ON, 0); +} + static int at803x_config_init(struct phy_device *phydev) { int ret; @@ -259,8 +542,20 @@ static int at803x_config_init(struct phy_device *phydev) ret = at803x_enable_tx_delay(phydev); else ret = at803x_disable_tx_delay(phydev); + if (ret < 0) + return ret; - return ret; + ret = at803x_clk_out_config(phydev); + if (ret < 0) + return ret; + + if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { + ret = at8031_pll_config(phydev); + if (ret < 0) + return ret; + } + + return 0; } static int at803x_ack_interrupt(struct phy_device *phydev) @@ -413,6 +708,7 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8035_PHY_ID, .name = "Atheros 8035 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, + .probe = at803x_probe, .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, @@ -427,6 +723,7 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8030_PHY_ID, .name = "Atheros 8030 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, + .probe = at803x_probe, .config_init = at803x_config_init, .link_change_notify = at803x_link_change_notify, .set_wol = at803x_set_wol, @@ -441,6 +738,7 @@ static struct phy_driver at803x_driver[] = { .phy_id = ATH8031_PHY_ID, .name = "Atheros 8031 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, + .probe = at803x_probe, .config_init = at803x_config_init, .set_wol = at803x_set_wol, .get_wol = at803x_get_wol, @@ -455,6 +753,7 @@ static struct phy_driver at803x_driver[] = { /* ATHEROS AR9331 */ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), .name = "Atheros AR9331 built-in PHY", + .probe = at803x_probe, .config_init = at803x_config_init, .suspend = at803x_suspend, .resume = at803x_resume, -- cgit v1.2.3-59-g8ed1b From 428061f70f1aa3a56fdf53d57adbac0caef3e663 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 6 Nov 2019 23:36:15 +0100 Subject: net: phy: at803x: mention AR8033 as same as AR8031 The AR8033 is the AR8031 without PTP support. All other registers are the same. Unfortunately, they share the same PHY ID. Therefore, we cannot distinguish between the one with PTP support and the one without. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 2 +- drivers/net/phy/at803x.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 1b884ebb4e48..8bccadf17e60 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -442,7 +442,7 @@ config NXP_TJA11XX_PHY config AT803X_PHY tristate "Qualcomm Atheros AR803X PHYs" help - Currently supports the AR8030, AR8031 and AR8035 model + Currently supports the AR8030, AR8031, AR8033 and AR8035 model config QSEMI_PHY tristate "Quality Semiconductor PHYs" diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index aa782b28615b..716672edd415 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -93,8 +93,8 @@ #define AT803X_CLK_OUT_125MHZ_PLL 6 #define AT803X_CLK_OUT_125MHZ_DSP 7 -/* The AR8035 has another mask which is compatible with the AR8031 mask but - * doesn't support choosing between XTAL/PLL and DSP. +/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask + * but doesn't support choosing between XTAL/PLL and DSP. */ #define AT8035_CLK_OUT_MASK GENMASK(4, 3) @@ -449,7 +449,9 @@ static int at803x_parse_dt(struct phy_device *phydev) } } - /* Only supported on AR8031, the AR8030/AR8035 use strapping options */ + /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping + * options. + */ if (at803x_match_phy_id(phydev, ATH8031_PHY_ID)) { if (of_property_read_bool(node, "qca,keep-pll-enabled")) priv->flags |= AT803X_KEEP_PLL_ENABLED; @@ -734,9 +736,9 @@ static struct phy_driver at803x_driver[] = { .ack_interrupt = at803x_ack_interrupt, .config_intr = at803x_config_intr, }, { - /* ATHEROS 8031 */ + /* ATHEROS 8031/8033 */ .phy_id = ATH8031_PHY_ID, - .name = "Atheros 8031 ethernet", + .name = "Atheros 8031/8033 ethernet", .phy_id_mask = AT803X_PHY_ID_MASK, .probe = at803x_probe, .config_init = at803x_config_init, -- cgit v1.2.3-59-g8ed1b From 96c3671204b86042cd69dfdf06f4f65997cb9452 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 6 Nov 2019 23:36:16 +0100 Subject: net: phy: at803x: fix the PHY names Fix at least the displayed strings. The actual name of the chip is AR803x. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 716672edd415..4434d501cd4f 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -2,7 +2,7 @@ /* * drivers/net/phy/at803x.c * - * Driver for Atheros 803x PHY + * Driver for Qualcomm Atheros AR803x PHY * * Author: Matus Ujhelyi */ @@ -109,7 +109,7 @@ #define ATH8035_PHY_ID 0x004dd072 #define AT803X_PHY_ID_MASK 0xffffffef -MODULE_DESCRIPTION("Atheros 803x PHY driver"); +MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); @@ -706,9 +706,9 @@ static int at803x_read_status(struct phy_device *phydev) static struct phy_driver at803x_driver[] = { { - /* ATHEROS 8035 */ + /* Qualcomm Atheros AR8035 */ .phy_id = ATH8035_PHY_ID, - .name = "Atheros 8035 ethernet", + .name = "Qualcomm Atheros AR8035", .phy_id_mask = AT803X_PHY_ID_MASK, .probe = at803x_probe, .config_init = at803x_config_init, @@ -721,9 +721,9 @@ static struct phy_driver at803x_driver[] = { .ack_interrupt = at803x_ack_interrupt, .config_intr = at803x_config_intr, }, { - /* ATHEROS 8030 */ + /* Qualcomm Atheros AR8030 */ .phy_id = ATH8030_PHY_ID, - .name = "Atheros 8030 ethernet", + .name = "Qualcomm Atheros AR8030", .phy_id_mask = AT803X_PHY_ID_MASK, .probe = at803x_probe, .config_init = at803x_config_init, @@ -736,9 +736,9 @@ static struct phy_driver at803x_driver[] = { .ack_interrupt = at803x_ack_interrupt, .config_intr = at803x_config_intr, }, { - /* ATHEROS 8031/8033 */ + /* Qualcomm Atheros AR8031/AR8033 */ .phy_id = ATH8031_PHY_ID, - .name = "Atheros 8031/8033 ethernet", + .name = "Qualcomm Atheros AR8031/AR8033", .phy_id_mask = AT803X_PHY_ID_MASK, .probe = at803x_probe, .config_init = at803x_config_init, @@ -754,7 +754,7 @@ static struct phy_driver at803x_driver[] = { }, { /* ATHEROS AR9331 */ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), - .name = "Atheros AR9331 built-in PHY", + .name = "Qualcomm Atheros AR9331 built-in PHY", .probe = at803x_probe, .config_init = at803x_config_init, .suspend = at803x_suspend, -- cgit v1.2.3-59-g8ed1b From ed7fa2ad40556557cc0ba12649191680d992ed58 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 6 Nov 2019 23:36:17 +0100 Subject: net: phy: at803x: remove config_init for AR9331 According to its datasheet, the internal PHY doesn't have debug registers nor MMDs. Since config_init() only configures delays and clocks and so on in these registers it won't be needed on this PHY. Remove it. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/at803x.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index 4434d501cd4f..aee62610bade 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -755,8 +755,6 @@ static struct phy_driver at803x_driver[] = { /* ATHEROS AR9331 */ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), .name = "Qualcomm Atheros AR9331 built-in PHY", - .probe = at803x_probe, - .config_init = at803x_config_init, .suspend = at803x_suspend, .resume = at803x_resume, /* PHY_BASIC_FEATURES */ -- cgit v1.2.3-59-g8ed1b From 64a26007a8f51442a9efddf7d98d50e2ca4349cd Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 7 Nov 2019 01:18:00 +0100 Subject: net: dsa: mv8e6xxx: Fix stub function parameters mv88e6xxx_g2_atu_stats_get() takes two parameters. Make the stub function also take two, otherwise we get compile errors. Fixes: c5f299d59261 ("net: dsa: mv88e6xxx: global1_atu: Add helper for get next") Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/global2.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h index d80ad203d126..1f42ee656816 100644 --- a/drivers/net/dsa/mv88e6xxx/global2.h +++ b/drivers/net/dsa/mv88e6xxx/global2.h @@ -532,7 +532,8 @@ static inline int mv88e6xxx_g2_atu_stats_set(struct mv88e6xxx_chip *chip, return -EOPNOTSUPP; } -static inline int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip) +static inline int mv88e6xxx_g2_atu_stats_get(struct mv88e6xxx_chip *chip, + u16 *stats) { return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From 2d791e3bf218a8880e306eb2fa79dcf1429d01b3 Mon Sep 17 00:00:00 2001 From: Chenwandun Date: Thu, 7 Nov 2019 09:39:49 +0800 Subject: dpaa2-ptp: fix compile error phylink_set_port_modes will be compiled if CONFIG_PHYLINK enabled, dpaa2_mac_validate will be compiled if CONFIG_FSL_DPAA2_ETH enabled, it should select CONFIG_PHYLINK when dpaa2_mac_validate call phylink_set_port_modes drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.o: In function `dpaa2_mac_validate': dpaa2-mac.c:(.text+0x3a1): undefined reference to `phylink_set_port_modes' drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.o: In function `dpaa2_mac_connect': dpaa2-mac.c:(.text+0x91a): undefined reference to `phylink_create' dpaa2-mac.c:(.text+0x94e): undefined reference to `phylink_of_phy_connect' dpaa2-mac.c:(.text+0x97f): undefined reference to `phylink_destroy' drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.o: In function `dpaa2_mac_disconnect': dpaa2-mac.c:(.text+0xa9f): undefined reference to `phylink_disconnect_phy' dpaa2-mac.c:(.text+0xab0): undefined reference to `phylink_destroy' make: *** [vmlinux] Error 1 Fixes: 719479230893 ("dpaa2-eth: add MAC/PHY support through phylink") Signed-off-by: Chenwandun Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa2/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/Kconfig b/drivers/net/ethernet/freescale/dpaa2/Kconfig index fbef2829f3de..c6fb8e4021ac 100644 --- a/drivers/net/ethernet/freescale/dpaa2/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa2/Kconfig @@ -2,6 +2,7 @@ config FSL_DPAA2_ETH tristate "Freescale DPAA2 Ethernet" depends on FSL_MC_BUS && FSL_MC_DPIO + select PHYLINK help This is the DPAA2 Ethernet driver supporting Freescale SoCs with DPAA2 (DataPath Acceleration Architecture v2). -- cgit v1.2.3-59-g8ed1b From ab0367ea42217d45f0d8681a12ccff0efede9c39 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:04 +0530 Subject: cxgb4: query firmware for QoS offload resources QoS offload needs Ethernet Offload (ETHOFLD) resources present in the NIC. These resources are shared with other ULDs. So, query firmware for the available number of traffic classes, as well as, start and end indices (EOTID) of the ETHOFLD region. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 6 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 52 +++++++++++++++++++++---- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 10 +++++ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 2 + 4 files changed, 62 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1fbb640e896a..f2f643be7905 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -392,6 +392,7 @@ struct adapter_params { struct arch_specific_params arch; /* chip specific params */ unsigned char offload; unsigned char crypto; /* HW capability for crypto */ + unsigned char ethofld; /* QoS support */ unsigned char bypass; unsigned char hash_filter; @@ -1293,6 +1294,11 @@ static inline int is_uld(const struct adapter *adap) return (adap->params.offload || adap->params.crypto); } +static inline int is_ethofld(const struct adapter *adap) +{ + return adap->params.ethofld; +} + static inline u32 t4_read_reg(struct adapter *adap, u32 reg_addr) { return readl(adap->regs + reg_addr); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 33a923cfd82e..20d1687adea2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1458,19 +1458,23 @@ static int tid_init(struct tid_info *t) struct adapter *adap = container_of(t, struct adapter, tids); unsigned int max_ftids = t->nftids + t->nsftids; unsigned int natids = t->natids; + unsigned int eotid_bmap_size; unsigned int stid_bmap_size; unsigned int ftid_bmap_size; size_t size; stid_bmap_size = BITS_TO_LONGS(t->nstids + t->nsftids); ftid_bmap_size = BITS_TO_LONGS(t->nftids); + eotid_bmap_size = BITS_TO_LONGS(t->neotids); size = t->ntids * sizeof(*t->tid_tab) + natids * sizeof(*t->atid_tab) + t->nstids * sizeof(*t->stid_tab) + t->nsftids * sizeof(*t->stid_tab) + stid_bmap_size * sizeof(long) + max_ftids * sizeof(*t->ftid_tab) + - ftid_bmap_size * sizeof(long); + ftid_bmap_size * sizeof(long) + + t->neotids * sizeof(*t->eotid_tab) + + eotid_bmap_size * sizeof(long); t->tid_tab = kvzalloc(size, GFP_KERNEL); if (!t->tid_tab) @@ -1481,6 +1485,8 @@ static int tid_init(struct tid_info *t) t->stid_bmap = (unsigned long *)&t->stid_tab[t->nstids + t->nsftids]; t->ftid_tab = (struct filter_entry *)&t->stid_bmap[stid_bmap_size]; t->ftid_bmap = (unsigned long *)&t->ftid_tab[max_ftids]; + t->eotid_tab = (struct eotid_entry *)&t->ftid_bmap[ftid_bmap_size]; + t->eotid_bmap = (unsigned long *)&t->eotid_tab[t->neotids]; spin_lock_init(&t->stid_lock); spin_lock_init(&t->atid_lock); spin_lock_init(&t->ftid_lock); @@ -1507,6 +1513,9 @@ static int tid_init(struct tid_info *t) if (!t->stid_base && CHELSIO_CHIP_VERSION(adap->params.chip) <= CHELSIO_T5) __set_bit(0, t->stid_bmap); + + if (t->neotids) + bitmap_zero(t->eotid_bmap, t->neotids); } bitmap_zero(t->ftid_bmap, t->nftids); @@ -4604,11 +4613,18 @@ static int adap_init0(struct adapter *adap, int vpd_skip) adap->clipt_start = val[0]; adap->clipt_end = val[1]; - /* We don't yet have a PARAMs calls to retrieve the number of Traffic - * Classes supported by the hardware/firmware so we hard code it here - * for now. - */ - adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16; + /* Get the supported number of traffic classes */ + params[0] = FW_PARAM_DEV(NUM_TM_CLASS); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val); + if (ret < 0) { + /* We couldn't retrieve the number of Traffic Classes + * supported by the hardware/firmware. So we hard + * code it here. + */ + adap->params.nsched_cls = is_t4(adap->params.chip) ? 15 : 16; + } else { + adap->params.nsched_cls = val[0]; + } /* query params related to active filter region */ params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START); @@ -4693,7 +4709,8 @@ static int adap_init0(struct adapter *adap, int vpd_skip) adap->params.offload = 1; if (caps_cmd.ofldcaps || - (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER))) { + (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_HASHFILTER)) || + (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD))) { /* query offload-related parameters */ params[0] = FW_PARAM_DEV(NTID); params[1] = FW_PARAM_PFVF(SERVER_START); @@ -4735,6 +4752,19 @@ static int adap_init0(struct adapter *adap, int vpd_skip) } else { adap->num_ofld_uld += 1; } + + if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_ETHOFLD)) { + params[0] = FW_PARAM_PFVF(ETHOFLD_START); + params[1] = FW_PARAM_PFVF(ETHOFLD_END); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, + params, val); + if (!ret) { + adap->tids.eotid_base = val[0]; + adap->tids.neotids = min_t(u32, MAX_ATIDS, + val[1] - val[0] + 1); + adap->params.ethofld = 1; + } + } } if (caps_cmd.rdmacaps) { params[0] = FW_PARAM_PFVF(STAG_START); @@ -5942,8 +5972,14 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_LIST_HEAD(&adapter->mac_hlist); for_each_port(adapter, i) { + /* For supporting MQPRIO Offload, need some extra + * queues for each ETHOFLD TIDs. Keep it equal to + * MAX_ATIDs for now. Once we connect to firmware + * later and query the EOTID params, we'll come to + * know the actual # of EOTIDs supported. + */ netdev = alloc_etherdev_mq(sizeof(struct port_info), - MAX_ETH_QSETS); + MAX_ETH_QSETS + MAX_ATIDS); if (!netdev) { err = -ENOMEM; goto out_free_dev; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index cee582e36134..b78feef23dc4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -89,6 +89,10 @@ union aopen_entry { union aopen_entry *next; }; +struct eotid_entry { + void *data; +}; + /* * Holds the size, base address, free list start, etc of the TID, server TID, * and active-open TID tables. The tables themselves are allocated dynamically. @@ -126,6 +130,12 @@ struct tid_info { unsigned int v6_stids_in_use; unsigned int sftids_in_use; + /* ETHOFLD range */ + struct eotid_entry *eotid_tab; + unsigned long *eotid_bmap; + unsigned int eotid_base; + unsigned int neotids; + /* TIDs in the TCAM */ atomic_t tids_in_use; /* TIDs in the HASH */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 65313f6b5704..d603334bae95 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -1134,6 +1134,7 @@ enum fw_caps_config_nic { FW_CAPS_CONFIG_NIC = 0x00000001, FW_CAPS_CONFIG_NIC_VM = 0x00000002, FW_CAPS_CONFIG_NIC_HASHFILTER = 0x00000020, + FW_CAPS_CONFIG_NIC_ETHOFLD = 0x00000040, }; enum fw_caps_config_ofld { @@ -1276,6 +1277,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_HASHFILTER_WITH_OFLD = 0x28, FW_PARAMS_PARAM_DEV_DBQ_TIMER = 0x29, FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK = 0x2A, + FW_PARAMS_PARAM_DEV_NUM_TM_CLASS = 0x2B, FW_PARAMS_PARAM_DEV_FILTER = 0x2E, }; -- cgit v1.2.3-59-g8ed1b From 76c3a552e80ea47b7a9e4ba3f6e6af9659b23e7f Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:05 +0530 Subject: cxgb4: rework queue config and MSI-X allocation Simplify queue configuration and MSI-X allocation logic. Use a single MSI-X information table for both NIC and ULDs. Remove hard-coded MSI-X indices for firmware event queue and non data interrupts. Instead, use the MSI-X bitmap to obtain a free MSI-X index dynamically. Save each Rxq's index into the MSI-X information table, within the Rxq structures themselves, for easier cleanup. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 24 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 437 +++++++++++++++--------- drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 95 ++---- drivers/net/ethernet/chelsio/cxgb4/sge.c | 13 +- 4 files changed, 323 insertions(+), 246 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index f2f643be7905..dbfde3fbfce4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -712,6 +712,7 @@ struct sge_eth_rxq { /* SW Ethernet Rx queue */ struct sge_rspq rspq; struct sge_fl fl; struct sge_eth_stats stats; + struct msix_info *msix; } ____cacheline_aligned_in_smp; struct sge_ofld_stats { /* offload queue statistics */ @@ -725,6 +726,7 @@ struct sge_ofld_rxq { /* SW offload Rx queue */ struct sge_rspq rspq; struct sge_fl fl; struct sge_ofld_stats stats; + struct msix_info *msix; } ____cacheline_aligned_in_smp; struct tx_desc { @@ -789,7 +791,6 @@ struct sge_ctrl_txq { /* state for an SGE control Tx queue */ struct sge_uld_rxq_info { char name[IFNAMSIZ]; /* name of ULD driver */ struct sge_ofld_rxq *uldrxq; /* Rxq's for ULD */ - u16 *msix_tbl; /* msix_tbl for uld */ u16 *rspq_id; /* response queue id's of rxq */ u16 nrxq; /* # of ingress uld queues */ u16 nciq; /* # of completion queues */ @@ -842,6 +843,9 @@ struct sge { unsigned long *blocked_fl; struct timer_list rx_timer; /* refills starving FLs */ struct timer_list tx_timer; /* checks Tx queues */ + + int fwevtq_msix_idx; /* Index to firmware event queue MSI-X info */ + int nd_msix_idx; /* Index to non-data interrupts MSI-X info */ }; #define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++) @@ -871,13 +875,13 @@ struct hash_mac_addr { unsigned int iface_mac; }; -struct uld_msix_bmap { +struct msix_bmap { unsigned long *msix_bmap; unsigned int mapsize; spinlock_t lock; /* lock for acquiring bitmap */ }; -struct uld_msix_info { +struct msix_info { unsigned short vec; char desc[IFNAMSIZ + 10]; unsigned int idx; @@ -946,14 +950,9 @@ struct adapter { struct cxgb4_virt_res vres; unsigned int swintr; - struct msix_info { - unsigned short vec; - char desc[IFNAMSIZ + 10]; - cpumask_var_t aff_mask; - } msix_info[MAX_INGQ + 1]; - struct uld_msix_info *msix_info_ulds; /* msix info for uld's */ - struct uld_msix_bmap msix_bmap_ulds; /* msix bitmap for all uld */ - int msi_idx; + /* MSI-X Info for NIC and OFLD queues */ + struct msix_info *msix_info; + struct msix_bmap msix_bmap; struct doorbell_stats db_stats; struct sge sge; @@ -1954,5 +1953,6 @@ int cxgb4_alloc_raw_mac_filt(struct adapter *adap, int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, int *tcam_idx, const u8 *addr, bool persistent, u8 *smt_idx); - +int cxgb4_get_msix_idx_from_bmap(struct adapter *adap); +void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, u32 msix_idx); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 20d1687adea2..d8a1bd80b293 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -685,31 +685,6 @@ static irqreturn_t t4_nondata_intr(int irq, void *cookie) return IRQ_HANDLED; } -/* - * Name the MSI-X interrupts. - */ -static void name_msix_vecs(struct adapter *adap) -{ - int i, j, msi_idx = 2, n = sizeof(adap->msix_info[0].desc); - - /* non-data interrupts */ - snprintf(adap->msix_info[0].desc, n, "%s", adap->port[0]->name); - - /* FW events */ - snprintf(adap->msix_info[1].desc, n, "%s-FWeventq", - adap->port[0]->name); - - /* Ethernet queues */ - for_each_port(adap, j) { - struct net_device *d = adap->port[j]; - const struct port_info *pi = netdev_priv(d); - - for (i = 0; i < pi->nqsets; i++, msi_idx++) - snprintf(adap->msix_info[msi_idx].desc, n, "%s-Rx%d", - d->name, i); - } -} - int cxgb4_set_msix_aff(struct adapter *adap, unsigned short vec, cpumask_var_t *aff_mask, int idx) { @@ -743,15 +718,19 @@ static int request_msix_queue_irqs(struct adapter *adap) struct sge *s = &adap->sge; struct msix_info *minfo; int err, ethqidx; - int msi_index = 2; - err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0, - adap->msix_info[1].desc, &s->fw_evtq); + if (s->fwevtq_msix_idx < 0) + return -ENOMEM; + + err = request_irq(adap->msix_info[s->fwevtq_msix_idx].vec, + t4_sge_intr_msix, 0, + adap->msix_info[s->fwevtq_msix_idx].desc, + &s->fw_evtq); if (err) return err; for_each_ethrxq(s, ethqidx) { - minfo = &adap->msix_info[msi_index]; + minfo = s->ethrxq[ethqidx].msix; err = request_irq(minfo->vec, t4_sge_intr_msix, 0, minfo->desc, @@ -761,18 +740,16 @@ static int request_msix_queue_irqs(struct adapter *adap) cxgb4_set_msix_aff(adap, minfo->vec, &minfo->aff_mask, ethqidx); - msi_index++; } return 0; unwind: while (--ethqidx >= 0) { - msi_index--; - minfo = &adap->msix_info[msi_index]; + minfo = s->ethrxq[ethqidx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); free_irq(minfo->vec, &s->ethrxq[ethqidx].rspq); } - free_irq(adap->msix_info[1].vec, &s->fw_evtq); + free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); return err; } @@ -780,11 +757,11 @@ static void free_msix_queue_irqs(struct adapter *adap) { struct sge *s = &adap->sge; struct msix_info *minfo; - int i, msi_index = 2; + int i; - free_irq(adap->msix_info[1].vec, &s->fw_evtq); + free_irq(adap->msix_info[s->fwevtq_msix_idx].vec, &s->fw_evtq); for_each_ethrxq(s, i) { - minfo = &adap->msix_info[msi_index++]; + minfo = s->ethrxq[i].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); free_irq(minfo->vec, &s->ethrxq[i].rspq); } @@ -919,11 +896,14 @@ static void quiesce_rx(struct adapter *adap) /* Disable interrupt and napi handler */ static void disable_interrupts(struct adapter *adap) { + struct sge *s = &adap->sge; + if (adap->flags & CXGB4_FULL_INIT_DONE) { t4_intr_disable(adap); if (adap->flags & CXGB4_USING_MSIX) { free_msix_queue_irqs(adap); - free_irq(adap->msix_info[0].vec, adap); + free_irq(adap->msix_info[s->nd_msix_idx].vec, + adap); } else { free_irq(adap->pdev->irq, adap); } @@ -953,27 +933,58 @@ static void enable_rx(struct adapter *adap) } } +static int setup_non_data_intr(struct adapter *adap) +{ + int msix; + + adap->sge.nd_msix_idx = -1; + if (!(adap->flags & CXGB4_USING_MSIX)) + return 0; + + /* Request MSI-X vector for non-data interrupt */ + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + return -ENOMEM; + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s", adap->port[0]->name); + + adap->sge.nd_msix_idx = msix; + return 0; +} static int setup_fw_sge_queues(struct adapter *adap) { struct sge *s = &adap->sge; - int err = 0; + int msix, err = 0; bitmap_zero(s->starving_fl, s->egr_sz); bitmap_zero(s->txq_maperr, s->egr_sz); - if (adap->flags & CXGB4_USING_MSIX) - adap->msi_idx = 1; /* vector 0 is for non-queue interrupts */ - else { + if (adap->flags & CXGB4_USING_MSIX) { + s->fwevtq_msix_idx = -1; + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + return -ENOMEM; + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s-FWeventq", adap->port[0]->name); + } else { err = t4_sge_alloc_rxq(adap, &s->intrq, false, adap->port[0], 0, NULL, NULL, NULL, -1); if (err) return err; - adap->msi_idx = -((int)s->intrq.abs_id + 1); + msix = -((int)s->intrq.abs_id + 1); } err = t4_sge_alloc_rxq(adap, &s->fw_evtq, true, adap->port[0], - adap->msi_idx, NULL, fwevtq_handler, NULL, -1); + msix, NULL, fwevtq_handler, NULL, -1); + if (err && msix >= 0) + cxgb4_free_msix_idx_in_bmap(adap, msix); + + s->fwevtq_msix_idx = msix; return err; } @@ -987,14 +998,17 @@ static int setup_fw_sge_queues(struct adapter *adap) */ static int setup_sge_queues(struct adapter *adap) { - int err, i, j; - struct sge *s = &adap->sge; struct sge_uld_rxq_info *rxq_info = NULL; + struct sge *s = &adap->sge; unsigned int cmplqid = 0; + int err, i, j, msix = 0; if (is_uld(adap)) rxq_info = s->uld_rxq_info[CXGB4_ULD_RDMA]; + if (!(adap->flags & CXGB4_USING_MSIX)) + msix = -((int)s->intrq.abs_id + 1); + for_each_port(adap, i) { struct net_device *dev = adap->port[i]; struct port_info *pi = netdev_priv(dev); @@ -1002,10 +1016,21 @@ static int setup_sge_queues(struct adapter *adap) struct sge_eth_txq *t = &s->ethtxq[pi->first_qset]; for (j = 0; j < pi->nqsets; j++, q++) { - if (adap->msi_idx > 0) - adap->msi_idx++; + if (msix >= 0) { + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) { + err = msix; + goto freeout; + } + + snprintf(adap->msix_info[msix].desc, + sizeof(adap->msix_info[msix].desc), + "%s-Rx%d", dev->name, j); + q->msix = &adap->msix_info[msix]; + } + err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, - adap->msi_idx, &q->fl, + msix, &q->fl, t4_ethrx_handler, NULL, t4_get_tp_ch_map(adap, @@ -2372,6 +2397,7 @@ static void update_clip(const struct adapter *adap) */ static int cxgb_up(struct adapter *adap) { + struct sge *s = &adap->sge; int err; mutex_lock(&uld_mutex); @@ -2383,16 +2409,20 @@ static int cxgb_up(struct adapter *adap) goto freeq; if (adap->flags & CXGB4_USING_MSIX) { - name_msix_vecs(adap); - err = request_irq(adap->msix_info[0].vec, t4_nondata_intr, 0, - adap->msix_info[0].desc, adap); + if (s->nd_msix_idx < 0) { + err = -ENOMEM; + goto irq_err; + } + + err = request_irq(adap->msix_info[s->nd_msix_idx].vec, + t4_nondata_intr, 0, + adap->msix_info[s->nd_msix_idx].desc, adap); if (err) goto irq_err; + err = request_msix_queue_irqs(adap); - if (err) { - free_irq(adap->msix_info[0].vec, adap); - goto irq_err; - } + if (err) + goto irq_err_free_nd_msix; } else { err = request_irq(adap->pdev->irq, t4_intr_handler(adap), (adap->flags & CXGB4_USING_MSI) ? 0 @@ -2414,11 +2444,13 @@ static int cxgb_up(struct adapter *adap) #endif return err; - irq_err: +irq_err_free_nd_msix: + free_irq(adap->msix_info[s->nd_msix_idx].vec, adap); +irq_err: dev_err(adap->pdev_dev, "request_irq failed, err %d\n", err); - freeq: +freeq: t4_free_sge_resources(adap); - rel_lock: +rel_lock: mutex_unlock(&uld_mutex); return err; } @@ -5187,26 +5219,25 @@ static inline bool is_x_10g_port(const struct link_config *lc) return high_speeds != 0; } -/* - * Perform default configuration of DMA queues depending on the number and type +/* Perform default configuration of DMA queues depending on the number and type * of ports we found and the number of available CPUs. Most settings can be * modified by the admin prior to actual use. */ static int cfg_queues(struct adapter *adap) { + u32 avail_qsets, avail_eth_qsets, avail_uld_qsets; + u32 niqflint, neq, num_ulds; struct sge *s = &adap->sge; - int i, n10g = 0, qidx = 0; - int niqflint, neq, avail_eth_qsets; - int max_eth_qsets = 32; + u32 i, n10g = 0, qidx = 0; #ifndef CONFIG_CHELSIO_T4_DCB int q10g = 0; #endif - /* Reduce memory usage in kdump environment, disable all offload. - */ + /* Reduce memory usage in kdump environment, disable all offload. */ if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) { adap->params.offload = 0; adap->params.crypto = 0; + adap->params.ethofld = 0; } /* Calculate the number of Ethernet Queue Sets available based on @@ -5225,14 +5256,11 @@ static int cfg_queues(struct adapter *adap) if (!(adap->flags & CXGB4_USING_MSIX)) niqflint--; neq = adap->params.pfres.neq / 2; - avail_eth_qsets = min(niqflint, neq); + avail_qsets = min(niqflint, neq); - if (avail_eth_qsets > max_eth_qsets) - avail_eth_qsets = max_eth_qsets; - - if (avail_eth_qsets < adap->params.nports) { + if (avail_qsets < adap->params.nports) { dev_err(adap->pdev_dev, "avail_eth_qsets=%d < nports=%d\n", - avail_eth_qsets, adap->params.nports); + avail_qsets, adap->params.nports); return -ENOMEM; } @@ -5240,6 +5268,7 @@ static int cfg_queues(struct adapter *adap) for_each_port(adap, i) n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); + avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS); #ifdef CONFIG_CHELSIO_T4_DCB /* For Data Center Bridging support we need to be able to support up * to 8 Traffic Priorities; each of which will be assigned to its @@ -5259,8 +5288,7 @@ static int cfg_queues(struct adapter *adap) qidx += pi->nqsets; } #else /* !CONFIG_CHELSIO_T4_DCB */ - /* - * We default to 1 queue per non-10G port and up to # of cores queues + /* We default to 1 queue per non-10G port and up to # of cores queues * per 10G port. */ if (n10g) @@ -5282,19 +5310,27 @@ static int cfg_queues(struct adapter *adap) s->ethqsets = qidx; s->max_ethqsets = qidx; /* MSI-X may lower it later */ + avail_qsets -= qidx; if (is_uld(adap)) { - /* - * For offload we use 1 queue/channel if all ports are up to 1G, + /* For offload we use 1 queue/channel if all ports are up to 1G, * otherwise we divide all available queues amongst the channels * capped by the number of available cores. */ - if (n10g) { - i = min_t(int, MAX_OFLD_QSETS, num_online_cpus()); - s->ofldqsets = roundup(i, adap->params.nports); - } else { + num_ulds = adap->num_uld + adap->num_ofld_uld; + i = min_t(u32, MAX_OFLD_QSETS, num_online_cpus()); + avail_uld_qsets = roundup(i, adap->params.nports); + if (avail_qsets < num_ulds * adap->params.nports) { + adap->params.offload = 0; + adap->params.crypto = 0; + s->ofldqsets = 0; + } else if (avail_qsets < num_ulds * avail_uld_qsets || !n10g) { s->ofldqsets = adap->params.nports; + } else { + s->ofldqsets = avail_uld_qsets; } + + avail_qsets -= num_ulds * s->ofldqsets; } for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { @@ -5347,42 +5383,62 @@ static void reduce_ethqs(struct adapter *adap, int n) } } -static int get_msix_info(struct adapter *adap) +static int alloc_msix_info(struct adapter *adap, u32 num_vec) { - struct uld_msix_info *msix_info; - unsigned int max_ingq = 0; - - if (is_offload(adap)) - max_ingq += MAX_OFLD_QSETS * adap->num_ofld_uld; - if (is_pci_uld(adap)) - max_ingq += MAX_OFLD_QSETS * adap->num_uld; - - if (!max_ingq) - goto out; + struct msix_info *msix_info; - msix_info = kcalloc(max_ingq, sizeof(*msix_info), GFP_KERNEL); + msix_info = kcalloc(num_vec, sizeof(*msix_info), GFP_KERNEL); if (!msix_info) return -ENOMEM; - adap->msix_bmap_ulds.msix_bmap = kcalloc(BITS_TO_LONGS(max_ingq), - sizeof(long), GFP_KERNEL); - if (!adap->msix_bmap_ulds.msix_bmap) { + adap->msix_bmap.msix_bmap = kcalloc(BITS_TO_LONGS(num_vec), + sizeof(long), GFP_KERNEL); + if (!adap->msix_bmap.msix_bmap) { kfree(msix_info); return -ENOMEM; } - spin_lock_init(&adap->msix_bmap_ulds.lock); - adap->msix_info_ulds = msix_info; -out: + + spin_lock_init(&adap->msix_bmap.lock); + adap->msix_bmap.mapsize = num_vec; + + adap->msix_info = msix_info; return 0; } static void free_msix_info(struct adapter *adap) { - if (!(adap->num_uld && adap->num_ofld_uld)) - return; + kfree(adap->msix_bmap.msix_bmap); + kfree(adap->msix_info); +} + +int cxgb4_get_msix_idx_from_bmap(struct adapter *adap) +{ + struct msix_bmap *bmap = &adap->msix_bmap; + unsigned int msix_idx; + unsigned long flags; - kfree(adap->msix_info_ulds); - kfree(adap->msix_bmap_ulds.msix_bmap); + spin_lock_irqsave(&bmap->lock, flags); + msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); + if (msix_idx < bmap->mapsize) { + __set_bit(msix_idx, bmap->msix_bmap); + } else { + spin_unlock_irqrestore(&bmap->lock, flags); + return -ENOSPC; + } + + spin_unlock_irqrestore(&bmap->lock, flags); + return msix_idx; +} + +void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, + unsigned int msix_idx) +{ + struct msix_bmap *bmap = &adap->msix_bmap; + unsigned long flags; + + spin_lock_irqsave(&bmap->lock, flags); + __clear_bit(msix_idx, bmap->msix_bmap); + spin_unlock_irqrestore(&bmap->lock, flags); } /* 2 MSI-X vectors needed for the FW queue and non-data interrupts */ @@ -5390,88 +5446,142 @@ static void free_msix_info(struct adapter *adap) static int enable_msix(struct adapter *adap) { - int ofld_need = 0, uld_need = 0; - int i, j, want, need, allocated; + u8 num_uld = 0, nchan = adap->params.nports; + u32 ethqsets = 0, ofldqsets = 0; + u32 eth_need, uld_need = 0; + u32 i, want, need, num_vec; struct sge *s = &adap->sge; - unsigned int nchan = adap->params.nports; struct msix_entry *entries; - int max_ingq = MAX_INGQ; - - if (is_pci_uld(adap)) - max_ingq += (MAX_OFLD_QSETS * adap->num_uld); - if (is_offload(adap)) - max_ingq += (MAX_OFLD_QSETS * adap->num_ofld_uld); - entries = kmalloc_array(max_ingq + 1, sizeof(*entries), - GFP_KERNEL); - if (!entries) - return -ENOMEM; - - /* map for msix */ - if (get_msix_info(adap)) { - adap->params.offload = 0; - adap->params.crypto = 0; - } - - for (i = 0; i < max_ingq + 1; ++i) - entries[i].entry = i; + struct port_info *pi; + int allocated, ret; - want = s->max_ethqsets + EXTRA_VECS; - if (is_offload(adap)) { - want += adap->num_ofld_uld * s->ofldqsets; - ofld_need = adap->num_ofld_uld * nchan; - } - if (is_pci_uld(adap)) { - want += adap->num_uld * s->ofldqsets; - uld_need = adap->num_uld * nchan; - } + want = s->max_ethqsets; #ifdef CONFIG_CHELSIO_T4_DCB /* For Data Center Bridging we need 8 Ethernet TX Priority Queues for * each port. */ - need = 8 * adap->params.nports + EXTRA_VECS + ofld_need + uld_need; + need = 8 * nchan; #else - need = adap->params.nports + EXTRA_VECS + ofld_need + uld_need; + need = nchan; #endif + eth_need = need; + if (is_uld(adap)) { + num_uld = adap->num_ofld_uld + adap->num_uld; + want += num_uld * s->ofldqsets; + uld_need = num_uld * nchan; + need += uld_need; + } + + want += EXTRA_VECS; + need += EXTRA_VECS; + + entries = kmalloc_array(want, sizeof(*entries), GFP_KERNEL); + if (!entries) + return -ENOMEM; + + for (i = 0; i < want; i++) + entries[i].entry = i; + allocated = pci_enable_msix_range(adap->pdev, entries, need, want); if (allocated < 0) { - dev_info(adap->pdev_dev, "not enough MSI-X vectors left," - " not using MSI-X\n"); - kfree(entries); - return allocated; + /* Disable offload and attempt to get vectors for NIC + * only mode. + */ + want = s->max_ethqsets + EXTRA_VECS; + need = eth_need + EXTRA_VECS; + allocated = pci_enable_msix_range(adap->pdev, entries, + need, want); + if (allocated < 0) { + dev_info(adap->pdev_dev, + "Disabling MSI-X due to insufficient MSI-X vectors\n"); + ret = allocated; + goto out_free; + } + + dev_info(adap->pdev_dev, + "Disabling offload due to insufficient MSI-X vectors\n"); + adap->params.offload = 0; + adap->params.crypto = 0; + adap->params.ethofld = 0; + s->ofldqsets = 0; + uld_need = 0; } - /* Distribute available vectors to the various queue groups. - * Every group gets its minimum requirement and NIC gets top - * priority for leftovers. - */ - i = allocated - EXTRA_VECS - ofld_need - uld_need; - if (i < s->max_ethqsets) { - s->max_ethqsets = i; - if (i < s->ethqsets) - reduce_ethqs(adap, i); + num_vec = allocated; + if (num_vec < want) { + /* Distribute available vectors to the various queue groups. + * Every group gets its minimum requirement and NIC gets top + * priority for leftovers. + */ + ethqsets = eth_need; + if (is_uld(adap)) + ofldqsets = nchan; + + num_vec -= need; + while (num_vec) { + if (num_vec < eth_need || + ethqsets > s->max_ethqsets) + break; + + for_each_port(adap, i) { + pi = adap2pinfo(adap, i); + if (pi->nqsets < 2) + continue; + + ethqsets++; + num_vec--; + } + } + + if (is_uld(adap)) { + while (num_vec) { + if (num_vec < uld_need || + ofldqsets > s->ofldqsets) + break; + + ofldqsets++; + num_vec -= uld_need; + } + } + } else { + ethqsets = s->max_ethqsets; + if (is_uld(adap)) + ofldqsets = s->ofldqsets; + } + + if (ethqsets < s->max_ethqsets) { + s->max_ethqsets = ethqsets; + reduce_ethqs(adap, ethqsets); } + if (is_uld(adap)) { - if (allocated < want) - s->nqs_per_uld = nchan; - else - s->nqs_per_uld = s->ofldqsets; + s->ofldqsets = ofldqsets; + s->nqs_per_uld = s->ofldqsets; } - for (i = 0; i < (s->max_ethqsets + EXTRA_VECS); ++i) + /* map for msix */ + ret = alloc_msix_info(adap, allocated); + if (ret) + goto out_disable_msix; + + for (i = 0; i < allocated; i++) { adap->msix_info[i].vec = entries[i].vector; - if (is_uld(adap)) { - for (j = 0 ; i < allocated; ++i, j++) { - adap->msix_info_ulds[j].vec = entries[i].vector; - adap->msix_info_ulds[j].idx = i; - } - adap->msix_bmap_ulds.mapsize = j; + adap->msix_info[i].idx = i; } - dev_info(adap->pdev_dev, "%d MSI-X vectors allocated, " - "nic %d per uld %d\n", + + dev_info(adap->pdev_dev, + "%d MSI-X vectors allocated, nic %d per uld %d\n", allocated, s->max_ethqsets, s->nqs_per_uld); kfree(entries); return 0; + +out_disable_msix: + pci_disable_msix(adap->pdev); + +out_free: + kfree(entries); + return ret; } #undef EXTRA_VECS @@ -6163,6 +6273,13 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_free_dev; + err = setup_non_data_intr(adapter); + if (err) { + dev_err(adapter->pdev_dev, + "Non Data interrupt allocation failed, err: %d\n", err); + goto out_free_dev; + } + err = setup_fw_sge_queues(adapter); if (err) { dev_err(adapter->pdev_dev, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 86b528d8364c..3d9401354af2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -53,35 +53,6 @@ #define for_each_uldrxq(m, i) for (i = 0; i < ((m)->nrxq + (m)->nciq); i++) -static int get_msix_idx_from_bmap(struct adapter *adap) -{ - struct uld_msix_bmap *bmap = &adap->msix_bmap_ulds; - unsigned long flags; - unsigned int msix_idx; - - spin_lock_irqsave(&bmap->lock, flags); - msix_idx = find_first_zero_bit(bmap->msix_bmap, bmap->mapsize); - if (msix_idx < bmap->mapsize) { - __set_bit(msix_idx, bmap->msix_bmap); - } else { - spin_unlock_irqrestore(&bmap->lock, flags); - return -ENOSPC; - } - - spin_unlock_irqrestore(&bmap->lock, flags); - return msix_idx; -} - -static void free_msix_idx_in_bmap(struct adapter *adap, unsigned int msix_idx) -{ - struct uld_msix_bmap *bmap = &adap->msix_bmap_ulds; - unsigned long flags; - - spin_lock_irqsave(&bmap->lock, flags); - __clear_bit(msix_idx, bmap->msix_bmap); - spin_unlock_irqrestore(&bmap->lock, flags); -} - /* Flush the aggregated lro sessions */ static void uldrx_flush_handler(struct sge_rspq *q) { @@ -138,9 +109,9 @@ static int alloc_uld_rxqs(struct adapter *adap, struct sge_uld_rxq_info *rxq_info, bool lro) { unsigned int nq = rxq_info->nrxq + rxq_info->nciq; - int i, err, msi_idx, que_idx = 0, bmap_idx = 0; struct sge_ofld_rxq *q = rxq_info->uldrxq; unsigned short *ids = rxq_info->rspq_id; + int i, err, msi_idx, que_idx = 0; struct sge *s = &adap->sge; unsigned int per_chan; @@ -159,12 +130,18 @@ static int alloc_uld_rxqs(struct adapter *adap, } if (msi_idx >= 0) { - bmap_idx = get_msix_idx_from_bmap(adap); - if (bmap_idx < 0) { + msi_idx = cxgb4_get_msix_idx_from_bmap(adap); + if (msi_idx < 0) { err = -ENOSPC; goto freeout; } - msi_idx = adap->msix_info_ulds[bmap_idx].idx; + + snprintf(adap->msix_info[msi_idx].desc, + sizeof(adap->msix_info[msi_idx].desc), + "%s-%s%d", + adap->port[0]->name, rxq_info->name, i); + + q->msix = &adap->msix_info[msi_idx]; } err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[que_idx++ / per_chan], @@ -175,8 +152,7 @@ static int alloc_uld_rxqs(struct adapter *adap, 0); if (err) goto freeout; - if (msi_idx >= 0) - rxq_info->msix_tbl[i] = bmap_idx; + memset(&q->stats, 0, sizeof(q->stats)); if (ids) ids[i] = q->rspq.abs_id; @@ -188,6 +164,8 @@ freeout: if (q->rspq.desc) free_rspq_fl(adap, &q->rspq, q->fl.size ? &q->fl : NULL); + if (q->msix) + cxgb4_free_msix_idx_in_bmap(adap, q->msix->idx); } return err; } @@ -198,14 +176,6 @@ setup_sge_queues_uld(struct adapter *adap, unsigned int uld_type, bool lro) struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int i, ret = 0; - if (adap->flags & CXGB4_USING_MSIX) { - rxq_info->msix_tbl = kcalloc((rxq_info->nrxq + rxq_info->nciq), - sizeof(unsigned short), - GFP_KERNEL); - if (!rxq_info->msix_tbl) - return -ENOMEM; - } - ret = !(!alloc_uld_rxqs(adap, rxq_info, lro)); /* Tell uP to route control queue completions to rdma rspq */ @@ -261,8 +231,6 @@ static void free_sge_queues_uld(struct adapter *adap, unsigned int uld_type) t4_free_uld_rxqs(adap, rxq_info->nciq, rxq_info->uldrxq + rxq_info->nrxq); t4_free_uld_rxqs(adap, rxq_info->nrxq, rxq_info->uldrxq); - if (adap->flags & CXGB4_USING_MSIX) - kfree(rxq_info->msix_tbl); } static int cfg_queues_uld(struct adapter *adap, unsigned int uld_type, @@ -355,13 +323,12 @@ static int request_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - struct uld_msix_info *minfo; + struct msix_info *minfo; + unsigned int idx; int err = 0; - unsigned int idx, bmap_idx; for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; + minfo = rxq_info->uldrxq[idx].msix; err = request_irq(minfo->vec, t4_sge_intr_msix, 0, minfo->desc, @@ -376,10 +343,9 @@ request_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) unwind: while (idx-- > 0) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; + minfo = rxq_info->uldrxq[idx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); - free_msix_idx_in_bmap(adap, bmap_idx); + cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); } return err; @@ -389,33 +355,17 @@ static void free_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - struct uld_msix_info *minfo; - unsigned int idx, bmap_idx; + struct msix_info *minfo; + unsigned int idx; for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - minfo = &adap->msix_info_ulds[bmap_idx]; - + minfo = rxq_info->uldrxq[idx].msix; cxgb4_clear_msix_aff(minfo->vec, minfo->aff_mask); - free_msix_idx_in_bmap(adap, bmap_idx); + cxgb4_free_msix_idx_in_bmap(adap, minfo->idx); free_irq(minfo->vec, &rxq_info->uldrxq[idx].rspq); } } -static void name_msix_vecs_uld(struct adapter *adap, unsigned int uld_type) -{ - struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; - int n = sizeof(adap->msix_info_ulds[0].desc); - unsigned int idx, bmap_idx; - - for_each_uldrxq(rxq_info, idx) { - bmap_idx = rxq_info->msix_tbl[idx]; - - snprintf(adap->msix_info_ulds[bmap_idx].desc, n, "%s-%s%d", - adap->port[0]->name, rxq_info->name, idx); - } -} - static void enable_rx(struct adapter *adap, struct sge_rspq *q) { if (!q) @@ -750,7 +700,6 @@ void cxgb4_register_uld(enum cxgb4_uld type, if (ret) goto free_queues; if (adap->flags & CXGB4_USING_MSIX) { - name_msix_vecs_uld(adap, type); ret = request_msix_queue_irqs_uld(adap, type); if (ret) goto free_rxq; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 928bfea5457b..82d8e13fc7d2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -4060,6 +4060,10 @@ void t4_free_sge_resources(struct adapter *adap) if (eq->rspq.desc) free_rspq_fl(adap, &eq->rspq, eq->fl.size ? &eq->fl : NULL); + if (eq->msix) { + cxgb4_free_msix_idx_in_bmap(adap, eq->msix->idx); + eq->msix = NULL; + } etq = &adap->sge.ethtxq[i]; if (etq->q.desc) { @@ -4086,8 +4090,15 @@ void t4_free_sge_resources(struct adapter *adap) } } - if (adap->sge.fw_evtq.desc) + if (adap->sge.fw_evtq.desc) { free_rspq_fl(adap, &adap->sge.fw_evtq, NULL); + if (adap->sge.fwevtq_msix_idx >= 0) + cxgb4_free_msix_idx_in_bmap(adap, + adap->sge.fwevtq_msix_idx); + } + + if (adap->sge.nd_msix_idx >= 0) + cxgb4_free_msix_idx_in_bmap(adap, adap->sge.nd_msix_idx); if (adap->sge.intrq.desc) free_rspq_fl(adap, &adap->sge.intrq, NULL); -- cgit v1.2.3-59-g8ed1b From b1396c2bd67556b8d9a31ea2b26e133cb6c802d3 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:06 +0530 Subject: cxgb4: parse and configure TC-MQPRIO offload Add logic for validation and configuration of TC-MQPRIO Qdisc offload. Also, add support to manage EOSW_TXQ, which have 1-to-1 mapping with EOTIDs, and expose them to network stack. Move common skb validation in Tx path to a separate function and add minimal Tx path for ETHOFLD. Update Tx queue selection to return normal NIC Txq to send traffic pattern that can't go through ETHOFLD Tx path. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 40 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 38 ++- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 346 +++++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h | 30 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 29 ++ drivers/net/ethernet/chelsio/cxgb4/sge.c | 162 +++++++--- 7 files changed, 597 insertions(+), 50 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 20390f6afbb4..49a19308073b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \ cxgb4_uld.o srq.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o cxgb4_mps.o \ - cudbg_common.o cudbg_lib.o cudbg_zlib.o + cudbg_common.o cudbg_lib.o cudbg_zlib.o cxgb4_tc_mqprio.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index dbfde3fbfce4..04a81276e9c8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -803,6 +803,38 @@ struct sge_uld_txq_info { u16 ntxq; /* # of egress uld queues */ }; +enum sge_eosw_state { + CXGB4_EO_STATE_CLOSED = 0, /* Not ready to accept traffic */ +}; + +struct sge_eosw_desc { + struct sk_buff *skb; /* SKB to free after getting completion */ + dma_addr_t addr[MAX_SKB_FRAGS + 1]; /* DMA mapped addresses */ +}; + +struct sge_eosw_txq { + spinlock_t lock; /* Per queue lock to synchronize completions */ + enum sge_eosw_state state; /* Current ETHOFLD State */ + struct sge_eosw_desc *desc; /* Descriptor ring to hold packets */ + u32 ndesc; /* Number of descriptors */ + u32 pidx; /* Current Producer Index */ + u32 last_pidx; /* Last successfully transmitted Producer Index */ + u32 cidx; /* Current Consumer Index */ + u32 last_cidx; /* Last successfully reclaimed Consumer Index */ + u32 inuse; /* Number of packets held in ring */ + + u32 cred; /* Current available credits */ + u32 ncompl; /* # of completions posted */ + u32 last_compl; /* # of credits consumed since last completion req */ + + u32 eotid; /* Index into EOTID table in software */ + u32 hwtid; /* Hardware EOTID index */ + + u32 hwqid; /* Underlying hardware queue index */ + struct net_device *netdev; /* Pointer to netdevice */ + struct tasklet_struct qresume_tsk; /* Restarts the queue */ +}; + struct sge { struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; struct sge_eth_txq ptptxq; @@ -1044,6 +1076,9 @@ struct adapter { #if IS_ENABLED(CONFIG_THERMAL) struct ch_thermal ch_thermal; #endif + + /* TC MQPRIO offload */ + struct cxgb4_tc_mqprio *tc_mqprio; }; /* Support for "sched-class" command to allow a TX Scheduling Class to be @@ -1895,6 +1930,9 @@ int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port, void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, struct sge_fl *fl); void free_tx_desc(struct adapter *adap, struct sge_txq *q, unsigned int n, bool unmap); +void cxgb4_eosw_txq_free_desc(struct adapter *adap, struct sge_eosw_txq *txq, + u32 ndesc); +void cxgb4_ethofld_restart(unsigned long data); void free_txq(struct adapter *adap, struct sge_txq *q); void cxgb4_reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, bool unmap); @@ -1955,4 +1993,6 @@ int cxgb4_update_mac_filt(struct port_info *pi, unsigned int viid, bool persistent, u8 *smt_idx); int cxgb4_get_msix_idx_from_bmap(struct adapter *adap); void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, u32 msix_idx); +int cxgb_open(struct net_device *dev); +int cxgb_close(struct net_device *dev); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index d8a1bd80b293..fe3ea60843c3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -65,6 +65,7 @@ #include #include #include +#include #include "cxgb4.h" #include "cxgb4_filter.h" @@ -82,6 +83,7 @@ #include "sched.h" #include "cxgb4_tc_u32.h" #include "cxgb4_tc_flower.h" +#include "cxgb4_tc_mqprio.h" #include "cxgb4_ptp.h" #include "cxgb4_cudbg.h" @@ -1117,6 +1119,18 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, } #endif /* CONFIG_CHELSIO_T4_DCB */ + if (dev->num_tc) { + struct port_info *pi = netdev2pinfo(dev); + + /* Send unsupported traffic pattern to normal NIC queues. */ + txq = netdev_pick_tx(dev, skb, sb_dev); + if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) || + ip_hdr(skb)->protocol != IPPROTO_TCP) + txq = txq % pi->nqsets; + + return txq; + } + if (select_queue) { txq = (skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) @@ -2472,11 +2486,11 @@ static void cxgb_down(struct adapter *adapter) /* * net_device operations */ -static int cxgb_open(struct net_device *dev) +int cxgb_open(struct net_device *dev) { - int err; struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; + int err; netif_carrier_off(dev); @@ -2499,7 +2513,7 @@ static int cxgb_open(struct net_device *dev) return err; } -static int cxgb_close(struct net_device *dev) +int cxgb_close(struct net_device *dev) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; @@ -3233,6 +3247,17 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data, } } +static int cxgb_setup_tc_mqprio(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio) +{ + struct adapter *adap = netdev2adap(dev); + + if (!is_ethofld(adap) || !adap->tc_mqprio) + return -ENOMEM; + + return cxgb4_setup_tc_mqprio(dev, mqprio); +} + static LIST_HEAD(cxgb_block_cb_list); static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type, @@ -3241,6 +3266,8 @@ static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type, struct port_info *pi = netdev2pinfo(dev); switch (type) { + case TC_SETUP_QDISC_MQPRIO: + return cxgb_setup_tc_mqprio(dev, type_data); case TC_SETUP_BLOCK: return flow_block_cb_setup_simple(type_data, &cxgb_block_cb_list, @@ -5668,6 +5695,7 @@ static void free_some_resources(struct adapter *adapter) kvfree(adapter->srq); t4_cleanup_sched(adapter); kvfree(adapter->tids.tid_tab); + cxgb4_cleanup_tc_mqprio(adapter); cxgb4_cleanup_tc_flower(adapter); cxgb4_cleanup_tc_u32(adapter); kfree(adapter->sge.egr_map); @@ -6237,6 +6265,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (cxgb4_init_tc_flower(adapter)) dev_warn(&pdev->dev, "could not offload tc flower, continuing\n"); + + if (cxgb4_init_tc_mqprio(adapter)) + dev_warn(&pdev->dev, + "could not offload tc mqprio, continuing\n"); } if (is_offload(adapter) || is_hashfilter(adapter)) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c new file mode 100644 index 000000000000..8cdf3dc1da16 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2019 Chelsio Communications. All rights reserved. */ + +#include "cxgb4.h" +#include "cxgb4_tc_mqprio.h" + +static int cxgb4_mqprio_validate(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio) +{ + u64 min_rate = 0, max_rate = 0, max_link_rate; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + u32 qcount = 0, qoffset = 0; + u32 link_ok, speed, mtu; + int ret; + u8 i; + + if (!mqprio->qopt.num_tc) + return 0; + + if (mqprio->qopt.hw != TC_MQPRIO_HW_OFFLOAD_TCS) { + netdev_err(dev, "Only full TC hardware offload is supported\n"); + return -EINVAL; + } else if (mqprio->mode != TC_MQPRIO_MODE_CHANNEL) { + netdev_err(dev, "Only channel mode offload is supported\n"); + return -EINVAL; + } else if (mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE) { + netdev_err(dev, "Only bandwidth rate shaper supported\n"); + return -EINVAL; + } else if (mqprio->qopt.num_tc > adap->params.nsched_cls) { + netdev_err(dev, + "Only %u traffic classes supported by hardware\n", + adap->params.nsched_cls); + return -ERANGE; + } + + ret = t4_get_link_params(pi, &link_ok, &speed, &mtu); + if (ret) { + netdev_err(dev, "Failed to get link speed, ret: %d\n", ret); + return -EINVAL; + } + + /* Convert from Mbps to bps */ + max_link_rate = (u64)speed * 1000 * 1000; + + for (i = 0; i < mqprio->qopt.num_tc; i++) { + qoffset = max_t(u16, mqprio->qopt.offset[i], qoffset); + qcount += mqprio->qopt.count[i]; + + /* Convert byte per second to bits per second */ + min_rate += (mqprio->min_rate[i] * 8); + max_rate += (mqprio->max_rate[i] * 8); + } + + if (qoffset >= adap->tids.neotids || qcount > adap->tids.neotids) + return -ENOMEM; + + if (min_rate > max_link_rate || max_rate > max_link_rate) { + netdev_err(dev, + "Total Min/Max (%llu/%llu) Rate > supported (%llu)\n", + min_rate, max_rate, max_link_rate); + return -EINVAL; + } + + return 0; +} + +static int cxgb4_init_eosw_txq(struct net_device *dev, + struct sge_eosw_txq *eosw_txq, + u32 eotid, u32 hwqid) +{ + struct adapter *adap = netdev2adap(dev); + struct sge_eosw_desc *ring; + + memset(eosw_txq, 0, sizeof(*eosw_txq)); + + ring = kcalloc(CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM, + sizeof(*ring), GFP_KERNEL); + if (!ring) + return -ENOMEM; + + eosw_txq->desc = ring; + eosw_txq->ndesc = CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM; + spin_lock_init(&eosw_txq->lock); + eosw_txq->state = CXGB4_EO_STATE_CLOSED; + eosw_txq->eotid = eotid; + eosw_txq->hwtid = adap->tids.eotid_base + eosw_txq->eotid; + eosw_txq->cred = adap->params.ofldq_wr_cred; + eosw_txq->hwqid = hwqid; + eosw_txq->netdev = dev; + tasklet_init(&eosw_txq->qresume_tsk, cxgb4_ethofld_restart, + (unsigned long)eosw_txq); + return 0; +} + +static void cxgb4_clean_eosw_txq(struct net_device *dev, + struct sge_eosw_txq *eosw_txq) +{ + struct adapter *adap = netdev2adap(dev); + + cxgb4_eosw_txq_free_desc(adap, eosw_txq, eosw_txq->ndesc); + eosw_txq->pidx = 0; + eosw_txq->last_pidx = 0; + eosw_txq->cidx = 0; + eosw_txq->last_cidx = 0; + eosw_txq->inuse = 0; + eosw_txq->cred = adap->params.ofldq_wr_cred; + eosw_txq->ncompl = 0; + eosw_txq->last_compl = 0; + eosw_txq->state = CXGB4_EO_STATE_CLOSED; +} + +static void cxgb4_free_eosw_txq(struct net_device *dev, + struct sge_eosw_txq *eosw_txq) +{ + spin_lock_bh(&eosw_txq->lock); + cxgb4_clean_eosw_txq(dev, eosw_txq); + kfree(eosw_txq->desc); + spin_unlock_bh(&eosw_txq->lock); + tasklet_kill(&eosw_txq->qresume_tsk); +} + +static int cxgb4_mqprio_enable_offload(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio) +{ + struct cxgb4_tc_port_mqprio *tc_port_mqprio; + u32 qoffset, qcount, tot_qcount, qid, hwqid; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_eosw_txq *eosw_txq; + int eotid, ret; + u16 i, j; + + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; + for (i = 0; i < mqprio->qopt.num_tc; i++) { + qoffset = mqprio->qopt.offset[i]; + qcount = mqprio->qopt.count[i]; + for (j = 0; j < qcount; j++) { + eotid = cxgb4_get_free_eotid(&adap->tids); + if (eotid < 0) { + ret = -ENOMEM; + goto out_free_eotids; + } + + qid = qoffset + j; + hwqid = pi->first_qset + (eotid % pi->nqsets); + eosw_txq = &tc_port_mqprio->eosw_txq[qid]; + ret = cxgb4_init_eosw_txq(dev, eosw_txq, + eotid, hwqid); + if (ret) + goto out_free_eotids; + + cxgb4_alloc_eotid(&adap->tids, eotid, eosw_txq); + } + } + + memcpy(&tc_port_mqprio->mqprio, mqprio, + sizeof(struct tc_mqprio_qopt_offload)); + + /* Inform the stack about the configured tc params. + * + * Set the correct queue map. If no queue count has been + * specified, then send the traffic through default NIC + * queues; instead of ETHOFLD queues. + */ + ret = netdev_set_num_tc(dev, mqprio->qopt.num_tc); + if (ret) + goto out_free_eotids; + + tot_qcount = pi->nqsets; + for (i = 0; i < mqprio->qopt.num_tc; i++) { + qcount = mqprio->qopt.count[i]; + if (qcount) { + qoffset = mqprio->qopt.offset[i] + pi->nqsets; + } else { + qcount = pi->nqsets; + qoffset = 0; + } + + ret = netdev_set_tc_queue(dev, i, qcount, qoffset); + if (ret) + goto out_reset_tc; + + tot_qcount += mqprio->qopt.count[i]; + } + + ret = netif_set_real_num_tx_queues(dev, tot_qcount); + if (ret) + goto out_reset_tc; + + tc_port_mqprio->state = CXGB4_MQPRIO_STATE_ACTIVE; + return 0; + +out_reset_tc: + netdev_reset_tc(dev); + i = mqprio->qopt.num_tc; + +out_free_eotids: + while (i-- > 0) { + qoffset = mqprio->qopt.offset[i]; + qcount = mqprio->qopt.count[i]; + for (j = 0; j < qcount; j++) { + eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j]; + cxgb4_free_eotid(&adap->tids, eosw_txq->eotid); + cxgb4_free_eosw_txq(dev, eosw_txq); + } + } + + return ret; +} + +static void cxgb4_mqprio_disable_offload(struct net_device *dev) +{ + struct cxgb4_tc_port_mqprio *tc_port_mqprio; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_eosw_txq *eosw_txq; + u32 qoffset, qcount; + u16 i, j; + + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; + if (tc_port_mqprio->state != CXGB4_MQPRIO_STATE_ACTIVE) + return; + + netdev_reset_tc(dev); + netif_set_real_num_tx_queues(dev, pi->nqsets); + + for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++) { + qoffset = tc_port_mqprio->mqprio.qopt.offset[i]; + qcount = tc_port_mqprio->mqprio.qopt.count[i]; + for (j = 0; j < qcount; j++) { + eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j]; + cxgb4_free_eotid(&adap->tids, eosw_txq->eotid); + cxgb4_free_eosw_txq(dev, eosw_txq); + } + } + + memset(&tc_port_mqprio->mqprio, 0, + sizeof(struct tc_mqprio_qopt_offload)); + + tc_port_mqprio->state = CXGB4_MQPRIO_STATE_DISABLED; +} + +int cxgb4_setup_tc_mqprio(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio) +{ + bool needs_bring_up = false; + int ret; + + ret = cxgb4_mqprio_validate(dev, mqprio); + if (ret) + return ret; + + /* To configure tc params, the current allocated EOTIDs must + * be freed up. However, they can't be freed up if there's + * traffic running on the interface. So, ensure interface is + * down before configuring tc params. + */ + if (netif_running(dev)) { + cxgb_close(dev); + needs_bring_up = true; + } + + cxgb4_mqprio_disable_offload(dev); + + /* If requested for clear, then just return since resources are + * already freed up by now. + */ + if (!mqprio->qopt.num_tc) + goto out; + + ret = cxgb4_mqprio_enable_offload(dev, mqprio); + +out: + if (needs_bring_up) + cxgb_open(dev); + + return ret; +} + +int cxgb4_init_tc_mqprio(struct adapter *adap) +{ + struct cxgb4_tc_port_mqprio *tc_port_mqprio, *port_mqprio; + struct cxgb4_tc_mqprio *tc_mqprio; + struct sge_eosw_txq *eosw_txq; + int ret = 0; + u8 i; + + tc_mqprio = kzalloc(sizeof(*tc_mqprio), GFP_KERNEL); + if (!tc_mqprio) + return -ENOMEM; + + tc_port_mqprio = kcalloc(adap->params.nports, sizeof(*tc_port_mqprio), + GFP_KERNEL); + if (!tc_port_mqprio) { + ret = -ENOMEM; + goto out_free_mqprio; + } + + tc_mqprio->port_mqprio = tc_port_mqprio; + for (i = 0; i < adap->params.nports; i++) { + port_mqprio = &tc_mqprio->port_mqprio[i]; + eosw_txq = kcalloc(adap->tids.neotids, sizeof(*eosw_txq), + GFP_KERNEL); + if (!eosw_txq) { + ret = -ENOMEM; + goto out_free_ports; + } + port_mqprio->eosw_txq = eosw_txq; + } + + adap->tc_mqprio = tc_mqprio; + return 0; + +out_free_ports: + for (i = 0; i < adap->params.nports; i++) { + port_mqprio = &tc_mqprio->port_mqprio[i]; + kfree(port_mqprio->eosw_txq); + } + kfree(tc_port_mqprio); + +out_free_mqprio: + kfree(tc_mqprio); + return ret; +} + +void cxgb4_cleanup_tc_mqprio(struct adapter *adap) +{ + struct cxgb4_tc_port_mqprio *port_mqprio; + u8 i; + + if (adap->tc_mqprio) { + if (adap->tc_mqprio->port_mqprio) { + for (i = 0; i < adap->params.nports; i++) { + struct net_device *dev = adap->port[i]; + + if (dev) + cxgb4_mqprio_disable_offload(dev); + port_mqprio = &adap->tc_mqprio->port_mqprio[i]; + kfree(port_mqprio->eosw_txq); + } + kfree(adap->tc_mqprio->port_mqprio); + } + kfree(adap->tc_mqprio); + } +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h new file mode 100644 index 000000000000..125664b82236 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2019 Chelsio Communications. All rights reserved. */ + +#ifndef __CXGB4_TC_MQPRIO_H__ +#define __CXGB4_TC_MQPRIO_H__ + +#include + +#define CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM 128 + +enum cxgb4_mqprio_state { + CXGB4_MQPRIO_STATE_DISABLED = 0, + CXGB4_MQPRIO_STATE_ACTIVE, +}; + +struct cxgb4_tc_port_mqprio { + enum cxgb4_mqprio_state state; /* Current MQPRIO offload state */ + struct tc_mqprio_qopt_offload mqprio; /* MQPRIO offload params */ + struct sge_eosw_txq *eosw_txq; /* Netdev SW Tx queue array */ +}; + +struct cxgb4_tc_mqprio { + struct cxgb4_tc_port_mqprio *port_mqprio; /* Per port MQPRIO info */ +}; + +int cxgb4_setup_tc_mqprio(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio); +int cxgb4_init_tc_mqprio(struct adapter *adap); +void cxgb4_cleanup_tc_mqprio(struct adapter *adap); +#endif /* __CXGB4_TC_MQPRIO_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index b78feef23dc4..861b25d28ed6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -186,6 +186,35 @@ static inline void cxgb4_insert_tid(struct tid_info *t, void *data, atomic_inc(&t->conns_in_use); } +static inline struct eotid_entry *cxgb4_lookup_eotid(struct tid_info *t, + u32 eotid) +{ + return eotid < t->neotids ? &t->eotid_tab[eotid] : NULL; +} + +static inline int cxgb4_get_free_eotid(struct tid_info *t) +{ + int eotid; + + eotid = find_first_zero_bit(t->eotid_bmap, t->neotids); + if (eotid >= t->neotids) + eotid = -1; + + return eotid; +} + +static inline void cxgb4_alloc_eotid(struct tid_info *t, u32 eotid, void *data) +{ + set_bit(eotid, t->eotid_bmap); + t->eotid_tab[eotid].data = data; +} + +static inline void cxgb4_free_eotid(struct tid_info *t, u32 eotid) +{ + clear_bit(eotid, t->eotid_bmap); + t->eotid_tab[eotid].data = NULL; +} + int cxgb4_alloc_atid(struct tid_info *t, void *data); int cxgb4_alloc_stid(struct tid_info *t, int family, void *data); int cxgb4_alloc_sftid(struct tid_info *t, int family, void *data); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 82d8e13fc7d2..ed1418d2364f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -269,7 +269,6 @@ out_err: } EXPORT_SYMBOL(cxgb4_map_skb); -#ifdef CONFIG_NEED_DMA_MAP_STATE static void unmap_skb(struct device *dev, const struct sk_buff *skb, const dma_addr_t *addr) { @@ -284,6 +283,7 @@ static void unmap_skb(struct device *dev, const struct sk_buff *skb, dma_unmap_page(dev, *addr++, skb_frag_size(fp), DMA_TO_DEVICE); } +#ifdef CONFIG_NEED_DMA_MAP_STATE /** * deferred_unmap_destructor - unmap a packet when it is freed * @skb: the packet @@ -1347,6 +1347,31 @@ int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq, return reclaimed; } +static inline int cxgb4_validate_skb(struct sk_buff *skb, + struct net_device *dev, + u32 min_pkt_len) +{ + u32 max_pkt_len; + + /* The chip min packet length is 10 octets but some firmware + * commands have a minimum packet length requirement. So, play + * safe and reject anything shorter than @min_pkt_len. + */ + if (unlikely(skb->len < min_pkt_len)) + return -EINVAL; + + /* Discard the packet if the length is greater than mtu */ + max_pkt_len = ETH_HLEN + dev->mtu; + + if (skb_vlan_tagged(skb)) + max_pkt_len += VLAN_HLEN; + + if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) + return -EINVAL; + + return 0; +} + /** * cxgb4_eth_xmit - add a packet to an Ethernet Tx queue * @skb: the packet @@ -1356,41 +1381,24 @@ int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq, */ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 wr_mid, ctrl0, op; - u64 cntrl, *end, *sgl; - int qidx, credits; - unsigned int flits, ndesc; - struct adapter *adap; - struct sge_eth_txq *q; - const struct port_info *pi; + enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; + bool ptp_enabled = is_ptp_enabled(skb, dev); + dma_addr_t addr[MAX_SKB_FRAGS + 1]; + const struct skb_shared_info *ssi; struct fw_eth_tx_pkt_wr *wr; struct cpl_tx_pkt_core *cpl; - const struct skb_shared_info *ssi; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; + int len, qidx, credits, ret; + const struct port_info *pi; + unsigned int flits, ndesc; bool immediate = false; - int len, max_pkt_len; - bool ptp_enabled = is_ptp_enabled(skb, dev); + u32 wr_mid, ctrl0, op; + u64 cntrl, *end, *sgl; + struct sge_eth_txq *q; unsigned int chip_ver; - enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; - -#ifdef CONFIG_CHELSIO_T4_FCOE - int err; -#endif /* CONFIG_CHELSIO_T4_FCOE */ - - /* - * The chip min packet length is 10 octets but play safe and reject - * anything shorter than an Ethernet header. - */ - if (unlikely(skb->len < ETH_HLEN)) { -out_free: dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } + struct adapter *adap; - /* Discard the packet if the length is greater than mtu */ - max_pkt_len = ETH_HLEN + dev->mtu; - if (skb_vlan_tagged(skb)) - max_pkt_len += VLAN_HLEN; - if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) + ret = cxgb4_validate_skb(skb, dev, ETH_HLEN); + if (ret) goto out_free; pi = netdev_priv(dev); @@ -1421,8 +1429,8 @@ out_free: dev_kfree_skb_any(skb); cntrl = TXPKT_L4CSUM_DIS_F | TXPKT_IPCSUM_DIS_F; #ifdef CONFIG_CHELSIO_T4_FCOE - err = cxgb_fcoe_offload(skb, adap, pi, &cntrl); - if (unlikely(err == -ENOTSUPP)) { + ret = cxgb_fcoe_offload(skb, adap, pi, &cntrl); + if (unlikely(ret == -ENOTSUPP)) { if (ptp_enabled) spin_unlock(&adap->ptp_lock); goto out_free; @@ -1622,6 +1630,10 @@ out_free: dev_kfree_skb_any(skb); if (ptp_enabled) spin_unlock(&adap->ptp_lock); return NETDEV_TX_OK; + +out_free: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } /* Constants ... */ @@ -1710,32 +1722,25 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, dma_addr_t addr[MAX_SKB_FRAGS + 1]; const struct skb_shared_info *ssi; struct fw_eth_tx_pkt_vm_wr *wr; - int qidx, credits, max_pkt_len; struct cpl_tx_pkt_core *cpl; const struct port_info *pi; unsigned int flits, ndesc; struct sge_eth_txq *txq; struct adapter *adapter; + int qidx, credits, ret; + size_t fw_hdr_copy_len; u64 cntrl, *end; u32 wr_mid; - const size_t fw_hdr_copy_len = sizeof(wr->ethmacdst) + - sizeof(wr->ethmacsrc) + - sizeof(wr->ethtype) + - sizeof(wr->vlantci); /* The chip minimum packet length is 10 octets but the firmware * command that we are using requires that we copy the Ethernet header * (including the VLAN tag) into the header so we reject anything * smaller than that ... */ - if (unlikely(skb->len < fw_hdr_copy_len)) - goto out_free; - - /* Discard the packet if the length is greater than mtu */ - max_pkt_len = ETH_HLEN + dev->mtu; - if (skb_vlan_tag_present(skb)) - max_pkt_len += VLAN_HLEN; - if (!skb_shinfo(skb)->gso_size && (unlikely(skb->len > max_pkt_len))) + fw_hdr_copy_len = sizeof(wr->ethmacdst) + sizeof(wr->ethmacsrc) + + sizeof(wr->ethtype) + sizeof(wr->vlantci); + ret = cxgb4_validate_skb(skb, dev, fw_hdr_copy_len); + if (ret) goto out_free; /* Figure out which TX Queue we're going to use. */ @@ -1991,13 +1996,62 @@ out_free: return NETDEV_TX_OK; } +static inline void eosw_txq_advance_index(u32 *idx, u32 n, u32 max) +{ + u32 val = *idx + n; + + if (val >= max) + val -= max; + + *idx = val; +} + +void cxgb4_eosw_txq_free_desc(struct adapter *adap, + struct sge_eosw_txq *eosw_txq, u32 ndesc) +{ + struct sge_eosw_desc *d; + + d = &eosw_txq->desc[eosw_txq->last_cidx]; + while (ndesc--) { + if (d->skb) { + if (d->addr[0]) { + unmap_skb(adap->pdev_dev, d->skb, d->addr); + memset(d->addr, 0, sizeof(d->addr)); + } + dev_consume_skb_any(d->skb); + d->skb = NULL; + } + eosw_txq_advance_index(&eosw_txq->last_cidx, 1, + eosw_txq->ndesc); + d = &eosw_txq->desc[eosw_txq->last_cidx]; + } +} + +static netdev_tx_t cxgb4_ethofld_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + int ret; + + ret = cxgb4_validate_skb(skb, dev, ETH_HLEN); + if (ret) + goto out_free; + +out_free: + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct port_info *pi = netdev_priv(dev); + u16 qid = skb_get_queue_mapping(skb); if (unlikely(pi->eth_flags & PRIV_FLAG_PORT_TX_VM)) return cxgb4_vf_eth_xmit(skb, dev); + if (unlikely(qid >= pi->nqsets)) + return cxgb4_ethofld_xmit(skb, dev); + return cxgb4_eth_xmit(skb, dev); } @@ -3311,6 +3365,22 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) return work_done; } +void cxgb4_ethofld_restart(unsigned long data) +{ + struct sge_eosw_txq *eosw_txq = (struct sge_eosw_txq *)data; + int pktcount; + + spin_lock(&eosw_txq->lock); + pktcount = eosw_txq->cidx - eosw_txq->last_cidx; + if (pktcount < 0) + pktcount += eosw_txq->ndesc; + + if (pktcount) + cxgb4_eosw_txq_free_desc(netdev2adap(eosw_txq->netdev), + eosw_txq, pktcount); + spin_unlock(&eosw_txq->lock); +} + /* * The MSI-X interrupt handler for an SGE response queue. */ -- cgit v1.2.3-59-g8ed1b From 2d0cb84dd9731d5d0e1326f0e10be893cb2fe698 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:07 +0530 Subject: cxgb4: add ETHOFLD hardware queue support Add support for configuring and managing ETHOFLD hardware queues. Keep the queue count and MSI-X allocation scheme same as NIC queues. ETHOFLD hardware queues are dynamically allocated/destroyed as TC-MQPRIO Qdisc offload is enabled/disabled on the corresponding interface, respectively. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 3 + drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 21 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 20 +++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 53 ++++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 72 +++++++-- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 168 +++++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h | 10 ++ drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 40 ++--- drivers/net/ethernet/chelsio/cxgb4/sge.c | 95 +++++++++--- 9 files changed, 419 insertions(+), 63 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index 69746696a929..f5be3ee1bdb4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -325,6 +325,9 @@ enum cudbg_qdesc_qtype { CUDBG_QTYPE_CRYPTO_FLQ, CUDBG_QTYPE_TLS_RXQ, CUDBG_QTYPE_TLS_FLQ, + CUDBG_QTYPE_ETHOFLD_TXQ, + CUDBG_QTYPE_ETHOFLD_RXQ, + CUDBG_QTYPE_ETHOFLD_FLQ, CUDBG_QTYPE_MAX, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index c2e92786608b..c9d3dea4413e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -2930,6 +2930,10 @@ void cudbg_fill_qdesc_num_and_size(const struct adapter *padap, tot_size += CXGB4_ULD_MAX * MAX_ULD_QSETS * SGE_MAX_IQ_SIZE * MAX_RXQ_DESC_SIZE; + /* ETHOFLD TXQ, RXQ, and FLQ */ + tot_entries += MAX_OFLD_QSETS * 3; + tot_size += MAX_OFLD_QSETS * MAX_TXQ_ENTRIES * MAX_TXQ_DESC_SIZE; + tot_size += sizeof(struct cudbg_ver_hdr) + sizeof(struct cudbg_qdesc_info) + sizeof(struct cudbg_qdesc_entry) * tot_entries; @@ -3087,6 +3091,23 @@ int cudbg_collect_qdesc(struct cudbg_init *pdbg_init, } } + /* ETHOFLD TXQ */ + if (s->eohw_txq) + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_TXQ(&s->eohw_txq[i].q, + CUDBG_QTYPE_ETHOFLD_TXQ, out); + + /* ETHOFLD RXQ and FLQ */ + if (s->eohw_rxq) { + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_RXQ(&s->eohw_rxq[i].rspq, + CUDBG_QTYPE_ETHOFLD_RXQ, out); + + for (i = 0; i < s->eoqsets; i++) + QDESC_GET_FLQ(&s->eohw_rxq[i].fl, + CUDBG_QTYPE_ETHOFLD_FLQ, out); + } + out_unlock: mutex_unlock(&uld_mutex); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 04a81276e9c8..d9d92dc0d0c5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -835,6 +835,16 @@ struct sge_eosw_txq { struct tasklet_struct qresume_tsk; /* Restarts the queue */ }; +struct sge_eohw_txq { + spinlock_t lock; /* Per queue lock */ + struct sge_txq q; /* HW Txq */ + struct adapter *adap; /* Backpointer to adapter */ + unsigned long tso; /* # of TSO requests */ + unsigned long tx_cso; /* # of Tx checksum offloads */ + unsigned long vlan_ins; /* # of Tx VLAN insertions */ + unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ +}; + struct sge { struct sge_eth_txq ethtxq[MAX_ETH_QSETS]; struct sge_eth_txq ptptxq; @@ -848,11 +858,16 @@ struct sge { struct sge_rspq intrq ____cacheline_aligned_in_smp; spinlock_t intrq_lock; + struct sge_eohw_txq *eohw_txq; + struct sge_ofld_rxq *eohw_rxq; + u16 max_ethqsets; /* # of available Ethernet queue sets */ u16 ethqsets; /* # of active Ethernet queue sets */ u16 ethtxq_rover; /* Tx queue to clean up next */ u16 ofldqsets; /* # of active ofld queue sets */ u16 nqs_per_uld; /* # of Rx queues per ULD */ + u16 eoqsets; /* # of ETHOFLD queues */ + u16 timer_val[SGE_NTIMERS]; u8 counter_val[SGE_NCOUNTERS]; u16 dbqtimer_tick; @@ -1466,6 +1481,9 @@ int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid, int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, struct net_device *dev, unsigned int iqid, unsigned int uld_type); +int t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, + struct net_device *dev, u32 iqid); +void t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq); irqreturn_t t4_sge_intr_msix(int irq, void *cookie); int t4_sge_init(struct adapter *adap); void t4_sge_start(struct adapter *adap); @@ -1995,4 +2013,6 @@ int cxgb4_get_msix_idx_from_bmap(struct adapter *adap); void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, u32 msix_idx); int cxgb_open(struct net_device *dev); int cxgb_close(struct net_device *dev); +void cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q); +void cxgb4_quiesce_rx(struct sge_rspq *q); #endif /* __CXGB4_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index ae6a47dd7dc9..a13b03f771cc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2658,6 +2658,7 @@ static int sge_qinfo_uld_ciq_entries(const struct adapter *adap, int uld) static int sge_qinfo_show(struct seq_file *seq, void *v) { + int eth_entries, ctrl_entries, eo_entries = 0; int uld_rxq_entries[CXGB4_ULD_MAX] = { 0 }; int uld_ciq_entries[CXGB4_ULD_MAX] = { 0 }; int uld_txq_entries[CXGB4_TX_MAX] = { 0 }; @@ -2665,11 +2666,12 @@ static int sge_qinfo_show(struct seq_file *seq, void *v) const struct sge_uld_rxq_info *urxq_info; struct adapter *adap = seq->private; int i, n, r = (uintptr_t)v - 1; - int eth_entries, ctrl_entries; struct sge *s = &adap->sge; eth_entries = DIV_ROUND_UP(adap->sge.ethqsets, 4); ctrl_entries = DIV_ROUND_UP(MAX_CTRL_QUEUES, 4); + if (adap->sge.eohw_txq) + eo_entries = DIV_ROUND_UP(adap->sge.eoqsets, 4); mutex_lock(&uld_mutex); if (s->uld_txq_info) @@ -2761,6 +2763,54 @@ do { \ } r -= eth_entries; + if (r < eo_entries) { + int base_qset = r * 4; + const struct sge_ofld_rxq *rx = &s->eohw_rxq[base_qset]; + const struct sge_eohw_txq *tx = &s->eohw_txq[base_qset]; + + n = min(4, s->eoqsets - 4 * r); + + S("QType:", "ETHOFLD"); + S("Interface:", + rx[i].rspq.netdev ? rx[i].rspq.netdev->name : "N/A"); + T("TxQ ID:", q.cntxt_id); + T("TxQ size:", q.size); + T("TxQ inuse:", q.in_use); + T("TxQ CIDX:", q.cidx); + T("TxQ PIDX:", q.pidx); + R("RspQ ID:", rspq.abs_id); + R("RspQ size:", rspq.size); + R("RspQE size:", rspq.iqe_len); + R("RspQ CIDX:", rspq.cidx); + R("RspQ Gen:", rspq.gen); + S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq)); + S3("u", "Intr pktcnt:", s->counter_val[rx[i].rspq.pktcnt_idx]); + R("FL ID:", fl.cntxt_id); + S3("u", "FL size:", rx->fl.size ? rx->fl.size - 8 : 0); + R("FL pend:", fl.pend_cred); + R("FL avail:", fl.avail); + R("FL PIDX:", fl.pidx); + R("FL CIDX:", fl.cidx); + RL("RxPackets:", stats.pkts); + RL("RxImm:", stats.imm); + RL("RxAN", stats.an); + RL("RxNoMem", stats.nomem); + TL("TSO:", tso); + TL("TxCSO:", tx_cso); + TL("VLANins:", vlan_ins); + TL("TxQFull:", q.stops); + TL("TxQRestarts:", q.restarts); + TL("TxMapErr:", mapping_err); + RL("FLAllocErr:", fl.alloc_failed); + RL("FLLrgAlcErr:", fl.large_alloc_failed); + RL("FLMapErr:", fl.mapping_err); + RL("FLLow:", fl.low); + RL("FLStarving:", fl.starving); + + goto unlock; + } + + r -= eo_entries; if (r < uld_txq_entries[CXGB4_TX_OFLD]) { const struct sge_uld_txq *tx; @@ -3007,6 +3057,7 @@ static int sge_queue_entries(const struct adapter *adap) mutex_unlock(&uld_mutex); return DIV_ROUND_UP(adap->sge.ethqsets, 4) + + (adap->sge.eohw_txq ? DIV_ROUND_UP(adap->sge.eoqsets, 4) : 0) + tot_uld_entries + DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index fe3ea60843c3..b5148c57e8bf 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -880,6 +880,12 @@ static unsigned int rxq_to_chan(const struct sge *p, unsigned int qid) return netdev2pinfo(p->ingr_map[qid]->netdev)->tx_chan; } +void cxgb4_quiesce_rx(struct sge_rspq *q) +{ + if (q->handler) + napi_disable(&q->napi); +} + /* * Wait until all NAPI handlers are descheduled. */ @@ -890,8 +896,10 @@ static void quiesce_rx(struct adapter *adap) for (i = 0; i < adap->sge.ingr_sz; i++) { struct sge_rspq *q = adap->sge.ingr_map[i]; - if (q && q->handler) - napi_disable(&q->napi); + if (!q) + continue; + + cxgb4_quiesce_rx(q); } } @@ -913,6 +921,17 @@ static void disable_interrupts(struct adapter *adap) } } +void cxgb4_enable_rx(struct adapter *adap, struct sge_rspq *q) +{ + if (q->handler) + napi_enable(&q->napi); + + /* 0-increment GTS to start the timer and enable interrupts */ + t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), + SEINTARM_V(q->intr_params) | + INGRESSQID_V(q->cntxt_id)); +} + /* * Enable NAPI scheduling and interrupt generation for all Rx queues. */ @@ -925,13 +944,8 @@ static void enable_rx(struct adapter *adap) if (!q) continue; - if (q->handler) - napi_enable(&q->napi); - /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), - SEINTARM_V(q->intr_params) | - INGRESSQID_V(q->cntxt_id)); + cxgb4_enable_rx(adap, q); } } @@ -5360,6 +5374,19 @@ static int cfg_queues(struct adapter *adap) avail_qsets -= num_ulds * s->ofldqsets; } + /* ETHOFLD Queues used for QoS offload should follow same + * allocation scheme as normal Ethernet Queues. + */ + if (is_ethofld(adap)) { + if (avail_qsets < s->max_ethqsets) { + adap->params.ethofld = 0; + s->eoqsets = 0; + } else { + s->eoqsets = s->max_ethqsets; + } + avail_qsets -= s->eoqsets; + } + for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) { struct sge_eth_rxq *r = &s->ethrxq[i]; @@ -5473,9 +5500,9 @@ void cxgb4_free_msix_idx_in_bmap(struct adapter *adap, static int enable_msix(struct adapter *adap) { + u32 eth_need, uld_need = 0, ethofld_need = 0; + u32 ethqsets = 0, ofldqsets = 0, eoqsets = 0; u8 num_uld = 0, nchan = adap->params.nports; - u32 ethqsets = 0, ofldqsets = 0; - u32 eth_need, uld_need = 0; u32 i, want, need, num_vec; struct sge *s = &adap->sge; struct msix_entry *entries; @@ -5499,6 +5526,12 @@ static int enable_msix(struct adapter *adap) need += uld_need; } + if (is_ethofld(adap)) { + want += s->eoqsets; + ethofld_need = eth_need; + need += ethofld_need; + } + want += EXTRA_VECS; need += EXTRA_VECS; @@ -5531,7 +5564,9 @@ static int enable_msix(struct adapter *adap) adap->params.crypto = 0; adap->params.ethofld = 0; s->ofldqsets = 0; + s->eoqsets = 0; uld_need = 0; + ethofld_need = 0; } num_vec = allocated; @@ -5543,10 +5578,12 @@ static int enable_msix(struct adapter *adap) ethqsets = eth_need; if (is_uld(adap)) ofldqsets = nchan; + if (is_ethofld(adap)) + eoqsets = ethofld_need; num_vec -= need; while (num_vec) { - if (num_vec < eth_need || + if (num_vec < eth_need + ethofld_need || ethqsets > s->max_ethqsets) break; @@ -5557,6 +5594,10 @@ static int enable_msix(struct adapter *adap) ethqsets++; num_vec--; + if (ethofld_need) { + eoqsets++; + num_vec--; + } } } @@ -5574,6 +5615,8 @@ static int enable_msix(struct adapter *adap) ethqsets = s->max_ethqsets; if (is_uld(adap)) ofldqsets = s->ofldqsets; + if (is_ethofld(adap)) + eoqsets = s->eoqsets; } if (ethqsets < s->max_ethqsets) { @@ -5586,6 +5629,9 @@ static int enable_msix(struct adapter *adap) s->nqs_per_uld = s->ofldqsets; } + if (is_ethofld(adap)) + s->eoqsets = eoqsets; + /* map for msix */ ret = alloc_msix_info(adap, allocated); if (ret) @@ -5597,8 +5643,8 @@ static int enable_msix(struct adapter *adap) } dev_info(adap->pdev_dev, - "%d MSI-X vectors allocated, nic %d per uld %d\n", - allocated, s->max_ethqsets, s->nqs_per_uld); + "%d MSI-X vectors allocated, nic %d eoqsets %d per uld %d\n", + allocated, s->max_ethqsets, s->eoqsets, s->nqs_per_uld); kfree(entries); return 0; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index 8cdf3dc1da16..66503ea259e7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -120,6 +120,166 @@ static void cxgb4_free_eosw_txq(struct net_device *dev, tasklet_kill(&eosw_txq->qresume_tsk); } +static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_ofld_rxq *eorxq; + struct sge_eohw_txq *eotxq; + int ret, msix = 0; + u32 i; + + /* Allocate ETHOFLD hardware queue structures if not done already */ + if (!refcount_read(&adap->tc_mqprio->refcnt)) { + adap->sge.eohw_rxq = kcalloc(adap->sge.eoqsets, + sizeof(struct sge_ofld_rxq), + GFP_KERNEL); + if (!adap->sge.eohw_rxq) + return -ENOMEM; + + adap->sge.eohw_txq = kcalloc(adap->sge.eoqsets, + sizeof(struct sge_eohw_txq), + GFP_KERNEL); + if (!adap->sge.eohw_txq) { + kfree(adap->sge.eohw_rxq); + return -ENOMEM; + } + } + + if (!(adap->flags & CXGB4_USING_MSIX)) + msix = -((int)adap->sge.intrq.abs_id + 1); + + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + /* Allocate Rxqs for receiving ETHOFLD Tx completions */ + if (msix >= 0) { + msix = cxgb4_get_msix_idx_from_bmap(adap); + if (msix < 0) + goto out_free_queues; + + eorxq->msix = &adap->msix_info[msix]; + snprintf(eorxq->msix->desc, + sizeof(eorxq->msix->desc), + "%s-eorxq%d", dev->name, i); + } + + init_rspq(adap, &eorxq->rspq, + CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC, + CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT, + CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM, + CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE); + + eorxq->fl.size = CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM; + + ret = t4_sge_alloc_rxq(adap, &eorxq->rspq, false, + dev, msix, &eorxq->fl, NULL, + NULL, 0); + if (ret) + goto out_free_queues; + + /* Allocate ETHOFLD hardware Txqs */ + eotxq->q.size = CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM; + ret = t4_sge_alloc_ethofld_txq(adap, eotxq, dev, + eorxq->rspq.cntxt_id); + if (ret) + goto out_free_queues; + + /* Allocate IRQs, set IRQ affinity, and start Rx */ + if (adap->flags & CXGB4_USING_MSIX) { + ret = request_irq(eorxq->msix->vec, t4_sge_intr_msix, 0, + eorxq->msix->desc, &eorxq->rspq); + if (ret) + goto out_free_msix; + + cxgb4_set_msix_aff(adap, eorxq->msix->vec, + &eorxq->msix->aff_mask, i); + } + + if (adap->flags & CXGB4_FULL_INIT_DONE) + cxgb4_enable_rx(adap, &eorxq->rspq); + } + + refcount_inc(&adap->tc_mqprio->refcnt); + return 0; + +out_free_msix: + while (i-- > 0) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + + if (adap->flags & CXGB4_FULL_INIT_DONE) + cxgb4_quiesce_rx(&eorxq->rspq); + + if (adap->flags & CXGB4_USING_MSIX) { + cxgb4_clear_msix_aff(eorxq->msix->vec, + eorxq->msix->aff_mask); + free_irq(eorxq->msix->vec, &eorxq->rspq); + } + } + +out_free_queues: + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + if (eorxq->rspq.desc) + free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl); + if (eorxq->msix) + cxgb4_free_msix_idx_in_bmap(adap, eorxq->msix->idx); + t4_sge_free_ethofld_txq(adap, eotxq); + } + + kfree(adap->sge.eohw_txq); + kfree(adap->sge.eohw_rxq); + + return ret; +} + +void cxgb4_mqprio_free_hw_resources(struct net_device *dev) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_ofld_rxq *eorxq; + struct sge_eohw_txq *eotxq; + u32 i; + + /* Return if no ETHOFLD structures have been allocated yet */ + if (!refcount_read(&adap->tc_mqprio->refcnt)) + return; + + /* Return if no hardware queues have been allocated */ + if (!adap->sge.eohw_rxq[pi->first_qset].rspq.desc) + return; + + for (i = 0; i < pi->nqsets; i++) { + eorxq = &adap->sge.eohw_rxq[pi->first_qset + i]; + eotxq = &adap->sge.eohw_txq[pi->first_qset + i]; + + /* Device removal path will already disable NAPI + * before unregistering netdevice. So, only disable + * NAPI if we're not in device removal path + */ + if (!(adap->flags & CXGB4_SHUTTING_DOWN)) + cxgb4_quiesce_rx(&eorxq->rspq); + + if (adap->flags & CXGB4_USING_MSIX) { + cxgb4_clear_msix_aff(eorxq->msix->vec, + eorxq->msix->aff_mask); + free_irq(eorxq->msix->vec, &eorxq->rspq); + } + + free_rspq_fl(adap, &eorxq->rspq, &eorxq->fl); + t4_sge_free_ethofld_txq(adap, eotxq); + } + + /* Free up ETHOFLD structures if there are no users */ + if (refcount_dec_and_test(&adap->tc_mqprio->refcnt)) { + kfree(adap->sge.eohw_txq); + kfree(adap->sge.eohw_rxq); + } +} + static int cxgb4_mqprio_enable_offload(struct net_device *dev, struct tc_mqprio_qopt_offload *mqprio) { @@ -131,6 +291,10 @@ static int cxgb4_mqprio_enable_offload(struct net_device *dev, int eotid, ret; u16 i, j; + ret = cxgb4_mqprio_alloc_hw_resources(dev); + if (ret) + return -ENOMEM; + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; for (i = 0; i < mqprio->qopt.num_tc; i++) { qoffset = mqprio->qopt.offset[i]; @@ -206,6 +370,7 @@ out_free_eotids: } } + cxgb4_mqprio_free_hw_resources(dev); return ret; } @@ -235,6 +400,8 @@ static void cxgb4_mqprio_disable_offload(struct net_device *dev) } } + cxgb4_mqprio_free_hw_resources(dev); + memset(&tc_port_mqprio->mqprio, 0, sizeof(struct tc_mqprio_qopt_offload)); @@ -310,6 +477,7 @@ int cxgb4_init_tc_mqprio(struct adapter *adap) } adap->tc_mqprio = tc_mqprio; + refcount_set(&adap->tc_mqprio->refcnt, 0); return 0; out_free_ports: diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h index 125664b82236..6491ef91c8a9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h @@ -8,6 +8,15 @@ #define CXGB4_EOSW_TXQ_DEFAULT_DESC_NUM 128 +#define CXGB4_EOHW_TXQ_DEFAULT_DESC_NUM 1024 + +#define CXGB4_EOHW_RXQ_DEFAULT_DESC_NUM 1024 +#define CXGB4_EOHW_RXQ_DEFAULT_DESC_SIZE 64 +#define CXGB4_EOHW_RXQ_DEFAULT_INTR_USEC 5 +#define CXGB4_EOHW_RXQ_DEFAULT_PKT_CNT 8 + +#define CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM 72 + enum cxgb4_mqprio_state { CXGB4_MQPRIO_STATE_DISABLED = 0, CXGB4_MQPRIO_STATE_ACTIVE, @@ -20,6 +29,7 @@ struct cxgb4_tc_port_mqprio { }; struct cxgb4_tc_mqprio { + refcount_t refcnt; /* Refcount for adapter-wide resources */ struct cxgb4_tc_port_mqprio *port_mqprio; /* Per port MQPRIO info */ }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index 3d9401354af2..cce33d279094 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -366,33 +366,19 @@ free_msix_queue_irqs_uld(struct adapter *adap, unsigned int uld_type) } } -static void enable_rx(struct adapter *adap, struct sge_rspq *q) -{ - if (!q) - return; - - if (q->handler) - napi_enable(&q->napi); - - /* 0-increment GTS to start the timer and enable interrupts */ - t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A), - SEINTARM_V(q->intr_params) | - INGRESSQID_V(q->cntxt_id)); -} - -static void quiesce_rx(struct adapter *adap, struct sge_rspq *q) -{ - if (q && q->handler) - napi_disable(&q->napi); -} - static void enable_rx_uld(struct adapter *adap, unsigned int uld_type) { struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int idx; - for_each_uldrxq(rxq_info, idx) - enable_rx(adap, &rxq_info->uldrxq[idx].rspq); + for_each_uldrxq(rxq_info, idx) { + struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; + + if (!q) + continue; + + cxgb4_enable_rx(adap, q); + } } static void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type) @@ -400,8 +386,14 @@ static void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type) struct sge_uld_rxq_info *rxq_info = adap->sge.uld_rxq_info[uld_type]; int idx; - for_each_uldrxq(rxq_info, idx) - quiesce_rx(adap, &rxq_info->uldrxq[idx].rspq); + for_each_uldrxq(rxq_info, idx) { + struct sge_rspq *q = &rxq_info->uldrxq[idx].rspq; + + if (!q) + continue; + + cxgb4_quiesce_rx(q); + } } static void diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index ed1418d2364f..3ea2eccde262 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -3982,30 +3982,30 @@ int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid, return t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val); } -int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, - struct net_device *dev, unsigned int iqid, - unsigned int uld_type) +static int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_txq *q, + struct net_device *dev, u32 cmd, u32 iqid) { unsigned int chip_ver = CHELSIO_CHIP_VERSION(adap->params.chip); - int ret, nentries; - struct fw_eq_ofld_cmd c; - struct sge *s = &adap->sge; struct port_info *pi = netdev_priv(dev); - int cmd = FW_EQ_OFLD_CMD; + struct sge *s = &adap->sge; + struct fw_eq_ofld_cmd c; + u32 fb_min, nentries; + int ret; /* Add status entries */ - nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc); - - txq->q.desc = alloc_ring(adap->pdev_dev, txq->q.size, - sizeof(struct tx_desc), sizeof(struct tx_sw_desc), - &txq->q.phys_addr, &txq->q.sdesc, s->stat_len, - NUMA_NO_NODE); - if (!txq->q.desc) + nentries = q->size + s->stat_len / sizeof(struct tx_desc); + q->desc = alloc_ring(adap->pdev_dev, q->size, sizeof(struct tx_desc), + sizeof(struct tx_sw_desc), &q->phys_addr, + &q->sdesc, s->stat_len, NUMA_NO_NODE); + if (!q->desc) return -ENOMEM; + if (chip_ver <= CHELSIO_T5) + fb_min = FETCHBURSTMIN_64B_X; + else + fb_min = FETCHBURSTMIN_64B_T6_X; + memset(&c, 0, sizeof(c)); - if (unlikely(uld_type == CXGB4_TX_CRYPTO)) - cmd = FW_EQ_CTRL_CMD; c.op_to_vfn = htonl(FW_CMD_OP_V(cmd) | FW_CMD_REQUEST_F | FW_CMD_WRITE_F | FW_CMD_EXEC_F | FW_EQ_OFLD_CMD_PFN_V(adap->pf) | @@ -4017,27 +4017,42 @@ int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, FW_EQ_OFLD_CMD_PCIECHN_V(pi->tx_chan) | FW_EQ_OFLD_CMD_FETCHRO_F | FW_EQ_OFLD_CMD_IQID_V(iqid)); c.dcaen_to_eqsize = - htonl(FW_EQ_OFLD_CMD_FBMIN_V(chip_ver <= CHELSIO_T5 - ? FETCHBURSTMIN_64B_X - : FETCHBURSTMIN_64B_T6_X) | + htonl(FW_EQ_OFLD_CMD_FBMIN_V(fb_min) | FW_EQ_OFLD_CMD_FBMAX_V(FETCHBURSTMAX_512B_X) | FW_EQ_OFLD_CMD_CIDXFTHRESH_V(CIDXFLUSHTHRESH_32_X) | FW_EQ_OFLD_CMD_EQSIZE_V(nentries)); - c.eqaddr = cpu_to_be64(txq->q.phys_addr); + c.eqaddr = cpu_to_be64(q->phys_addr); ret = t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), &c); if (ret) { - kfree(txq->q.sdesc); - txq->q.sdesc = NULL; + kfree(q->sdesc); + q->sdesc = NULL; dma_free_coherent(adap->pdev_dev, nentries * sizeof(struct tx_desc), - txq->q.desc, txq->q.phys_addr); - txq->q.desc = NULL; + q->desc, q->phys_addr); + q->desc = NULL; return ret; } + init_txq(adap, q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd))); + return 0; +} + +int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, + struct net_device *dev, unsigned int iqid, + unsigned int uld_type) +{ + u32 cmd = FW_EQ_OFLD_CMD; + int ret; + + if (unlikely(uld_type == CXGB4_TX_CRYPTO)) + cmd = FW_EQ_CTRL_CMD; + + ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, cmd, iqid); + if (ret) + return ret; + txq->q.q_type = CXGB4_TXQ_ULD; - init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd))); txq->adap = adap; skb_queue_head_init(&txq->sendq); tasklet_init(&txq->qresume_tsk, restart_ofldq, (unsigned long)txq); @@ -4046,6 +4061,25 @@ int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq, return 0; } +int t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, + struct net_device *dev, u32 iqid) +{ + int ret; + + ret = t4_sge_alloc_ofld_txq(adap, &txq->q, dev, FW_EQ_OFLD_CMD, iqid); + if (ret) + return ret; + + txq->q.q_type = CXGB4_TXQ_ULD; + spin_lock_init(&txq->lock); + txq->adap = adap; + txq->tso = 0; + txq->tx_cso = 0; + txq->vlan_ins = 0; + txq->mapping_err = 0; + return 0; +} + void free_txq(struct adapter *adap, struct sge_txq *q) { struct sge *s = &adap->sge; @@ -4101,6 +4135,17 @@ void t4_free_ofld_rxqs(struct adapter *adap, int n, struct sge_ofld_rxq *q) q->fl.size ? &q->fl : NULL); } +void t4_sge_free_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq) +{ + if (txq->q.desc) { + t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0, + txq->q.cntxt_id); + free_tx_desc(adap, &txq->q, txq->q.in_use, false); + kfree(txq->q.sdesc); + free_txq(adap, &txq->q); + } +} + /** * t4_free_sge_resources - free SGE resources * @adap: the adapter -- cgit v1.2.3-59-g8ed1b From 4846d5330dafc82990be7ffe1d1b383157268bd9 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:08 +0530 Subject: cxgb4: add Tx and Rx path for ETHOFLD traffic Implement Tx path for traffic flowing through software EOSW_TXQ and EOHW_TXQ. Since multiple EOSW_TXQ can post packets to a single EOHW_TXQ, protect the hardware queue with necessary spinlock. Also, move common code used to generate TSO work request to a common function. Implement Rx path to handle Tx completions for successfully transmitted packets. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 3 + .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 3 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 423 ++++++++++++++++++--- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 5 + drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 30 ++ 5 files changed, 415 insertions(+), 49 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index d9d92dc0d0c5..2dfa98c2d525 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -805,6 +805,7 @@ struct sge_uld_txq_info { enum sge_eosw_state { CXGB4_EO_STATE_CLOSED = 0, /* Not ready to accept traffic */ + CXGB4_EO_STATE_ACTIVE, /* Ready to accept traffic */ }; struct sge_eosw_desc { @@ -1951,6 +1952,8 @@ void free_tx_desc(struct adapter *adap, struct sge_txq *q, void cxgb4_eosw_txq_free_desc(struct adapter *adap, struct sge_eosw_txq *txq, u32 ndesc); void cxgb4_ethofld_restart(unsigned long data); +int cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *si); void free_txq(struct adapter *adap, struct sge_txq *q); void cxgb4_reclaim_completed_tx(struct adapter *adap, struct sge_txq *q, bool unmap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index 66503ea259e7..e7d3638131e3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -174,7 +174,8 @@ static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev) eorxq->fl.size = CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM; ret = t4_sge_alloc_rxq(adap, &eorxq->rspq, false, - dev, msix, &eorxq->fl, NULL, + dev, msix, &eorxq->fl, + cxgb4_ethofld_rx_handler, NULL, 0); if (ret) goto out_free_queues; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 3ea2eccde262..6083d54afd00 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -55,6 +55,7 @@ #include "t4fw_api.h" #include "cxgb4_ptp.h" #include "cxgb4_uld.h" +#include "cxgb4_tc_mqprio.h" /* * Rx buffer size. We use largish buffers if possible but settle for single @@ -1309,6 +1310,35 @@ static inline void t6_fill_tnl_lso(struct sk_buff *skb, tnl_lso->EthLenOffset_Size = htonl(CPL_TX_TNL_LSO_SIZE_V(skb->len)); } +static inline void *write_tso_wr(struct adapter *adap, struct sk_buff *skb, + struct cpl_tx_pkt_lso_core *lso) +{ + int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + int l3hdr_len = skb_network_header_len(skb); + const struct skb_shared_info *ssi; + bool ipv6 = false; + + ssi = skb_shinfo(skb); + if (ssi->gso_type & SKB_GSO_TCPV6) + ipv6 = true; + + lso->lso_ctrl = htonl(LSO_OPCODE_V(CPL_TX_PKT_LSO) | + LSO_FIRST_SLICE_F | LSO_LAST_SLICE_F | + LSO_IPV6_V(ipv6) | + LSO_ETHHDR_LEN_V(eth_xtra_len / 4) | + LSO_IPHDR_LEN_V(l3hdr_len / 4) | + LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff)); + lso->ipid_ofst = htons(0); + lso->mss = htons(ssi->gso_size); + lso->seqno_offset = htonl(0); + if (is_t4(adap->params.chip)) + lso->len = htonl(skb->len); + else + lso->len = htonl(LSO_T5_XFER_SIZE_V(skb->len)); + + return (void *)(lso + 1); +} + /** * t4_sge_eth_txq_egress_update - handle Ethernet TX Queue update * @adap: the adapter @@ -1498,9 +1528,6 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) len += sizeof(*cpl); if (ssi->gso_size) { struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); - bool v6 = (ssi->gso_type & SKB_GSO_TCPV6) != 0; - int l3hdr_len = skb_network_header_len(skb); - int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; struct cpl_tx_tnl_lso *tnl_lso = (void *)(wr + 1); if (tnl_type) @@ -1527,30 +1554,8 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->ip_summed == CHECKSUM_PARTIAL) cntrl = hwcsum(adap->params.chip, skb); } else { - lso->lso_ctrl = htonl(LSO_OPCODE_V(CPL_TX_PKT_LSO) | - LSO_FIRST_SLICE_F | LSO_LAST_SLICE_F | - LSO_IPV6_V(v6) | - LSO_ETHHDR_LEN_V(eth_xtra_len / 4) | - LSO_IPHDR_LEN_V(l3hdr_len / 4) | - LSO_TCPHDR_LEN_V(tcp_hdr(skb)->doff)); - lso->ipid_ofst = htons(0); - lso->mss = htons(ssi->gso_size); - lso->seqno_offset = htonl(0); - if (is_t4(adap->params.chip)) - lso->len = htonl(skb->len); - else - lso->len = htonl(LSO_T5_XFER_SIZE_V(skb->len)); - cpl = (void *)(lso + 1); - - if (CHELSIO_CHIP_VERSION(adap->params.chip) - <= CHELSIO_T5) - cntrl = TXPKT_ETHHDR_LEN_V(eth_xtra_len); - else - cntrl = T6_TXPKT_ETHHDR_LEN_V(eth_xtra_len); - - cntrl |= TXPKT_CSUM_TYPE_V(v6 ? - TX_CSUM_TCPIP6 : TX_CSUM_TCPIP) | - TXPKT_IPHDR_LEN_V(l3hdr_len); + cpl = write_tso_wr(adap, skb, lso); + cntrl = hwcsum(adap->params.chip, skb); } sgl = (u64 *)(cpl + 1); /* sgl start here */ if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) { @@ -1996,6 +2001,26 @@ out_free: return NETDEV_TX_OK; } +/** + * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs + * @q: the SGE control Tx queue + * + * This is a variant of cxgb4_reclaim_completed_tx() that is used + * for Tx queues that send only immediate data (presently just + * the control queues) and thus do not have any sk_buffs to release. + */ +static inline void reclaim_completed_tx_imm(struct sge_txq *q) +{ + int hw_cidx = ntohs(READ_ONCE(q->stat->cidx)); + int reclaim = hw_cidx - q->cidx; + + if (reclaim < 0) + reclaim += q->size; + + q->in_use -= reclaim; + q->cidx = hw_cidx; +} + static inline void eosw_txq_advance_index(u32 *idx, u32 n, u32 max) { u32 val = *idx + n; @@ -2027,15 +2052,263 @@ void cxgb4_eosw_txq_free_desc(struct adapter *adap, } } +static inline void eosw_txq_advance(struct sge_eosw_txq *eosw_txq, u32 n) +{ + eosw_txq_advance_index(&eosw_txq->pidx, n, eosw_txq->ndesc); + eosw_txq->inuse += n; +} + +static inline int eosw_txq_enqueue(struct sge_eosw_txq *eosw_txq, + struct sk_buff *skb) +{ + if (eosw_txq->inuse == eosw_txq->ndesc) + return -ENOMEM; + + eosw_txq->desc[eosw_txq->pidx].skb = skb; + return 0; +} + +static inline struct sk_buff *eosw_txq_peek(struct sge_eosw_txq *eosw_txq) +{ + return eosw_txq->desc[eosw_txq->last_pidx].skb; +} + +static inline u8 ethofld_calc_tx_flits(struct adapter *adap, + struct sk_buff *skb, u32 hdr_len) +{ + u8 flits, nsgl = 0; + u32 wrlen; + + wrlen = sizeof(struct fw_eth_tx_eo_wr) + sizeof(struct cpl_tx_pkt_core); + if (skb_shinfo(skb)->gso_size) + wrlen += sizeof(struct cpl_tx_pkt_lso_core); + + wrlen += roundup(hdr_len, 16); + + /* Packet headers + WR + CPLs */ + flits = DIV_ROUND_UP(wrlen, 8); + + if (skb_shinfo(skb)->nr_frags > 0) + nsgl = sgl_len(skb_shinfo(skb)->nr_frags); + else if (skb->len - hdr_len) + nsgl = sgl_len(1); + + return flits + nsgl; +} + +static inline void *write_eo_wr(struct adapter *adap, + struct sge_eosw_txq *eosw_txq, + struct sk_buff *skb, struct fw_eth_tx_eo_wr *wr, + u32 hdr_len, u32 wrlen) +{ + const struct skb_shared_info *ssi = skb_shinfo(skb); + struct cpl_tx_pkt_core *cpl; + u32 immd_len, wrlen16; + bool compl = false; + + wrlen16 = DIV_ROUND_UP(wrlen, 16); + immd_len = sizeof(struct cpl_tx_pkt_core); + if (skb_shinfo(skb)->gso_size) { + if (skb->encapsulation && + CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) + immd_len += sizeof(struct cpl_tx_tnl_lso); + else + immd_len += sizeof(struct cpl_tx_pkt_lso_core); + } + immd_len += hdr_len; + + if (!eosw_txq->ncompl || + eosw_txq->last_compl >= adap->params.ofldq_wr_cred / 2) { + compl = true; + eosw_txq->ncompl++; + eosw_txq->last_compl = 0; + } + + wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_EO_WR) | + FW_ETH_TX_EO_WR_IMMDLEN_V(immd_len) | + FW_WR_COMPL_V(compl)); + wr->equiq_to_len16 = cpu_to_be32(FW_WR_LEN16_V(wrlen16) | + FW_WR_FLOWID_V(eosw_txq->hwtid)); + wr->r3 = 0; + wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG; + wr->u.tcpseg.ethlen = skb_network_offset(skb); + wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); + wr->u.tcpseg.tcplen = tcp_hdrlen(skb); + wr->u.tcpseg.tsclk_tsoff = 0; + wr->u.tcpseg.r4 = 0; + wr->u.tcpseg.r5 = 0; + wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len); + + if (ssi->gso_size) { + struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); + + wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size); + cpl = write_tso_wr(adap, skb, lso); + } else { + wr->u.tcpseg.mss = cpu_to_be16(0xffff); + cpl = (void *)(wr + 1); + } + + eosw_txq->cred -= wrlen16; + eosw_txq->last_compl += wrlen16; + return cpl; +} + +static void ethofld_hard_xmit(struct net_device *dev, + struct sge_eosw_txq *eosw_txq) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + u32 wrlen, wrlen16, hdr_len, data_len; + u64 cntrl, *start, *end, *sgl; + struct sge_eohw_txq *eohw_txq; + struct cpl_tx_pkt_core *cpl; + struct fw_eth_tx_eo_wr *wr; + struct sge_eosw_desc *d; + struct sk_buff *skb; + u8 flits, ndesc; + int left; + + eohw_txq = &adap->sge.eohw_txq[eosw_txq->hwqid]; + spin_lock(&eohw_txq->lock); + reclaim_completed_tx_imm(&eohw_txq->q); + + d = &eosw_txq->desc[eosw_txq->last_pidx]; + skb = d->skb; + skb_tx_timestamp(skb); + + wr = (struct fw_eth_tx_eo_wr *)&eohw_txq->q.desc[eohw_txq->q.pidx]; + hdr_len = eth_get_headlen(dev, skb->data, skb_headlen(skb)); + data_len = skb->len - hdr_len; + flits = ethofld_calc_tx_flits(adap, skb, hdr_len); + ndesc = flits_to_desc(flits); + wrlen = flits * 8; + wrlen16 = DIV_ROUND_UP(wrlen, 16); + + /* If there are no CPL credits, then wait for credits + * to come back and retry again + */ + if (unlikely(wrlen16 > eosw_txq->cred)) + goto out_unlock; + + cpl = write_eo_wr(adap, eosw_txq, skb, wr, hdr_len, wrlen); + cntrl = hwcsum(adap->params.chip, skb); + if (skb_vlan_tag_present(skb)) + cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); + + cpl->ctrl0 = cpu_to_be32(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | + TXPKT_INTF_V(pi->tx_chan) | + TXPKT_PF_V(adap->pf)); + cpl->pack = 0; + cpl->len = cpu_to_be16(skb->len); + cpl->ctrl1 = cpu_to_be64(cntrl); + + start = (u64 *)(cpl + 1); + + sgl = (u64 *)inline_tx_skb_header(skb, &eohw_txq->q, (void *)start, + hdr_len); + if (data_len) { + if (unlikely(cxgb4_map_skb(adap->pdev_dev, skb, d->addr))) { + memset(d->addr, 0, sizeof(d->addr)); + eohw_txq->mapping_err++; + goto out_unlock; + } + + end = (u64 *)wr + flits; + if (unlikely(start > sgl)) { + left = (u8 *)end - (u8 *)eohw_txq->q.stat; + end = (void *)eohw_txq->q.desc + left; + } + + if (unlikely((u8 *)sgl >= (u8 *)eohw_txq->q.stat)) { + /* If current position is already at the end of the + * txq, reset the current to point to start of the queue + * and update the end ptr as well. + */ + left = (u8 *)end - (u8 *)eohw_txq->q.stat; + + end = (void *)eohw_txq->q.desc + left; + sgl = (void *)eohw_txq->q.desc; + } + + cxgb4_write_sgl(skb, &eohw_txq->q, (void *)sgl, end, hdr_len, + d->addr); + } + + txq_advance(&eohw_txq->q, ndesc); + cxgb4_ring_tx_db(adap, &eohw_txq->q, ndesc); + eosw_txq_advance_index(&eosw_txq->last_pidx, 1, eosw_txq->ndesc); + +out_unlock: + spin_unlock(&eohw_txq->lock); +} + +static void ethofld_xmit(struct net_device *dev, struct sge_eosw_txq *eosw_txq) +{ + struct sk_buff *skb; + int pktcount; + + switch (eosw_txq->state) { + case CXGB4_EO_STATE_ACTIVE: + pktcount = eosw_txq->pidx - eosw_txq->last_pidx; + if (pktcount < 0) + pktcount += eosw_txq->ndesc; + break; + case CXGB4_EO_STATE_CLOSED: + default: + return; + }; + + while (pktcount--) { + skb = eosw_txq_peek(eosw_txq); + if (!skb) { + eosw_txq_advance_index(&eosw_txq->last_pidx, 1, + eosw_txq->ndesc); + continue; + } + + ethofld_hard_xmit(dev, eosw_txq); + } +} + static netdev_tx_t cxgb4_ethofld_xmit(struct sk_buff *skb, struct net_device *dev) { + struct cxgb4_tc_port_mqprio *tc_port_mqprio; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sge_eosw_txq *eosw_txq; + u32 qid; int ret; ret = cxgb4_validate_skb(skb, dev, ETH_HLEN); if (ret) goto out_free; + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; + qid = skb_get_queue_mapping(skb) - pi->nqsets; + eosw_txq = &tc_port_mqprio->eosw_txq[qid]; + spin_lock_bh(&eosw_txq->lock); + if (eosw_txq->state != CXGB4_EO_STATE_ACTIVE) + goto out_unlock; + + ret = eosw_txq_enqueue(eosw_txq, skb); + if (ret) + goto out_unlock; + + /* SKB is queued for processing until credits are available. + * So, call the destructor now and we'll free the skb later + * after it has been successfully transmitted. + */ + skb_orphan(skb); + + eosw_txq_advance(eosw_txq, 1); + ethofld_xmit(dev, eosw_txq); + spin_unlock_bh(&eosw_txq->lock); + return NETDEV_TX_OK; + +out_unlock: + spin_unlock_bh(&eosw_txq->lock); out_free: dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -2055,26 +2328,6 @@ netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev) return cxgb4_eth_xmit(skb, dev); } -/** - * reclaim_completed_tx_imm - reclaim completed control-queue Tx descs - * @q: the SGE control Tx queue - * - * This is a variant of cxgb4_reclaim_completed_tx() that is used - * for Tx queues that send only immediate data (presently just - * the control queues) and thus do not have any sk_buffs to release. - */ -static inline void reclaim_completed_tx_imm(struct sge_txq *q) -{ - int hw_cidx = ntohs(READ_ONCE(q->stat->cidx)); - int reclaim = hw_cidx - q->cidx; - - if (reclaim < 0) - reclaim += q->size; - - q->in_use -= reclaim; - q->cidx = hw_cidx; -} - /** * is_imm - check whether a packet can be sent as immediate data * @skb: the packet @@ -3375,12 +3628,86 @@ void cxgb4_ethofld_restart(unsigned long data) if (pktcount < 0) pktcount += eosw_txq->ndesc; - if (pktcount) + if (pktcount) { cxgb4_eosw_txq_free_desc(netdev2adap(eosw_txq->netdev), eosw_txq, pktcount); + eosw_txq->inuse -= pktcount; + } + + /* There may be some packets waiting for completions. So, + * attempt to send these packets now. + */ + ethofld_xmit(eosw_txq->netdev, eosw_txq); spin_unlock(&eosw_txq->lock); } +/* cxgb4_ethofld_rx_handler - Process ETHOFLD Tx completions + * @q: the response queue that received the packet + * @rsp: the response queue descriptor holding the CPL message + * @si: the gather list of packet fragments + * + * Process a ETHOFLD Tx completion. Increment the cidx here, but + * free up the descriptors in a tasklet later. + */ +int cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, + const struct pkt_gl *si) +{ + u8 opcode = ((const struct rss_header *)rsp)->opcode; + + /* skip RSS header */ + rsp++; + + if (opcode == CPL_FW4_ACK) { + const struct cpl_fw4_ack *cpl; + struct sge_eosw_txq *eosw_txq; + struct eotid_entry *entry; + struct sk_buff *skb; + u32 hdr_len, eotid; + u8 flits, wrlen16; + int credits; + + cpl = (const struct cpl_fw4_ack *)rsp; + eotid = CPL_FW4_ACK_FLOWID_G(ntohl(OPCODE_TID(cpl))) - + q->adap->tids.eotid_base; + entry = cxgb4_lookup_eotid(&q->adap->tids, eotid); + if (!entry) + goto out_done; + + eosw_txq = (struct sge_eosw_txq *)entry->data; + if (!eosw_txq) + goto out_done; + + spin_lock(&eosw_txq->lock); + credits = cpl->credits; + while (credits > 0) { + skb = eosw_txq->desc[eosw_txq->cidx].skb; + if (!skb) + break; + + hdr_len = eth_get_headlen(eosw_txq->netdev, skb->data, + skb_headlen(skb)); + flits = ethofld_calc_tx_flits(q->adap, skb, hdr_len); + eosw_txq_advance_index(&eosw_txq->cidx, 1, + eosw_txq->ndesc); + wrlen16 = DIV_ROUND_UP(flits * 8, 16); + credits -= wrlen16; + } + + eosw_txq->cred += cpl->credits; + eosw_txq->ncompl--; + + spin_unlock(&eosw_txq->lock); + + /* Schedule a tasklet to reclaim SKBs and restart ETHOFLD Tx, + * if there were packets waiting for completion. + */ + tasklet_schedule(&eosw_txq->qresume_tsk); + } + +out_done: + return 0; +} + /* * The MSI-X interrupt handler for an SGE response queue. */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 38dd41eb959e..575c6abcdae7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -1421,6 +1421,11 @@ enum { CPL_FW4_ACK_FLAGS_FLOWC = 0x4, /* fw_flowc_wr complete */ }; +#define CPL_FW4_ACK_FLOWID_S 0 +#define CPL_FW4_ACK_FLOWID_M 0xffffff +#define CPL_FW4_ACK_FLOWID_G(x) \ + (((x) >> CPL_FW4_ACK_FLOWID_S) & CPL_FW4_ACK_FLOWID_M) + struct cpl_fw6_msg { u8 opcode; u8 type; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index d603334bae95..ea395b43dbf4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -87,6 +87,7 @@ enum fw_wr_opcodes { FW_ULPTX_WR = 0x04, FW_TP_WR = 0x05, FW_ETH_TX_PKT_WR = 0x08, + FW_ETH_TX_EO_WR = 0x1c, FW_OFLD_CONNECTION_WR = 0x2f, FW_FLOWC_WR = 0x0a, FW_OFLD_TX_DATA_WR = 0x0b, @@ -534,6 +535,35 @@ struct fw_eth_tx_pkt_wr { __be64 r3; }; +enum fw_eth_tx_eo_type { + FW_ETH_TX_EO_TYPE_TCPSEG = 1, +}; + +struct fw_eth_tx_eo_wr { + __be32 op_immdlen; + __be32 equiq_to_len16; + __be64 r3; + union fw_eth_tx_eo { + struct fw_eth_tx_eo_tcpseg { + __u8 type; + __u8 ethlen; + __be16 iplen; + __u8 tcplen; + __u8 tsclk_tsoff; + __be16 r4; + __be16 mss; + __be16 r5; + __be32 plen; + } tcpseg; + } u; +}; + +#define FW_ETH_TX_EO_WR_IMMDLEN_S 0 +#define FW_ETH_TX_EO_WR_IMMDLEN_M 0x1ff +#define FW_ETH_TX_EO_WR_IMMDLEN_V(x) ((x) << FW_ETH_TX_EO_WR_IMMDLEN_S) +#define FW_ETH_TX_EO_WR_IMMDLEN_G(x) \ + (((x) >> FW_ETH_TX_EO_WR_IMMDLEN_S) & FW_ETH_TX_EO_WR_IMMDLEN_M) + struct fw_ofld_connection_wr { __be32 op_compl; __be32 len16_pkd; -- cgit v1.2.3-59-g8ed1b From 0e395b3cb1fb82f5d056fd5425025a77da4d4f62 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Thu, 7 Nov 2019 21:29:09 +0530 Subject: cxgb4: add FLOWC based QoS offload Rework SCHED API to allow offloading TC-MQPRIO QoS configuration. The existing QUEUE based rate limiting throttles all queues sharing a traffic class, to the specified max rate limit value. So, if multiple queues share a traffic class, then all the queues get the aggregate specified max rate limit. So, introduce the new FLOWC based rate limiting, where multiple queues can share a traffic class with each queue getting its own individual specified max rate limit. For example, if 2 queues are bound to class 0, which is rate limited to 1 Gbps, then 2 queues using QUEUE based rate limiting, get the aggregate output of 1 Gbps only. In FLOWC based rate limiting, each queue gets its own output of max 1 Gbps each; i.e. 2 queues * 1 Gbps rate limit = 2 Gbps. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 16 ++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 134 ++++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h | 3 + drivers/net/ethernet/chelsio/cxgb4/sched.c | 229 ++++++++++++++++----- drivers/net/ethernet/chelsio/cxgb4/sched.h | 10 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 150 +++++++++++++- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 6 + 7 files changed, 495 insertions(+), 53 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 2dfa98c2d525..1fb273b294a1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -805,7 +805,11 @@ struct sge_uld_txq_info { enum sge_eosw_state { CXGB4_EO_STATE_CLOSED = 0, /* Not ready to accept traffic */ + CXGB4_EO_STATE_FLOWC_OPEN_SEND, /* Send FLOWC open request */ + CXGB4_EO_STATE_FLOWC_OPEN_REPLY, /* Waiting for FLOWC open reply */ CXGB4_EO_STATE_ACTIVE, /* Ready to accept traffic */ + CXGB4_EO_STATE_FLOWC_CLOSE_SEND, /* Send FLOWC close request */ + CXGB4_EO_STATE_FLOWC_CLOSE_REPLY, /* Waiting for FLOWC close reply */ }; struct sge_eosw_desc { @@ -822,6 +826,7 @@ struct sge_eosw_txq { u32 last_pidx; /* Last successfully transmitted Producer Index */ u32 cidx; /* Current Consumer Index */ u32 last_cidx; /* Last successfully reclaimed Consumer Index */ + u32 flowc_idx; /* Descriptor containing a FLOWC request */ u32 inuse; /* Number of packets held in ring */ u32 cred; /* Current available credits */ @@ -834,6 +839,7 @@ struct sge_eosw_txq { u32 hwqid; /* Underlying hardware queue index */ struct net_device *netdev; /* Pointer to netdevice */ struct tasklet_struct qresume_tsk; /* Restarts the queue */ + struct completion completion; /* completion for FLOWC rendezvous */ }; struct sge_eohw_txq { @@ -1128,6 +1134,7 @@ enum { enum { SCHED_CLASS_MODE_CLASS = 0, /* per-class scheduling */ + SCHED_CLASS_MODE_FLOW, /* per-flow scheduling */ }; enum { @@ -1151,6 +1158,14 @@ struct ch_sched_queue { s8 class; /* class index */ }; +/* Support for "sched_flowc" command to allow one or more FLOWC + * to be bound to a TX Scheduling Class. + */ +struct ch_sched_flowc { + s32 tid; /* TID to bind */ + s8 class; /* class index */ +}; + /* Defined bit width of user definable filter tuples */ #define ETHTYPE_BITWIDTH 16 @@ -1951,6 +1966,7 @@ void free_tx_desc(struct adapter *adap, struct sge_txq *q, unsigned int n, bool unmap); void cxgb4_eosw_txq_free_desc(struct adapter *adap, struct sge_eosw_txq *txq, u32 ndesc); +int cxgb4_ethofld_send_flowc(struct net_device *dev, u32 eotid, u32 tc); void cxgb4_ethofld_restart(unsigned long data); int cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, const struct pkt_gl *si); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index e7d3638131e3..fb28bce01270 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -3,6 +3,7 @@ #include "cxgb4.h" #include "cxgb4_tc_mqprio.h" +#include "sched.h" static int cxgb4_mqprio_validate(struct net_device *dev, struct tc_mqprio_qopt_offload *mqprio) @@ -103,6 +104,7 @@ static void cxgb4_clean_eosw_txq(struct net_device *dev, eosw_txq->last_pidx = 0; eosw_txq->cidx = 0; eosw_txq->last_cidx = 0; + eosw_txq->flowc_idx = 0; eosw_txq->inuse = 0; eosw_txq->cred = adap->params.ofldq_wr_cred; eosw_txq->ncompl = 0; @@ -281,6 +283,109 @@ void cxgb4_mqprio_free_hw_resources(struct net_device *dev) } } +static int cxgb4_mqprio_alloc_tc(struct net_device *dev, + struct tc_mqprio_qopt_offload *mqprio) +{ + struct ch_sched_params p = { + .type = SCHED_CLASS_TYPE_PACKET, + .u.params.level = SCHED_CLASS_LEVEL_CL_RL, + .u.params.mode = SCHED_CLASS_MODE_FLOW, + .u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS, + .u.params.ratemode = SCHED_CLASS_RATEMODE_ABS, + .u.params.class = SCHED_CLS_NONE, + .u.params.weight = 0, + .u.params.pktsize = dev->mtu, + }; + struct cxgb4_tc_port_mqprio *tc_port_mqprio; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct sched_class *e; + int ret; + u8 i; + + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; + p.u.params.channel = pi->tx_chan; + for (i = 0; i < mqprio->qopt.num_tc; i++) { + /* Convert from bytes per second to Kbps */ + p.u.params.minrate = mqprio->min_rate[i] * 8 / 1000; + p.u.params.maxrate = mqprio->max_rate[i] * 8 / 1000; + + e = cxgb4_sched_class_alloc(dev, &p); + if (!e) { + ret = -ENOMEM; + goto out_err; + } + + tc_port_mqprio->tc_hwtc_map[i] = e->idx; + } + + return 0; + +out_err: + while (i--) + cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]); + + return ret; +} + +static void cxgb4_mqprio_free_tc(struct net_device *dev) +{ + struct cxgb4_tc_port_mqprio *tc_port_mqprio; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + u8 i; + + tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; + for (i = 0; i < tc_port_mqprio->mqprio.qopt.num_tc; i++) + cxgb4_sched_class_free(dev, tc_port_mqprio->tc_hwtc_map[i]); +} + +static int cxgb4_mqprio_class_bind(struct net_device *dev, + struct sge_eosw_txq *eosw_txq, + u8 tc) +{ + struct ch_sched_flowc fe; + int ret; + + init_completion(&eosw_txq->completion); + + fe.tid = eosw_txq->eotid; + fe.class = tc; + + ret = cxgb4_sched_class_bind(dev, &fe, SCHED_FLOWC); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&eosw_txq->completion, + CXGB4_FLOWC_WAIT_TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +static void cxgb4_mqprio_class_unbind(struct net_device *dev, + struct sge_eosw_txq *eosw_txq, + u8 tc) +{ + struct adapter *adap = netdev2adap(dev); + struct ch_sched_flowc fe; + + /* If we're shutting down, interrupts are disabled and no completions + * come back. So, skip waiting for completions in this scenario. + */ + if (!(adap->flags & CXGB4_SHUTTING_DOWN)) + init_completion(&eosw_txq->completion); + + fe.tid = eosw_txq->eotid; + fe.class = tc; + cxgb4_sched_class_unbind(dev, &fe, SCHED_FLOWC); + + if (!(adap->flags & CXGB4_SHUTTING_DOWN)) + wait_for_completion_timeout(&eosw_txq->completion, + CXGB4_FLOWC_WAIT_TIMEOUT); +} + static int cxgb4_mqprio_enable_offload(struct net_device *dev, struct tc_mqprio_qopt_offload *mqprio) { @@ -291,6 +396,7 @@ static int cxgb4_mqprio_enable_offload(struct net_device *dev, struct sge_eosw_txq *eosw_txq; int eotid, ret; u16 i, j; + u8 hwtc; ret = cxgb4_mqprio_alloc_hw_resources(dev); if (ret) @@ -316,6 +422,11 @@ static int cxgb4_mqprio_enable_offload(struct net_device *dev, goto out_free_eotids; cxgb4_alloc_eotid(&adap->tids, eotid, eosw_txq); + + hwtc = tc_port_mqprio->tc_hwtc_map[i]; + ret = cxgb4_mqprio_class_bind(dev, eosw_txq, hwtc); + if (ret) + goto out_free_eotids; } } @@ -366,6 +477,10 @@ out_free_eotids: qcount = mqprio->qopt.count[i]; for (j = 0; j < qcount; j++) { eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j]; + + hwtc = tc_port_mqprio->tc_hwtc_map[i]; + cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc); + cxgb4_free_eotid(&adap->tids, eosw_txq->eotid); cxgb4_free_eosw_txq(dev, eosw_txq); } @@ -383,6 +498,7 @@ static void cxgb4_mqprio_disable_offload(struct net_device *dev) struct sge_eosw_txq *eosw_txq; u32 qoffset, qcount; u16 i, j; + u8 hwtc; tc_port_mqprio = &adap->tc_mqprio->port_mqprio[pi->port_id]; if (tc_port_mqprio->state != CXGB4_MQPRIO_STATE_ACTIVE) @@ -396,6 +512,10 @@ static void cxgb4_mqprio_disable_offload(struct net_device *dev) qcount = tc_port_mqprio->mqprio.qopt.count[i]; for (j = 0; j < qcount; j++) { eosw_txq = &tc_port_mqprio->eosw_txq[qoffset + j]; + + hwtc = tc_port_mqprio->tc_hwtc_map[i]; + cxgb4_mqprio_class_unbind(dev, eosw_txq, hwtc); + cxgb4_free_eotid(&adap->tids, eosw_txq->eotid); cxgb4_free_eosw_txq(dev, eosw_txq); } @@ -403,6 +523,9 @@ static void cxgb4_mqprio_disable_offload(struct net_device *dev) cxgb4_mqprio_free_hw_resources(dev); + /* Free up the traffic classes */ + cxgb4_mqprio_free_tc(dev); + memset(&tc_port_mqprio->mqprio, 0, sizeof(struct tc_mqprio_qopt_offload)); @@ -437,7 +560,18 @@ int cxgb4_setup_tc_mqprio(struct net_device *dev, if (!mqprio->qopt.num_tc) goto out; + /* Allocate free available traffic classes and configure + * their rate parameters. + */ + ret = cxgb4_mqprio_alloc_tc(dev, mqprio); + if (ret) + goto out; + ret = cxgb4_mqprio_enable_offload(dev, mqprio); + if (ret) { + cxgb4_mqprio_free_tc(dev); + goto out; + } out: if (needs_bring_up) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h index 6491ef91c8a9..c532f1ef8451 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.h @@ -17,6 +17,8 @@ #define CXGB4_EOHW_FLQ_DEFAULT_DESC_NUM 72 +#define CXGB4_FLOWC_WAIT_TIMEOUT (5 * HZ) + enum cxgb4_mqprio_state { CXGB4_MQPRIO_STATE_DISABLED = 0, CXGB4_MQPRIO_STATE_ACTIVE, @@ -26,6 +28,7 @@ struct cxgb4_tc_port_mqprio { enum cxgb4_mqprio_state state; /* Current MQPRIO offload state */ struct tc_mqprio_qopt_offload mqprio; /* MQPRIO offload params */ struct sge_eosw_txq *eosw_txq; /* Netdev SW Tx queue array */ + u8 tc_hwtc_map[TC_QOPT_MAX_QUEUE]; /* MQPRIO tc to hardware tc map */ }; struct cxgb4_tc_mqprio { diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c index 60218dc676a8..0a98c4dbb36b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -92,45 +92,69 @@ static int t4_sched_bind_unbind_op(struct port_info *pi, void *arg, pf = adap->pf; vf = 0; + + err = t4_set_params(adap, adap->mbox, pf, vf, 1, + &fw_param, &fw_class); + break; + } + case SCHED_FLOWC: { + struct sched_flowc_entry *fe; + + fe = (struct sched_flowc_entry *)arg; + + fw_class = bind ? fe->param.class : FW_SCHED_CLS_NONE; + err = cxgb4_ethofld_send_flowc(adap->port[pi->port_id], + fe->param.tid, fw_class); break; } default: err = -ENOTSUPP; - goto out; + break; } - err = t4_set_params(adap, adap->mbox, pf, vf, 1, &fw_param, &fw_class); - -out: return err; } -static struct sched_class *t4_sched_queue_lookup(struct port_info *pi, - const unsigned int qid, - int *index) +static void *t4_sched_entry_lookup(struct port_info *pi, + enum sched_bind_type type, + const u32 val) { struct sched_table *s = pi->sched_tbl; struct sched_class *e, *end; - struct sched_class *found = NULL; - int i; + void *found = NULL; - /* Look for a class with matching bound queue parameters */ + /* Look for an entry with matching @val */ end = &s->tab[s->sched_size]; for (e = &s->tab[0]; e != end; ++e) { - struct sched_queue_entry *qe; - - i = 0; - if (e->state == SCHED_STATE_UNUSED) + if (e->state == SCHED_STATE_UNUSED || + e->bind_type != type) continue; - list_for_each_entry(qe, &e->queue_list, list) { - if (qe->cntxt_id == qid) { - found = e; - if (index) - *index = i; - break; + switch (type) { + case SCHED_QUEUE: { + struct sched_queue_entry *qe; + + list_for_each_entry(qe, &e->entry_list, list) { + if (qe->cntxt_id == val) { + found = qe; + break; + } } - i++; + break; + } + case SCHED_FLOWC: { + struct sched_flowc_entry *fe; + + list_for_each_entry(fe, &e->entry_list, list) { + if (fe->param.tid == val) { + found = fe; + break; + } + } + break; + } + default: + return NULL; } if (found) @@ -142,35 +166,26 @@ static struct sched_class *t4_sched_queue_lookup(struct port_info *pi, static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) { - struct adapter *adap = pi->adapter; - struct sched_class *e; struct sched_queue_entry *qe = NULL; + struct adapter *adap = pi->adapter; struct sge_eth_txq *txq; - unsigned int qid; - int index = -1; + struct sched_class *e; int err = 0; if (p->queue < 0 || p->queue >= pi->nqsets) return -ERANGE; txq = &adap->sge.ethtxq[pi->first_qset + p->queue]; - qid = txq->q.cntxt_id; - - /* Find the existing class that the queue is bound to */ - e = t4_sched_queue_lookup(pi, qid, &index); - if (e && index >= 0) { - int i = 0; - list_for_each_entry(qe, &e->queue_list, list) { - if (i == index) - break; - i++; - } + /* Find the existing entry that the queue is bound to */ + qe = t4_sched_entry_lookup(pi, SCHED_QUEUE, txq->q.cntxt_id); + if (qe) { err = t4_sched_bind_unbind_op(pi, (void *)qe, SCHED_QUEUE, false); if (err) return err; + e = &pi->sched_tbl->tab[qe->param.class]; list_del(&qe->list); kvfree(qe); if (atomic_dec_and_test(&e->refcnt)) { @@ -183,11 +198,11 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p) { - struct adapter *adap = pi->adapter; struct sched_table *s = pi->sched_tbl; - struct sched_class *e; struct sched_queue_entry *qe = NULL; + struct adapter *adap = pi->adapter; struct sge_eth_txq *txq; + struct sched_class *e; unsigned int qid; int err = 0; @@ -215,7 +230,8 @@ static int t4_sched_queue_bind(struct port_info *pi, struct ch_sched_queue *p) if (err) goto out_err; - list_add_tail(&qe->list, &e->queue_list); + list_add_tail(&qe->list, &e->entry_list); + e->bind_type = SCHED_QUEUE; atomic_inc(&e->refcnt); return err; @@ -224,6 +240,73 @@ out_err: return err; } +static int t4_sched_flowc_unbind(struct port_info *pi, struct ch_sched_flowc *p) +{ + struct sched_flowc_entry *fe = NULL; + struct adapter *adap = pi->adapter; + struct sched_class *e; + int err = 0; + + if (p->tid < 0 || p->tid >= adap->tids.neotids) + return -ERANGE; + + /* Find the existing entry that the flowc is bound to */ + fe = t4_sched_entry_lookup(pi, SCHED_FLOWC, p->tid); + if (fe) { + err = t4_sched_bind_unbind_op(pi, (void *)fe, SCHED_FLOWC, + false); + if (err) + return err; + + e = &pi->sched_tbl->tab[fe->param.class]; + list_del(&fe->list); + kvfree(fe); + if (atomic_dec_and_test(&e->refcnt)) { + e->state = SCHED_STATE_UNUSED; + memset(&e->info, 0, sizeof(e->info)); + } + } + return err; +} + +static int t4_sched_flowc_bind(struct port_info *pi, struct ch_sched_flowc *p) +{ + struct sched_table *s = pi->sched_tbl; + struct sched_flowc_entry *fe = NULL; + struct adapter *adap = pi->adapter; + struct sched_class *e; + int err = 0; + + if (p->tid < 0 || p->tid >= adap->tids.neotids) + return -ERANGE; + + fe = kvzalloc(sizeof(*fe), GFP_KERNEL); + if (!fe) + return -ENOMEM; + + /* Unbind flowc from any existing class */ + err = t4_sched_flowc_unbind(pi, p); + if (err) + goto out_err; + + /* Bind flowc to specified class */ + memcpy(&fe->param, p, sizeof(fe->param)); + + e = &s->tab[fe->param.class]; + err = t4_sched_bind_unbind_op(pi, (void *)fe, SCHED_FLOWC, true); + if (err) + goto out_err; + + list_add_tail(&fe->list, &e->entry_list); + e->bind_type = SCHED_FLOWC; + atomic_inc(&e->refcnt); + return err; + +out_err: + kvfree(fe); + return err; +} + static void t4_sched_class_unbind_all(struct port_info *pi, struct sched_class *e, enum sched_bind_type type) @@ -235,10 +318,17 @@ static void t4_sched_class_unbind_all(struct port_info *pi, case SCHED_QUEUE: { struct sched_queue_entry *qe; - list_for_each_entry(qe, &e->queue_list, list) + list_for_each_entry(qe, &e->entry_list, list) t4_sched_queue_unbind(pi, &qe->param); break; } + case SCHED_FLOWC: { + struct sched_flowc_entry *fe; + + list_for_each_entry(fe, &e->entry_list, list) + t4_sched_flowc_unbind(pi, &fe->param); + break; + } default: break; } @@ -262,6 +352,15 @@ static int t4_sched_class_bind_unbind_op(struct port_info *pi, void *arg, err = t4_sched_queue_unbind(pi, qe); break; } + case SCHED_FLOWC: { + struct ch_sched_flowc *fe = (struct ch_sched_flowc *)arg; + + if (bind) + err = t4_sched_flowc_bind(pi, fe); + else + err = t4_sched_flowc_unbind(pi, fe); + break; + } default: err = -ENOTSUPP; break; @@ -299,6 +398,12 @@ int cxgb4_sched_class_bind(struct net_device *dev, void *arg, class_id = qe->class; break; } + case SCHED_FLOWC: { + struct ch_sched_flowc *fe = (struct ch_sched_flowc *)arg; + + class_id = fe->class; + break; + } default: return -ENOTSUPP; } @@ -340,6 +445,12 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg, class_id = qe->class; break; } + case SCHED_FLOWC: { + struct ch_sched_flowc *fe = (struct ch_sched_flowc *)arg; + + class_id = fe->class; + break; + } default: return -ENOTSUPP; } @@ -355,10 +466,13 @@ static struct sched_class *t4_sched_class_lookup(struct port_info *pi, const struct ch_sched_params *p) { struct sched_table *s = pi->sched_tbl; - struct sched_class *e, *end; struct sched_class *found = NULL; + struct sched_class *e, *end; - if (!p) { + /* Only allow tc to be shared among SCHED_FLOWC types. For + * other types, always allocate a new tc. + */ + if (!p || p->u.params.mode != SCHED_CLASS_MODE_FLOW) { /* Get any available unused class */ end = &s->tab[s->sched_size]; for (e = &s->tab[0]; e != end; ++e) { @@ -467,9 +581,32 @@ struct sched_class *cxgb4_sched_class_alloc(struct net_device *dev, return t4_sched_class_alloc(pi, p); } -static void t4_sched_class_free(struct port_info *pi, struct sched_class *e) +/** + * cxgb4_sched_class_free - free a scheduling class + * @dev: net_device pointer + * @e: scheduling class + * + * Frees a scheduling class if there are no users. + */ +void cxgb4_sched_class_free(struct net_device *dev, u8 classid) +{ + struct port_info *pi = netdev2pinfo(dev); + struct sched_table *s = pi->sched_tbl; + struct sched_class *e; + + e = &s->tab[classid]; + if (!atomic_read(&e->refcnt)) { + e->state = SCHED_STATE_UNUSED; + memset(&e->info, 0, sizeof(e->info)); + } +} + +static void t4_sched_class_free(struct net_device *dev, struct sched_class *e) { - t4_sched_class_unbind_all(pi, e, SCHED_QUEUE); + struct port_info *pi = netdev2pinfo(dev); + + t4_sched_class_unbind_all(pi, e, e->bind_type); + cxgb4_sched_class_free(dev, e->idx); } struct sched_table *t4_init_sched(unsigned int sched_size) @@ -487,7 +624,7 @@ struct sched_table *t4_init_sched(unsigned int sched_size) memset(&s->tab[i], 0, sizeof(struct sched_class)); s->tab[i].idx = i; s->tab[i].state = SCHED_STATE_UNUSED; - INIT_LIST_HEAD(&s->tab[i].queue_list); + INIT_LIST_HEAD(&s->tab[i].entry_list); atomic_set(&s->tab[i].refcnt, 0); } return s; @@ -510,7 +647,7 @@ void t4_cleanup_sched(struct adapter *adap) e = &s->tab[i]; if (e->state == SCHED_STATE_ACTIVE) - t4_sched_class_free(pi, e); + t4_sched_class_free(adap->port[j], e); } kvfree(s); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h index 168fb4ce3759..80bed8e59362 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.h +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h @@ -56,6 +56,7 @@ enum sched_fw_ops { enum sched_bind_type { SCHED_QUEUE, + SCHED_FLOWC, }; struct sched_queue_entry { @@ -64,11 +65,17 @@ struct sched_queue_entry { struct ch_sched_queue param; }; +struct sched_flowc_entry { + struct list_head list; + struct ch_sched_flowc param; +}; + struct sched_class { u8 state; u8 idx; struct ch_sched_params info; - struct list_head queue_list; + enum sched_bind_type bind_type; + struct list_head entry_list; atomic_t refcnt; }; @@ -102,6 +109,7 @@ int cxgb4_sched_class_unbind(struct net_device *dev, void *arg, struct sched_class *cxgb4_sched_class_alloc(struct net_device *dev, struct ch_sched_params *p); +void cxgb4_sched_class_free(struct net_device *dev, u8 classid); struct sched_table *t4_init_sched(unsigned int size); void t4_cleanup_sched(struct adapter *adap); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 6083d54afd00..e346830ebca9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -56,6 +56,7 @@ #include "cxgb4_ptp.h" #include "cxgb4_uld.h" #include "cxgb4_tc_mqprio.h" +#include "sched.h" /* * Rx buffer size. We use largish buffers if possible but settle for single @@ -2160,10 +2161,12 @@ static void ethofld_hard_xmit(struct net_device *dev, struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); u32 wrlen, wrlen16, hdr_len, data_len; + enum sge_eosw_state next_state; u64 cntrl, *start, *end, *sgl; struct sge_eohw_txq *eohw_txq; struct cpl_tx_pkt_core *cpl; struct fw_eth_tx_eo_wr *wr; + bool skip_eotx_wr = false; struct sge_eosw_desc *d; struct sk_buff *skb; u8 flits, ndesc; @@ -2178,9 +2181,21 @@ static void ethofld_hard_xmit(struct net_device *dev, skb_tx_timestamp(skb); wr = (struct fw_eth_tx_eo_wr *)&eohw_txq->q.desc[eohw_txq->q.pidx]; - hdr_len = eth_get_headlen(dev, skb->data, skb_headlen(skb)); - data_len = skb->len - hdr_len; - flits = ethofld_calc_tx_flits(adap, skb, hdr_len); + if (unlikely(eosw_txq->state != CXGB4_EO_STATE_ACTIVE && + eosw_txq->last_pidx == eosw_txq->flowc_idx)) { + hdr_len = skb->len; + data_len = 0; + flits = DIV_ROUND_UP(hdr_len, 8); + if (eosw_txq->state == CXGB4_EO_STATE_FLOWC_OPEN_SEND) + next_state = CXGB4_EO_STATE_FLOWC_OPEN_REPLY; + else + next_state = CXGB4_EO_STATE_FLOWC_CLOSE_REPLY; + skip_eotx_wr = true; + } else { + hdr_len = eth_get_headlen(dev, skb->data, skb_headlen(skb)); + data_len = skb->len - hdr_len; + flits = ethofld_calc_tx_flits(adap, skb, hdr_len); + } ndesc = flits_to_desc(flits); wrlen = flits * 8; wrlen16 = DIV_ROUND_UP(wrlen, 16); @@ -2191,6 +2206,12 @@ static void ethofld_hard_xmit(struct net_device *dev, if (unlikely(wrlen16 > eosw_txq->cred)) goto out_unlock; + if (unlikely(skip_eotx_wr)) { + start = (u64 *)wr; + eosw_txq->state = next_state; + goto write_wr_headers; + } + cpl = write_eo_wr(adap, eosw_txq, skb, wr, hdr_len, wrlen); cntrl = hwcsum(adap->params.chip, skb); if (skb_vlan_tag_present(skb)) @@ -2205,6 +2226,7 @@ static void ethofld_hard_xmit(struct net_device *dev, start = (u64 *)(cpl + 1); +write_wr_headers: sgl = (u64 *)inline_tx_skb_header(skb, &eohw_txq->q, (void *)start, hdr_len); if (data_len) { @@ -2250,10 +2272,14 @@ static void ethofld_xmit(struct net_device *dev, struct sge_eosw_txq *eosw_txq) switch (eosw_txq->state) { case CXGB4_EO_STATE_ACTIVE: + case CXGB4_EO_STATE_FLOWC_OPEN_SEND: + case CXGB4_EO_STATE_FLOWC_CLOSE_SEND: pktcount = eosw_txq->pidx - eosw_txq->last_pidx; if (pktcount < 0) pktcount += eosw_txq->ndesc; break; + case CXGB4_EO_STATE_FLOWC_OPEN_REPLY: + case CXGB4_EO_STATE_FLOWC_CLOSE_REPLY: case CXGB4_EO_STATE_CLOSED: default: return; @@ -2328,6 +2354,101 @@ netdev_tx_t t4_start_xmit(struct sk_buff *skb, struct net_device *dev) return cxgb4_eth_xmit(skb, dev); } +/** + * cxgb4_ethofld_send_flowc - Send ETHOFLD flowc request to bind eotid to tc. + * @dev - netdevice + * @eotid - ETHOFLD tid to bind/unbind + * @tc - traffic class. If set to FW_SCHED_CLS_NONE, then unbinds the @eotid + * + * Send a FLOWC work request to bind an ETHOFLD TID to a traffic class. + * If @tc is set to FW_SCHED_CLS_NONE, then the @eotid is unbound from + * a traffic class. + */ +int cxgb4_ethofld_send_flowc(struct net_device *dev, u32 eotid, u32 tc) +{ + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + enum sge_eosw_state next_state; + struct sge_eosw_txq *eosw_txq; + u32 len, len16, nparams = 6; + struct fw_flowc_wr *flowc; + struct eotid_entry *entry; + struct sge_ofld_rxq *rxq; + struct sk_buff *skb; + int ret = 0; + + len = sizeof(*flowc) + sizeof(struct fw_flowc_mnemval) * nparams; + len16 = DIV_ROUND_UP(len, 16); + + entry = cxgb4_lookup_eotid(&adap->tids, eotid); + if (!entry) + return -ENOMEM; + + eosw_txq = (struct sge_eosw_txq *)entry->data; + if (!eosw_txq) + return -ENOMEM; + + skb = alloc_skb(len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + spin_lock_bh(&eosw_txq->lock); + if (tc != FW_SCHED_CLS_NONE) { + if (eosw_txq->state != CXGB4_EO_STATE_CLOSED) + goto out_unlock; + + next_state = CXGB4_EO_STATE_FLOWC_OPEN_SEND; + } else { + if (eosw_txq->state != CXGB4_EO_STATE_ACTIVE) + goto out_unlock; + + next_state = CXGB4_EO_STATE_FLOWC_CLOSE_SEND; + } + + flowc = __skb_put(skb, len); + memset(flowc, 0, len); + + rxq = &adap->sge.eohw_rxq[eosw_txq->hwqid]; + flowc->flowid_len16 = cpu_to_be32(FW_WR_LEN16_V(len16) | + FW_WR_FLOWID_V(eosw_txq->hwtid)); + flowc->op_to_nparams = cpu_to_be32(FW_WR_OP_V(FW_FLOWC_WR) | + FW_FLOWC_WR_NPARAMS_V(nparams) | + FW_WR_COMPL_V(1)); + flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; + flowc->mnemval[0].val = cpu_to_be32(FW_PFVF_CMD_PFN_V(adap->pf)); + flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; + flowc->mnemval[1].val = cpu_to_be32(pi->tx_chan); + flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; + flowc->mnemval[2].val = cpu_to_be32(pi->tx_chan); + flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; + flowc->mnemval[3].val = cpu_to_be32(rxq->rspq.abs_id); + flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SCHEDCLASS; + flowc->mnemval[4].val = cpu_to_be32(tc); + flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_EOSTATE; + flowc->mnemval[5].val = cpu_to_be32(tc == FW_SCHED_CLS_NONE ? + FW_FLOWC_MNEM_EOSTATE_CLOSING : + FW_FLOWC_MNEM_EOSTATE_ESTABLISHED); + + eosw_txq->cred -= len16; + eosw_txq->ncompl++; + eosw_txq->last_compl = 0; + + ret = eosw_txq_enqueue(eosw_txq, skb); + if (ret) { + dev_consume_skb_any(skb); + goto out_unlock; + } + + eosw_txq->state = next_state; + eosw_txq->flowc_idx = eosw_txq->pidx; + eosw_txq_advance(eosw_txq, 1); + ethofld_xmit(dev, eosw_txq); + +out_unlock: + spin_unlock_bh(&eosw_txq->lock); + return ret; +} + /** * is_imm - check whether a packet can be sent as immediate data * @skb: the packet @@ -3684,9 +3805,26 @@ int cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, if (!skb) break; - hdr_len = eth_get_headlen(eosw_txq->netdev, skb->data, - skb_headlen(skb)); - flits = ethofld_calc_tx_flits(q->adap, skb, hdr_len); + if (unlikely((eosw_txq->state == + CXGB4_EO_STATE_FLOWC_OPEN_REPLY || + eosw_txq->state == + CXGB4_EO_STATE_FLOWC_CLOSE_REPLY) && + eosw_txq->cidx == eosw_txq->flowc_idx)) { + hdr_len = skb->len; + flits = DIV_ROUND_UP(skb->len, 8); + if (eosw_txq->state == + CXGB4_EO_STATE_FLOWC_OPEN_REPLY) + eosw_txq->state = CXGB4_EO_STATE_ACTIVE; + else + eosw_txq->state = CXGB4_EO_STATE_CLOSED; + complete(&eosw_txq->completion); + } else { + hdr_len = eth_get_headlen(eosw_txq->netdev, + skb->data, + skb_headlen(skb)); + flits = ethofld_calc_tx_flits(q->adap, skb, + hdr_len); + } eosw_txq_advance_index(&eosw_txq->cidx, 1, eosw_txq->ndesc); wrlen16 = DIV_ROUND_UP(flits * 8, 16); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index ea395b43dbf4..414e5cca293e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -690,6 +690,12 @@ enum fw_flowc_mnem_tcpstate { FW_FLOWC_MNEM_TCPSTATE_TIMEWAIT = 10, /* not expected */ }; +enum fw_flowc_mnem_eostate { + FW_FLOWC_MNEM_EOSTATE_ESTABLISHED = 1, /* default */ + /* graceful close, after sending outstanding payload */ + FW_FLOWC_MNEM_EOSTATE_CLOSING = 2, +}; + enum fw_flowc_mnem { FW_FLOWC_MNEM_PFNVFN, /* PFN [15:8] VFN [7:0] */ FW_FLOWC_MNEM_CH, -- cgit v1.2.3-59-g8ed1b From 630d4e75dd2969bf7da40beb3d4704356d12ae39 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 6 Nov 2019 14:52:31 +0000 Subject: mlxsw: spectrum: Fix error return code in mlxsw_sp_port_module_info_init() Fix to return negative error code -ENOMEM from the error handling case instead of 0, as done elsewhere in this function. Fixes: 4a7f970f1240 ("mlxsw: spectrum: Replace port_to_module array with array of structs") Signed-off-by: Wei Yongjun Reviewed-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index ea4cc2aa99e0..838c014f6ed1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4079,8 +4079,10 @@ static int mlxsw_sp_port_module_info_init(struct mlxsw_sp *mlxsw_sp) mlxsw_sp->port_mapping[i] = kmemdup(&port_mapping, sizeof(port_mapping), GFP_KERNEL); - if (!mlxsw_sp->port_mapping[i]) + if (!mlxsw_sp->port_mapping[i]) { + err = -ENOMEM; goto err_port_module_info_dup; + } } return 0; -- cgit v1.2.3-59-g8ed1b From a613bafec516bcca3658d054bdc339008d20ac8a Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 Nov 2019 09:39:37 +0100 Subject: enetc: add ioctl() support for PHY-related ops If there is an attached PHY try to handle the requested ioctl with its handler, which allows the userspace to access PHY registers, for example. This will make mii-diag and similar tools work. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index b6ff89307409..25af207f1962 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1599,7 +1599,10 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) if (cmd == SIOCGHWTSTAMP) return enetc_hwtstamp_get(ndev, rq); #endif - return -EINVAL; + + if (!ndev->phydev) + return -EINVAL; + return phy_mii_ioctl(ndev->phydev, rq, cmd); } int enetc_alloc_msix(struct enetc_ndev_priv *priv) -- cgit v1.2.3-59-g8ed1b From 88c8562b16a031045acb519fcbaae9908f323017 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 7 Nov 2019 09:40:00 +0100 Subject: enetc: ethtool: add wake-on-lan callbacks If there is an external PHY, pass the wake-on-lan request to the PHY. Signed-off-by: Michael Walle Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../net/ethernet/freescale/enetc/enetc_ethtool.c | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index fcb52efec075..880a8ed8bb47 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -584,6 +584,31 @@ static int enetc_get_ts_info(struct net_device *ndev, return 0; } +static void enetc_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + + if (dev->phydev) + phy_ethtool_get_wol(dev->phydev, wol); +} + +static int enetc_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + int ret; + + if (!dev->phydev) + return -EOPNOTSUPP; + + ret = phy_ethtool_set_wol(dev->phydev, wol); + if (!ret) + device_set_wakeup_enable(&dev->dev, wol->wolopts); + + return ret; +} + static const struct ethtool_ops enetc_pf_ethtool_ops = { .get_regs_len = enetc_get_reglen, .get_regs = enetc_get_regs, @@ -601,6 +626,8 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = { .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_link = ethtool_op_get_link, .get_ts_info = enetc_get_ts_info, + .get_wol = enetc_get_wol, + .set_wol = enetc_set_wol, }; static const struct ethtool_ops enetc_vf_ethtool_ops = { -- cgit v1.2.3-59-g8ed1b From 991df1fbb0dc3b44a88b4775b32d95839bf779e6 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Thu, 7 Nov 2019 12:44:48 +0200 Subject: dpaa2-eth: add ethtool MAC counters When a DPNI is connected to a MAC, export its associated counters. Ethtool related functions are added in dpaa2_mac for returning the number of counters, their strings and also their values. Signed-off-by: Ioana Ciornei Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- .../net/ethernet/freescale/dpaa2/dpaa2-ethtool.c | 13 +++- drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c | 68 ++++++++++++++++++ drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h | 6 ++ drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h | 11 +++ drivers/net/ethernet/freescale/dpaa2/dpmac.c | 34 +++++++++ drivers/net/ethernet/freescale/dpaa2/dpmac.h | 82 ++++++++++++++++++++++ 6 files changed, 213 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c index 0883620631b8..96676abcebd5 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-ethtool.c @@ -173,6 +173,7 @@ static int dpaa2_eth_set_pauseparam(struct net_device *net_dev, static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { + struct dpaa2_eth_priv *priv = netdev_priv(netdev); u8 *p = data; int i; @@ -186,15 +187,22 @@ static void dpaa2_eth_get_strings(struct net_device *netdev, u32 stringset, strlcpy(p, dpaa2_ethtool_extras[i], ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } + if (priv->mac) + dpaa2_mac_get_strings(p); break; } } static int dpaa2_eth_get_sset_count(struct net_device *net_dev, int sset) { + int num_ss_stats = DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS; + struct dpaa2_eth_priv *priv = netdev_priv(net_dev); + switch (sset) { case ETH_SS_STATS: /* ethtool_get_stats(), ethtool_get_drvinfo() */ - return DPAA2_ETH_NUM_STATS + DPAA2_ETH_NUM_EXTRA_STATS; + if (priv->mac) + num_ss_stats += dpaa2_mac_get_sset_count(); + return num_ss_stats; default: return -EOPNOTSUPP; } @@ -293,6 +301,9 @@ static void dpaa2_eth_get_ethtool_stats(struct net_device *net_dev, return; } *(data + i++) = buf_cnt; + + if (priv->mac) + dpaa2_mac_get_ethtool_stats(priv->mac, data + i); } static int prep_eth_rule(struct ethhdr *eth_value, struct ethhdr *eth_mask, diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c index d322123ed373..84233e467ed1 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.c @@ -305,3 +305,71 @@ void dpaa2_mac_disconnect(struct dpaa2_mac *mac) phylink_destroy(mac->phylink); dpmac_close(mac->mc_io, 0, mac->mc_dev->mc_handle); } + +static char dpaa2_mac_ethtool_stats[][ETH_GSTRING_LEN] = { + [DPMAC_CNT_ING_ALL_FRAME] = "[mac] rx all frames", + [DPMAC_CNT_ING_GOOD_FRAME] = "[mac] rx frames ok", + [DPMAC_CNT_ING_ERR_FRAME] = "[mac] rx frame errors", + [DPMAC_CNT_ING_FRAME_DISCARD] = "[mac] rx frame discards", + [DPMAC_CNT_ING_UCAST_FRAME] = "[mac] rx u-cast", + [DPMAC_CNT_ING_BCAST_FRAME] = "[mac] rx b-cast", + [DPMAC_CNT_ING_MCAST_FRAME] = "[mac] rx m-cast", + [DPMAC_CNT_ING_FRAME_64] = "[mac] rx 64 bytes", + [DPMAC_CNT_ING_FRAME_127] = "[mac] rx 65-127 bytes", + [DPMAC_CNT_ING_FRAME_255] = "[mac] rx 128-255 bytes", + [DPMAC_CNT_ING_FRAME_511] = "[mac] rx 256-511 bytes", + [DPMAC_CNT_ING_FRAME_1023] = "[mac] rx 512-1023 bytes", + [DPMAC_CNT_ING_FRAME_1518] = "[mac] rx 1024-1518 bytes", + [DPMAC_CNT_ING_FRAME_1519_MAX] = "[mac] rx 1519-max bytes", + [DPMAC_CNT_ING_FRAG] = "[mac] rx frags", + [DPMAC_CNT_ING_JABBER] = "[mac] rx jabber", + [DPMAC_CNT_ING_ALIGN_ERR] = "[mac] rx align errors", + [DPMAC_CNT_ING_OVERSIZED] = "[mac] rx oversized", + [DPMAC_CNT_ING_VALID_PAUSE_FRAME] = "[mac] rx pause", + [DPMAC_CNT_ING_BYTE] = "[mac] rx bytes", + [DPMAC_CNT_EGR_GOOD_FRAME] = "[mac] tx frames ok", + [DPMAC_CNT_EGR_UCAST_FRAME] = "[mac] tx u-cast", + [DPMAC_CNT_EGR_MCAST_FRAME] = "[mac] tx m-cast", + [DPMAC_CNT_EGR_BCAST_FRAME] = "[mac] tx b-cast", + [DPMAC_CNT_EGR_ERR_FRAME] = "[mac] tx frame errors", + [DPMAC_CNT_EGR_UNDERSIZED] = "[mac] tx undersized", + [DPMAC_CNT_EGR_VALID_PAUSE_FRAME] = "[mac] tx b-pause", + [DPMAC_CNT_EGR_BYTE] = "[mac] tx bytes", +}; + +#define DPAA2_MAC_NUM_STATS ARRAY_SIZE(dpaa2_mac_ethtool_stats) + +int dpaa2_mac_get_sset_count(void) +{ + return DPAA2_MAC_NUM_STATS; +} + +void dpaa2_mac_get_strings(u8 *data) +{ + u8 *p = data; + int i; + + for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) { + strlcpy(p, dpaa2_mac_ethtool_stats[i], ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } +} + +void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data) +{ + struct fsl_mc_device *dpmac_dev = mac->mc_dev; + int i, err; + u64 value; + + for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) { + err = dpmac_get_counter(mac->mc_io, 0, dpmac_dev->mc_handle, + i, &value); + if (err) { + netdev_err_once(mac->net_dev, + "dpmac_get_counter error %d\n", err); + *(data + i) = U64_MAX; + continue; + } + *(data + i) = value; + } +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h index 8634d0de7ef3..4da8079b9155 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-mac.h @@ -29,4 +29,10 @@ int dpaa2_mac_connect(struct dpaa2_mac *mac); void dpaa2_mac_disconnect(struct dpaa2_mac *mac); +int dpaa2_mac_get_sset_count(void); + +void dpaa2_mac_get_strings(u8 *data); + +void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data); + #endif /* DPAA2_MAC_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h index 96a9b0d0992e..3ea51dd9374b 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac-cmd.h @@ -22,6 +22,8 @@ #define DPMAC_CMDID_GET_ATTR DPMAC_CMD(0x004) #define DPMAC_CMDID_SET_LINK_STATE DPMAC_CMD_V2(0x0c3) +#define DPMAC_CMDID_GET_COUNTER DPMAC_CMD(0x0c4) + /* Macros for accessing command fields smaller than 1byte */ #define DPMAC_MASK(field) \ GENMASK(DPMAC_##field##_SHIFT + DPMAC_##field##_SIZE - 1, \ @@ -59,4 +61,13 @@ struct dpmac_cmd_set_link_state { __le64 advertising; }; +struct dpmac_cmd_get_counter { + u8 id; +}; + +struct dpmac_rsp_get_counter { + u64 pad; + u64 counter; +}; + #endif /* _FSL_DPMAC_CMD_H */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.c b/drivers/net/ethernet/freescale/dpaa2/dpmac.c index b75189deffb1..d5997b654562 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.c @@ -147,3 +147,37 @@ int dpmac_set_link_state(struct fsl_mc_io *mc_io, /* send command to mc*/ return mc_send_command(mc_io, &cmd); } + +/** + * dpmac_get_counter() - Read a specific DPMAC counter + * @mc_io: Pointer to opaque I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPMAC object + * @id: The requested counter ID + * @value: Returned counter value + * + * Return: The requested counter; '0' otherwise. + */ +int dpmac_get_counter(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpmac_counter_id id, u64 *value) +{ + struct dpmac_cmd_get_counter *dpmac_cmd; + struct dpmac_rsp_get_counter *dpmac_rsp; + struct fsl_mc_command cmd = { 0 }; + int err = 0; + + cmd.header = mc_encode_cmd_header(DPMAC_CMDID_GET_COUNTER, + cmd_flags, + token); + dpmac_cmd = (struct dpmac_cmd_get_counter *)cmd.params; + dpmac_cmd->id = id; + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + dpmac_rsp = (struct dpmac_rsp_get_counter *)cmd.params; + *value = le64_to_cpu(dpmac_rsp->counter); + + return 0; +} diff --git a/drivers/net/ethernet/freescale/dpaa2/dpmac.h b/drivers/net/ethernet/freescale/dpaa2/dpmac.h index 4efc410a479e..135f143097a5 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpmac.h +++ b/drivers/net/ethernet/freescale/dpaa2/dpmac.h @@ -141,4 +141,86 @@ int dpmac_set_link_state(struct fsl_mc_io *mc_io, u16 token, struct dpmac_link_state *link_state); +/** + * enum dpmac_counter_id - DPMAC counter types + * + * @DPMAC_CNT_ING_FRAME_64: counts 64-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_127: counts 65- to 127-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_255: counts 128- to 255-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_511: counts 256- to 511-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_1023: counts 512- to 1023-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_1518: counts 1024- to 1518-bytes frames, good or bad. + * @DPMAC_CNT_ING_FRAME_1519_MAX: counts 1519-bytes frames and larger + * (up to max frame length specified), + * good or bad. + * @DPMAC_CNT_ING_FRAG: counts frames which are shorter than 64 bytes received + * with a wrong CRC + * @DPMAC_CNT_ING_JABBER: counts frames longer than the maximum frame length + * specified, with a bad frame check sequence. + * @DPMAC_CNT_ING_FRAME_DISCARD: counts dropped frames due to internal errors. + * Occurs when a receive FIFO overflows. + * Includes also frames truncated as a result of + * the receive FIFO overflow. + * @DPMAC_CNT_ING_ALIGN_ERR: counts frames with an alignment error + * (optional used for wrong SFD). + * @DPMAC_CNT_EGR_UNDERSIZED: counts frames transmitted that was less than 64 + * bytes long with a good CRC. + * @DPMAC_CNT_ING_OVERSIZED: counts frames longer than the maximum frame length + * specified, with a good frame check sequence. + * @DPMAC_CNT_ING_VALID_PAUSE_FRAME: counts valid pause frames (regular and PFC) + * @DPMAC_CNT_EGR_VALID_PAUSE_FRAME: counts valid pause frames transmitted + * (regular and PFC). + * @DPMAC_CNT_ING_BYTE: counts bytes received except preamble for all valid + * frames and valid pause frames. + * @DPMAC_CNT_ING_MCAST_FRAME: counts received multicast frames. + * @DPMAC_CNT_ING_BCAST_FRAME: counts received broadcast frames. + * @DPMAC_CNT_ING_ALL_FRAME: counts each good or bad frames received. + * @DPMAC_CNT_ING_UCAST_FRAME: counts received unicast frames. + * @DPMAC_CNT_ING_ERR_FRAME: counts frames received with an error + * (except for undersized/fragment frame). + * @DPMAC_CNT_EGR_BYTE: counts bytes transmitted except preamble for all valid + * frames and valid pause frames transmitted. + * @DPMAC_CNT_EGR_MCAST_FRAME: counts transmitted multicast frames. + * @DPMAC_CNT_EGR_BCAST_FRAME: counts transmitted broadcast frames. + * @DPMAC_CNT_EGR_UCAST_FRAME: counts transmitted unicast frames. + * @DPMAC_CNT_EGR_ERR_FRAME: counts frames transmitted with an error. + * @DPMAC_CNT_ING_GOOD_FRAME: counts frames received without error, including + * pause frames. + * @DPMAC_CNT_EGR_GOOD_FRAME: counts frames transmitted without error, including + * pause frames. + */ +enum dpmac_counter_id { + DPMAC_CNT_ING_FRAME_64, + DPMAC_CNT_ING_FRAME_127, + DPMAC_CNT_ING_FRAME_255, + DPMAC_CNT_ING_FRAME_511, + DPMAC_CNT_ING_FRAME_1023, + DPMAC_CNT_ING_FRAME_1518, + DPMAC_CNT_ING_FRAME_1519_MAX, + DPMAC_CNT_ING_FRAG, + DPMAC_CNT_ING_JABBER, + DPMAC_CNT_ING_FRAME_DISCARD, + DPMAC_CNT_ING_ALIGN_ERR, + DPMAC_CNT_EGR_UNDERSIZED, + DPMAC_CNT_ING_OVERSIZED, + DPMAC_CNT_ING_VALID_PAUSE_FRAME, + DPMAC_CNT_EGR_VALID_PAUSE_FRAME, + DPMAC_CNT_ING_BYTE, + DPMAC_CNT_ING_MCAST_FRAME, + DPMAC_CNT_ING_BCAST_FRAME, + DPMAC_CNT_ING_ALL_FRAME, + DPMAC_CNT_ING_UCAST_FRAME, + DPMAC_CNT_ING_ERR_FRAME, + DPMAC_CNT_EGR_BYTE, + DPMAC_CNT_EGR_MCAST_FRAME, + DPMAC_CNT_EGR_BCAST_FRAME, + DPMAC_CNT_EGR_UCAST_FRAME, + DPMAC_CNT_EGR_ERR_FRAME, + DPMAC_CNT_ING_GOOD_FRAME, + DPMAC_CNT_EGR_GOOD_FRAME +}; + +int dpmac_get_counter(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, + enum dpmac_counter_id id, u64 *value); + #endif /* __FSL_DPMAC_H */ -- cgit v1.2.3-59-g8ed1b From dddb318b9f989acba9ccca9babc4715a9075eae8 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 7 Nov 2019 15:03:44 +0200 Subject: net: phy: at803x: add missing dependency on CONFIG_REGULATOR Compilation fails on PPC targets as CONFIG_REGULATOR is not set and drivers/regulator/devres.c is not compiled in while functions exported there are used by drivers/net/phy/at803x.c. Here's the error log: LD .tmp_vmlinux1 drivers/net/phy/at803x.o: In function `at803x_rgmii_reg_set_voltage_sel': drivers/net/phy/at803x.c:294: undefined reference to `.rdev_get_drvdata' drivers/net/phy/at803x.o: In function `at803x_rgmii_reg_get_voltage_sel': drivers/net/phy/at803x.c:306: undefined reference to `.rdev_get_drvdata' drivers/net/phy/at803x.o: In function `at8031_register_regulators': drivers/net/phy/at803x.c:359: undefined reference to `.devm_regulator_register' drivers/net/phy/at803x.c:365: undefined reference to `.devm_regulator_register' drivers/net/phy/at803x.o:(.data.rel+0x0): undefined reference to `regulator_list_voltage_table' linux/Makefile:1074: recipe for target 'vmlinux' failed make[1]: *** [vmlinux] Error 1 Fixes: 2f664823a470 ("net: phy: at803x: add device tree binding") Signed-off-by: Madalin Bucur Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8bccadf17e60..fd6a82ce49a4 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -441,6 +441,7 @@ config NXP_TJA11XX_PHY config AT803X_PHY tristate "Qualcomm Atheros AR803X PHYs" + depends on REGULATOR help Currently supports the AR8030, AR8031, AR8033 and AR8035 model -- cgit v1.2.3-59-g8ed1b From c55b810abb136191b6c9f40301eb5efcf8503f38 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Fri, 8 Nov 2019 00:58:21 +0100 Subject: enetc: fix return value for enetc_ioctl() Return -EOPNOTSUPP instead of -EINVAL if the requested ioctl is not implemented. Signed-off-by: Michael Walle Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 25af207f1962..3e8f9819f08c 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1601,7 +1601,7 @@ int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) #endif if (!ndev->phydev) - return -EINVAL; + return -EOPNOTSUPP; return phy_mii_ioctl(ndev->phydev, rq, cmd); } -- cgit v1.2.3-59-g8ed1b From dbc684f15818c081421300560dc7edc856a33e73 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Thu, 7 Nov 2019 18:42:10 +0200 Subject: mlxsw: Add layer 3 devlink-trap support Add the trap IDs and trap group used to report layer 3 drops. Register layer 3 packet traps and associated layer 3 trap group with devlink during driver initialization. Signed-off-by: Amit Cohen Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/reg.h | 1 + .../net/ethernet/mellanox/mlxsw/spectrum_trap.c | 37 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 11 +++++++ 3 files changed, 49 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h index bec035ee5349..5294a1622643 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/reg.h +++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h @@ -5480,6 +5480,7 @@ enum mlxsw_reg_htgt_trap_group { enum mlxsw_reg_htgt_discard_trap_group { MLXSW_REG_HTGT_DISCARD_TRAP_GROUP_BASE = MLXSW_REG_HTGT_TRAP_GROUP_MAX, MLXSW_REG_HTGT_TRAP_GROUP_SP_L2_DISCARDS, + MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS, }; /* reg_htgt_trap_group diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index 7c03b661ae7e..f0e6811baa1c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -30,6 +30,16 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(INGRESS_STP_FILTER, L2_DROPS), MLXSW_SP_TRAP_DROP(EMPTY_TX_LIST, L2_DROPS), MLXSW_SP_TRAP_DROP(PORT_LOOPBACK_FILTER, L2_DROPS), + MLXSW_SP_TRAP_DROP(BLACKHOLE_ROUTE, L3_DROPS), + MLXSW_SP_TRAP_DROP(NON_IP_PACKET, L3_DROPS), + MLXSW_SP_TRAP_DROP(UC_DIP_MC_DMAC, L3_DROPS), + MLXSW_SP_TRAP_DROP(DIP_LB, L3_DROPS), + MLXSW_SP_TRAP_DROP(SIP_MC, L3_DROPS), + MLXSW_SP_TRAP_DROP(SIP_LB, L3_DROPS), + MLXSW_SP_TRAP_DROP(CORRUPTED_IP_HDR, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS), + MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS), }; static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { @@ -40,6 +50,16 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_UC, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_MC_NULL, L2_DISCARDS), MLXSW_SP_RXL_DISCARD(LOOKUP_SWITCH_LB, L2_DISCARDS), + MLXSW_SP_RXL_DISCARD(ROUTER2, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_NON_IP_PACKET, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_UC_DIP_MC_DMAC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_DIP_LB, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_MC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_SIP_LB, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_CORRUPTED_IP_HDR, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS), + MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS), }; /* Mapping between hardware trap and devlink trap. Multiple hardware traps can @@ -54,6 +74,16 @@ static u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, DEVLINK_TRAP_GENERIC_ID_EMPTY_TX_LIST, DEVLINK_TRAP_GENERIC_ID_PORT_LOOPBACK_FILTER, + DEVLINK_TRAP_GENERIC_ID_BLACKHOLE_ROUTE, + DEVLINK_TRAP_GENERIC_ID_NON_IP_PACKET, + DEVLINK_TRAP_GENERIC_ID_UC_DIP_MC_DMAC, + DEVLINK_TRAP_GENERIC_ID_DIP_LB, + DEVLINK_TRAP_GENERIC_ID_SIP_MC, + DEVLINK_TRAP_GENERIC_ID_SIP_LB, + DEVLINK_TRAP_GENERIC_ID_CORRUPTED_IP_HDR, + DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC, + DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE, + DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, }; static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, @@ -211,6 +241,7 @@ mlxsw_sp_trap_group_policer_init(struct mlxsw_sp *mlxsw_sp, u32 rate; switch (group->id) { + case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS:/* fall through */ case DEVLINK_TRAP_GROUP_GENERIC_ID_L2_DROPS: policer_id = MLXSW_SP_DISCARD_POLICER_ID; ir_units = MLXSW_REG_QPCR_IR_UNITS_M; @@ -242,6 +273,12 @@ __mlxsw_sp_trap_group_init(struct mlxsw_sp *mlxsw_sp, priority = 0; tc = 1; break; + case DEVLINK_TRAP_GROUP_GENERIC_ID_L3_DROPS: + group_id = MLXSW_REG_HTGT_TRAP_GROUP_SP_L3_DISCARDS; + policer_id = MLXSW_SP_DISCARD_POLICER_ID; + priority = 0; + tc = 1; + break; default: return -EINVAL; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index 7618f084cae9..a4969982fce1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -66,6 +66,7 @@ enum { MLXSW_TRAP_ID_NVE_ENCAP_ARP = 0xBD, MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6, MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7, + MLXSW_TRAP_ID_DISCARD_ROUTER2 = 0x130, MLXSW_TRAP_ID_DISCARD_ING_PACKET_SMAC_MC = 0x140, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VTAG_ALLOW = 0x148, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VLAN = 0x149, @@ -73,6 +74,16 @@ enum { MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_UC = 0x150, MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_MC_NULL = 0x151, MLXSW_TRAP_ID_DISCARD_LOOKUP_SWITCH_LB = 0x152, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_NON_IP_PACKET = 0x160, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_UC_DIP_MC_DMAC = 0x161, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_DIP_LB = 0x162, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_MC = 0x163, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_SIP_LB = 0x165, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_CORRUPTED_IP_HDR = 0x167, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_SIP_BC = 0x16A, + MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_DIP_LOCAL_NET = 0x16B, + MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_RESERVED_SCOPE = 0x1B0, + MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 0x1B1, MLXSW_TRAP_ID_ACL0 = 0x1C0, /* Multicast trap used for routes with trap action */ MLXSW_TRAP_ID_ACL1 = 0x1C1, -- cgit v1.2.3-59-g8ed1b From 21151f64a458bef8308d57cc08551e043d20ace0 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Thu, 7 Nov 2019 18:42:15 +0200 Subject: mlxsw: Add new FIB entry type for reject routes Currently, packets that cannot be routed in hardware (e.g., nexthop device is not upper of mlxsw), are trapped to the kernel for forwarding. Such packets are trapped using "RTR_INGRESS0" trap. This trap also traps packets that hit reject routes (e.g., "unreachable") so that the kernel will generate the appropriate ICMP error message for them. Subsequent patch will need to only report to devlink packets that hit a reject route, which is impossible as long as "RTR_INGRESS0" is overloaded like that. Solve this by using "RTR_INGRESS1" trap for packets that hit reject routes. Signed-off-by: Amit Cohen Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 + .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 25 ++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 838c014f6ed1..f7b29872db6c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4515,6 +4515,7 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(MTUERROR, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(TTLERROR, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_L3_MARK(LBERROR, MIRROR_TO_CPU, LBERROR, false), + MLXSW_SP_RXL_MARK(RTR_INGRESS1, TRAP_TO_CPU, REMOTE_ROUTE, false), MLXSW_SP_RXL_MARK(IP2ME, TRAP_TO_CPU, IP2ME, false), MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP, false), diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 0e99b64450ca..39c573b39faf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -367,6 +367,7 @@ enum mlxsw_sp_fib_entry_type { MLXSW_SP_FIB_ENTRY_TYPE_LOCAL, MLXSW_SP_FIB_ENTRY_TYPE_TRAP, MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE, + MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE, /* This is a special case of local delivery, where a packet should be * decapsulated on reception. Note that there is no corresponding ENCAP, @@ -4273,6 +4274,23 @@ static int mlxsw_sp_fib_entry_op_blackhole(struct mlxsw_sp *mlxsw_sp, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); } +static int +mlxsw_sp_fib_entry_op_unreachable(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fib_entry *fib_entry, + enum mlxsw_reg_ralue_op op) +{ + enum mlxsw_reg_ralue_trap_action trap_action; + char ralue_pl[MLXSW_REG_RALUE_LEN]; + u16 trap_id; + + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; + trap_id = MLXSW_TRAP_ID_RTR_INGRESS1; + + mlxsw_sp_fib_entry_ralue_pack(ralue_pl, fib_entry, op); + mlxsw_reg_ralue_act_local_pack(ralue_pl, trap_action, trap_id, 0); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); +} + static int mlxsw_sp_fib_entry_op_ipip_decap(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, @@ -4314,6 +4332,9 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_fib_entry_op_trap(mlxsw_sp, fib_entry, op); case MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE: return mlxsw_sp_fib_entry_op_blackhole(mlxsw_sp, fib_entry, op); + case MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE: + return mlxsw_sp_fib_entry_op_unreachable(mlxsw_sp, fib_entry, + op); case MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP: return mlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp, fib_entry, op); @@ -4391,7 +4412,7 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp, * can do so with a lower priority than packets directed * at the host, so use action type local instead of trap. */ - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; return 0; case RTN_UNICAST: if (mlxsw_sp_fi_is_gateway(mlxsw_sp, fi)) @@ -5351,7 +5372,7 @@ static void mlxsw_sp_fib6_entry_type_set(struct mlxsw_sp *mlxsw_sp, else if (rt->fib6_type == RTN_BLACKHOLE) fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_BLACKHOLE; else if (rt->fib6_flags & RTF_REJECT) - fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_LOCAL; + fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_UNREACHABLE; else if (mlxsw_sp_rt6_is_gateway(mlxsw_sp, rt)) fib_entry->type = MLXSW_SP_FIB_ENTRY_TYPE_REMOTE; else diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index a4969982fce1..b7d83c67491f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -49,6 +49,7 @@ enum { MLXSW_TRAP_ID_IPV6_DHCP = 0x69, MLXSW_TRAP_ID_IPV6_ALL_ROUTERS_LINK = 0x6F, MLXSW_TRAP_ID_RTR_INGRESS0 = 0x70, + MLXSW_TRAP_ID_RTR_INGRESS1 = 0x71, MLXSW_TRAP_ID_IPV6_PIM = 0x79, MLXSW_TRAP_ID_IPV6_VRRP = 0x7A, MLXSW_TRAP_ID_IPV4_BGP = 0x88, -- cgit v1.2.3-59-g8ed1b From 0c3cbbf96def619ef1c766c53a7db5f3602898df Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Thu, 7 Nov 2019 18:42:16 +0200 Subject: mlxsw: Add specific trap for packets routed via invalid nexthops Currently, mlxsw does not differentiate between these two cases of routes with invalid nexthops: 1. Nexthops whose nexthop device is a mlxsw upper (has a RIF), but whose neighbour could not be resolved 2. Nexthops whose nexthop device is not a mlxsw upper (e.g., management interface) Up until now this did not matter and mlxsw trapped packets for both cases using the same trap ID. However, packets that should have been routed in hardware (case 1), but incurred a problem are considered exceptions and should be reported to the user. The two cases should therefore be split between two different trap IDs. Allocate a new adjacency entry during initialization and upon the insertion of the first route with an invalid mlxsw nexthop, program this entry to discard packets. Packets hitting this entry will be reported using new trap ID - "DISCARD_ROUTER3". In the future, the entry could be written during initialization, but currently firmware requires a valid RIF, which is not available at this stage. Signed-off-by: Amit Cohen Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 ++ .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 36 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 + 3 files changed, 39 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index f7b29872db6c..d9bcb3b8d032 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4528,6 +4528,8 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(IPV6_OSPF, TRAP_TO_CPU, OSPF, false), MLXSW_SP_RXL_MARK(IPV6_DHCP, TRAP_TO_CPU, DHCP, false), MLXSW_SP_RXL_MARK(RTR_INGRESS0, TRAP_TO_CPU, REMOTE_ROUTE, false), + MLXSW_SP_RXL_MARK(DISCARD_ROUTER3, TRAP_EXCEPTION_TO_CPU, REMOTE_ROUTE, + false), MLXSW_SP_RXL_MARK(IPV4_BGP, TRAP_TO_CPU, BGP, false), MLXSW_SP_RXL_MARK(IPV6_BGP, TRAP_TO_CPU, BGP, false), MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, TRAP_TO_CPU, IPV6_ND, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 39c573b39faf..1aa436054490 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -77,6 +77,7 @@ struct mlxsw_sp_router { struct notifier_block inet6addr_nb; const struct mlxsw_sp_rif_ops **rif_ops_arr; const struct mlxsw_sp_ipip_ops **ipip_ops_arr; + u32 adj_discard_index; }; struct mlxsw_sp_rif { @@ -4197,15 +4198,31 @@ mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl, } } +static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) +{ + u32 adj_discard_index = mlxsw_sp->router->adj_discard_index; + enum mlxsw_reg_ratr_trap_action trap_action; + char ratr_pl[MLXSW_REG_RATR_LEN]; + + trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS; + mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, + MLXSW_REG_RATR_TYPE_ETHERNET, adj_discard_index, + rif_index); + mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); +} + static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_fib_entry *fib_entry, enum mlxsw_reg_ralue_op op) { + struct mlxsw_sp_nexthop_group *nh_group = fib_entry->nh_group; char ralue_pl[MLXSW_REG_RALUE_LEN]; enum mlxsw_reg_ralue_trap_action trap_action; u16 trap_id = 0; u32 adjacency_index = 0; u16 ecmp_size = 0; + int err; /* In case the nexthop group adjacency index is valid, use it * with provided ECMP size. Otherwise, setup trap and pass @@ -4215,6 +4232,15 @@ static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; adjacency_index = fib_entry->nh_group->adj_index; ecmp_size = fib_entry->nh_group->ecmp_size; + } else if (!nh_group->adj_index_valid && nh_group->count && + nh_group->nh_rif) { + err = mlxsw_sp_adj_discard_write(mlxsw_sp, + nh_group->nh_rif->rif_index); + if (err) + return err; + trap_action = MLXSW_REG_RALUE_TRAP_ACTION_NOP; + adjacency_index = mlxsw_sp->router->adj_discard_index; + ecmp_size = 1; } else { trap_action = MLXSW_REG_RALUE_TRAP_ACTION_TRAP; trap_id = MLXSW_TRAP_ID_RTR_INGRESS0; @@ -8144,6 +8170,11 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_neigh_init; + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + &router->adj_discard_index); + if (err) + goto err_adj_discard_index_alloc; + mlxsw_sp->router->netevent_nb.notifier_call = mlxsw_sp_router_netevent_event; err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb); @@ -8172,6 +8203,9 @@ err_dscp_init: err_mp_hash_init: unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); err_register_netevent_notifier: + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + router->adj_discard_index); +err_adj_discard_index_alloc: mlxsw_sp_neigh_fini(mlxsw_sp); err_neigh_init: mlxsw_sp_vrs_fini(mlxsw_sp); @@ -8203,6 +8237,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->router->fib_nb); unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + mlxsw_sp->router->adj_discard_index); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_mr_fini(mlxsw_sp); diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index b7d83c67491f..b84b7f07dce2 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -68,6 +68,7 @@ enum { MLXSW_TRAP_ID_ROUTER_ALERT_IPV4 = 0xD6, MLXSW_TRAP_ID_ROUTER_ALERT_IPV6 = 0xD7, MLXSW_TRAP_ID_DISCARD_ROUTER2 = 0x130, + MLXSW_TRAP_ID_DISCARD_ROUTER3 = 0x131, MLXSW_TRAP_ID_DISCARD_ING_PACKET_SMAC_MC = 0x140, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VTAG_ALLOW = 0x148, MLXSW_TRAP_ID_DISCARD_ING_SWITCH_VLAN = 0x149, -- cgit v1.2.3-59-g8ed1b From fd74feeb2452c94f6e381e1fcef00d69b55723b8 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Thu, 7 Nov 2019 18:42:17 +0200 Subject: mlxsw: Add layer 3 devlink-trap exceptions support Add the trap IDs used to report layer 3 exceptions. Trapped packets are first reported to devlink and then injected to the kernel's receive path. All the packets have 'offload_fwd_mark' set in order to prevent them from potentially being forwarded by the bridge again. Signed-off-by: Amit Cohen Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 8 --- .../net/ethernet/mellanox/mlxsw/spectrum_trap.c | 63 ++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/trap.h | 2 + 3 files changed, 65 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d9bcb3b8d032..471478eb1d86 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4512,10 +4512,7 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_NO_MARK(IPV6_MLDV2_LISTENER_REPORT, TRAP_TO_CPU, IPV6_MLD, false), /* L3 traps */ - MLXSW_SP_RXL_MARK(MTUERROR, TRAP_TO_CPU, ROUTER_EXP, false), - MLXSW_SP_RXL_MARK(TTLERROR, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_L3_MARK(LBERROR, MIRROR_TO_CPU, LBERROR, false), - MLXSW_SP_RXL_MARK(RTR_INGRESS1, TRAP_TO_CPU, REMOTE_ROUTE, false), MLXSW_SP_RXL_MARK(IP2ME, TRAP_TO_CPU, IP2ME, false), MLXSW_SP_RXL_MARK(IPV6_UNSPECIFIED_ADDRESS, TRAP_TO_CPU, ROUTER_EXP, false), @@ -4528,8 +4525,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(IPV6_OSPF, TRAP_TO_CPU, OSPF, false), MLXSW_SP_RXL_MARK(IPV6_DHCP, TRAP_TO_CPU, DHCP, false), MLXSW_SP_RXL_MARK(RTR_INGRESS0, TRAP_TO_CPU, REMOTE_ROUTE, false), - MLXSW_SP_RXL_MARK(DISCARD_ROUTER3, TRAP_EXCEPTION_TO_CPU, REMOTE_ROUTE, - false), MLXSW_SP_RXL_MARK(IPV4_BGP, TRAP_TO_CPU, BGP, false), MLXSW_SP_RXL_MARK(IPV6_BGP, TRAP_TO_CPU, BGP, false), MLXSW_SP_RXL_MARK(L3_IPV6_ROUTER_SOLICITATION, TRAP_TO_CPU, IPV6_ND, @@ -4543,8 +4538,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { MLXSW_SP_RXL_MARK(L3_IPV6_REDIRECTION, TRAP_TO_CPU, IPV6_ND, false), MLXSW_SP_RXL_MARK(IPV6_MC_LINK_LOCAL_DEST, TRAP_TO_CPU, ROUTER_EXP, false), - MLXSW_SP_RXL_MARK(HOST_MISS_IPV4, TRAP_TO_CPU, HOST_MISS, false), - MLXSW_SP_RXL_MARK(HOST_MISS_IPV6, TRAP_TO_CPU, HOST_MISS, false), MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV4, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(ROUTER_ALERT_IPV6, TRAP_TO_CPU, ROUTER_EXP, false), MLXSW_SP_RXL_MARK(IPIP_DECAP_ERROR, TRAP_TO_CPU, ROUTER_EXP, false), @@ -4559,7 +4552,6 @@ static const struct mlxsw_listener mlxsw_sp_listener[] = { /* Multicast Router Traps */ MLXSW_SP_RXL_MARK(IPV4_PIM, TRAP_TO_CPU, PIM, false), MLXSW_SP_RXL_MARK(IPV6_PIM, TRAP_TO_CPU, PIM, false), - MLXSW_SP_RXL_MARK(RPF, TRAP_TO_CPU, RPF, false), MLXSW_SP_RXL_MARK(ACL1, TRAP_TO_CPU, MULTICAST, false), MLXSW_SP_RXL_L3_MARK(ACL2, TRAP_TO_CPU, MULTICAST, false), /* NVE traps */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c index f0e6811baa1c..e0d7c49ffae0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_trap.c @@ -13,16 +13,27 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, void *priv); +static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx); #define MLXSW_SP_TRAP_DROP(_id, _group_id) \ DEVLINK_TRAP_GENERIC(DROP, DROP, _id, \ DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ MLXSW_SP_TRAP_METADATA) +#define MLXSW_SP_TRAP_EXCEPTION(_id, _group_id) \ + DEVLINK_TRAP_GENERIC(EXCEPTION, TRAP, _id, \ + DEVLINK_TRAP_GROUP_GENERIC(_group_id), \ + MLXSW_SP_TRAP_METADATA) + #define MLXSW_SP_RXL_DISCARD(_id, _group_id) \ MLXSW_RXL(mlxsw_sp_rx_drop_listener, DISCARD_##_id, SET_FW_DEFAULT, \ false, SP_##_group_id, DISCARD) +#define MLXSW_SP_RXL_EXCEPTION(_id, _group_id, _action) \ + MLXSW_RXL(mlxsw_sp_rx_exception_listener, _id, \ + _action, false, SP_##_group_id, DISCARD) + static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(SMAC_MC, L2_DROPS), MLXSW_SP_TRAP_DROP(VLAN_TAG_MISMATCH, L2_DROPS), @@ -40,6 +51,13 @@ static struct devlink_trap mlxsw_sp_traps_arr[] = { MLXSW_SP_TRAP_DROP(IPV4_SIP_BC, L3_DROPS), MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_RESERVED_SCOPE, L3_DROPS), MLXSW_SP_TRAP_DROP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(MTU_ERROR, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(TTL_ERROR, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(RPF, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(REJECT_ROUTE, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(UNRESOLVED_NEIGH, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(IPV4_LPM_UNICAST_MISS, L3_DROPS), + MLXSW_SP_TRAP_EXCEPTION(IPV6_LPM_UNICAST_MISS, L3_DROPS), }; static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { @@ -60,6 +78,18 @@ static struct mlxsw_listener mlxsw_sp_listeners_arr[] = { MLXSW_SP_RXL_DISCARD(ING_ROUTER_IPV4_SIP_BC, L3_DISCARDS), MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_RESERVED_SCOPE, L3_DISCARDS), MLXSW_SP_RXL_DISCARD(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, L3_DISCARDS), + MLXSW_SP_RXL_EXCEPTION(MTUERROR, ROUTER_EXP, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(TTLERROR, ROUTER_EXP, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(RPF, RPF, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(RTR_INGRESS1, REMOTE_ROUTE, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV4, HOST_MISS, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(HOST_MISS_IPV6, HOST_MISS, TRAP_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER3, REMOTE_ROUTE, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM4, ROUTER_EXP, + TRAP_EXCEPTION_TO_CPU), + MLXSW_SP_RXL_EXCEPTION(DISCARD_ROUTER_LPM6, ROUTER_EXP, + TRAP_EXCEPTION_TO_CPU), }; /* Mapping between hardware trap and devlink trap. Multiple hardware traps can @@ -84,6 +114,15 @@ static u16 mlxsw_sp_listener_devlink_map[] = { DEVLINK_TRAP_GENERIC_ID_IPV4_SIP_BC, DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_RESERVED_SCOPE, DEVLINK_TRAP_GENERIC_ID_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, + DEVLINK_TRAP_GENERIC_ID_MTU_ERROR, + DEVLINK_TRAP_GENERIC_ID_TTL_ERROR, + DEVLINK_TRAP_GENERIC_ID_RPF, + DEVLINK_TRAP_GENERIC_ID_REJECT_ROUTE, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_UNRESOLVED_NEIGH, + DEVLINK_TRAP_GENERIC_ID_IPV4_LPM_UNICAST_MISS, + DEVLINK_TRAP_GENERIC_ID_IPV6_LPM_UNICAST_MISS, }; static int mlxsw_sp_rx_listener(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, @@ -134,6 +173,30 @@ static void mlxsw_sp_rx_drop_listener(struct sk_buff *skb, u8 local_port, consume_skb(skb); } +static void mlxsw_sp_rx_exception_listener(struct sk_buff *skb, u8 local_port, + void *trap_ctx) +{ + struct devlink_port *in_devlink_port; + struct mlxsw_sp_port *mlxsw_sp_port; + struct mlxsw_sp *mlxsw_sp; + struct devlink *devlink; + + mlxsw_sp = devlink_trap_ctx_priv(trap_ctx); + mlxsw_sp_port = mlxsw_sp->ports[local_port]; + + if (mlxsw_sp_rx_listener(mlxsw_sp, skb, local_port, mlxsw_sp_port)) + return; + + devlink = priv_to_devlink(mlxsw_sp->core); + in_devlink_port = mlxsw_core_port_devlink_port_get(mlxsw_sp->core, + local_port); + skb_push(skb, ETH_HLEN); + devlink_trap_report(devlink, skb, trap_ctx, in_devlink_port); + skb_pull(skb, ETH_HLEN); + skb->offload_fwd_mark = 1; + netif_receive_skb(skb); +} + int mlxsw_sp_devlink_traps_init(struct mlxsw_sp *mlxsw_sp) { struct devlink *devlink = priv_to_devlink(mlxsw_sp->core); diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h index b84b7f07dce2..0c1c142bb6b0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/trap.h +++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h @@ -84,6 +84,8 @@ enum { MLXSW_TRAP_ID_DISCARD_ING_ROUTER_CORRUPTED_IP_HDR = 0x167, MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_SIP_BC = 0x16A, MLXSW_TRAP_ID_DISCARD_ING_ROUTER_IPV4_DIP_LOCAL_NET = 0x16B, + MLXSW_TRAP_ID_DISCARD_ROUTER_LPM4 = 0x17B, + MLXSW_TRAP_ID_DISCARD_ROUTER_LPM6 = 0x17C, MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_RESERVED_SCOPE = 0x1B0, MLXSW_TRAP_ID_DISCARD_IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE = 0x1B1, MLXSW_TRAP_ID_ACL0 = 0x1C0, -- cgit v1.2.3-59-g8ed1b From d993e14bd872e1e30e2028cbaa0302acf2661579 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:49 +0000 Subject: net: atlantic: update firmware interface Here we improve FW interface structures layout and prepare these for the wake phy feature implementation. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 18 ++- .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 173 ++++++++------------- 2 files changed, 72 insertions(+), 119 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 6fc5640065bd..6c7caff9a96b 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -858,22 +858,26 @@ static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac) memset(prpc, 0, sizeof(*prpc)); if (wol_enabled) { - rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_wol); + rpc_size = offsetof(struct hw_atl_utils_fw_rpc, msg_wol_add) + + sizeof(prpc->msg_wol_add); + prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD; - prpc->msg_wol.priority = + prpc->msg_wol_add.priority = HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR; - prpc->msg_wol.pattern_id = + prpc->msg_wol_add.pattern_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; - prpc->msg_wol.wol_packet_type = + prpc->msg_wol_add.packet_type = HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT; - ether_addr_copy((u8 *)&prpc->msg_wol.wol_pattern, mac); + ether_addr_copy((u8 *)&prpc->msg_wol_add.magic_packet_pattern, + mac); } else { - rpc_size = sizeof(prpc->msg_id) + sizeof(prpc->msg_del_id); + rpc_size = sizeof(prpc->msg_wol_remove) + + offsetof(struct hw_atl_utils_fw_rpc, msg_wol_remove); prpc->msg_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL; - prpc->msg_wol.pattern_id = + prpc->msg_wol_add.pattern_id = HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN; } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index ee11b107f0a5..c6708f0d5d3e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -70,104 +70,41 @@ struct __packed hw_atl_stats_s { u32 dpc; }; -union __packed ip_addr { - struct { - u8 addr[16]; - } v6; - struct { - u8 padding[12]; - u8 addr[4]; - } v4; -}; - -struct __packed hw_atl_utils_fw_rpc { - u32 msg_id; - +struct __packed drv_msg_enable_wakeup { union { - struct { - u32 pong; - } msg_ping; + u32 pattern_mask; struct { - u8 mac_addr[6]; - u32 ip_addr_cnt; + u32 reason_arp_v4_pkt : 1; + u32 reason_ipv4_ping_pkt : 1; + u32 reason_ipv6_ns_pkt : 1; + u32 reason_ipv6_ping_pkt : 1; + u32 reason_link_up : 1; + u32 reason_link_down : 1; + u32 reason_maximum : 1; + }; + }; - struct { - union ip_addr addr; - union ip_addr mask; - } ip[1]; - } msg_arp; + union { + u32 offload_mask; + }; +}; - struct { - u32 len; - u8 packet[1514U]; - } msg_inject; +struct __packed magic_packet_pattern_s { + u8 mac_addr[ETH_ALEN]; +}; - struct { - u32 priority; - u32 wol_packet_type; - u32 pattern_id; - u32 next_wol_pattern_offset; - - union { - struct { - u32 flags; - u8 ipv4_source_address[4]; - u8 ipv4_dest_address[4]; - u16 tcp_source_port_number; - u16 tcp_dest_port_number; - } ipv4_tcp_syn_parameters; - - struct { - u32 flags; - u8 ipv6_source_address[16]; - u8 ipv6_dest_address[16]; - u16 tcp_source_port_number; - u16 tcp_dest_port_number; - } ipv6_tcp_syn_parameters; - - struct { - u32 flags; - } eapol_request_id_message_parameters; - - struct { - u32 flags; - u32 mask_offset; - u32 mask_size; - u32 pattern_offset; - u32 pattern_size; - } wol_bit_map_pattern; - - struct { - u8 mac_addr[ETH_ALEN]; - } wol_magic_packet_patter; - } wol_pattern; - } msg_wol; +struct __packed drv_msg_wol_add { + u32 priority; + u32 packet_type; + u32 pattern_id; + u32 next_pattern_offset; - struct { - union { - u32 pattern_mask; - - struct { - u32 reason_arp_v4_pkt : 1; - u32 reason_ipv4_ping_pkt : 1; - u32 reason_ipv6_ns_pkt : 1; - u32 reason_ipv6_ping_pkt : 1; - u32 reason_link_up : 1; - u32 reason_link_down : 1; - u32 reason_maximum : 1; - }; - }; - - union { - u32 offload_mask; - }; - } msg_enable_wakeup; + struct magic_packet_pattern_s magic_packet_pattern; +}; - struct { - u32 id; - } msg_del_id; - }; +struct __packed drv_msg_wol_remove { + u32 id; }; struct __packed hw_atl_utils_mbox_header { @@ -189,6 +126,13 @@ struct __packed hw_aq_ptp_offset { u16 egress_10000; }; +struct __packed hw_atl_cable_diag { + u8 fault; + u8 distance; + u8 far_distance; + u8 reserved; +}; + enum gpio_pin_function { GPIO_PIN_FUNCTION_NC, GPIO_PIN_FUNCTION_VAUX_ENABLE, @@ -210,7 +154,7 @@ struct __packed hw_aq_info { u16 phy_temperature; u8 cable_len; u8 reserved1; - u32 cable_diag_data[4]; + struct hw_atl_cable_diag cable_diag_data[4]; struct hw_aq_ptp_offset ptp_offset; u8 reserved2[12]; u32 caps_lo; @@ -236,25 +180,22 @@ struct __packed hw_atl_utils_mbox { struct hw_aq_info info; }; -/* fw2x */ -typedef u32 fw_offset_t; - struct __packed offload_ip_info { u8 v4_local_addr_count; u8 v4_addr_count; u8 v6_local_addr_count; u8 v6_addr_count; - fw_offset_t v4_addr; - fw_offset_t v4_prefix; - fw_offset_t v6_addr; - fw_offset_t v6_prefix; + u32 v4_addr; + u32 v4_prefix; + u32 v6_addr; + u32 v6_prefix; }; struct __packed offload_port_info { u16 udp_port_count; u16 tcp_port_count; - fw_offset_t udp_port; - fw_offset_t tcp_port; + u32 udp_port; + u32 tcp_port; }; struct __packed offload_ka_info { @@ -262,15 +203,15 @@ struct __packed offload_ka_info { u16 v6_ka_count; u32 retry_count; u32 retry_interval; - fw_offset_t v4_ka; - fw_offset_t v6_ka; + u32 v4_ka; + u32 v6_ka; }; struct __packed offload_rr_info { u32 rr_count; u32 rr_buf_len; - fw_offset_t rr_id_x; - fw_offset_t rr_buf; + u32 rr_id_x; + u32 rr_buf; }; struct __packed offload_info { @@ -287,6 +228,19 @@ struct __packed offload_info { u8 buf[0]; }; +struct __packed hw_atl_utils_fw_rpc { + u32 msg_id; + + union { + /* fw1x structures */ + struct drv_msg_wol_add msg_wol_add; + struct drv_msg_wol_remove msg_wol_remove; + struct drv_msg_enable_wakeup msg_enable_wakeup; + /* fw2x structures */ + struct offload_info fw2x_offloads; + }; +}; + /* Mailbox FW Request interface */ struct __packed hw_fw_request_ptp_gpio_ctrl { u32 index; @@ -326,6 +280,9 @@ struct __packed hw_fw_request_iface { enum hw_atl_rx_action_with_traffic { HW_ATL_RX_DISCARD, HW_ATL_RX_HOST, + HW_ATL_RX_MNGMNT, + HW_ATL_RX_HOST_AND_MNGMNT, + HW_ATL_RX_WOL }; struct aq_rx_filter_vlan { @@ -407,20 +364,12 @@ enum hal_atl_utils_fw_state_e { #define HAL_ATLANTIC_RATE_100M BIT(5) #define HAL_ATLANTIC_RATE_INVALID BIT(6) -#define HAL_ATLANTIC_UTILS_FW_MSG_PING 0x1U -#define HAL_ATLANTIC_UTILS_FW_MSG_ARP 0x2U -#define HAL_ATLANTIC_UTILS_FW_MSG_INJECT 0x3U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_ADD 0x4U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PRIOR 0x10000000U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_PATTERN 0x1U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_MAG_PKT 0x2U #define HAL_ATLANTIC_UTILS_FW_MSG_WOL_DEL 0x5U #define HAL_ATLANTIC_UTILS_FW_MSG_ENABLE_WAKEUP 0x6U -#define HAL_ATLANTIC_UTILS_FW_MSG_MSM_PFC 0x7U -#define HAL_ATLANTIC_UTILS_FW_MSG_PROVISIONING 0x8U -#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_ADD 0x9U -#define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_DEL 0xAU -#define HAL_ATLANTIC_UTILS_FW_MSG_CABLE_DIAG 0xDU enum hw_atl_fw2x_rate { FW2X_RATE_100M = 0x20, -- cgit v1.2.3-59-g8ed1b From 837c637869bef28b06653462cd010ccc0c2ce984 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:50 +0000 Subject: net: atlantic: implement wake_phy feature Wake on PHY allows to configure device to wakeup host as soon as PHY link status is changed to active. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 3 + .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 18 ++-- drivers/net/ethernet/aquantia/atlantic/aq_main.c | 4 +- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 34 ++++--- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 6 +- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 7 +- .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 111 ++++++--------------- 7 files changed, 73 insertions(+), 110 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 8c633caf79d2..d02b0d79f68a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -78,6 +78,9 @@ #define AQ_CFG_FC_MODE AQ_NIC_FC_FULL +/* Default WOL modes used on initialization */ +#define AQ_CFG_WOL_MODES WAKE_MAGIC + #define AQ_CFG_SPEED_MSK 0xFFFFU /* 0xFFFFU==auto_neg */ #define AQ_CFG_IS_AUTONEG_DEF 1U diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 1ae8aabcc41a..3c55cf13cf14 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -356,11 +356,8 @@ static void aq_ethtool_get_wol(struct net_device *ndev, struct aq_nic_s *aq_nic = netdev_priv(ndev); struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); - wol->supported = WAKE_MAGIC; - wol->wolopts = 0; - - if (cfg->wol) - wol->wolopts |= WAKE_MAGIC; + wol->supported = AQ_NIC_WOL_MODES; + wol->wolopts = cfg->wol; } static int aq_ethtool_set_wol(struct net_device *ndev, @@ -371,11 +368,12 @@ static int aq_ethtool_set_wol(struct net_device *ndev, struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); int err = 0; - if (wol->wolopts & WAKE_MAGIC) - cfg->wol |= AQ_NIC_WOL_ENABLED; - else - cfg->wol &= ~AQ_NIC_WOL_ENABLED; - err = device_set_wakeup_enable(&pdev->dev, wol->wolopts); + if (wol->wolopts & ~AQ_NIC_WOL_MODES) + return -EOPNOTSUPP; + + cfg->wol = wol->wolopts; + + err = device_set_wakeup_enable(&pdev->dev, !!cfg->wol); return err; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index a26d4a69efad..2c1096561614 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -74,7 +74,7 @@ static int aq_ndev_open(struct net_device *ndev) err_exit: if (err < 0) - aq_nic_deinit(aq_nic); + aq_nic_deinit(aq_nic, true); return err; } @@ -86,7 +86,7 @@ static int aq_ndev_close(struct net_device *ndev) err = aq_nic_stop(aq_nic); if (err < 0) goto err_exit; - aq_nic_deinit(aq_nic); + aq_nic_deinit(aq_nic, true); err_exit: return err; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 433adc099e44..75faf288a2fc 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -79,6 +79,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF; cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF; cfg->flow_control = AQ_CFG_FC_MODE; + cfg->wol = AQ_CFG_WOL_MODES; cfg->mtu = AQ_CFG_MTU_DEF; cfg->link_speed_msk = AQ_CFG_SPEED_MSK; @@ -1000,7 +1001,20 @@ int aq_nic_stop(struct aq_nic_s *self) return self->aq_hw_ops->hw_stop(self->aq_hw); } -void aq_nic_deinit(struct aq_nic_s *self) +void aq_nic_set_power(struct aq_nic_s *self) +{ + if (self->power_state != AQ_HW_POWER_STATE_D0 || + self->aq_hw->aq_nic_cfg->wol) + if (likely(self->aq_fw_ops->set_power)) { + mutex_lock(&self->fwreq_mutex); + self->aq_fw_ops->set_power(self->aq_hw, + self->power_state, + self->ndev->dev_addr); + mutex_unlock(&self->fwreq_mutex); + } +} + +void aq_nic_deinit(struct aq_nic_s *self, bool link_down) { struct aq_vec_s *aq_vec = NULL; unsigned int i = 0U; @@ -1017,23 +1031,12 @@ void aq_nic_deinit(struct aq_nic_s *self) aq_ptp_ring_free(self); aq_ptp_free(self); - if (likely(self->aq_fw_ops->deinit)) { + if (likely(self->aq_fw_ops->deinit) && link_down) { mutex_lock(&self->fwreq_mutex); self->aq_fw_ops->deinit(self->aq_hw); mutex_unlock(&self->fwreq_mutex); } - if (self->power_state != AQ_HW_POWER_STATE_D0 || - self->aq_hw->aq_nic_cfg->wol) - if (likely(self->aq_fw_ops->set_power)) { - mutex_lock(&self->fwreq_mutex); - self->aq_fw_ops->set_power(self->aq_hw, - self->power_state, - self->ndev->dev_addr); - mutex_unlock(&self->fwreq_mutex); - } - - err_exit:; } @@ -1072,7 +1075,7 @@ int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg) if (err < 0) goto err_exit; - aq_nic_deinit(self); + aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol); } else { err = aq_nic_init(self); if (err < 0) @@ -1108,7 +1111,8 @@ void aq_nic_shutdown(struct aq_nic_s *self) if (err < 0) goto err_exit; } - aq_nic_deinit(self); + aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol); + aq_nic_set_power(self); err_exit: rtnl_unlock(); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index c2513b79b9e9..8c23ad4ddf38 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -60,7 +60,8 @@ struct aq_nic_cfg_s { #define AQ_NIC_FLAG_ERR_UNPLUG 0x40000000U #define AQ_NIC_FLAG_ERR_HW 0x80000000U -#define AQ_NIC_WOL_ENABLED BIT(0) +#define AQ_NIC_WOL_MODES (WAKE_MAGIC |\ + WAKE_PHY) #define AQ_NIC_TCVEC2RING(_NIC_, _TC_, _VEC_) \ ((_TC_) * AQ_CFG_TCS_MAX + (_VEC_)) @@ -141,7 +142,8 @@ int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p); int aq_nic_get_regs_count(struct aq_nic_s *self); void aq_nic_get_stats(struct aq_nic_s *self, u64 *data); int aq_nic_stop(struct aq_nic_s *self); -void aq_nic_deinit(struct aq_nic_s *self); +void aq_nic_deinit(struct aq_nic_s *self, bool link_down); +void aq_nic_set_power(struct aq_nic_s *self); void aq_nic_free_hot_resources(struct aq_nic_s *self); void aq_nic_free_vectors(struct aq_nic_s *self); int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index 6c7caff9a96b..fd2c6be4e22e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -845,7 +845,8 @@ int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) return 0; } -static int aq_fw1x_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac) +static int aq_fw1x_set_wake_magic(struct aq_hw_s *self, bool wol_enabled, + u8 *mac) { struct hw_atl_utils_fw_rpc *prpc = NULL; unsigned int rpc_size = 0U; @@ -894,8 +895,8 @@ static int aq_fw1x_set_power(struct aq_hw_s *self, unsigned int power_state, unsigned int rpc_size = 0U; int err = 0; - if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) { - err = aq_fw1x_set_wol(self, 1, mac); + if (self->aq_nic_cfg->wol & WAKE_MAGIC) { + err = aq_fw1x_set_wake_magic(self, 1, mac); if (err < 0) goto err_exit; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index f649ac949d06..9b89622fa5d4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -34,6 +34,7 @@ #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) +#define HW_ATL_FW2X_CTRL_WAKE_ON_LINK BIT(CTRL_WAKE_ON_LINK) #define HW_ATL_FW2X_CTRL_SLEEP_PROXY BIT(CTRL_SLEEP_PROXY) #define HW_ATL_FW2X_CTRL_WOL BIT(CTRL_WOL) #define HW_ATL_FW2X_CTRL_LINK_DROP BIT(CTRL_LINK_DROP) @@ -345,87 +346,46 @@ static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp) return 0; } -static int aq_fw2x_set_sleep_proxy(struct aq_hw_s *self, u8 *mac) +static int aq_fw2x_set_wol(struct aq_hw_s *self, u8 *mac) { struct hw_atl_utils_fw_rpc *rpc = NULL; - struct offload_info *cfg = NULL; - unsigned int rpc_size = 0U; - u32 mpi_opts; + struct offload_info *info = NULL; + u32 wol_bits = 0; + u32 rpc_size; int err = 0; u32 val; - rpc_size = sizeof(rpc->msg_id) + sizeof(*cfg); - - err = hw_atl_utils_fw_rpc_wait(self, &rpc); - if (err < 0) - goto err_exit; - - memset(rpc, 0, rpc_size); - cfg = (struct offload_info *)(&rpc->msg_id + 1); - - memcpy(cfg->mac_addr, mac, ETH_ALEN); - cfg->len = sizeof(*cfg); - - /* Clear bit 0x36C.23 and 0x36C.22 */ - mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); - mpi_opts &= ~HW_ATL_FW2X_CTRL_SLEEP_PROXY; - mpi_opts &= ~HW_ATL_FW2X_CTRL_LINK_DROP; - - aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); - - err = hw_atl_utils_fw_rpc_call(self, rpc_size); - if (err < 0) - goto err_exit; - - /* Set bit 0x36C.23 */ - mpi_opts |= HW_ATL_FW2X_CTRL_SLEEP_PROXY; - aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); - - err = readx_poll_timeout_atomic(aq_fw2x_state2_get, - self, val, - val & HW_ATL_FW2X_CTRL_SLEEP_PROXY, - 1U, 100000U); - -err_exit: - return err; -} - -static int aq_fw2x_set_wol_params(struct aq_hw_s *self, u8 *mac) -{ - struct hw_atl_utils_fw_rpc *rpc = NULL; - struct fw2x_msg_wol *msg = NULL; - u32 mpi_opts; - int err = 0; - u32 val; - - err = hw_atl_utils_fw_rpc_wait(self, &rpc); - if (err < 0) - goto err_exit; - - msg = (struct fw2x_msg_wol *)rpc; - - memset(msg, 0, sizeof(*msg)); + if (self->aq_nic_cfg->wol & WAKE_PHY) { + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, + HW_ATL_FW2X_CTRL_LINK_DROP); + readx_poll_timeout_atomic(aq_fw2x_state2_get, self, val, + (val & + HW_ATL_FW2X_CTRL_LINK_DROP) != 0, + 1000, 100000); + wol_bits |= HW_ATL_FW2X_CTRL_WAKE_ON_LINK; + } - msg->msg_id = HAL_ATLANTIC_UTILS_FW2X_MSG_WOL; - msg->magic_packet_enabled = true; - memcpy(msg->hw_addr, mac, ETH_ALEN); + if (self->aq_nic_cfg->wol & WAKE_MAGIC) { + wol_bits |= HW_ATL_FW2X_CTRL_SLEEP_PROXY | + HW_ATL_FW2X_CTRL_WOL; - mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); - mpi_opts &= ~(HW_ATL_FW2X_CTRL_SLEEP_PROXY | HW_ATL_FW2X_CTRL_WOL); + err = hw_atl_utils_fw_rpc_wait(self, &rpc); + if (err < 0) + goto err_exit; - aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + rpc_size = sizeof(*info) + + offsetof(struct hw_atl_utils_fw_rpc, fw2x_offloads); + memset(rpc, 0, rpc_size); + info = &rpc->fw2x_offloads; + memcpy(info->mac_addr, mac, ETH_ALEN); + info->len = sizeof(*info); - err = hw_atl_utils_fw_rpc_call(self, sizeof(*msg)); - if (err < 0) - goto err_exit; + err = hw_atl_utils_fw_rpc_call(self, rpc_size); + if (err < 0) + goto err_exit; + } - /* Set bit 0x36C.24 */ - mpi_opts |= HW_ATL_FW2X_CTRL_WOL; - aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); - - err = readx_poll_timeout_atomic(aq_fw2x_state2_get, - self, val, val & HW_ATL_FW2X_CTRL_WOL, - 1U, 10000U); + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, wol_bits); err_exit: return err; @@ -436,14 +396,9 @@ static int aq_fw2x_set_power(struct aq_hw_s *self, unsigned int power_state, { int err = 0; - if (self->aq_nic_cfg->wol & AQ_NIC_WOL_ENABLED) { - err = aq_fw2x_set_sleep_proxy(self, mac); - if (err < 0) - goto err_exit; - err = aq_fw2x_set_wol_params(self, mac); - } + if (self->aq_nic_cfg->wol) + err = aq_fw2x_set_wol(self, mac); -err_exit: return err; } -- cgit v1.2.3-59-g8ed1b From 8aaa112a57c1d725c92dfad32c0694bd21b374d0 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:52 +0000 Subject: net: atlantic: refactoring pm logic We now implement .driver.pm callbacks, these allows driver to work correctly in hibernate usecases, especially when used in conjunction with WOL feature. Before that driver only reacted to legacy .suspend/.resume callbacks, that was a limitation in some cases. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 38 ---------- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 1 - .../net/ethernet/aquantia/atlantic/aq_pci_func.c | 87 +++++++++++++++++++--- 3 files changed, 78 insertions(+), 48 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 75faf288a2fc..d5764228cea5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -1057,44 +1057,6 @@ void aq_nic_free_vectors(struct aq_nic_s *self) err_exit:; } -int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg) -{ - int err = 0; - - if (!netif_running(self->ndev)) { - err = 0; - goto out; - } - rtnl_lock(); - if (pm_msg->event & PM_EVENT_SLEEP || pm_msg->event & PM_EVENT_FREEZE) { - self->power_state = AQ_HW_POWER_STATE_D3; - netif_device_detach(self->ndev); - netif_tx_stop_all_queues(self->ndev); - - err = aq_nic_stop(self); - if (err < 0) - goto err_exit; - - aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol); - } else { - err = aq_nic_init(self); - if (err < 0) - goto err_exit; - - err = aq_nic_start(self); - if (err < 0) - goto err_exit; - - netif_device_attach(self->ndev); - netif_tx_start_all_queues(self->ndev); - } - -err_exit: - rtnl_unlock(); -out: - return err; -} - void aq_nic_shutdown(struct aq_nic_s *self) { int err = 0; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 8c23ad4ddf38..ab3176dfc209 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -157,7 +157,6 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self, const struct ethtool_link_ksettings *cmd); struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); u32 aq_nic_get_fw_version(struct aq_nic_s *self); -int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); void aq_nic_shutdown(struct aq_nic_s *self); u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index e82c96b50373..3169951fe6ab 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -347,29 +347,98 @@ static void aq_pci_shutdown(struct pci_dev *pdev) } } -static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg) +static int aq_suspend_common(struct device *dev, bool deep) { - struct aq_nic_s *self = pci_get_drvdata(pdev); + struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev)); + + rtnl_lock(); + + nic->power_state = AQ_HW_POWER_STATE_D3; + netif_device_detach(nic->ndev); + netif_tx_stop_all_queues(nic->ndev); - return aq_nic_change_pm_state(self, &pm_msg); + aq_nic_stop(nic); + + if (deep) { + aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol); + aq_nic_set_power(nic); + } + + rtnl_unlock(); + + return 0; } -static int aq_pci_resume(struct pci_dev *pdev) +static int atl_resume_common(struct device *dev, bool deep) { - struct aq_nic_s *self = pci_get_drvdata(pdev); - pm_message_t pm_msg = PMSG_RESTORE; + struct pci_dev *pdev = to_pci_dev(dev); + struct aq_nic_s *nic; + int ret; + + nic = pci_get_drvdata(pdev); + + rtnl_lock(); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (deep) { + ret = aq_nic_init(nic); + if (ret) + goto err_exit; + } + + ret = aq_nic_start(nic); + if (ret) + goto err_exit; + + netif_device_attach(nic->ndev); + netif_tx_start_all_queues(nic->ndev); - return aq_nic_change_pm_state(self, &pm_msg); +err_exit: + rtnl_unlock(); + + return ret; +} + +static int aq_pm_freeze(struct device *dev) +{ + return aq_suspend_common(dev, false); } +static int aq_pm_suspend_poweroff(struct device *dev) +{ + return aq_suspend_common(dev, true); +} + +static int aq_pm_thaw(struct device *dev) +{ + return atl_resume_common(dev, false); +} + +static int aq_pm_resume_restore(struct device *dev) +{ + return atl_resume_common(dev, true); +} + +const struct dev_pm_ops aq_pm_ops = { + .suspend = aq_pm_suspend_poweroff, + .poweroff = aq_pm_suspend_poweroff, + .freeze = aq_pm_freeze, + .resume = aq_pm_resume_restore, + .restore = aq_pm_resume_restore, + .thaw = aq_pm_thaw, +}; + static struct pci_driver aq_pci_ops = { .name = AQ_CFG_DRV_NAME, .id_table = aq_pci_tbl, .probe = aq_pci_probe, .remove = aq_pci_remove, - .suspend = aq_pci_suspend, - .resume = aq_pci_resume, .shutdown = aq_pci_shutdown, +#ifdef CONFIG_PM + .driver.pm = &aq_pm_ops, +#endif }; int aq_pci_func_register_driver(void) -- cgit v1.2.3-59-g8ed1b From 58128fa0265b75be21ec244680426da50ca72850 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:54 +0000 Subject: net: atlantic: add msglevel configuration We add ethtool msglevel configuration and change some printouts to use netdev_info set of functions. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | 16 ++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 7 ++++--- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 3c55cf13cf14..5be273892430 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -607,6 +607,20 @@ err_exit: return err; } +static u32 aq_get_msg_level(struct net_device *ndev) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + + return aq_nic->msg_enable; +} + +static void aq_set_msg_level(struct net_device *ndev, u32 data) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + + aq_nic->msg_enable = data; +} + const struct ethtool_ops aq_ethtool_ops = { .get_link = aq_ethtool_get_link, .get_regs_len = aq_ethtool_get_regs_len, @@ -628,6 +642,8 @@ const struct ethtool_ops aq_ethtool_ops = { .set_rxfh = aq_ethtool_set_rss, .get_rxnfc = aq_ethtool_get_rxnfc, .set_rxnfc = aq_ethtool_set_rxnfc, + .get_msglevel = aq_get_msg_level, + .set_msglevel = aq_set_msg_level, .get_sset_count = aq_ethtool_get_sset_count, .get_ethtool_stats = aq_ethtool_stats, .get_link_ksettings = aq_ethtool_get_link_ksettings, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index d5764228cea5..8f83e91f8146 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -144,9 +144,9 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) return err; if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) { - pr_info("%s: link change old %d new %d\n", - AQ_CFG_DRV_NAME, self->link_status.mbps, - self->aq_hw->aq_link_status.mbps); + netdev_info(self->ndev, "%s: link change old %d new %d\n", + AQ_CFG_DRV_NAME, self->link_status.mbps, + self->aq_hw->aq_link_status.mbps); aq_nic_update_interrupt_moderation_settings(self); if (self->aq_ptp) { @@ -306,6 +306,7 @@ void aq_nic_ndev_init(struct aq_nic_s *self) self->ndev->priv_flags = aq_hw_caps->hw_priv_flags; self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + self->msg_enable = NETIF_MSG_DRV | NETIF_MSG_LINK; self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN; self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index ab3176dfc209..527273502d54 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -88,6 +88,7 @@ struct aq_hw_rx_fltrs_s { struct aq_nic_s { atomic_t flags; + u32 msg_enable; struct aq_vec_s *aq_vec[AQ_CFG_VECS_MAX]; struct aq_ring_s *aq_ring_tx[AQ_CFG_VECS_MAX * AQ_CFG_TCS_MAX]; struct aq_hw_s *aq_hw; -- cgit v1.2.3-59-g8ed1b From d1287ce4ffa1d1f121571ce90ed7ebd410e31a21 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:55 +0000 Subject: net: atlantic: adding ethtool physical identification `ethtool -p eth0` will blink leds helping identify physical port. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 30 ++++++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 5 ++++ .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 1 + .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 14 ++++++++++ 4 files changed, 50 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 5be273892430..2f877fb46615 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -153,6 +153,35 @@ static void aq_ethtool_get_strings(struct net_device *ndev, } } +static int aq_ethtool_set_phys_id(struct net_device *ndev, + enum ethtool_phys_id_state state) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + struct aq_hw_s *hw = aq_nic->aq_hw; + int ret = 0; + + if (!aq_nic->aq_fw_ops->led_control) + return -EOPNOTSUPP; + + mutex_lock(&aq_nic->fwreq_mutex); + + switch (state) { + case ETHTOOL_ID_ACTIVE: + ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_BLINK | + AQ_HW_LED_BLINK << 2 | AQ_HW_LED_BLINK << 4); + break; + case ETHTOOL_ID_INACTIVE: + ret = aq_nic->aq_fw_ops->led_control(hw, AQ_HW_LED_DEFAULT); + break; + default: + break; + } + + mutex_unlock(&aq_nic->fwreq_mutex); + + return ret; +} + static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) { int ret = 0; @@ -627,6 +656,7 @@ const struct ethtool_ops aq_ethtool_ops = { .get_regs = aq_ethtool_get_regs, .get_drvinfo = aq_ethtool_get_drvinfo, .get_strings = aq_ethtool_get_strings, + .set_phys_id = aq_ethtool_set_phys_id, .get_rxfh_indir_size = aq_ethtool_get_rss_indir_size, .get_wol = aq_ethtool_get_wol, .set_wol = aq_ethtool_set_wol, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 5246cf44ce51..c2725a58f050 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -119,6 +119,9 @@ struct aq_stats_s { #define AQ_HW_MULTICAST_ADDRESS_MAX 32U +#define AQ_HW_LED_BLINK 0x2U +#define AQ_HW_LED_DEFAULT 0x0U + struct aq_hw_s { atomic_t flags; u8 rbl_enabled:1; @@ -304,6 +307,8 @@ struct aq_fw_ops { int (*set_flow_control)(struct aq_hw_s *self); + int (*led_control)(struct aq_hw_s *self, u32 mode); + int (*set_power)(struct aq_hw_s *self, unsigned int power_state, u8 *mac); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index fd2c6be4e22e..fc82ede18b20 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -970,4 +970,5 @@ const struct aq_fw_ops aq_fw_1x_ops = { .set_flow_control = NULL, .send_fw_request = NULL, .enable_ptp = NULL, + .led_control = NULL, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 9b89622fa5d4..4eab51b5b400 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -17,6 +17,7 @@ #include "hw_atl_utils.h" #include "hw_atl_llh.h" +#define HW_ATL_FW2X_MPI_LED_ADDR 0x31c #define HW_ATL_FW2X_MPI_RPC_ADDR 0x334 #define HW_ATL_FW2X_MPI_MBOX_ADDR 0x360 @@ -51,6 +52,8 @@ #define HAL_ATLANTIC_WOL_FILTERS_COUNT 8 #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E +#define HW_ATL_FW_VER_LED 0x03010026U + struct __packed fw2x_msg_wol_pattern { u8 mask[16]; u32 crc; @@ -450,6 +453,16 @@ static void aq_fw3x_enable_ptp(struct aq_hw_s *self, int enable) aq_hw_write_reg(self, HW_ATL_FW3X_EXT_CONTROL_ADDR, ptp_opts); } +static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode) +{ + if (self->fw_ver_actual < HW_ATL_FW_VER_LED) + return -EOPNOTSUPP; + + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_LED_ADDR, mode); + + return 0; +} + static int aq_fw2x_set_eee_rate(struct aq_hw_s *self, u32 speed) { u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); @@ -557,4 +570,5 @@ const struct aq_fw_ops aq_fw_2x_ops = { .get_flow_control = aq_fw2x_get_flow_control, .send_fw_request = aq_fw2x_send_fw_request, .enable_ptp = aq_fw3x_enable_ptp, + .led_control = aq_fw2x_led_control, }; -- cgit v1.2.3-59-g8ed1b From dc12f75afcc677f225e5465b0654c54a14945168 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:41:57 +0000 Subject: net: atlantic: add fw configuration memory area Device FW has a separate memory area where various config fields are stored and could be used by the driver. Here we modify download/upload infrastructure to allow accessing this area. Lateron this will be used to configure various behaviours Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 1 + .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 129 +++++++++++++++------ .../aquantia/atlantic/hw_atl/hw_atl_utils.h | 47 +++++++- .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 19 ++- 4 files changed, 159 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index c2725a58f050..57396e516939 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -140,6 +140,7 @@ struct aq_hw_s { atomic_t dpc; u32 mbox_addr; u32 rpc_addr; + u32 settings_addr; u32 rpc_tid; struct hw_atl_utils_fw_rpc rpc; s64 ptp_clk_offset; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index fc82ede18b20..db8c09c5a768 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -47,6 +47,11 @@ #define FORCE_FLASHLESS 0 +enum mcp_area { + MCP_AREA_CONFIG = 0x80000000, + MCP_AREA_SETTINGS = 0x20000000, +}; + static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual); static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, @@ -327,10 +332,75 @@ err_exit: return err; } -int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt) +static int hw_atl_utils_write_b1_mbox(struct aq_hw_s *self, u32 addr, + u32 *p, u32 cnt, enum mcp_area area) +{ + u32 data_offset = 0; + u32 offset = addr; + int err = 0; + u32 val; + + switch (area) { + case MCP_AREA_CONFIG: + offset -= self->rpc_addr; + break; + + case MCP_AREA_SETTINGS: + offset -= self->settings_addr; + break; + } + + offset = offset / sizeof(u32); + + for (; data_offset < cnt; ++data_offset, ++offset) { + aq_hw_write_reg(self, 0x328, p[data_offset]); + aq_hw_write_reg(self, 0x32C, + (area | (0xFFFF & (offset * 4)))); + hw_atl_mcp_up_force_intr_set(self, 1); + /* 1000 times by 10us = 10ms */ + err = readx_poll_timeout_atomic(hw_atl_scrpad12_get, + self, val, + (val & 0xF0000000) != + area, + 10U, 10000U); + + if (err < 0) + break; + } + + return err; +} + +static int hw_atl_utils_write_b0_mbox(struct aq_hw_s *self, u32 addr, + u32 *p, u32 cnt) { + u32 offset = 0; + int err = 0; u32 val; + + aq_hw_write_reg(self, 0x208, addr); + + for (; offset < cnt; ++offset) { + aq_hw_write_reg(self, 0x20C, p[offset]); + aq_hw_write_reg(self, 0x200, 0xC000); + + err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, + self, val, + (val & 0x100) == 0U, + 10U, 10000U); + + if (err < 0) + break; + } + + return err; +} + +static int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 addr, u32 *p, + u32 cnt, enum mcp_area area) +{ int err = 0; + u32 val; err = readx_poll_timeout_atomic(hw_atl_sem_ram_get, self, val, val == 1U, @@ -338,43 +408,35 @@ int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt) if (err < 0) goto err_exit; - if (IS_CHIP_FEATURE(REVISION_B1)) { - u32 offset = 0; - - for (; offset < cnt; ++offset) { - aq_hw_write_reg(self, 0x328, p[offset]); - aq_hw_write_reg(self, 0x32C, - (0x80000000 | (0xFFFF & (offset * 4)))); - hw_atl_mcp_up_force_intr_set(self, 1); - /* 1000 times by 10us = 10ms */ - err = readx_poll_timeout_atomic(hw_atl_scrpad12_get, - self, val, - (val & 0xF0000000) != - 0x80000000, - 10U, 10000U); - } - } else { - u32 offset = 0; - - aq_hw_write_reg(self, 0x208, a); + if (IS_CHIP_FEATURE(REVISION_B1)) + err = hw_atl_utils_write_b1_mbox(self, addr, p, cnt, area); + else + err = hw_atl_utils_write_b0_mbox(self, addr, p, cnt); - for (; offset < cnt; ++offset) { - aq_hw_write_reg(self, 0x20C, p[offset]); - aq_hw_write_reg(self, 0x200, 0xC000); + hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); - err = readx_poll_timeout_atomic(hw_atl_utils_mif_cmd_get, - self, val, - (val & 0x100) == 0, - 1000U, 10000U); - } - } + if (err < 0) + goto err_exit; - hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM); + err = aq_hw_err_from_flags(self); err_exit: return err; } +int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt) +{ + return hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, p, + cnt, MCP_AREA_CONFIG); +} + +int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, + u32 cnt) +{ + return hw_atl_utils_fw_upload_dwords(self, self->settings_addr + offset, + p, cnt, MCP_AREA_SETTINGS); +} + static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) { int err = 0; @@ -437,10 +499,9 @@ int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) err = -1; goto err_exit; } - err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr, - (u32 *)(void *)&self->rpc, - (rpc_size + sizeof(u32) - - sizeof(u8)) / sizeof(u32)); + err = hw_atl_write_fwcfg_dwords(self, (u32 *)(void *)&self->rpc, + (rpc_size + sizeof(u32) - + sizeof(u8)) / sizeof(u32)); if (err < 0) goto err_exit; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index c6708f0d5d3e..68fe17ec171d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -277,6 +277,48 @@ struct __packed hw_fw_request_iface { }; }; +struct __packed hw_atl_utils_settings { + u32 mtu; + u32 downshift_retry_count; + u32 link_pause_frame_quanta_100m; + u32 link_pause_frame_threshold_100m; + u32 link_pause_frame_quanta_1g; + u32 link_pause_frame_threshold_1g; + u32 link_pause_frame_quanta_2p5g; + u32 link_pause_frame_threshold_2p5g; + u32 link_pause_frame_quanta_5g; + u32 link_pause_frame_threshold_5g; + u32 link_pause_frame_quanta_10g; + u32 link_pause_frame_threshold_10g; + u32 pfc_quanta_class_0; + u32 pfc_threshold_class_0; + u32 pfc_quanta_class_1; + u32 pfc_threshold_class_1; + u32 pfc_quanta_class_2; + u32 pfc_threshold_class_2; + u32 pfc_quanta_class_3; + u32 pfc_threshold_class_3; + u32 pfc_quanta_class_4; + u32 pfc_threshold_class_4; + u32 pfc_quanta_class_5; + u32 pfc_threshold_class_5; + u32 pfc_quanta_class_6; + u32 pfc_threshold_class_6; + u32 pfc_quanta_class_7; + u32 pfc_threshold_class_7; + u32 eee_link_down_timeout; + u32 eee_link_up_timeout; + u32 eee_max_link_drops; + u32 eee_rates_mask; + u32 wake_timer; + u32 thermal_shutdown_off_temp; + u32 thermal_shutdown_warning_temp; + u32 thermal_shutdown_cold_temp; + u32 msm_options; + u32 dac_cable_serdes_modes; + u32 media_detect; +}; + enum hw_atl_rx_action_with_traffic { HW_ATL_RX_DISCARD, HW_ATL_RX_HOST, @@ -554,7 +596,10 @@ struct aq_stats_s *hw_atl_utils_get_hw_stats(struct aq_hw_s *self); int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); -int hw_atl_utils_fw_upload_dwords(struct aq_hw_s *self, u32 a, u32 *p, u32 cnt); +int hw_atl_write_fwcfg_dwords(struct aq_hw_s *self, u32 *p, u32 cnt); + +int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, + u32 cnt); int hw_atl_utils_fw_set_wol(struct aq_hw_s *self, bool wol_enabled, u8 *mac); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 4eab51b5b400..3dbce03c5a94 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -78,6 +78,7 @@ static int aq_fw2x_set_state(struct aq_hw_s *self, static u32 aq_fw2x_mbox_get(struct aq_hw_s *self); static u32 aq_fw2x_rpc_get(struct aq_hw_s *self); +static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr); static u32 aq_fw2x_state2_get(struct aq_hw_s *self); static int aq_fw2x_init(struct aq_hw_s *self) @@ -95,6 +96,8 @@ static int aq_fw2x_init(struct aq_hw_s *self) self->rpc_addr != 0U, 1000U, 100000U); + err = aq_fw2x_settings_get(self, &self->settings_addr); + return err; } @@ -418,8 +421,7 @@ static int aq_fw2x_send_fw_request(struct aq_hw_s *self, dword_cnt = size / sizeof(u32); if (size % sizeof(u32)) dword_cnt++; - err = hw_atl_utils_fw_upload_dwords(self, aq_fw2x_rpc_get(self), - (void *)fw_req, dword_cnt); + err = hw_atl_write_fwcfg_dwords(self, (void *)fw_req, dword_cnt); if (err < 0) goto err_exit; @@ -547,6 +549,19 @@ static u32 aq_fw2x_rpc_get(struct aq_hw_s *self) return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_RPC_ADDR); } +static int aq_fw2x_settings_get(struct aq_hw_s *self, u32 *addr) +{ + int err = 0; + u32 offset; + + offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, + info.setting_address); + + err = hw_atl_utils_fw_downld_dwords(self, offset, addr, 1); + + return err; +} + static u32 aq_fw2x_state2_get(struct aq_hw_s *self) { return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); -- cgit v1.2.3-59-g8ed1b From ea4b4d7fc1065165874c27b8add252e04d104137 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Thu, 7 Nov 2019 22:41:58 +0000 Subject: net: atlantic: loopback tests via private flags Here we add a number of ethtool private flags to allow enabling various loopbacks on HW. Thats useful for verification and bringup works. Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../device_drivers/aquantia/atlantic.txt | 25 ++++++++++ .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 55 +++++++++++++++++++++- .../net/ethernet/aquantia/atlantic/aq_ethtool.h | 1 + drivers/net/ethernet/aquantia/atlantic/aq_hw.h | 18 +++++++ drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 45 ++++++++++++++++++ drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 2 + .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 30 +++++++++++- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | 26 ++++++++++ .../ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | 11 +++++ .../aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | 54 +++++++++++++++++++++ .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 32 +++++++++++++ 11 files changed, 297 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/Documentation/networking/device_drivers/aquantia/atlantic.txt b/Documentation/networking/device_drivers/aquantia/atlantic.txt index d235cbaeccc6..cf3e88ca885e 100644 --- a/Documentation/networking/device_drivers/aquantia/atlantic.txt +++ b/Documentation/networking/device_drivers/aquantia/atlantic.txt @@ -325,6 +325,31 @@ Supported ethtool options Example: ethtool -N eth0 flow-type udp4 action 0 loc 32 + Private flags (testing) + --------------------------------- + + Atlantic driver supports private flags for hardware custom features: + + $ ethtool --show-priv-flags ethX + + Private flags for ethX: + DMASystemLoopback : off + PKTSystemLoopback : off + DMANetworkLoopback : off + PHYInternalLoopback: off + PHYExternalLoopback: off + + Example: + + $ ethtool --set-priv-flags ethX DMASystemLoopback on + + DMASystemLoopback: DMA Host loopback. + PKTSystemLoopback: Packet buffer host loopback. + DMANetworkLoopback: Network side loopback on DMA block. + PHYInternalLoopback: Internal loopback on Phy. + PHYExternalLoopback: External loopback on Phy (with loopback ethernet cable). + + Command Line Parameters ======================= The following command line parameters are available on atlantic driver: diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 2f877fb46615..963bf6e67573 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -92,6 +92,14 @@ static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = { "Queue[%d] InErrors", }; +static const char aq_ethtool_priv_flag_names[][ETH_GSTRING_LEN] = { + "DMASystemLoopback", + "PKTSystemLoopback", + "DMANetworkLoopback", + "PHYInternalLoopback", + "PHYExternalLoopback", +}; + static void aq_ethtool_stats(struct net_device *ndev, struct ethtool_stats *stats, u64 *data) { @@ -137,7 +145,8 @@ static void aq_ethtool_get_strings(struct net_device *ndev, struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); u8 *p = data; - if (stringset == ETH_SS_STATS) { + switch (stringset) { + case ETH_SS_STATS: memcpy(p, aq_ethtool_stat_names, sizeof(aq_ethtool_stat_names)); p = p + sizeof(aq_ethtool_stat_names); @@ -150,6 +159,11 @@ static void aq_ethtool_get_strings(struct net_device *ndev, p += ETH_GSTRING_LEN; } } + break; + case ETH_SS_PRIV_FLAGS: + memcpy(p, aq_ethtool_priv_flag_names, + sizeof(aq_ethtool_priv_flag_names)); + break; } } @@ -193,6 +207,9 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) ret = ARRAY_SIZE(aq_ethtool_stat_names) + cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names); break; + case ETH_SS_PRIV_FLAGS: + ret = ARRAY_SIZE(aq_ethtool_priv_flag_names); + break; default: ret = -EOPNOTSUPP; } @@ -650,6 +667,40 @@ static void aq_set_msg_level(struct net_device *ndev, u32 data) aq_nic->msg_enable = data; } +u32 aq_ethtool_get_priv_flags(struct net_device *ndev) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + + return aq_nic->aq_nic_cfg.priv_flags; +} + +int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags) +{ + struct aq_nic_s *aq_nic = netdev_priv(ndev); + struct aq_nic_cfg_s *cfg; + u32 priv_flags; + + cfg = aq_nic_get_cfg(aq_nic); + priv_flags = cfg->priv_flags; + + if (flags & ~AQ_PRIV_FLAGS_MASK) + return -EOPNOTSUPP; + + cfg->priv_flags = flags; + + if ((priv_flags ^ flags) & BIT(AQ_HW_LOOPBACK_DMA_NET)) { + if (netif_running(ndev)) { + dev_close(ndev); + + dev_open(ndev, NULL); + } + } else if ((priv_flags ^ flags) & AQ_HW_LOOPBACK_MASK) { + aq_nic_set_loopback(aq_nic); + } + + return 0; +} + const struct ethtool_ops aq_ethtool_ops = { .get_link = aq_ethtool_get_link, .get_regs_len = aq_ethtool_get_regs_len, @@ -676,6 +727,8 @@ const struct ethtool_ops aq_ethtool_ops = { .set_msglevel = aq_set_msg_level, .get_sset_count = aq_ethtool_get_sset_count, .get_ethtool_stats = aq_ethtool_stats, + .get_priv_flags = aq_ethtool_get_priv_flags, + .set_priv_flags = aq_ethtool_set_priv_flags, .get_link_ksettings = aq_ethtool_get_link_ksettings, .set_link_ksettings = aq_ethtool_set_link_ksettings, .get_coalesce = aq_ethtool_get_coalesce, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h index 632b5531db4a..6d5be5ebeb13 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.h @@ -12,5 +12,6 @@ #include "aq_common.h" extern const struct ethtool_ops aq_ethtool_ops; +#define AQ_PRIV_FLAGS_MASK (AQ_HW_LOOPBACK_MASK) #endif /* AQ_ETHTOOL_H */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 57396e516939..cc70c606b6ef 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h @@ -122,6 +122,20 @@ struct aq_stats_s { #define AQ_HW_LED_BLINK 0x2U #define AQ_HW_LED_DEFAULT 0x0U +enum aq_priv_flags { + AQ_HW_LOOPBACK_DMA_SYS, + AQ_HW_LOOPBACK_PKT_SYS, + AQ_HW_LOOPBACK_DMA_NET, + AQ_HW_LOOPBACK_PHYINT_SYS, + AQ_HW_LOOPBACK_PHYEXT_SYS, +}; + +#define AQ_HW_LOOPBACK_MASK (BIT(AQ_HW_LOOPBACK_DMA_SYS) |\ + BIT(AQ_HW_LOOPBACK_PKT_SYS) |\ + BIT(AQ_HW_LOOPBACK_DMA_NET) |\ + BIT(AQ_HW_LOOPBACK_PHYINT_SYS) |\ + BIT(AQ_HW_LOOPBACK_PHYEXT_SYS)) + struct aq_hw_s { atomic_t flags; u8 rbl_enabled:1; @@ -280,6 +294,8 @@ struct aq_hw_ops { u64 *timestamp); int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); + + int (*hw_set_loopback)(struct aq_hw_s *self, u32 mode, bool enable); }; struct aq_fw_ops { @@ -310,6 +326,8 @@ struct aq_fw_ops { int (*led_control)(struct aq_hw_s *self, u32 mode); + int (*set_phyloopback)(struct aq_hw_s *self, u32 mode, bool enable); + int (*set_power)(struct aq_hw_s *self, unsigned int power_state, u8 *mac); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 8f83e91f8146..5462b7efcf2f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -406,6 +406,8 @@ int aq_nic_start(struct aq_nic_s *self) INIT_WORK(&self->service_task, aq_nic_service_task); + aq_nic_set_loopback(self); + timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0); aq_nic_service_timer_cb(&self->service_timer); @@ -625,6 +627,11 @@ int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb) aq_ring_update_queue_state(ring); + if (self->aq_nic_cfg.priv_flags & BIT(AQ_HW_LOOPBACK_DMA_NET)) { + err = NETDEV_TX_BUSY; + goto err_exit; + } + /* Above status update may stop the queue. Check this. */ if (__netif_subqueue_stopped(self->ndev, ring->idx)) { err = NETDEV_TX_BUSY; @@ -973,6 +980,44 @@ u32 aq_nic_get_fw_version(struct aq_nic_s *self) return fw_version; } +int aq_nic_set_loopback(struct aq_nic_s *self) +{ + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; + + if (!self->aq_hw_ops->hw_set_loopback || + !self->aq_fw_ops->set_phyloopback) + return -ENOTSUPP; + + mutex_lock(&self->fwreq_mutex); + self->aq_hw_ops->hw_set_loopback(self->aq_hw, + AQ_HW_LOOPBACK_DMA_SYS, + !!(cfg->priv_flags & + BIT(AQ_HW_LOOPBACK_DMA_SYS))); + + self->aq_hw_ops->hw_set_loopback(self->aq_hw, + AQ_HW_LOOPBACK_PKT_SYS, + !!(cfg->priv_flags & + BIT(AQ_HW_LOOPBACK_PKT_SYS))); + + self->aq_hw_ops->hw_set_loopback(self->aq_hw, + AQ_HW_LOOPBACK_DMA_NET, + !!(cfg->priv_flags & + BIT(AQ_HW_LOOPBACK_DMA_NET))); + + self->aq_fw_ops->set_phyloopback(self->aq_hw, + AQ_HW_LOOPBACK_PHYINT_SYS, + !!(cfg->priv_flags & + BIT(AQ_HW_LOOPBACK_PHYINT_SYS))); + + self->aq_fw_ops->set_phyloopback(self->aq_hw, + AQ_HW_LOOPBACK_PHYEXT_SYS, + !!(cfg->priv_flags & + BIT(AQ_HW_LOOPBACK_PHYEXT_SYS))); + mutex_unlock(&self->fwreq_mutex); + + return 0; +} + int aq_nic_stop(struct aq_nic_s *self) { struct aq_vec_s *aq_vec = NULL; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 527273502d54..bb4957a31498 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -46,6 +46,7 @@ struct aq_nic_cfg_s { bool is_polling; bool is_rss; bool is_lro; + u32 priv_flags; u8 tcs; struct aq_rss_parameters aq_rss; u32 eee_speeds; @@ -158,6 +159,7 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self, const struct ethtool_link_ksettings *cmd); struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); u32 aq_nic_get_fw_version(struct aq_nic_s *self); +int aq_nic_set_loopback(struct aq_nic_s *self); int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); void aq_nic_shutdown(struct aq_nic_s *self); u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index c7297ca03624..1165689af37d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -1427,6 +1427,30 @@ static int hw_atl_b0_hw_vlan_ctrl(struct aq_hw_s *self, bool enable) return aq_hw_err_from_flags(self); } +static int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable) +{ + switch (mode) { + case AQ_HW_LOOPBACK_DMA_SYS: + hw_atl_tpb_tx_dma_sys_lbk_en_set(self, enable); + hw_atl_rpb_dma_sys_lbk_set(self, enable); + break; + case AQ_HW_LOOPBACK_PKT_SYS: + hw_atl_tpo_tx_pkt_sys_lbk_en_set(self, enable); + hw_atl_rpf_tpo_to_rpf_sys_lbk_set(self, enable); + break; + case AQ_HW_LOOPBACK_DMA_NET: + hw_atl_rpf_vlan_prom_mode_en_set(self, enable); + hw_atl_rpfl2promiscuous_mode_en_set(self, enable); + hw_atl_tpb_tx_tx_clk_gate_en_set(self, !enable); + hw_atl_tpb_tx_dma_net_lbk_en_set(self, enable); + hw_atl_rpb_dma_net_lbk_set(self, enable); + break; + default: + return -EINVAL; + } + return 0; +} + const struct aq_hw_ops hw_atl_ops_b0 = { .hw_set_mac_address = hw_atl_b0_hw_mac_addr_set, .hw_init = hw_atl_b0_hw_init, @@ -1481,5 +1505,9 @@ const struct aq_hw_ops hw_atl_ops_b0 = { .rx_extract_ts = hw_atl_b0_rx_extract_ts, .extract_hwts = hw_atl_b0_extract_hwts, .hw_set_offload = hw_atl_b0_hw_offload_set, - .hw_set_fc = hw_atl_b0_set_fc, + .hw_get_hw_stats = hw_atl_utils_get_hw_stats, + .hw_get_fw_version = hw_atl_utils_get_fw_version, + .hw_set_offload = hw_atl_b0_hw_offload_set, + .hw_set_loopback = hw_atl_b0_set_loopback, + .hw_set_fc = hw_atl_b0_set_fc, }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index 6cadc9054544..d1f68fc16291 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c @@ -563,6 +563,13 @@ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk) HW_ATL_RPB_DMA_SYS_LBK_SHIFT, dma_sys_lbk); } +void hw_atl_rpb_dma_net_lbk_set(struct aq_hw_s *aq_hw, u32 dma_net_lbk) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_RPB_DMA_NET_LBK_ADR, + HW_ATL_RPB_DMA_NET_LBK_MSK, + HW_ATL_RPB_DMA_NET_LBK_SHIFT, dma_net_lbk); +} + void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, u32 rx_traf_class_mode) { @@ -1341,7 +1348,26 @@ void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_ tx_dma_sys_lbk_en); } +void hw_atl_tpb_tx_dma_net_lbk_en_set(struct aq_hw_s *aq_hw, + u32 tx_dma_net_lbk_en) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_DMA_NET_LBK_ADR, + HW_ATL_TPB_DMA_NET_LBK_MSK, + HW_ATL_TPB_DMA_NET_LBK_SHIFT, + tx_dma_net_lbk_en); +} + +void hw_atl_tpb_tx_tx_clk_gate_en_set(struct aq_hw_s *aq_hw, + u32 tx_clk_gate_en) +{ + aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_TX_CLK_GATE_EN_ADR, + HW_ATL_TPB_TX_CLK_GATE_EN_MSK, + HW_ATL_TPB_TX_CLK_GATE_EN_SHIFT, + tx_clk_gate_en); +} + void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, + u32 tx_pkt_buff_size_per_tc, u32 buffer) { aq_hw_write_reg_bit(aq_hw, HW_ATL_TPB_TXBBUF_SIZE_ADR(buffer), diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 5750b0c9cae7..62992b23c0e8 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h @@ -288,6 +288,9 @@ void hw_atl_reg_glb_cpu_scratch_scp_set(struct aq_hw_s *aq_hw, /* set dma system loopback */ void hw_atl_rpb_dma_sys_lbk_set(struct aq_hw_s *aq_hw, u32 dma_sys_lbk); +/* set dma network loopback */ +void hw_atl_rpb_dma_net_lbk_set(struct aq_hw_s *aq_hw, u32 dma_net_lbk); + /* set rx traffic class mode */ void hw_atl_rpb_rpf_rx_traf_class_mode_set(struct aq_hw_s *aq_hw, u32 rx_traf_class_mode); @@ -629,6 +632,14 @@ void hw_atl_tpb_tx_buff_lo_threshold_per_tc_set(struct aq_hw_s *aq_hw, /* set tx dma system loopback enable */ void hw_atl_tpb_tx_dma_sys_lbk_en_set(struct aq_hw_s *aq_hw, u32 tx_dma_sys_lbk_en); +/* set tx dma network loopback enable */ +void hw_atl_tpb_tx_dma_net_lbk_en_set(struct aq_hw_s *aq_hw, + u32 tx_dma_net_lbk_en); + +/* set tx clock gating enable */ +void hw_atl_tpb_tx_tx_clk_gate_en_set(struct aq_hw_s *aq_hw, + u32 tx_clk_gate_en); + /* set tx packet buffer size (per tc) */ void hw_atl_tpb_tx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, u32 tx_pkt_buff_size_per_tc, diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index ec3bcdcefc4d..18de2f7b8959 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h @@ -554,6 +554,24 @@ /* default value of bitfield dma_sys_loopback */ #define HW_ATL_RPB_DMA_SYS_LBK_DEFAULT 0x0 +/* rx dma_net_loopback bitfield definitions + * preprocessor definitions for the bitfield "dma_net_loopback". + * port="pif_rpb_dma_net_lbk_i" + */ + +/* register address for bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_ADR 0x00005000 +/* bitmask for bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_MSK 0x00000010 +/* inverted bitmask for bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_MSKN 0xffffffef +/* lower bit position of bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_SHIFT 4 +/* width of bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_WIDTH 1 +/* default value of bitfield dma_net_loopback */ +#define HW_ATL_RPB_DMA_NET_LBK_DEFAULT 0x0 + /* rx rx_tc_mode bitfield definitions * preprocessor definitions for the bitfield "rx_tc_mode". * port="pif_rpb_rx_tc_mode_i,pif_rpf_rx_tc_mode_i" @@ -2107,6 +2125,24 @@ /* default value of bitfield dma_sys_loopback */ #define HW_ATL_TPB_DMA_SYS_LBK_DEFAULT 0x0 +/* tx dma_net_loopback bitfield definitions + * preprocessor definitions for the bitfield "dma_net_loopback". + * port="pif_tpb_dma_net_lbk_i" + */ + +/* register address for bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_ADR 0x00007000 +/* bitmask for bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_MSK 0x00000010 +/* inverted bitmask for bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_MSKN 0xffffffef +/* lower bit position of bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_SHIFT 4 +/* width of bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_WIDTH 1 +/* default value of bitfield dma_net_loopback */ +#define HW_ATL_TPB_DMA_NET_LBK_DEFAULT 0x0 + /* tx tx{b}_buf_size[7:0] bitfield definitions * preprocessor definitions for the bitfield "tx{b}_buf_size[7:0]". * parameter: buffer {b} | stride size 0x10 | range [0, 7] @@ -2144,6 +2180,24 @@ /* default value of bitfield tx_scp_ins_en */ #define HW_ATL_TPB_TX_SCP_INS_EN_DEFAULT 0x0 +/* tx tx_clk_gate_en bitfield definitions + * preprocessor definitions for the bitfield "tx_clk_gate_en". + * port="pif_tpb_clk_gate_en_i" + */ + +/* register address for bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_ADR 0x00007900 +/* bitmask for bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_MSK 0x00000010 +/* inverted bitmask for bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_MSKN 0xffffffef +/* lower bit position of bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_SHIFT 4 +/* width of bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_WIDTH 1 +/* default value of bitfield tx_clk_gate_en */ +#define HW_ATL_TPB_TX_CLK_GATE_EN_DEFAULT 0x1 + /* tx ipv4_chk_en bitfield definitions * preprocessor definitions for the bitfield "ipv4_chk_en". * port="pif_tpo_ipv4_chk_en_i" diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 3dbce03c5a94..feef2b0177b2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -42,6 +42,9 @@ #define HW_ATL_FW2X_CTRL_PAUSE BIT(CTRL_PAUSE) #define HW_ATL_FW2X_CTRL_TEMPERATURE BIT(CTRL_TEMPERATURE) #define HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE BIT(CTRL_ASYMMETRIC_PAUSE) +#define HW_ATL_FW2X_CTRL_INT_LOOPBACK BIT(CTRL_INT_LOOPBACK) +#define HW_ATL_FW2X_CTRL_EXT_LOOPBACK BIT(CTRL_EXT_LOOPBACK) +#define HW_ATL_FW2X_CTRL_DOWNSHIFT BIT(CTRL_DOWNSHIFT) #define HW_ATL_FW2X_CTRL_FORCE_RECONNECT BIT(CTRL_FORCE_RECONNECT) #define HW_ATL_FW2X_CAP_EEE_1G_MASK BIT(CAPS_HI_1000BASET_FD_EEE) @@ -53,6 +56,7 @@ #define HAL_ATLANTIC_UTILS_FW2X_MSG_WOL 0x0E #define HW_ATL_FW_VER_LED 0x03010026U +#define HW_ATL_FW_VER_MEDIA_CONTROL 0x0301005aU struct __packed fw2x_msg_wol_pattern { u8 mask[16]; @@ -539,6 +543,33 @@ static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode) return 0; } +static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable) +{ + u32 mpi_opts; + + switch (mode) { + case AQ_HW_LOOPBACK_PHYINT_SYS: + mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + if (enable) + mpi_opts |= HW_ATL_FW2X_CTRL_INT_LOOPBACK; + else + mpi_opts &= ~HW_ATL_FW2X_CTRL_INT_LOOPBACK; + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + break; + case AQ_HW_LOOPBACK_PHYEXT_SYS: + mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); + if (enable) + mpi_opts |= HW_ATL_FW2X_CTRL_EXT_LOOPBACK; + else + mpi_opts &= ~HW_ATL_FW2X_CTRL_EXT_LOOPBACK; + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); + break; + default: + return -EINVAL; + } + return 0; +} + static u32 aq_fw2x_mbox_get(struct aq_hw_s *self) { return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_MBOX_ADDR); @@ -586,4 +617,5 @@ const struct aq_fw_ops aq_fw_2x_ops = { .send_fw_request = aq_fw2x_send_fw_request, .enable_ptp = aq_fw3x_enable_ptp, .led_control = aq_fw2x_led_control, + .set_phyloopback = aq_fw2x_set_phyloopback, }; -- cgit v1.2.3-59-g8ed1b From 7b0c342f1f67543f1f16099238d279584d6834e0 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:42:00 +0000 Subject: net: atlantic: code style cleanup Thats a pure checkpatck walkthrough the code with no functional changes. Reverse christmas tree, spacing, etc. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 108 ++++++++++++++------- .../net/ethernet/aquantia/atlantic/aq_hw_utils.c | 1 + drivers/net/ethernet/aquantia/atlantic/aq_main.c | 11 ++- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 39 +++++--- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 4 +- .../net/ethernet/aquantia/atlantic/aq_pci_func.c | 8 +- drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 6 +- drivers/net/ethernet/aquantia/atlantic/aq_vec.c | 8 +- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 39 +++++--- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 69 ++++++++----- .../aquantia/atlantic/hw_atl/hw_atl_utils.c | 52 ++++++---- .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 34 ++++--- 12 files changed, 240 insertions(+), 139 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 963bf6e67573..8286c77d43a5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -18,7 +18,9 @@ static void aq_ethtool_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *p) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - u32 regs_count = aq_nic_get_regs_count(aq_nic); + u32 regs_count; + + regs_count = aq_nic_get_regs_count(aq_nic); memset(p, 0, regs_count * sizeof(u32)); aq_nic_get_regs(aq_nic, regs, p); @@ -27,7 +29,9 @@ static void aq_ethtool_get_regs(struct net_device *ndev, static int aq_ethtool_get_regs_len(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - u32 regs_count = aq_nic_get_regs_count(aq_nic); + u32 regs_count; + + regs_count = aq_nic_get_regs_count(aq_nic); return regs_count * sizeof(u32); } @@ -104,7 +108,9 @@ static void aq_ethtool_stats(struct net_device *ndev, struct ethtool_stats *stats, u64 *data) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) + ARRAY_SIZE(aq_ethtool_queue_stat_names) * @@ -115,11 +121,15 @@ static void aq_ethtool_stats(struct net_device *ndev, static void aq_ethtool_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *drvinfo) { - struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); - u32 firmware_version = aq_nic_get_fw_version(aq_nic); - u32 regs_count = aq_nic_get_regs_count(aq_nic); + struct aq_nic_s *aq_nic = netdev_priv(ndev); + struct aq_nic_cfg_s *cfg; + u32 firmware_version; + u32 regs_count; + + cfg = aq_nic_get_cfg(aq_nic); + firmware_version = aq_nic_get_fw_version(aq_nic); + regs_count = aq_nic_get_regs_count(aq_nic); strlcat(drvinfo->driver, AQ_CFG_DRV_NAME, sizeof(drvinfo->driver)); strlcat(drvinfo->version, AQ_CFG_DRV_VERSION, sizeof(drvinfo->version)); @@ -140,10 +150,12 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev, static void aq_ethtool_get_strings(struct net_device *ndev, u32 stringset, u8 *data) { - int i, si; struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; u8 *p = data; + int i, si; + + cfg = aq_nic_get_cfg(aq_nic); switch (stringset) { case ETH_SS_STATS: @@ -198,9 +210,11 @@ static int aq_ethtool_set_phys_id(struct net_device *ndev, static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) { - int ret = 0; struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + int ret = 0; + + cfg = aq_nic_get_cfg(aq_nic); switch (stringset) { case ETH_SS_STATS: @@ -213,6 +227,7 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) default: ret = -EOPNOTSUPP; } + return ret; } @@ -224,7 +239,9 @@ static u32 aq_ethtool_get_rss_indir_size(struct net_device *ndev) static u32 aq_ethtool_get_rss_key_size(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); return sizeof(cfg->aq_rss.hash_secret_key); } @@ -233,9 +250,11 @@ static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key, u8 *hfunc) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; unsigned int i = 0U; + cfg = aq_nic_get_cfg(aq_nic); + if (hfunc) *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */ if (indir) { @@ -245,6 +264,7 @@ static int aq_ethtool_get_rss(struct net_device *ndev, u32 *indir, u8 *key, if (key) memcpy(key, cfg->aq_rss.hash_secret_key, sizeof(cfg->aq_rss.hash_secret_key)); + return 0; } @@ -288,9 +308,11 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev, u32 *rule_locs) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; int err = 0; + cfg = aq_nic_get_cfg(aq_nic); + switch (cmd->cmd) { case ETHTOOL_GRXRINGS: cmd->data = cfg->vecs; @@ -315,8 +337,8 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev, static int aq_ethtool_set_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *cmd) { - int err = 0; struct aq_nic_s *aq_nic = netdev_priv(ndev); + int err = 0; switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS: @@ -337,7 +359,9 @@ static int aq_ethtool_get_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON || cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) { @@ -351,6 +375,7 @@ static int aq_ethtool_get_coalesce(struct net_device *ndev, coal->rx_max_coalesced_frames = 1; coal->tx_max_coalesced_frames = 1; } + return 0; } @@ -358,7 +383,9 @@ static int aq_ethtool_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *coal) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); /* This is not yet supported */ @@ -400,7 +427,9 @@ static void aq_ethtool_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); wol->supported = AQ_NIC_WOL_MODES; wol->wolopts = cfg->wol; @@ -411,9 +440,11 @@ static int aq_ethtool_set_wol(struct net_device *ndev, { struct pci_dev *pdev = to_pci_dev(ndev->dev.parent); struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; int err = 0; + cfg = aq_nic_get_cfg(aq_nic); + if (wol->wolopts & ~AQ_NIC_WOL_MODES) return -EOPNOTSUPP; @@ -599,23 +630,28 @@ static void aq_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *ring) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); + struct aq_nic_cfg_s *cfg; + + cfg = aq_nic_get_cfg(aq_nic); - ring->rx_pending = aq_nic_cfg->rxds; - ring->tx_pending = aq_nic_cfg->txds; + ring->rx_pending = cfg->rxds; + ring->tx_pending = cfg->txds; - ring->rx_max_pending = aq_nic_cfg->aq_hw_caps->rxds_max; - ring->tx_max_pending = aq_nic_cfg->aq_hw_caps->txds_max; + ring->rx_max_pending = cfg->aq_hw_caps->rxds_max; + ring->tx_max_pending = cfg->aq_hw_caps->txds_max; } static int aq_set_ringparam(struct net_device *ndev, struct ethtool_ringparam *ring) { - int err = 0; - bool ndev_running = false; struct aq_nic_s *aq_nic = netdev_priv(ndev); - struct aq_nic_cfg_s *aq_nic_cfg = aq_nic_get_cfg(aq_nic); - const struct aq_hw_caps_s *hw_caps = aq_nic_cfg->aq_hw_caps; + const struct aq_hw_caps_s *hw_caps; + bool ndev_running = false; + struct aq_nic_cfg_s *cfg; + int err = 0; + + cfg = aq_nic_get_cfg(aq_nic); + hw_caps = cfg->aq_hw_caps; if (ring->rx_mini_pending || ring->rx_jumbo_pending) { err = -EOPNOTSUPP; @@ -629,18 +665,18 @@ static int aq_set_ringparam(struct net_device *ndev, aq_nic_free_vectors(aq_nic); - aq_nic_cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min); - aq_nic_cfg->rxds = min(aq_nic_cfg->rxds, hw_caps->rxds_max); - aq_nic_cfg->rxds = ALIGN(aq_nic_cfg->rxds, AQ_HW_RXD_MULTIPLE); + cfg->rxds = max(ring->rx_pending, hw_caps->rxds_min); + cfg->rxds = min(cfg->rxds, hw_caps->rxds_max); + cfg->rxds = ALIGN(cfg->rxds, AQ_HW_RXD_MULTIPLE); - aq_nic_cfg->txds = max(ring->tx_pending, hw_caps->txds_min); - aq_nic_cfg->txds = min(aq_nic_cfg->txds, hw_caps->txds_max); - aq_nic_cfg->txds = ALIGN(aq_nic_cfg->txds, AQ_HW_TXD_MULTIPLE); + cfg->txds = max(ring->tx_pending, hw_caps->txds_min); + cfg->txds = min(cfg->txds, hw_caps->txds_max); + cfg->txds = ALIGN(cfg->txds, AQ_HW_TXD_MULTIPLE); - for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < aq_nic_cfg->vecs; + for (aq_nic->aq_vecs = 0; aq_nic->aq_vecs < cfg->vecs; aq_nic->aq_vecs++) { aq_nic->aq_vec[aq_nic->aq_vecs] = - aq_vec_alloc(aq_nic, aq_nic->aq_vecs, aq_nic_cfg); + aq_vec_alloc(aq_nic, aq_nic->aq_vecs, cfg); if (unlikely(!aq_nic->aq_vec[aq_nic->aq_vecs])) { err = -ENOMEM; goto err_exit; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c index 9c7a226d81b6..7dbf49adcea6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw_utils.c @@ -59,6 +59,7 @@ u64 aq_hw_read_reg64(struct aq_hw_s *hw, u32 reg) u64 value = aq_hw_read_reg(hw, reg); value |= (u64)aq_hw_read_reg(hw, reg + 4) << 32; + return value; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index 2c1096561614..538f460a3da7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c @@ -53,8 +53,8 @@ struct net_device *aq_ndev_alloc(void) static int aq_ndev_open(struct net_device *ndev) { - int err = 0; struct aq_nic_s *aq_nic = netdev_priv(ndev); + int err = 0; err = aq_nic_init(aq_nic); if (err < 0) @@ -75,13 +75,14 @@ static int aq_ndev_open(struct net_device *ndev) err_exit: if (err < 0) aq_nic_deinit(aq_nic, true); + return err; } static int aq_ndev_close(struct net_device *ndev) { - int err = 0; struct aq_nic_s *aq_nic = netdev_priv(ndev); + int err = 0; err = aq_nic_stop(aq_nic); if (err < 0) @@ -120,7 +121,9 @@ static int aq_ndev_start_xmit(struct sk_buff *skb, struct net_device *ndev) static int aq_ndev_change_mtu(struct net_device *ndev, int new_mtu) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - int err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN); + int err; + + err = aq_nic_set_mtu(aq_nic, new_mtu + ETH_HLEN); if (err < 0) goto err_exit; @@ -133,8 +136,8 @@ err_exit: static int aq_ndev_set_features(struct net_device *ndev, netdev_features_t features) { - bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX); bool is_vlan_tx_insert = !!(features & NETIF_F_HW_VLAN_CTAG_TX); + bool is_vlan_rx_strip = !!(features & NETIF_F_HW_VLAN_CTAG_RX); struct aq_nic_s *aq_nic = netdev_priv(ndev); bool need_ndev_restart = false; struct aq_nic_cfg_s *aq_cfg; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 5462b7efcf2f..d3739f21b18e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -41,10 +41,6 @@ static void aq_nic_update_ndev_stats(struct aq_nic_s *self); static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues) { - struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; - struct aq_rss_parameters *rss_params = &cfg->aq_rss; - int i = 0; - static u8 rss_key[AQ_CFG_RSS_HASHKEY_SIZE] = { 0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d, 0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18, @@ -52,6 +48,11 @@ static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues) 0x19, 0x13, 0x4b, 0xa9, 0xd0, 0x3e, 0xfe, 0x70, 0x25, 0x03, 0xab, 0x50, 0x6a, 0x8b, 0x82, 0x0c }; + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; + struct aq_rss_parameters *rss_params; + int i = 0; + + rss_params = &cfg->aq_rss; rss_params->hash_secret_key_size = sizeof(rss_key); memcpy(rss_params->hash_secret_key, rss_key, sizeof(rss_key)); @@ -180,6 +181,7 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) netif_tx_disable(self->ndev); aq_utils_obj_set(&self->flags, AQ_NIC_LINK_DOWN); } + return 0; } @@ -194,6 +196,7 @@ static irqreturn_t aq_linkstate_threaded_isr(int irq, void *private) self->aq_hw_ops->hw_irq_enable(self->aq_hw, BIT(self->aq_nic_cfg.link_irq_vec)); + return IRQ_HANDLED; } @@ -224,7 +227,8 @@ static void aq_nic_service_timer_cb(struct timer_list *t) { struct aq_nic_s *self = from_timer(self, t, service_timer); - mod_timer(&self->service_timer, jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL); + mod_timer(&self->service_timer, + jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL); aq_ndev_schedule_work(&self->service_task); } @@ -326,8 +330,8 @@ struct net_device *aq_nic_get_ndev(struct aq_nic_s *self) int aq_nic_init(struct aq_nic_s *self) { struct aq_vec_s *aq_vec = NULL; - int err = 0; unsigned int i = 0U; + int err = 0; self->power_state = AQ_HW_POWER_STATE_D0; mutex_lock(&self->fwreq_mutex); @@ -371,8 +375,8 @@ err_exit: int aq_nic_start(struct aq_nic_s *self) { struct aq_vec_s *aq_vec = NULL; - int err = 0; unsigned int i = 0U; + int err = 0; err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, self->mc_list.ar, @@ -464,14 +468,16 @@ err_exit: unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, struct aq_ring_s *ring) { - unsigned int ret = 0U; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; - unsigned int frag_count = 0U; - unsigned int dx = ring->sw_tail; struct aq_ring_buff_s *first = NULL; - struct aq_ring_buff_s *dx_buff = &ring->buff_ring[dx]; + struct aq_ring_buff_s *dx_buff; bool need_context_tag = false; + unsigned int frag_count = 0U; + unsigned int ret = 0U; + unsigned int dx; + dx = ring->sw_tail; + dx_buff = &ring->buff_ring[dx]; dx_buff->flags = 0U; if (unlikely(skb_is_gso(skb))) { @@ -610,11 +616,11 @@ exit: int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb) { + unsigned int vec = skb->queue_mapping % self->aq_nic_cfg.vecs; struct aq_ring_s *ring = NULL; unsigned int frags = 0U; - unsigned int vec = skb->queue_mapping % self->aq_nic_cfg.vecs; - unsigned int tc = 0U; int err = NETDEV_TX_OK; + unsigned int tc = 0U; frags = skb_shinfo(skb)->nr_frags + 1; @@ -712,6 +718,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) if (err < 0) return err; } + return aq_nic_set_packet_filter(self, packet_filter); } @@ -756,10 +763,10 @@ int aq_nic_get_regs_count(struct aq_nic_s *self) void aq_nic_get_stats(struct aq_nic_s *self, u64 *data) { - unsigned int i = 0U; - unsigned int count = 0U; struct aq_vec_s *aq_vec = NULL; struct aq_stats_s *stats; + unsigned int count = 0U; + unsigned int i = 0U; if (self->aq_fw_ops->update_stats) { mutex_lock(&self->fwreq_mutex); @@ -809,8 +816,8 @@ err_exit:; static void aq_nic_update_ndev_stats(struct aq_nic_s *self) { - struct net_device *ndev = self->ndev; struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw); + struct net_device *ndev = self->ndev; ndev->stats.rx_packets = stats->dma_pkt_rc; ndev->stats.rx_bytes = stats->dma_oct_rc; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index bb4957a31498..98c3182bf1d0 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -72,8 +72,8 @@ struct aq_hw_rx_fl2 { }; struct aq_hw_rx_fl3l4 { - u8 active_ipv4; - u8 active_ipv6:2; + u8 active_ipv4; + u8 active_ipv6:2; u8 is_ipv6; u8 reserved_count; }; diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 3169951fe6ab..a161026cfbfd 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -185,6 +185,7 @@ unsigned int aq_pci_func_get_irq_type(struct aq_nic_s *self) return AQ_HW_IRQ_MSIX; if (self->pdev->msi_enabled) return AQ_HW_IRQ_MSI; + return AQ_HW_IRQ_LEGACY; } @@ -196,12 +197,12 @@ static void aq_pci_free_irq_vectors(struct aq_nic_s *self) static int aq_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { - struct aq_nic_s *self; - int err; struct net_device *ndev; resource_size_t mmio_pa; - u32 bar; + struct aq_nic_s *self; u32 numvecs; + u32 bar; + int err; err = pci_enable_device(pdev); if (err) @@ -311,6 +312,7 @@ err_ndev: pci_release_regions(pdev); err_pci_func: pci_disable_device(pdev); + return err; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index f756cc0bbdf0..951d86f8b66e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c @@ -30,8 +30,8 @@ static int aq_get_rxpage(struct aq_rxpage *rxpage, unsigned int order, struct device *dev) { struct page *page; - dma_addr_t daddr; int ret = -ENOMEM; + dma_addr_t daddr; page = dev_alloc_pages(order); if (unlikely(!page)) @@ -118,6 +118,7 @@ err_exit: aq_ring_free(self); self = NULL; } + return self; } @@ -144,6 +145,7 @@ err_exit: aq_ring_free(self); self = NULL; } + return self; } @@ -175,6 +177,7 @@ err_exit: aq_ring_free(self); self = NULL; } + return self; } @@ -207,6 +210,7 @@ int aq_ring_init(struct aq_ring_s *self) self->hw_head = 0; self->sw_head = 0; self->sw_tail = 0; + return 0; } diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index a95c263a45aa..6e19e27b6200 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -103,8 +103,8 @@ err_exit: struct aq_vec_s *aq_vec_alloc(struct aq_nic_s *aq_nic, unsigned int idx, struct aq_nic_cfg_s *aq_nic_cfg) { - struct aq_vec_s *self = NULL; struct aq_ring_s *ring = NULL; + struct aq_vec_s *self = NULL; unsigned int i = 0U; int err = 0; @@ -159,6 +159,7 @@ err_exit: aq_vec_free(self); self = NULL; } + return self; } @@ -263,6 +264,7 @@ void aq_vec_deinit(struct aq_vec_s *self) aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]); aq_ring_rx_deinit(&ring[AQ_VEC_RX_ID]); } + err_exit:; } @@ -305,8 +307,8 @@ err_exit: irqreturn_t aq_vec_isr_legacy(int irq, void *private) { struct aq_vec_s *self = private; + irqreturn_t err = 0; u64 irq_mask = 0U; - int err; if (!self) return IRQ_NONE; @@ -361,9 +363,9 @@ void aq_vec_add_stats(struct aq_vec_s *self, int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count) { - unsigned int count = 0U; struct aq_ring_stats_rx_s stats_rx; struct aq_ring_stats_tx_s stats_tx; + unsigned int count = 0U; memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s)); memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 359a4d387185..d2fb399f179f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -119,10 +119,10 @@ err_exit: static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self) { - u32 tc = 0U; - u32 buff_size = 0U; - unsigned int i_priority = 0U; bool is_rx_flow_control = false; + unsigned int i_priority = 0U; + u32 buff_size = 0U; + u32 tc = 0U; /* TPS Descriptor rate init */ hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U); @@ -180,9 +180,9 @@ static int hw_atl_a0_hw_rss_hash_set(struct aq_hw_s *self, struct aq_rss_parameters *rss_params) { struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; - int err = 0; - unsigned int i = 0U; unsigned int addr = 0U; + unsigned int i = 0U; + int err = 0; u32 val; for (i = 10, addr = 0U; i--; ++addr) { @@ -207,12 +207,12 @@ err_exit: static int hw_atl_a0_hw_rss_set(struct aq_hw_s *self, struct aq_rss_parameters *rss_params) { - u8 *indirection_table = rss_params->indirection_table; - u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); - int err = 0; + u8 *indirection_table = rss_params->indirection_table; u16 bitary[1 + (HW_ATL_A0_RSS_REDIRECTION_MAX * HW_ATL_A0_RSS_REDIRECTION_BITS / 16U)]; + int err = 0; + u32 i = 0U; u32 val; memset(bitary, 0, sizeof(bitary)); @@ -321,9 +321,9 @@ static int hw_atl_a0_hw_init_rx_path(struct aq_hw_s *self) static int hw_atl_a0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr) { - int err = 0; unsigned int h = 0U; unsigned int l = 0U; + int err = 0; if (!mac_addr) { err = -EINVAL; @@ -352,10 +352,9 @@ static int hw_atl_a0_hw_init(struct aq_hw_s *self, u8 *mac_addr) [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; - + struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg; int err = 0; - struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg; hw_atl_a0_hw_init_tx_path(self); hw_atl_a0_hw_init_rx_path(self); @@ -404,6 +403,7 @@ static int hw_atl_a0_hw_ring_tx_start(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_tdm_tx_desc_en_set(self, 1, ring->idx); + return aq_hw_err_from_flags(self); } @@ -411,6 +411,7 @@ static int hw_atl_a0_hw_ring_rx_start(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_rdm_rx_desc_en_set(self, 1, ring->idx); + return aq_hw_err_from_flags(self); } @@ -418,6 +419,7 @@ static int hw_atl_a0_hw_start(struct aq_hw_s *self) { hw_atl_tpb_tx_buff_en_set(self, 1); hw_atl_rpb_rx_buff_en_set(self, 1); + return aq_hw_err_from_flags(self); } @@ -425,6 +427,7 @@ static int hw_atl_a0_hw_tx_ring_tail_update(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_reg_tx_dma_desc_tail_ptr_set(self, ring->sw_tail, ring->idx); + return 0; } @@ -435,8 +438,8 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self, struct aq_ring_buff_s *buff = NULL; struct hw_atl_txd_s *txd = NULL; unsigned int buff_pa_len = 0U; - unsigned int pkt_len = 0U; unsigned int frag_count = 0U; + unsigned int pkt_len = 0U; bool is_gso = false; buff = &ring->buff_ring[ring->sw_tail]; @@ -500,6 +503,7 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self, } hw_atl_a0_hw_tx_ring_tail_update(self, ring); + return aq_hw_err_from_flags(self); } @@ -507,8 +511,8 @@ static int hw_atl_a0_hw_ring_rx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring, struct aq_ring_param_s *aq_ring_param) { - u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa; u32 dma_desc_addr_msw = (u32)(((u64)aq_ring->dx_ring_pa) >> 32); + u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa; hw_atl_rdm_rx_desc_en_set(self, false, aq_ring->idx); @@ -549,8 +553,8 @@ static int hw_atl_a0_hw_ring_tx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring, struct aq_ring_param_s *aq_ring_param) { - u32 dma_desc_lsw_addr = (u32)aq_ring->dx_ring_pa; u32 dma_desc_msw_addr = (u32)(((u64)aq_ring->dx_ring_pa) >> 32); + u32 dma_desc_lsw_addr = (u32)aq_ring->dx_ring_pa; hw_atl_reg_tx_dma_desc_base_addresslswset(self, dma_desc_lsw_addr, aq_ring->idx); @@ -599,8 +603,8 @@ static int hw_atl_a0_hw_ring_rx_fill(struct aq_hw_s *self, static int hw_atl_a0_hw_ring_tx_head_update(struct aq_hw_s *self, struct aq_ring_s *ring) { - int err = 0; unsigned int hw_head = hw_atl_tdm_tx_desc_head_ptr_get(self, ring->idx); + int err = 0; if (aq_utils_obj_test(&self->flags, AQ_HW_FLAG_ERR_UNPLUG)) { err = -ENXIO; @@ -720,6 +724,7 @@ static int hw_atl_a0_hw_irq_enable(struct aq_hw_s *self, u64 mask) { hw_atl_itr_irq_msk_setlsw_set(self, LODWORD(mask) | (1U << HW_ATL_A0_ERR_INT)); + return aq_hw_err_from_flags(self); } @@ -737,6 +742,7 @@ static int hw_atl_a0_hw_irq_disable(struct aq_hw_s *self, u64 mask) static int hw_atl_a0_hw_irq_read(struct aq_hw_s *self, u64 *mask) { *mask = hw_atl_itr_irq_statuslsw_get(self); + return aq_hw_err_from_flags(self); } @@ -859,6 +865,7 @@ static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self) static int hw_atl_a0_hw_stop(struct aq_hw_s *self) { hw_atl_a0_hw_irq_disable(self, HW_ATL_A0_INT_MASK); + return aq_hw_err_from_flags(self); } @@ -866,6 +873,7 @@ static int hw_atl_a0_hw_ring_tx_stop(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_tdm_tx_desc_en_set(self, 0U, ring->idx); + return aq_hw_err_from_flags(self); } @@ -873,6 +881,7 @@ static int hw_atl_a0_hw_ring_rx_stop(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_rdm_rx_desc_en_set(self, 0U, ring->idx); + return aq_hw_err_from_flags(self); } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 1165689af37d..8686462b32f9 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -107,14 +107,15 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self) static int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc) { hw_atl_rpb_rx_xoff_en_per_tc_set(self, !!(fc & AQ_NIC_FC_RX), tc); + return 0; } static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) { - u32 tc = 0U; - u32 buff_size = 0U; unsigned int i_priority = 0U; + u32 buff_size = 0U; + u32 tc = 0U; /* TPS Descriptor rate init */ hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U); @@ -188,9 +189,9 @@ static int hw_atl_b0_hw_rss_hash_set(struct aq_hw_s *self, struct aq_rss_parameters *rss_params) { struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; - int err = 0; - unsigned int i = 0U; unsigned int addr = 0U; + unsigned int i = 0U; + int err = 0; u32 val; for (i = 10, addr = 0U; i--; ++addr) { @@ -215,12 +216,12 @@ err_exit: static int hw_atl_b0_hw_rss_set(struct aq_hw_s *self, struct aq_rss_parameters *rss_params) { - u8 *indirection_table = rss_params->indirection_table; - u32 i = 0U; u32 num_rss_queues = max(1U, self->aq_nic_cfg->num_rss_queues); - int err = 0; + u8 *indirection_table = rss_params->indirection_table; u16 bitary[1 + (HW_ATL_B0_RSS_REDIRECTION_MAX * HW_ATL_B0_RSS_REDIRECTION_BITS / 16U)]; + int err = 0; + u32 i = 0U; u32 val; memset(bitary, 0, sizeof(bitary)); @@ -304,6 +305,7 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self, hw_atl_itr_rsc_delay_set(self, 1U); } + return aq_hw_err_from_flags(self); } @@ -382,9 +384,9 @@ static int hw_atl_b0_hw_init_rx_path(struct aq_hw_s *self) static int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr) { - int err = 0; unsigned int h = 0U; unsigned int l = 0U; + int err = 0; if (!mac_addr) { err = -EINVAL; @@ -413,11 +415,10 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr) [AQ_HW_IRQ_MSI] = { 0x20000021U, 0x20000025U }, [AQ_HW_IRQ_MSIX] = { 0x20000022U, 0x20000026U }, }; - + struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg; int err = 0; u32 val; - struct aq_nic_cfg_s *aq_nic_cfg = self->aq_nic_cfg; hw_atl_b0_hw_init_tx_path(self); hw_atl_b0_hw_init_rx_path(self); @@ -460,8 +461,10 @@ static int hw_atl_b0_hw_init(struct aq_hw_s *self, u8 *mac_addr) /* Interrupts */ hw_atl_reg_gen_irq_map_set(self, - ((HW_ATL_B0_ERR_INT << 0x18) | (1U << 0x1F)) | - ((HW_ATL_B0_ERR_INT << 0x10) | (1U << 0x17)), 0U); + ((HW_ATL_B0_ERR_INT << 0x18) | + (1U << 0x1F)) | + ((HW_ATL_B0_ERR_INT << 0x10) | + (1U << 0x17)), 0U); /* Enable link interrupt */ if (aq_nic_cfg->link_irq_vec) @@ -478,6 +481,7 @@ static int hw_atl_b0_hw_ring_tx_start(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_tdm_tx_desc_en_set(self, 1, ring->idx); + return aq_hw_err_from_flags(self); } @@ -485,6 +489,7 @@ static int hw_atl_b0_hw_ring_rx_start(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_rdm_rx_desc_en_set(self, 1, ring->idx); + return aq_hw_err_from_flags(self); } @@ -492,6 +497,7 @@ static int hw_atl_b0_hw_start(struct aq_hw_s *self) { hw_atl_tpb_tx_buff_en_set(self, 1); hw_atl_rpb_rx_buff_en_set(self, 1); + return aq_hw_err_from_flags(self); } @@ -499,6 +505,7 @@ static int hw_atl_b0_hw_tx_ring_tail_update(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_reg_tx_dma_desc_tail_ptr_set(self, ring->sw_tail, ring->idx); + return 0; } @@ -509,8 +516,8 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, struct aq_ring_buff_s *buff = NULL; struct hw_atl_txd_s *txd = NULL; unsigned int buff_pa_len = 0U; - unsigned int pkt_len = 0U; unsigned int frag_count = 0U; + unsigned int pkt_len = 0U; bool is_vlan = false; bool is_gso = false; @@ -586,6 +593,7 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, } hw_atl_b0_hw_tx_ring_tail_update(self, ring); + return aq_hw_err_from_flags(self); } @@ -593,9 +601,9 @@ static int hw_atl_b0_hw_ring_rx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring, struct aq_ring_param_s *aq_ring_param) { - u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa; u32 dma_desc_addr_msw = (u32)(((u64)aq_ring->dx_ring_pa) >> 32); u32 vlan_rx_stripping = self->aq_nic_cfg->is_vlan_rx_strip; + u32 dma_desc_addr_lsw = (u32)aq_ring->dx_ring_pa; hw_atl_rdm_rx_desc_en_set(self, false, aq_ring->idx); @@ -636,8 +644,8 @@ static int hw_atl_b0_hw_ring_tx_init(struct aq_hw_s *self, struct aq_ring_s *aq_ring, struct aq_ring_param_s *aq_ring_param) { - u32 dma_desc_lsw_addr = (u32)aq_ring->dx_ring_pa; u32 dma_desc_msw_addr = (u32)(((u64)aq_ring->dx_ring_pa) >> 32); + u32 dma_desc_lsw_addr = (u32)aq_ring->dx_ring_pa; hw_atl_reg_tx_dma_desc_base_addresslswset(self, dma_desc_lsw_addr, aq_ring->idx); @@ -726,8 +734,10 @@ static int hw_atl_b0_hw_ring_hwts_rx_receive(struct aq_hw_s *self, static int hw_atl_b0_hw_ring_tx_head_update(struct aq_hw_s *self, struct aq_ring_s *ring) { + unsigned int hw_head_; int err = 0; - unsigned int hw_head_ = hw_atl_tdm_tx_desc_head_ptr_get(self, ring->idx); + + hw_head_ = hw_atl_tdm_tx_desc_head_ptr_get(self, ring->idx); if (aq_utils_obj_test(&self->flags, AQ_HW_FLAG_ERR_UNPLUG)) { err = -ENXIO; @@ -843,6 +853,7 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self, static int hw_atl_b0_hw_irq_enable(struct aq_hw_s *self, u64 mask) { hw_atl_itr_irq_msk_setlsw_set(self, LODWORD(mask)); + return aq_hw_err_from_flags(self); } @@ -852,12 +863,14 @@ static int hw_atl_b0_hw_irq_disable(struct aq_hw_s *self, u64 mask) hw_atl_itr_irq_status_clearlsw_set(self, LODWORD(mask)); atomic_inc(&self->dpc); + return aq_hw_err_from_flags(self); } static int hw_atl_b0_hw_irq_read(struct aq_hw_s *self, u64 *mask) { *mask = hw_atl_itr_irq_statuslsw_get(self); + return aq_hw_err_from_flags(self); } @@ -866,8 +879,8 @@ static int hw_atl_b0_hw_irq_read(struct aq_hw_s *self, u64 *mask) static int hw_atl_b0_hw_packet_filter_set(struct aq_hw_s *self, unsigned int packet_filter) { - unsigned int i = 0U; struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; + unsigned int i = 0U; hw_atl_rpfl2promiscuous_mode_en_set(self, IS_FILTER_ENABLED(IFF_PROMISC)); @@ -905,29 +918,30 @@ static int hw_atl_b0_hw_multicast_list_set(struct aq_hw_s *self, u32 count) { int err = 0; + struct aq_nic_cfg_s *cfg = self->aq_nic_cfg; if (count > (HW_ATL_B0_MAC_MAX - HW_ATL_B0_MAC_MIN)) { err = -EBADRQC; goto err_exit; } - for (self->aq_nic_cfg->mc_list_count = 0U; - self->aq_nic_cfg->mc_list_count < count; - ++self->aq_nic_cfg->mc_list_count) { - u32 i = self->aq_nic_cfg->mc_list_count; + for (cfg->mc_list_count = 0U; + cfg->mc_list_count < count; + ++cfg->mc_list_count) { + u32 i = cfg->mc_list_count; u32 h = (ar_mac[i][0] << 8) | (ar_mac[i][1]); u32 l = (ar_mac[i][2] << 24) | (ar_mac[i][3] << 16) | (ar_mac[i][4] << 8) | ar_mac[i][5]; hw_atl_rpfl2_uc_flr_en_set(self, 0U, HW_ATL_B0_MAC_MIN + i); - hw_atl_rpfl2unicast_dest_addresslsw_set(self, - l, HW_ATL_B0_MAC_MIN + i); + hw_atl_rpfl2unicast_dest_addresslsw_set(self, l, + HW_ATL_B0_MAC_MIN + i); - hw_atl_rpfl2unicast_dest_addressmsw_set(self, - h, HW_ATL_B0_MAC_MIN + i); + hw_atl_rpfl2unicast_dest_addressmsw_set(self, h, + HW_ATL_B0_MAC_MIN + i); hw_atl_rpfl2_uc_flr_en_set(self, - (self->aq_nic_cfg->is_mc_list_enabled), + (cfg->is_mc_list_enabled), HW_ATL_B0_MAC_MIN + i); } @@ -1054,6 +1068,7 @@ static int hw_atl_b0_hw_ring_tx_stop(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_tdm_tx_desc_en_set(self, 0U, ring->idx); + return aq_hw_err_from_flags(self); } @@ -1061,6 +1076,7 @@ static int hw_atl_b0_hw_ring_rx_stop(struct aq_hw_s *self, struct aq_ring_s *ring) { hw_atl_rdm_rx_desc_en_set(self, 0U, ring->idx); + return aq_hw_err_from_flags(self); } @@ -1448,6 +1464,7 @@ static int hw_atl_b0_set_loopback(struct aq_hw_s *self, u32 mode, bool enable) default: return -EINVAL; } + return 0; } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index db8c09c5a768..8910b62e67ed 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c @@ -92,6 +92,7 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops) } self->aq_fw_ops = *fw_ops; err = self->aq_fw_ops->init(self); + return err; } @@ -242,9 +243,9 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self) int hw_atl_utils_soft_reset(struct aq_hw_s *self) { - int k; u32 boot_exit_code = 0; u32 val; + int k; for (k = 0; k < 1000; ++k) { u32 flb_status = aq_hw_read_reg(self, @@ -439,15 +440,16 @@ int hw_atl_write_fwsettings_dwords(struct aq_hw_s *self, u32 offset, u32 *p, static int hw_atl_utils_ver_match(u32 ver_expected, u32 ver_actual) { - int err = 0; const u32 dw_major_mask = 0xff000000U; const u32 dw_minor_mask = 0x00ffffffU; + int err = 0; err = (dw_major_mask & (ver_expected ^ ver_actual)) ? -EOPNOTSUPP : 0; if (err < 0) goto err_exit; err = ((dw_minor_mask & ver_expected) > (dw_minor_mask & ver_actual)) ? -EOPNOTSUPP : 0; + err_exit: return err; } @@ -492,8 +494,8 @@ struct aq_hw_atl_utils_fw_rpc_tid_s { int hw_atl_utils_fw_rpc_call(struct aq_hw_s *self, unsigned int rpc_size) { - int err = 0; struct aq_hw_atl_utils_fw_rpc_tid_s sw; + int err = 0; if (!IS_CHIP_FEATURE(MIPS)) { err = -1; @@ -516,9 +518,9 @@ err_exit: int hw_atl_utils_fw_rpc_wait(struct aq_hw_s *self, struct hw_atl_utils_fw_rpc **rpc) { - int err = 0; struct aq_hw_atl_utils_fw_rpc_tid_s sw; struct aq_hw_atl_utils_fw_rpc_tid_s fw; + int err = 0; do { sw.val = aq_hw_read_reg(self, HW_ATL_RPC_CONTROL_ADR); @@ -622,10 +624,10 @@ static int hw_atl_utils_mpi_set_speed(struct aq_hw_s *self, u32 speed) static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, enum hal_atl_utils_fw_state_e state) { - int err = 0; - u32 transaction_id = 0; - struct hw_atl_utils_mbox_header mbox; u32 val = aq_hw_read_reg(self, HW_ATL_MPI_CONTROL_ADR); + struct hw_atl_utils_mbox_header mbox; + u32 transaction_id = 0; + int err = 0; if (state == MPI_RESET) { hw_atl_utils_mpi_read_mbox(self, &mbox); @@ -653,20 +655,26 @@ static int hw_atl_utils_mpi_set_state(struct aq_hw_s *self, val |= state & HW_ATL_MPI_STATE_MSK; aq_hw_write_reg(self, HW_ATL_MPI_CONTROL_ADR, val); + err_exit: return err; } int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) { - u32 cp0x036C = hw_atl_utils_mpi_get_state(self); - u32 link_speed_mask = cp0x036C >> HW_ATL_MPI_SPEED_SHIFT; struct aq_hw_link_status_s *link_status = &self->aq_link_status; + u32 mpi_state; + u32 speed; + + mpi_state = hw_atl_utils_mpi_get_state(self); + speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | + FW2X_RATE_2G5 | FW2X_RATE_5G | + FW2X_RATE_10G); - if (!link_speed_mask) { + if (!speed) { link_status->mbps = 0U; } else { - switch (link_speed_mask) { + switch (speed) { case HAL_ATLANTIC_RATE_10G: link_status->mbps = 10000U; break; @@ -699,14 +707,15 @@ int hw_atl_utils_mpi_get_link_status(struct aq_hw_s *self) int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, u8 *mac) { + u32 mac_addr[2]; + u32 efuse_addr; int err = 0; u32 h = 0U; u32 l = 0U; - u32 mac_addr[2]; if (!aq_hw_read_reg(self, HW_ATL_UCP_0X370_REG)) { - unsigned int rnd = 0; unsigned int ucp_0x370 = 0; + unsigned int rnd = 0; get_random_bytes(&rnd, sizeof(unsigned int)); @@ -714,11 +723,10 @@ int hw_atl_utils_get_mac_permanent(struct aq_hw_s *self, aq_hw_write_reg(self, HW_ATL_UCP_0X370_REG, ucp_0x370); } - err = hw_atl_utils_fw_downld_dwords(self, - aq_hw_read_reg(self, 0x00000374U) + - (40U * 4U), - mac_addr, - ARRAY_SIZE(mac_addr)); + efuse_addr = aq_hw_read_reg(self, 0x00000374U); + + err = hw_atl_utils_fw_downld_dwords(self, efuse_addr + (40U * 4U), + mac_addr, ARRAY_SIZE(mac_addr)); if (err < 0) { mac_addr[0] = 0U; mac_addr[1] = 0U; @@ -780,14 +788,15 @@ unsigned int hw_atl_utils_mbps_2_speed_index(unsigned int mbps) default: break; } + return ret; } void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p) { - u32 chip_features = 0U; u32 val = hw_atl_reg_glb_mif_id_get(self); u32 mif_rev = val & 0xFFU; + u32 chip_features = 0U; if ((0xFU & mif_rev) == 1U) { chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 | @@ -814,13 +823,14 @@ static int hw_atl_fw1x_deinit(struct aq_hw_s *self) { hw_atl_utils_mpi_set_speed(self, 0); hw_atl_utils_mpi_set_state(self, MPI_DEINIT); + return 0; } int hw_atl_utils_update_stats(struct aq_hw_s *self) { - struct hw_atl_utils_mbox mbox; struct aq_stats_s *cs = &self->curr_stats; + struct hw_atl_utils_mbox mbox; hw_atl_utils_mpi_read_stats(self, &mbox); @@ -897,12 +907,14 @@ int hw_atl_utils_hw_get_regs(struct aq_hw_s *self, for (i = 0; i < aq_hw_caps->mac_regs_count; i++) regs_buff[i] = aq_hw_read_reg(self, hw_atl_utils_hw_mac_regs[i]); + return 0; } int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version) { *fw_version = aq_hw_read_reg(self, 0x18U); + return 0; } diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index feef2b0177b2..ce3ed86d8c0e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -226,15 +226,20 @@ static int aq_fw2x_set_state(struct aq_hw_s *self, break; } aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); + return 0; } static int aq_fw2x_update_link_status(struct aq_hw_s *self) { - u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); - u32 speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | - FW2X_RATE_2G5 | FW2X_RATE_5G | FW2X_RATE_10G); struct aq_hw_link_status_s *link_status = &self->aq_link_status; + u32 mpi_state; + u32 speed; + + mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR); + speed = mpi_state & (FW2X_RATE_100M | FW2X_RATE_1G | + FW2X_RATE_2G5 | FW2X_RATE_5G | + FW2X_RATE_10G); if (speed) { if (speed & FW2X_RATE_10G) @@ -258,11 +263,11 @@ static int aq_fw2x_update_link_status(struct aq_hw_s *self) static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) { + u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR); + u32 mac_addr[2] = { 0 }; int err = 0; u32 h = 0U; u32 l = 0U; - u32 mac_addr[2] = { 0 }; - u32 efuse_addr = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_EFUSE_ADDR); if (efuse_addr != 0) { err = hw_atl_utils_fw_downld_dwords(self, @@ -296,15 +301,16 @@ static int aq_fw2x_get_mac_permanent(struct aq_hw_s *self, u8 *mac) h >>= 8; mac[0] = (u8)(0xFFU & h); } + return err; } static int aq_fw2x_update_stats(struct aq_hw_s *self) { - int err = 0; u32 mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); u32 orig_stats_val = mpi_opts & BIT(CAPS_HI_STATISTICS); u32 stats_val; + int err = 0; /* Toggle statistics bit for FW to update */ mpi_opts = mpi_opts ^ BIT(CAPS_HI_STATISTICS); @@ -331,9 +337,9 @@ static int aq_fw2x_get_phy_temp(struct aq_hw_s *self, int *temp) int err = 0; u32 val; - phy_temp_offset = self->mbox_addr + - offsetof(struct hw_atl_utils_mbox, info) + - offsetof(struct hw_aq_info, phy_temperature); + phy_temp_offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, + info.phy_temperature); + /* Toggle statistics bit for FW to 0x36C.18 (CTRL_TEMPERATURE) */ mpi_opts = mpi_opts ^ HW_ATL_FW2X_CTRL_TEMPERATURE; aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); @@ -486,11 +492,12 @@ static int aq_fw2x_get_eee_rate(struct aq_hw_s *self, u32 *rate, u32 mpi_state; u32 caps_hi; int err = 0; - u32 addr = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, info) + - offsetof(struct hw_aq_info, caps_hi); + u32 offset; - err = hw_atl_utils_fw_downld_dwords(self, addr, &caps_hi, - sizeof(caps_hi) / sizeof(u32)); + offset = self->mbox_addr + offsetof(struct hw_atl_utils_mbox, + info.caps_hi); + + err = hw_atl_utils_fw_downld_dwords(self, offset, &caps_hi, 1); if (err) return err; @@ -567,6 +574,7 @@ static int aq_fw2x_set_phyloopback(struct aq_hw_s *self, u32 mode, bool enable) default: return -EINVAL; } + return 0; } -- cgit v1.2.3-59-g8ed1b From ddef55263271cd7108db3821c376e7104ba7cc5f Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Thu, 7 Nov 2019 22:42:02 +0000 Subject: net: atlantic: stylistic renames We are trying to follow the naming of the chip (atlantic), not company. So replace some old namings. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ptp.c | 6 +++--- drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c index 1f9eab74453e..58e8c641e8b3 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ptp.c @@ -1057,7 +1057,7 @@ static struct ptp_clock_info aq_ptp_clock = { ptp_offset[__idx].ingress = (__ingress); } \ while (0) -static void aq_ptp_offset_init_from_fw(const struct hw_aq_ptp_offset *offsets) +static void aq_ptp_offset_init_from_fw(const struct hw_atl_ptp_offset *offsets) { int i; @@ -1098,7 +1098,7 @@ static void aq_ptp_offset_init_from_fw(const struct hw_aq_ptp_offset *offsets) } } -static void aq_ptp_offset_init(const struct hw_aq_ptp_offset *offsets) +static void aq_ptp_offset_init(const struct hw_atl_ptp_offset *offsets) { memset(ptp_offset, 0, sizeof(ptp_offset)); @@ -1106,7 +1106,7 @@ static void aq_ptp_offset_init(const struct hw_aq_ptp_offset *offsets) } static void aq_ptp_gpio_init(struct ptp_clock_info *info, - struct hw_aq_info *hw_info) + struct hw_atl_info *hw_info) { struct ptp_pin_desc pin_desc[MAX_PTP_GPIO_COUNT]; u32 extts_pin_cnt = 0; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 68fe17ec171d..42f0c5c6ec2d 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h @@ -113,7 +113,7 @@ struct __packed hw_atl_utils_mbox_header { u32 error; }; -struct __packed hw_aq_ptp_offset { +struct __packed hw_atl_ptp_offset { u16 ingress_100; u16 egress_100; u16 ingress_1000; @@ -148,14 +148,14 @@ enum gpio_pin_function { GPIO_PIN_FUNCTION_SIZE }; -struct __packed hw_aq_info { +struct __packed hw_atl_info { u8 reserved[6]; u16 phy_fault_code; u16 phy_temperature; u8 cable_len; u8 reserved1; struct hw_atl_cable_diag cable_diag_data[4]; - struct hw_aq_ptp_offset ptp_offset; + struct hw_atl_ptp_offset ptp_offset; u8 reserved2[12]; u32 caps_lo; u32 caps_hi; @@ -177,7 +177,7 @@ struct __packed hw_aq_info { struct __packed hw_atl_utils_mbox { struct hw_atl_utils_mbox_header header; struct hw_atl_stats_s stats; - struct hw_aq_info info; + struct hw_atl_info info; }; struct __packed offload_ip_info { -- cgit v1.2.3-59-g8ed1b From 8009bb1928a6d5b0ce2d8a1dba79972f01e50533 Mon Sep 17 00:00:00 2001 From: Nikita Danilov Date: Thu, 7 Nov 2019 22:42:04 +0000 Subject: net: atlantic: update flow control logic We now differentiate requested and negotiated flow control modes. Therefore `ethtool -A` now operates on local requested FC values, and regular link settings shows the negotiated FC settings. Signed-off-by: Nikita Danilov Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | 6 --- .../net/ethernet/aquantia/atlantic/aq_ethtool.c | 10 ++--- drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 19 +++++---- drivers/net/ethernet/aquantia/atlantic/aq_nic.h | 14 ++++++- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 2 +- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 2 +- .../aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | 47 +++++++++++++--------- 7 files changed, 59 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index d02b0d79f68a..f0c41f7408e5 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h @@ -70,12 +70,6 @@ /*#define AQ_CFG_MAC_ADDR_PERMANENT {0x30, 0x0E, 0xE3, 0x12, 0x34, 0x56}*/ -#define AQ_NIC_FC_OFF 0U -#define AQ_NIC_FC_TX 1U -#define AQ_NIC_FC_RX 2U -#define AQ_NIC_FC_FULL 3U -#define AQ_NIC_FC_AUTO 4U - #define AQ_CFG_FC_MODE AQ_NIC_FC_FULL /* Default WOL modes used on initialization */ diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 8286c77d43a5..6353a5c5ed27 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -588,7 +588,7 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause) { struct aq_nic_s *aq_nic = netdev_priv(ndev); - u32 fc = aq_nic->aq_nic_cfg.flow_control; + u32 fc = aq_nic->aq_nic_cfg.fc.req; pause->autoneg = 0; @@ -610,14 +610,14 @@ static int aq_ethtool_set_pauseparam(struct net_device *ndev, return -EOPNOTSUPP; if (pause->rx_pause) - aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_RX; + aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_RX; else - aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_RX; + aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_RX; if (pause->tx_pause) - aq_nic->aq_hw->aq_nic_cfg->flow_control |= AQ_NIC_FC_TX; + aq_nic->aq_hw->aq_nic_cfg->fc.req |= AQ_NIC_FC_TX; else - aq_nic->aq_hw->aq_nic_cfg->flow_control &= ~AQ_NIC_FC_TX; + aq_nic->aq_hw->aq_nic_cfg->fc.req &= ~AQ_NIC_FC_TX; mutex_lock(&aq_nic->fwreq_mutex); err = aq_nic->aq_fw_ops->set_flow_control(aq_nic->aq_hw); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index d3739f21b18e..7ad8eb535d28 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -79,7 +79,7 @@ void aq_nic_cfg_start(struct aq_nic_s *self) cfg->is_rss = AQ_CFG_IS_RSS_DEF; cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF; cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF; - cfg->flow_control = AQ_CFG_FC_MODE; + cfg->fc.req = AQ_CFG_FC_MODE; cfg->wol = AQ_CFG_WOL_MODES; cfg->mtu = AQ_CFG_MTU_DEF; @@ -144,6 +144,10 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) if (err) return err; + if (self->aq_fw_ops->get_flow_control) + self->aq_fw_ops->get_flow_control(self->aq_hw, &fc); + self->aq_nic_cfg.fc.cur = fc; + if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) { netdev_info(self->ndev, "%s: link change old %d new %d\n", AQ_CFG_DRV_NAME, self->link_status.mbps, @@ -161,8 +165,6 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) * on any link event. * We should query FW whether it negotiated FC. */ - if (self->aq_fw_ops->get_flow_control) - self->aq_fw_ops->get_flow_control(self->aq_hw, &fc); if (self->aq_hw_ops->hw_set_fc) self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0); } @@ -862,9 +864,12 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full); - if (self->aq_nic_cfg.aq_hw_caps->flow_control) + if (self->aq_nic_cfg.aq_hw_caps->flow_control) { ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); + ethtool_link_ksettings_add_link_mode(cmd, supported, + Asym_Pause); + } ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); @@ -898,13 +903,13 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); - if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX) + if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX) ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); /* Asym is when either RX or TX, but not both */ - if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^ - !!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)) + if (!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_TX) ^ + !!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)) ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 98c3182bf1d0..a752f8bb4b08 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h @@ -20,6 +20,18 @@ struct aq_vec_s; struct aq_ptp_s; enum aq_rx_filter_type; +enum aq_fc_mode { + AQ_NIC_FC_OFF = 0, + AQ_NIC_FC_TX, + AQ_NIC_FC_RX, + AQ_NIC_FC_FULL, +}; + +struct aq_fc_info { + enum aq_fc_mode req; + enum aq_fc_mode cur; +}; + struct aq_nic_cfg_s { const struct aq_hw_caps_s *aq_hw_caps; u64 features; @@ -34,7 +46,7 @@ struct aq_nic_cfg_s { u32 rxpageorder; u32 num_rss_queues; u32 mtu; - u32 flow_control; + struct aq_fc_info fc; u32 link_speed_msk; u32 wol; u8 is_vlan_rx_strip; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index d2fb399f179f..03b62d7d9f1a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -155,7 +155,7 @@ static int hw_atl_a0_hw_qos_set(struct aq_hw_s *self) /* QoS Rx buf size per TC */ tc = 0; - is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->flow_control); + is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->fc.req); buff_size = HW_ATL_A0_RXBUF_MAX; hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 8686462b32f9..c5da60c12262 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -168,7 +168,7 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) (1024U / 32U) * 50U) / 100U, tc); - hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc); + hw_atl_b0_set_fc(self, self->aq_nic_cfg->fc.req, tc); /* Init TC2 for PTP_RX */ tc = 2; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index ce3ed86d8c0e..97ebf849695f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c @@ -181,17 +181,26 @@ static int aq_fw2x_set_link_speed(struct aq_hw_s *self, u32 speed) return 0; } -static void aq_fw2x_set_mpi_flow_control(struct aq_hw_s *self, u32 *mpi_state) +static void aq_fw2x_upd_flow_control_bits(struct aq_hw_s *self, + u32 *mpi_state, u32 fc) { - if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) - *mpi_state |= BIT(CAPS_HI_PAUSE); - else - *mpi_state &= ~BIT(CAPS_HI_PAUSE); + *mpi_state &= ~(HW_ATL_FW2X_CTRL_PAUSE | + HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE); - if (self->aq_nic_cfg->flow_control & AQ_NIC_FC_TX) - *mpi_state |= BIT(CAPS_HI_ASYMMETRIC_PAUSE); - else - *mpi_state &= ~BIT(CAPS_HI_ASYMMETRIC_PAUSE); + switch (fc) { + /* There is not explicit mode of RX only pause frames, + * thus, we join this mode with FC full. + * FC full is either Rx, either Tx, or both. + */ + case AQ_NIC_FC_FULL: + case AQ_NIC_FC_RX: + *mpi_state |= HW_ATL_FW2X_CTRL_PAUSE | + HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; + break; + case AQ_NIC_FC_TX: + *mpi_state |= HW_ATL_FW2X_CTRL_ASYMMETRIC_PAUSE; + break; + } } static void aq_fw2x_upd_eee_rate_bits(struct aq_hw_s *self, u32 *mpi_opts, @@ -215,7 +224,8 @@ static int aq_fw2x_set_state(struct aq_hw_s *self, case MPI_INIT: mpi_state &= ~BIT(CAPS_HI_LINK_DROP); aq_fw2x_upd_eee_rate_bits(self, &mpi_state, cfg->eee_speeds); - aq_fw2x_set_mpi_flow_control(self, &mpi_state); + aq_fw2x_upd_flow_control_bits(self, &mpi_state, + self->aq_nic_cfg->fc.req); break; case MPI_DEINIT: mpi_state |= BIT(CAPS_HI_LINK_DROP); @@ -525,7 +535,8 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self) { u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); - aq_fw2x_set_mpi_flow_control(self, &mpi_state); + aq_fw2x_upd_flow_control_bits(self, &mpi_state, + self->aq_nic_cfg->fc.req); aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_state); @@ -535,17 +546,13 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self) static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode) { u32 mpi_state = aq_fw2x_state2_get(self); + *fcmode = 0; if (mpi_state & HW_ATL_FW2X_CAP_PAUSE) - if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) - *fcmode = AQ_NIC_FC_RX; - else - *fcmode = AQ_NIC_FC_RX | AQ_NIC_FC_TX; - else - if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) - *fcmode = AQ_NIC_FC_TX; - else - *fcmode = 0; + *fcmode |= AQ_NIC_FC_RX; + + if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) + *fcmode |= AQ_NIC_FC_TX; return 0; } -- cgit v1.2.3-59-g8ed1b From 822cd114cd05a47b7c272de9b3a4da73114894ca Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Thu, 7 Nov 2019 22:42:06 +0000 Subject: net: atlantic: implement UDP GSO offload atlantic hardware does support UDP hardware segmentation offload. This allows user to specify one large contiguous buffer with data which then will be split automagically into multiple UDP packets of specified size. Bulk sending of large UDP streams lowers CPU usage and increases bandwidth. We did estimations both with udpgso_bench_tx test tool and with modified iperf3 measurement tool (4 streams, multithread, 200b packet size) over AQC<->AQC 10G link. Flow control is disabled to prevent RX side impact on measurements. No UDP GSO: iperf3 -c 10.0.1.2 -u -b0 -l 200 -P4 --multithread UDP GSO: iperf3 -c 10.0.1.2 -u -b0 -l 12600 --udp-lso 200 -P4 --multithread Mode CPU iperf speed Line speed Packets per second ------------------------------------------------------------- NO UDP GSO 350% 3.07 Gbps 3.8 Gbps 1,919,419 SW UDP GSO 200% 5.55 Gbps 6.4 Gbps 3,286,144 HW UDP GSO 90% 6.80 Gbps 8.4 Gbps 4,273,117 Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- .../device_drivers/aquantia/atlantic.txt | 15 +++++++ drivers/net/ethernet/aquantia/atlantic/aq_nic.c | 52 ++++++++++++---------- drivers/net/ethernet/aquantia/atlantic/aq_ring.h | 7 +-- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | 2 +- .../ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 11 +++-- 5 files changed, 55 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/Documentation/networking/device_drivers/aquantia/atlantic.txt b/Documentation/networking/device_drivers/aquantia/atlantic.txt index cf3e88ca885e..4c70f300e4eb 100644 --- a/Documentation/networking/device_drivers/aquantia/atlantic.txt +++ b/Documentation/networking/device_drivers/aquantia/atlantic.txt @@ -325,6 +325,21 @@ Supported ethtool options Example: ethtool -N eth0 flow-type udp4 action 0 loc 32 + UDP GSO hardware offload + --------------------------------- + UDP GSO allows to boost UDP tx rates by offloading UDP headers allocation + into hardware. A special userspace socket option is required for this, + could be validated with /kernel/tools/testing/selftests/net/ + + udpgso_bench_tx -u -4 -D 10.0.1.1 -s 6300 -S 100 + + Will cause sending out of 100 byte sized UDP packets formed from single + 6300 bytes user buffer. + + UDP GSO is configured by: + + ethtool -K eth0 tx-udp-segmentation on + Private flags (testing) --------------------------------- diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 7ad8eb535d28..a17a4da7bc15 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c @@ -309,6 +309,7 @@ void aq_nic_ndev_init(struct aq_nic_s *self) self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_RXHASH | NETIF_F_SG | NETIF_F_LRO | NETIF_F_TSO; + self->ndev->gso_partial_features = NETIF_F_GSO_UDP_L4; self->ndev->priv_flags = aq_hw_caps->hw_priv_flags; self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; @@ -472,11 +473,18 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, { unsigned int nr_frags = skb_shinfo(skb)->nr_frags; struct aq_ring_buff_s *first = NULL; + u8 ipver = ip_hdr(skb)->version; struct aq_ring_buff_s *dx_buff; bool need_context_tag = false; unsigned int frag_count = 0U; unsigned int ret = 0U; unsigned int dx; + u8 l4proto = 0; + + if (ipver == 4) + l4proto = ip_hdr(skb)->protocol; + else if (ipver == 6) + l4proto = ipv6_hdr(skb)->nexthdr; dx = ring->sw_tail; dx_buff = &ring->buff_ring[dx]; @@ -484,14 +492,24 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, if (unlikely(skb_is_gso(skb))) { dx_buff->mss = skb_shinfo(skb)->gso_size; - dx_buff->is_gso = 1U; + if (l4proto == IPPROTO_TCP) { + dx_buff->is_gso_tcp = 1U; + dx_buff->len_l4 = tcp_hdrlen(skb); + } else if (l4proto == IPPROTO_UDP) { + dx_buff->is_gso_udp = 1U; + dx_buff->len_l4 = sizeof(struct udphdr); + /* UDP GSO Hardware does not replace packet length. */ + udp_hdr(skb)->len = htons(dx_buff->mss + + dx_buff->len_l4); + } else { + WARN_ONCE(true, "Bad GSO mode"); + goto exit; + } dx_buff->len_pkt = skb->len; dx_buff->len_l2 = ETH_HLEN; - dx_buff->len_l3 = ip_hdrlen(skb); - dx_buff->len_l4 = tcp_hdrlen(skb); + dx_buff->len_l3 = skb_network_header_len(skb); dx_buff->eop_index = 0xffffU; - dx_buff->is_ipv6 = - (ip_hdr(skb)->version == 6) ? 1U : 0U; + dx_buff->is_ipv6 = (ipver == 6); need_context_tag = true; } @@ -525,24 +543,9 @@ unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, ++ret; if (skb->ip_summed == CHECKSUM_PARTIAL) { - dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol) ? - 1U : 0U; - - if (ip_hdr(skb)->version == 4) { - dx_buff->is_tcp_cso = - (ip_hdr(skb)->protocol == IPPROTO_TCP) ? - 1U : 0U; - dx_buff->is_udp_cso = - (ip_hdr(skb)->protocol == IPPROTO_UDP) ? - 1U : 0U; - } else if (ip_hdr(skb)->version == 6) { - dx_buff->is_tcp_cso = - (ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP) ? - 1U : 0U; - dx_buff->is_udp_cso = - (ipv6_hdr(skb)->nexthdr == NEXTHDR_UDP) ? - 1U : 0U; - } + dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol); + dx_buff->is_tcp_cso = (l4proto == IPPROTO_TCP); + dx_buff->is_udp_cso = (l4proto == IPPROTO_UDP); } for (; nr_frags--; ++frag_count) { @@ -597,7 +600,8 @@ mapping_error: --ret, dx = aq_ring_next_dx(ring, dx)) { dx_buff = &ring->buff_ring[dx]; - if (!dx_buff->is_gso && !dx_buff->is_vlan && dx_buff->pa) { + if (!(dx_buff->is_gso_tcp || dx_buff->is_gso_udp) && + !dx_buff->is_vlan && dx_buff->pa) { if (unlikely(dx_buff->is_sop)) { dma_unmap_single(aq_nic_get_dev(self), dx_buff->pa, diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h index be3702a4dcc9..991e4d31b094 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.h @@ -65,19 +65,20 @@ struct __packed aq_ring_buff_s { }; union { struct { - u16 len; + u32 len:16; u32 is_ip_cso:1; u32 is_udp_cso:1; u32 is_tcp_cso:1; u32 is_cso_err:1; u32 is_sop:1; u32 is_eop:1; - u32 is_gso:1; + u32 is_gso_tcp:1; + u32 is_gso_udp:1; u32 is_mapped:1; u32 is_cleaned:1; u32 is_error:1; u32 is_vlan:1; - u32 rsvd3:5; + u32 rsvd3:4; u16 eop_index; u16 rsvd4; }; diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index 03b62d7d9f1a..9b1062b8af64 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c @@ -454,7 +454,7 @@ static int hw_atl_a0_hw_ring_tx_xmit(struct aq_hw_s *self, buff = &ring->buff_ring[ring->sw_tail]; - if (buff->is_gso) { + if (buff->is_gso_tcp) { txd->ctl |= (buff->len_l3 << 31) | (buff->len_l2 << 24) | HW_ATL_A0_TXD_CTL_CMD_TCP | diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index c5da60c12262..58e891af6e09 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -43,7 +43,9 @@ NETIF_F_NTUPLE | \ NETIF_F_HW_VLAN_CTAG_FILTER | \ NETIF_F_HW_VLAN_CTAG_RX | \ - NETIF_F_HW_VLAN_CTAG_TX, \ + NETIF_F_HW_VLAN_CTAG_TX | \ + NETIF_F_GSO_UDP_L4 | \ + NETIF_F_GSO_PARTIAL, \ .hw_priv_flags = IFF_UNICAST_FLT, \ .flow_control = true, \ .mtu = HW_ATL_B0_MTU_JUMBO, \ @@ -533,8 +535,9 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, buff = &ring->buff_ring[ring->sw_tail]; - if (buff->is_gso) { - txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TCP; + if (buff->is_gso_tcp || buff->is_gso_udp) { + if (buff->is_gso_tcp) + txd->ctl |= HW_ATL_B0_TXD_CTL_CMD_TCP; txd->ctl |= HW_ATL_B0_TXD_CTL_DESC_TYPE_TXC; txd->ctl |= (buff->len_l3 << 31) | (buff->len_l2 << 24); @@ -554,7 +557,7 @@ static int hw_atl_b0_hw_ring_tx_xmit(struct aq_hw_s *self, txd->ctl |= buff->vlan_tx_tag << 4; is_vlan = true; } - if (!buff->is_gso && !buff->is_vlan) { + if (!buff->is_gso_tcp && !buff->is_gso_udp && !buff->is_vlan) { buff_pa_len = buff->len; txd->buf_addr = buff->pa; -- cgit v1.2.3-59-g8ed1b From 362cabda8d4da80152c20e11502ceee6672eb1c1 Mon Sep 17 00:00:00 2001 From: Igor Russkikh Date: Thu, 7 Nov 2019 22:42:08 +0000 Subject: net: atlantic: change email domains to Marvell Aquantia is now part of Marvell, eventually we'll cease standalone aquantia.com domain. Thus, change the maintainers file and some other references to @marvell.com domain Signed-off-by: Igor Russkikh Signed-off-by: David S. Miller --- Documentation/networking/device_drivers/aquantia/atlantic.txt | 6 +++--- MAINTAINERS | 4 ++-- drivers/net/ethernet/aquantia/atlantic/Makefile | 7 ------- 3 files changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/Documentation/networking/device_drivers/aquantia/atlantic.txt b/Documentation/networking/device_drivers/aquantia/atlantic.txt index 4c70f300e4eb..2013fcedc2da 100644 --- a/Documentation/networking/device_drivers/aquantia/atlantic.txt +++ b/Documentation/networking/device_drivers/aquantia/atlantic.txt @@ -1,5 +1,5 @@ -aQuantia AQtion Driver for the aQuantia Multi-Gigabit PCI Express Family of -Ethernet Adapters +Marvell(Aquantia) AQtion Driver for the aQuantia Multi-Gigabit PCI Express +Family of Ethernet Adapters ============================================================================= Contents @@ -466,7 +466,7 @@ Support If an issue is identified with the released source code on the supported kernel with a supported adapter, email the specific information related -to the issue to support@aquantia.com +to the issue to aqn_support@marvell.com License ======= diff --git a/MAINTAINERS b/MAINTAINERS index 709c60aacb58..a49282f3ad6a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1182,10 +1182,10 @@ S: Maintained F: drivers/media/i2c/aptina-pll.* AQUANTIA ETHERNET DRIVER (atlantic) -M: Igor Russkikh +M: Igor Russkikh L: netdev@vger.kernel.org S: Supported -W: http://www.aquantia.com +W: https://www.marvell.com/ Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/aquantia/atlantic/ F: Documentation/networking/device_drivers/aquantia/atlantic.txt diff --git a/drivers/net/ethernet/aquantia/atlantic/Makefile b/drivers/net/ethernet/aquantia/atlantic/Makefile index 0020726db204..6e0a6e234483 100644 --- a/drivers/net/ethernet/aquantia/atlantic/Makefile +++ b/drivers/net/ethernet/aquantia/atlantic/Makefile @@ -4,15 +4,8 @@ # aQuantia Ethernet Controller AQtion Linux Driver # Copyright(c) 2014-2017 aQuantia Corporation. # -# Contact Information: -# aQuantia Corporation, 105 E. Tasman Dr. San Jose, CA 95134, USA -# ################################################################################ -# -# Makefile for the AQtion(tm) Ethernet driver -# - obj-$(CONFIG_AQTION) += atlantic.o atlantic-objs := aq_main.o \ -- cgit v1.2.3-59-g8ed1b From 693bd8b7ae46f04d6d7c868a08b35d28baacdab1 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Thu, 7 Nov 2019 22:01:58 +0200 Subject: ethernet: ti: cpts: use ktime_get_real_ns helper Update on more short variant for getting real clock in ns. Signed-off-by: Ivan Khoronzhuk Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c index 61136428e2c0..729ce09dded9 100644 --- a/drivers/net/ethernet/ti/cpts.c +++ b/drivers/net/ethernet/ti/cpts.c @@ -459,7 +459,7 @@ int cpts_register(struct cpts *cpts) cpts_write32(cpts, CPTS_EN, control); cpts_write32(cpts, TS_PEND_EN, int_enable); - timecounter_init(&cpts->tc, &cpts->cc, ktime_to_ns(ktime_get_real())); + timecounter_init(&cpts->tc, &cpts->cc, ktime_get_real_ns()); cpts->clock = ptp_clock_register(&cpts->info, cpts->dev); if (IS_ERR(cpts->clock)) { -- cgit v1.2.3-59-g8ed1b From 12299132b3d3bad58eff16e227891405b14c7d80 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 7 Nov 2019 14:35:36 -0800 Subject: net: ethernet: intel: Demote MTU change prints to debug Changing a network device MTU can be a fairly frequent operation, and failure to change the MTU is reflected to user-space properly, both by an appropriate message as well as by looking at whether the device's MTU matches the configuration. Demote the prints to debug prints by using netdev_dbg(), making all Intel wired LAN drivers consistent, since they used a mixture of PCI device and network device prints before. Signed-off-by: Florian Fainelli Acked-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ethernet/intel/e1000/e1000_main.c | 4 ++-- drivers/net/ethernet/intel/e1000e/netdev.c | 3 ++- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- drivers/net/ethernet/intel/igb/igb_main.c | 5 ++--- drivers/net/ethernet/intel/igbvf/netdev.c | 4 ++-- drivers/net/ethernet/intel/igc/igc_main.c | 5 ++--- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 3 ++- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 86493fea56e4..416da9619928 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -3565,8 +3565,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))) adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; - pr_info("%s changing MTU from %d to %d\n", - netdev->name, netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 032b88619054..fe7997c18a10 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6031,7 +6031,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) usleep_range(1000, 1100); /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ adapter->max_frame_size = max_frame; - e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; pm_runtime_get_sync(netdev->dev.parent); diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9fac1cea6fa5..1ccabeafa44c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2664,8 +2664,8 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } - netdev_info(netdev, "changing MTU from %d to %d\n", - netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) i40e_vsi_reinit_locked(vsi); diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 48a40e4132f9..7337b3d3d1f6 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6236,7 +6236,6 @@ static void igb_get_stats64(struct net_device *netdev, static int igb_change_mtu(struct net_device *netdev, int new_mtu) { struct igb_adapter *adapter = netdev_priv(netdev); - struct pci_dev *pdev = adapter->pdev; int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; /* adjust max frame to be at least the size of a standard frame */ @@ -6252,8 +6251,8 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu) if (netif_running(netdev)) igb_down(adapter); - dev_info(&pdev->dev, "changing MTU from %d to %d\n", - netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 0f2b68f4bb0f..6003dc3ff5fd 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -2437,8 +2437,8 @@ static int igbvf_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; - dev_info(&adapter->pdev->dev, "changing MTU from %d to %d\n", - netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 6105c6d1f3c9..b9d46cd57b6a 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -2272,7 +2272,6 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu) { int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; struct igc_adapter *adapter = netdev_priv(netdev); - struct pci_dev *pdev = adapter->pdev; /* adjust max frame to be at least the size of a standard frame */ if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN)) @@ -2287,8 +2286,8 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu) if (netif_running(netdev)) igc_down(adapter); - dev_info(&pdev->dev, "changing MTU from %d to %d\n", - netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 1129ae70d5fb..25c097cd8100 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6725,7 +6725,8 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu) (new_mtu > ETH_DATA_LEN)) e_warn(probe, "Setting MTU > 1500 will disable legacy VFs\n"); - e_info(probe, "changing MTU from %d to %d\n", netdev->mtu, new_mtu); + netdev_dbg(netdev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); /* must set new MTU before calling down or up */ netdev->mtu = new_mtu; -- cgit v1.2.3-59-g8ed1b From 5409386679860fded7f666da143e4c33926c62da Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 7 Nov 2019 14:35:37 -0800 Subject: net: qcom/emac: Demote MTU change print to debug Changing the MTU can be a frequent operation and it is already clear when (or not) a MTU change is successful, demote prints to debug prints. Signed-off-by: Florian Fainelli Acked-by: Timur Tabi Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index c84ab052ef26..98f92268cbaa 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -213,9 +213,9 @@ static int emac_change_mtu(struct net_device *netdev, int new_mtu) { struct emac_adapter *adpt = netdev_priv(netdev); - netif_info(adpt, hw, adpt->netdev, - "changing MTU from %d to %d\n", netdev->mtu, - new_mtu); + netif_dbg(adpt, hw, adpt->netdev, + "changing MTU from %d to %d\n", netdev->mtu, + new_mtu); netdev->mtu = new_mtu; if (netif_running(netdev)) -- cgit v1.2.3-59-g8ed1b From de7d5084d82794a8e83afb994fcb07f82da3cd7b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:14 -0800 Subject: net: provide dev_lstats_read() helper Many network drivers use hand-coded implementation of the same thing, let's factorize things so that u64_stats_t adoption is done once. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/loopback.c | 24 +++++++++++++++++------- include/linux/netdevice.h | 2 ++ 2 files changed, 19 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 14545a8797a8..92336ac4c5e6 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -99,13 +99,13 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } -static void loopback_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *stats) +void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes) { - u64 bytes = 0; - u64 packets = 0; int i; + *packets = 0; + *bytes = 0; + for_each_possible_cpu(i) { const struct pcpu_lstats *lb_stats; u64 tbytes, tpackets; @@ -114,12 +114,22 @@ static void loopback_get_stats64(struct net_device *dev, lb_stats = per_cpu_ptr(dev->lstats, i); do { start = u64_stats_fetch_begin_irq(&lb_stats->syncp); - tbytes = lb_stats->bytes; tpackets = lb_stats->packets; + tbytes = lb_stats->bytes; } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); - bytes += tbytes; - packets += tpackets; + *bytes += tbytes; + *packets += tpackets; } +} +EXPORT_SYMBOL(dev_lstats_read); + +static void loopback_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + u64 packets, bytes; + + dev_lstats_read(dev, &packets, &bytes); + stats->rx_packets = packets; stats->tx_packets = packets; stats->rx_bytes = bytes; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1f140a6b66df..75561992c31f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2401,6 +2401,8 @@ struct pcpu_lstats { struct u64_stats_sync syncp; } __aligned(2 * sizeof(u64)); +void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes); + #define __netdev_alloc_pcpu_stats(type, gfp) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\ -- cgit v1.2.3-59-g8ed1b From dd5382a08157756510aa8d7269c662eccde775cb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:15 -0800 Subject: net: provide dev_lstats_add() helper Many network drivers need it and hand-coded the same function. In order to ease u64_stats_t adoption, it is time to factorize. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/loopback.c | 12 ++---------- include/linux/netdevice.h | 10 ++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 92336ac4c5e6..47ad2478b9f3 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -68,7 +68,6 @@ EXPORT_SYMBOL(blackhole_netdev); static netdev_tx_t loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcpu_lstats *lb_stats; int len; skb_tx_timestamp(skb); @@ -85,16 +84,9 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb, skb->protocol = eth_type_trans(skb, dev); - /* it's OK to use per_cpu_ptr() because BHs are off */ - lb_stats = this_cpu_ptr(dev->lstats); - len = skb->len; - if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { - u64_stats_update_begin(&lb_stats->syncp); - lb_stats->bytes += len; - lb_stats->packets++; - u64_stats_update_end(&lb_stats->syncp); - } + if (likely(netif_rx(skb) == NET_RX_SUCCESS)) + dev_lstats_add(dev, len); return NETDEV_TX_OK; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 75561992c31f..461a36220cf4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2403,6 +2403,16 @@ struct pcpu_lstats { void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes); +static inline void dev_lstats_add(struct net_device *dev, unsigned int len) +{ + struct pcpu_lstats *lstats = this_cpu_ptr(dev->lstats); + + u64_stats_update_begin(&lstats->syncp); + lstats->bytes += len; + lstats->packets++; + u64_stats_update_end(&lstats->syncp); +} + #define __netdev_alloc_pcpu_stats(type, gfp) \ ({ \ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\ -- cgit v1.2.3-59-g8ed1b From 3ed912264f1c057be6afcbbd2a362787ee020a92 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:16 -0800 Subject: net: nlmon: use standard dev_lstats_add() and dev_lstats_read() No need to hand-code the exact same functions. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/nlmon.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index 68771b2f351a..afb119f38325 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -9,13 +9,7 @@ static netdev_tx_t nlmon_xmit(struct sk_buff *skb, struct net_device *dev) { - int len = skb->len; - struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); - - u64_stats_update_begin(&stats->syncp); - stats->bytes += len; - stats->packets++; - u64_stats_update_end(&stats->syncp); + dev_lstats_add(dev, skb->len); dev_kfree_skb(skb); @@ -56,25 +50,9 @@ static int nlmon_close(struct net_device *dev) static void nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - int i; - u64 bytes = 0, packets = 0; - - for_each_possible_cpu(i) { - const struct pcpu_lstats *nl_stats; - u64 tbytes, tpackets; - unsigned int start; - - nl_stats = per_cpu_ptr(dev->lstats, i); - - do { - start = u64_stats_fetch_begin_irq(&nl_stats->syncp); - tbytes = nl_stats->bytes; - tpackets = nl_stats->packets; - } while (u64_stats_fetch_retry_irq(&nl_stats->syncp, start)); + u64 packets, bytes; - packets += tpackets; - bytes += tbytes; - } + dev_lstats_read(dev, &packets, &bytes); stats->rx_packets = packets; stats->tx_packets = 0; -- cgit v1.2.3-59-g8ed1b From b4fba476dc4ee56fa1a85659c79fa94bb648b39a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:17 -0800 Subject: veth: use standard dev_lstats_add() and dev_lstats_read() This cleanup will ease u64_stats_t adoption in a single location. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/veth.c | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 9f3c839f9e5f..a552df37a347 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -260,14 +260,8 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); if (likely(veth_forward_skb(rcv, skb, rq, rcv_xdp) == NET_RX_SUCCESS)) { - if (!rcv_xdp) { - struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); - - u64_stats_update_begin(&stats->syncp); - stats->bytes += length; - stats->packets++; - u64_stats_update_end(&stats->syncp); - } + if (!rcv_xdp) + dev_lstats_add(dev, length); } else { drop: atomic64_inc(&priv->dropped); @@ -281,26 +275,11 @@ drop: return NETDEV_TX_OK; } -static u64 veth_stats_tx(struct pcpu_lstats *result, struct net_device *dev) +static u64 veth_stats_tx(struct net_device *dev, u64 *packets, u64 *bytes) { struct veth_priv *priv = netdev_priv(dev); - int cpu; - - result->packets = 0; - result->bytes = 0; - for_each_possible_cpu(cpu) { - struct pcpu_lstats *stats = per_cpu_ptr(dev->lstats, cpu); - u64 packets, bytes; - unsigned int start; - do { - start = u64_stats_fetch_begin_irq(&stats->syncp); - packets = stats->packets; - bytes = stats->bytes; - } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); - result->packets += packets; - result->bytes += bytes; - } + dev_lstats_read(dev, packets, bytes); return atomic64_read(&priv->dropped); } @@ -335,11 +314,11 @@ static void veth_get_stats64(struct net_device *dev, struct veth_priv *priv = netdev_priv(dev); struct net_device *peer; struct veth_rq_stats rx; - struct pcpu_lstats tx; + u64 packets, bytes; - tot->tx_dropped = veth_stats_tx(&tx, dev); - tot->tx_bytes = tx.bytes; - tot->tx_packets = tx.packets; + tot->tx_dropped = veth_stats_tx(dev, &packets, &bytes); + tot->tx_bytes = bytes; + tot->tx_packets = packets; veth_stats_rx(&rx, dev); tot->rx_dropped = rx.xdp_drops; @@ -349,9 +328,9 @@ static void veth_get_stats64(struct net_device *dev, rcu_read_lock(); peer = rcu_dereference(priv->peer); if (peer) { - tot->rx_dropped += veth_stats_tx(&tx, peer); - tot->rx_bytes += tx.bytes; - tot->rx_packets += tx.packets; + tot->rx_dropped += veth_stats_tx(peer, &packets, &bytes); + tot->rx_bytes += bytes; + tot->rx_packets += packets; veth_stats_rx(&rx, peer); tot->tx_bytes += rx.xdp_bytes; -- cgit v1.2.3-59-g8ed1b From 4f77eb0941d182e94b4f54d49cf9de2b19e0a317 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:18 -0800 Subject: vsockmon: use standard dev_lstats_add() and dev_lstats_read() This cleanup will ease u64_stats_t adoption in a single location. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/vsockmon.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vsockmon.c b/drivers/net/vsockmon.c index 14e324b84617..e8563acf98e8 100644 --- a/drivers/net/vsockmon.c +++ b/drivers/net/vsockmon.c @@ -47,13 +47,7 @@ static int vsockmon_close(struct net_device *dev) static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev) { - int len = skb->len; - struct pcpu_lstats *stats = this_cpu_ptr(dev->lstats); - - u64_stats_update_begin(&stats->syncp); - stats->bytes += len; - stats->packets++; - u64_stats_update_end(&stats->syncp); + dev_lstats_add(dev, skb->len); dev_kfree_skb(skb); @@ -63,30 +57,9 @@ static netdev_tx_t vsockmon_xmit(struct sk_buff *skb, struct net_device *dev) static void vsockmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - int i; - u64 bytes = 0, packets = 0; - - for_each_possible_cpu(i) { - const struct pcpu_lstats *vstats; - u64 tbytes, tpackets; - unsigned int start; - - vstats = per_cpu_ptr(dev->lstats, i); + dev_lstats_read(dev, &stats->rx_packets, &stats->rx_bytes); - do { - start = u64_stats_fetch_begin_irq(&vstats->syncp); - tbytes = vstats->bytes; - tpackets = vstats->packets; - } while (u64_stats_fetch_retry_irq(&vstats->syncp, start)); - - packets += tpackets; - bytes += tbytes; - } - - stats->rx_packets = packets; stats->tx_packets = 0; - - stats->rx_bytes = bytes; stats->tx_bytes = 0; } -- cgit v1.2.3-59-g8ed1b From 4a43b1f96b1d94adcd296b2ff80d7294f82a9dc9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:19 -0800 Subject: net: dummy: use standard dev_lstats_add() and dev_lstats_read() This driver can simply use the common infrastructure instead of duplicating it. This cleanup will ease u64_stats_t adoption in a single location. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/dummy.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 54e4d8b07f0e..3031a5fc5427 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -51,41 +51,15 @@ static void set_multicast_list(struct net_device *dev) { } -struct pcpu_dstats { - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; -}; - static void dummy_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - int i; - - for_each_possible_cpu(i) { - const struct pcpu_dstats *dstats; - u64 tbytes, tpackets; - unsigned int start; - - dstats = per_cpu_ptr(dev->dstats, i); - do { - start = u64_stats_fetch_begin_irq(&dstats->syncp); - tbytes = dstats->tx_bytes; - tpackets = dstats->tx_packets; - } while (u64_stats_fetch_retry_irq(&dstats->syncp, start)); - stats->tx_bytes += tbytes; - stats->tx_packets += tpackets; - } + dev_lstats_read(dev, &stats->tx_packets, &stats->tx_bytes); } static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats); - - u64_stats_update_begin(&dstats->syncp); - dstats->tx_packets++; - dstats->tx_bytes += skb->len; - u64_stats_update_end(&dstats->syncp); + dev_lstats_add(dev, skb->len); skb_tx_timestamp(skb); dev_kfree_skb(skb); @@ -94,8 +68,8 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) static int dummy_dev_init(struct net_device *dev) { - dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats); - if (!dev->dstats) + dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); + if (!dev->lstats) return -ENOMEM; return 0; @@ -103,7 +77,7 @@ static int dummy_dev_init(struct net_device *dev) static void dummy_dev_uninit(struct net_device *dev) { - free_percpu(dev->dstats); + free_percpu(dev->lstats); } static int dummy_change_carrier(struct net_device *dev, bool new_carrier) -- cgit v1.2.3-59-g8ed1b From 5260dd3ed1ff7eba39251b28977e4d8950e2f099 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:21 -0800 Subject: tun: switch to u64_stats_t In order to fix this data-race found by KCSAN [1], switch to u64_stats_t helpers. They provide all the needed annotations, without adding extra cost. [1] BUG: KCSAN: data-race in tun_get_user / tun_net_get_stats64 read to 0xffffe8ffffd8aca8 of 8 bytes by task 4882 on cpu 0: tun_net_get_stats64+0x9b/0x230 drivers/net/tun.c:1171 dev_get_stats+0x89/0x1e0 net/core/dev.c:9103 rtnl_fill_stats+0x56/0x370 net/core/rtnetlink.c:1177 rtnl_fill_ifinfo+0xd3b/0x2100 net/core/rtnetlink.c:1667 rtmsg_ifinfo_build_skb+0xb0/0x150 net/core/rtnetlink.c:3472 rtmsg_ifinfo_event.part.0+0x4e/0xb0 net/core/rtnetlink.c:3504 rtmsg_ifinfo_event net/core/rtnetlink.c:3515 [inline] rtmsg_ifinfo+0x85/0x90 net/core/rtnetlink.c:3513 __dev_notify_flags+0x18b/0x200 net/core/dev.c:7649 dev_change_flags+0xb8/0xe0 net/core/dev.c:7691 dev_ifsioc+0x201/0x6a0 net/core/dev_ioctl.c:237 dev_ioctl+0x149/0x660 net/core/dev_ioctl.c:489 sock_do_ioctl+0xdb/0x230 net/socket.c:1061 sock_ioctl+0x3a3/0x5e0 net/socket.c:1189 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0x991/0xc60 fs/ioctl.c:696 write to 0xffffe8ffffd8aca8 of 8 bytes by task 4883 on cpu 1: tun_get_user+0x1d94/0x2ba0 drivers/net/tun.c:2002 tun_chr_write_iter+0x79/0xd0 drivers/net/tun.c:2022 call_write_iter include/linux/fs.h:1895 [inline] new_sync_write+0x388/0x4a0 fs/read_write.c:483 __vfs_write+0xb1/0xc0 fs/read_write.c:496 __kernel_write+0xb8/0x240 fs/read_write.c:515 write_pipe_buf+0xb6/0xf0 fs/splice.c:794 splice_from_pipe_feed fs/splice.c:500 [inline] __splice_from_pipe+0x248/0x480 fs/splice.c:624 splice_from_pipe+0xbb/0x100 fs/splice.c:659 default_file_splice_write+0x45/0x90 fs/splice.c:806 do_splice_from fs/splice.c:848 [inline] direct_splice_actor+0xa0/0xc0 fs/splice.c:1020 splice_direct_to_actor+0x215/0x510 fs/splice.c:975 do_splice_direct+0x161/0x1e0 fs/splice.c:1063 do_sendfile+0x384/0x7f0 fs/read_write.c:1464 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 4883 Comm: syz-executor.1 Not tainted 5.4.0-rc3+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/tun.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dab6cccfeb52..dcb63f1f9110 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -136,10 +136,10 @@ struct tap_filter { #define TUN_FLOW_EXPIRE (3 * HZ) struct tun_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; + u64_stats_t rx_packets; + u64_stats_t rx_bytes; + u64_stats_t tx_packets; + u64_stats_t tx_bytes; struct u64_stats_sync syncp; u32 rx_dropped; u32 tx_dropped; @@ -1167,10 +1167,10 @@ tun_net_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) p = per_cpu_ptr(tun->pcpu_stats, i); do { start = u64_stats_fetch_begin(&p->syncp); - rxpackets = p->rx_packets; - rxbytes = p->rx_bytes; - txpackets = p->tx_packets; - txbytes = p->tx_bytes; + rxpackets = u64_stats_read(&p->rx_packets); + rxbytes = u64_stats_read(&p->rx_bytes); + txpackets = u64_stats_read(&p->tx_packets); + txbytes = u64_stats_read(&p->tx_bytes); } while (u64_stats_fetch_retry(&p->syncp, start)); stats->rx_packets += rxpackets; @@ -1998,8 +1998,8 @@ drop: stats = get_cpu_ptr(tun->pcpu_stats); u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += len; + u64_stats_inc(&stats->rx_packets); + u64_stats_add(&stats->rx_bytes, len); u64_stats_update_end(&stats->syncp); put_cpu_ptr(stats); @@ -2052,8 +2052,8 @@ static ssize_t tun_put_user_xdp(struct tun_struct *tun, stats = get_cpu_ptr(tun->pcpu_stats); u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += ret; + u64_stats_inc(&stats->tx_packets); + u64_stats_add(&stats->tx_bytes, ret); u64_stats_update_end(&stats->syncp); put_cpu_ptr(tun->pcpu_stats); @@ -2147,8 +2147,8 @@ done: /* caller is in process context, */ stats = get_cpu_ptr(tun->pcpu_stats); u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += skb->len + vlan_hlen; + u64_stats_inc(&stats->tx_packets); + u64_stats_add(&stats->tx_bytes, skb->len + vlan_hlen); u64_stats_update_end(&stats->syncp); put_cpu_ptr(tun->pcpu_stats); @@ -2511,8 +2511,8 @@ build: */ stats = this_cpu_ptr(tun->pcpu_stats); u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += datasize; + u64_stats_inc(&stats->rx_packets); + u64_stats_add(&stats->rx_bytes, datasize); u64_stats_update_end(&stats->syncp); if (rxhash) -- cgit v1.2.3-59-g8ed1b From fd2f4737870eb866537fbbffa2b59414b9b0c0a2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Nov 2019 16:27:22 -0800 Subject: net: use u64_stats_t in struct pcpu_lstats In order to fix the data-race found by KCSAN, we can use the new u64_stats_t type and its accessors instead of plain u64 fields. This will still generate optimal code for both 32 and 64 bit platforms. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/loopback.c | 4 ++-- include/linux/netdevice.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 47ad2478b9f3..a1c77cc00416 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -106,8 +106,8 @@ void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes) lb_stats = per_cpu_ptr(dev->lstats, i); do { start = u64_stats_fetch_begin_irq(&lb_stats->syncp); - tpackets = lb_stats->packets; - tbytes = lb_stats->bytes; + tpackets = u64_stats_read(&lb_stats->packets); + tbytes = u64_stats_read(&lb_stats->bytes); } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); *bytes += tbytes; *packets += tpackets; diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 461a36220cf4..f857f01234f7 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2396,8 +2396,8 @@ struct pcpu_sw_netstats { } __aligned(4 * sizeof(u64)); struct pcpu_lstats { - u64 packets; - u64 bytes; + u64_stats_t packets; + u64_stats_t bytes; struct u64_stats_sync syncp; } __aligned(2 * sizeof(u64)); @@ -2408,8 +2408,8 @@ static inline void dev_lstats_add(struct net_device *dev, unsigned int len) struct pcpu_lstats *lstats = this_cpu_ptr(dev->lstats); u64_stats_update_begin(&lstats->syncp); - lstats->bytes += len; - lstats->packets++; + u64_stats_add(&lstats->bytes, len); + u64_stats_inc(&lstats->packets); u64_stats_update_end(&lstats->syncp); } -- cgit v1.2.3-59-g8ed1b From 21c60a28af58d7c376502c26fbb0064b39c32917 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 6 Nov 2019 13:30:55 -0800 Subject: rtw88: signal completion even on firmware-request failure Otherwise, the waiters (e.g., "modprobe rtwpci") will block forever. Fixes: f530c1961af2 ("rtw88: fix potential NULL pointer access for firmware") Cc: Dan Carpenter Cc: Yan-Hsuan Chuang Signed-off-by: Brian Norris Acked-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index de82d08ea29e..ae61415e1665 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -1026,6 +1026,7 @@ static void rtw_load_firmware_cb(const struct firmware *firmware, void *context) if (!firmware || !firmware->data) { rtw_err(rtwdev, "failed to request firmware\n"); + complete_all(&fw->completion); return; } -- cgit v1.2.3-59-g8ed1b From 05a11003a56507023f18d3249a4d4d119c0a3e9c Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 6 Nov 2019 20:04:37 +0200 Subject: ath10k: fix get invalid tx rate for Mesh metric ath10k does not provide transmit rate info per MSDU in tx completion, mark that as -1 so mac80211 will ignore the rates. This fixes mac80211 update Mesh link metric with invalid transmit rate info. Tested HW: QCA9984 Tested FW: 10.4-3.9.0.2-00035 Signed-off-by: Hou Bao Hou Signed-off-by: Anilkumar Kolli Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 4102df016931..39abf8b12903 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -95,6 +95,8 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); + info->status.rates[0].idx = -1; + trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) -- cgit v1.2.3-59-g8ed1b From 402838a05def2e23736cec834752f3edcc38dda7 Mon Sep 17 00:00:00 2001 From: Zhi Chen Date: Wed, 6 Nov 2019 20:04:42 +0200 Subject: ath10k: fix potential issue of peer stats allocation STA number was not restored if OOM happened. Tested: QCA9984 with firmware ver 10.4-3.9.0.1-00018 Signed-off-by: Zhi Chen Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e8bdb2ba9b18..5e3450cfb07b 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6604,6 +6604,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL); if (!arsta->tx_stats) { + ath10k_mac_dec_num_stations(arvif, sta); ret = -ENOMEM; goto exit; } -- cgit v1.2.3-59-g8ed1b From 3b58d6a599ba8c42cb4a3df8080f459ce7edcaa7 Mon Sep 17 00:00:00 2001 From: Ikjoon Jang Date: Wed, 6 Nov 2019 20:04:45 +0200 Subject: ath10k: disable cpuidle during downloading firmware Downloading ath10k firmware needs a large number of IOs and cpuidle's miss predictions make it worse. In the worst case, resume time can be three times longer than the average on sdio. This patch disables cpuidle during firmware downloading by applying PM_QOS_CPU_DMA_LATENCY in ath10k_download_fw(). Tested-on: QCA9880 Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00029 Signed-off-by: Ikjoon Jang Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 36c62d66c19e..4f76ba5d78a9 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "core.h" @@ -1027,6 +1028,7 @@ static int ath10k_download_fw(struct ath10k *ar) u32 address, data_len; const void *data; int ret; + struct pm_qos_request latency_qos; address = ar->hw_params.patch_load_addr; @@ -1060,8 +1062,14 @@ static int ath10k_download_fw(struct ath10k *ar) ret); } - return ath10k_bmi_fast_download(ar, address, - data, data_len); + memset(&latency_qos, 0, sizeof(latency_qos)); + pm_qos_add_request(&latency_qos, PM_QOS_CPU_DMA_LATENCY, 0); + + ret = ath10k_bmi_fast_download(ar, address, data, data_len); + + pm_qos_remove_request(&latency_qos); + + return ret; } void ath10k_core_free_board_files(struct ath10k *ar) -- cgit v1.2.3-59-g8ed1b From 7d13cf1e1d5300e9e0fd5ef110b5abe3854ea90b Mon Sep 17 00:00:00 2001 From: zhong jiang Date: Wed, 30 Oct 2019 11:01:02 +0800 Subject: mac80211_hwsim: use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs fops It is more clear to use DEFINE_DEBUGFS_ATTRIBUTE to define debugfs file operation rather than DEFINE_SIMPLE_ATTRIBUTE. It is detected with the help of coccinelle. Signed-off-by: zhong jiang Link: https://lore.kernel.org/r/1572404462-45462-1-git-send-email-zhongjiang@huawei.com Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 31ae6c4be3a7..03738107fd10 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -769,8 +769,8 @@ static int hwsim_fops_ps_write(void *dat, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, - "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, + "%llu\n"); static int hwsim_write_simulate_radar(void *dat, u64 val) { @@ -781,8 +781,8 @@ static int hwsim_write_simulate_radar(void *dat, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(hwsim_simulate_radar, NULL, - hwsim_write_simulate_radar, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, + hwsim_write_simulate_radar, "%llu\n"); static int hwsim_fops_group_read(void *dat, u64 *val) { @@ -798,9 +798,9 @@ static int hwsim_fops_group_write(void *dat, u64 val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, - hwsim_fops_group_read, hwsim_fops_group_write, - "%llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(hwsim_fops_group, + hwsim_fops_group_read, hwsim_fops_group_write, + "%llx\n"); static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev) -- cgit v1.2.3-59-g8ed1b From caee3174731ca342f8e418c642ae780ea9664a73 Mon Sep 17 00:00:00 2001 From: Christophe Roullier Date: Thu, 7 Nov 2019 09:47:54 +0100 Subject: net: ethernet: stmmac: Add support for syscfg clock Add optional support for syscfg clock in dwmac-stm32.c Now Syscfg clock is activated automatically when syscfg registers are used Signed-off-by: Christophe Roullier Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 595af2ec89fb..95ffaec4ab42 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -155,18 +155,14 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) ret = clk_prepare_enable(dwmac->syscfg_clk); if (ret) return ret; - - if (dwmac->clk_eth_ck) { - ret = clk_prepare_enable(dwmac->clk_eth_ck); - if (ret) { - clk_disable_unprepare(dwmac->syscfg_clk); + ret = clk_prepare_enable(dwmac->clk_eth_ck); + if (ret) { + clk_disable_unprepare(dwmac->syscfg_clk); return ret; - } } } else { clk_disable_unprepare(dwmac->syscfg_clk); - if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); + clk_disable_unprepare(dwmac->clk_eth_ck); } return ret; } @@ -320,12 +316,10 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, return PTR_ERR(dwmac->clk_ethstp); } - /* Clock for sysconfig */ + /* Optional Clock for sysconfig */ dwmac->syscfg_clk = devm_clk_get(dev, "syscfg-clk"); - if (IS_ERR(dwmac->syscfg_clk)) { - dev_err(dev, "No syscfg clock provided...\n"); - return PTR_ERR(dwmac->syscfg_clk); - } + if (IS_ERR(dwmac->syscfg_clk)) + dwmac->syscfg_clk = NULL; /* Get IRQ information early to have an ability to ask for deferred * probe if needed before we went too far with resource allocation. @@ -437,8 +431,7 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) clk_disable_unprepare(dwmac->clk_tx); clk_disable_unprepare(dwmac->syscfg_clk); - if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); + clk_disable_unprepare(dwmac->clk_eth_ck); return ret; } -- cgit v1.2.3-59-g8ed1b From c8119fa8922b0dfdda7c7152f7de55040aa5eb1d Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 7 Nov 2019 22:35:58 +0800 Subject: cxgb4: Use match_string() helper to simplify the code match_string() returns the array index of a matching string. Use it instead of the open-coded implementation. Signed-off-by: YueHaibing Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index c9d3dea4413e..19c11568113a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -4,6 +4,7 @@ */ #include +#include #include "t4_regs.h" #include "cxgb4.h" @@ -776,24 +777,18 @@ static int cudbg_get_mem_region(struct adapter *padap, struct cudbg_mem_desc *mem_desc) { u8 mc, found = 0; - u32 i, idx = 0; - int rc; + u32 idx = 0; + int rc, i; rc = cudbg_meminfo_get_mem_index(padap, meminfo, mem_type, &mc); if (rc) return rc; - for (i = 0; i < ARRAY_SIZE(cudbg_region); i++) { - if (!strcmp(cudbg_region[i], region_name)) { - found = 1; - idx = i; - break; - } - } - if (!found) + i = match_string(cudbg_region, ARRAY_SIZE(cudbg_region), region_name); + if (i < 0) return -EINVAL; - found = 0; + idx = i; for (i = 0; i < meminfo->mem_c; i++) { if (meminfo->mem[i].idx >= ARRAY_SIZE(cudbg_region)) continue; /* Skip holes */ -- cgit v1.2.3-59-g8ed1b From 97c20ea8a115b405288404d8c84a90f43425630d Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Fri, 8 Nov 2019 20:05:22 +0530 Subject: cxgb4: fix 64-bit division on i386 Fix following compile error on i386 architecture. ERROR: "__udivdi3" [drivers/net/ethernet/chelsio/cxgb4/cxgb4.ko] undefined! Fixes: 0e395b3cb1fb ("cxgb4: add FLOWC based QoS offload") Reported-by: kbuild test robot Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index fb28bce01270..143cb1f31bc0 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -307,8 +307,8 @@ static int cxgb4_mqprio_alloc_tc(struct net_device *dev, p.u.params.channel = pi->tx_chan; for (i = 0; i < mqprio->qopt.num_tc; i++) { /* Convert from bytes per second to Kbps */ - p.u.params.minrate = mqprio->min_rate[i] * 8 / 1000; - p.u.params.maxrate = mqprio->max_rate[i] * 8 / 1000; + p.u.params.minrate = div_u64(mqprio->min_rate[i] * 8, 1000); + p.u.params.maxrate = div_u64(mqprio->max_rate[i] * 8, 1000); e = cxgb4_sched_class_alloc(dev, &p); if (!e) { -- cgit v1.2.3-59-g8ed1b From 9d614b6425f844a722630d66b9cb7eb531fd706e Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 6 Nov 2019 02:05:27 -0800 Subject: ice: Use ice_ena_vsi and ice_dis_vsi in DCB configuration flow DCB configuration flow needs to disable and enable only the PF (main) VSI, so use ice_ena_vsi and ice_dis_vsi. To avoid the use of ifdef to control the staticness of these functions, move them to ice_lib.c. Also replace the allocate and copy of old_cfg to kmemdup() in ice_pf_dcb_cfg(). Signed-off-by: Anirudh Venkataramanan Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 -- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 31 ++++++++--- drivers/net/ethernet/intel/ice/ice_lib.c | 56 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.h | 4 ++ drivers/net/ethernet/intel/ice/ice_main.c | 79 ---------------------------- 5 files changed, 84 insertions(+), 90 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index f552a67467aa..7da4ae9608c4 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -502,10 +502,6 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size); void ice_print_link_msg(struct ice_vsi *vsi, bool isup); -#ifdef CONFIG_DCB -int ice_pf_ena_all_vsi(struct ice_pf *pf, bool locked); -void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked); -#endif /* CONFIG_DCB */ int ice_open(struct net_device *netdev); int ice_stop(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 13da89e22123..baea28c712ee 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -150,6 +150,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) { struct ice_dcbx_cfg *old_cfg, *curr_cfg; struct ice_aqc_port_ets_elem buf = { 0 }; + struct ice_vsi *pf_vsi; int ret = 0; curr_cfg = &pf->hw.port_info->local_dcbx_cfg; @@ -169,15 +170,23 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) } /* Store old config in case FW config fails */ - old_cfg = devm_kzalloc(&pf->pdev->dev, sizeof(*old_cfg), GFP_KERNEL); - memcpy(old_cfg, curr_cfg, sizeof(*old_cfg)); + old_cfg = kmemdup(curr_cfg, sizeof(*old_cfg), GFP_KERNEL); + if (!old_cfg) + return -ENOMEM; + + pf_vsi = ice_get_main_vsi(pf); + if (!pf_vsi) { + dev_dbg(&pf->pdev->dev, "PF VSI doesn't exist\n"); + ret = -EINVAL; + goto free_cfg; + } /* avoid race conditions by holding the lock while disabling and * re-enabling the VSI */ if (!locked) rtnl_lock(); - ice_pf_dis_all_vsi(pf, true); + ice_dis_vsi(pf_vsi, true); memcpy(curr_cfg, new_cfg, sizeof(*curr_cfg)); memcpy(&curr_cfg->etsrec, &curr_cfg->etscfg, sizeof(curr_cfg->etsrec)); @@ -204,10 +213,11 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) ice_pf_dcb_recfg(pf); out: - ice_pf_ena_all_vsi(pf, true); + ice_ena_vsi(pf_vsi, true); if (!locked) rtnl_unlock(); - devm_kfree(&pf->pdev->dev, old_cfg); +free_cfg: + kfree(old_cfg); return ret; } @@ -690,6 +700,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, struct ice_dcbx_cfg tmp_dcbx_cfg; bool need_reconfig = false; struct ice_port_info *pi; + struct ice_vsi *pf_vsi; u8 type; int ret; @@ -761,8 +772,14 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, clear_bit(ICE_FLAG_DCB_ENA, pf->flags); } + pf_vsi = ice_get_main_vsi(pf); + if (!pf_vsi) { + dev_dbg(&pf->pdev->dev, "PF VSI doesn't exist\n"); + return; + } + rtnl_lock(); - ice_pf_dis_all_vsi(pf, true); + ice_dis_vsi(pf_vsi, true); ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); if (ret) { @@ -774,6 +791,6 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* changes in configuration update VSI */ ice_pf_dcb_recfg(pf); - ice_pf_ena_all_vsi(pf, true); + ice_ena_vsi(pf_vsi, true); rtnl_unlock(); } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index b1e96cac5b1f..f3cfd5017e29 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2040,6 +2040,62 @@ void ice_vsi_close(struct ice_vsi *vsi) ice_vsi_free_rx_rings(vsi); } +/** + * ice_ena_vsi - resume a VSI + * @vsi: the VSI being resume + * @locked: is the rtnl_lock already held + */ +int ice_ena_vsi(struct ice_vsi *vsi, bool locked) +{ + int err = 0; + + if (!test_bit(__ICE_NEEDS_RESTART, vsi->state)) + return 0; + + clear_bit(__ICE_NEEDS_RESTART, vsi->state); + + if (vsi->netdev && vsi->type == ICE_VSI_PF) { + if (netif_running(vsi->netdev)) { + if (!locked) + rtnl_lock(); + + err = ice_open(vsi->netdev); + + if (!locked) + rtnl_unlock(); + } + } + + return err; +} + +/** + * ice_dis_vsi - pause a VSI + * @vsi: the VSI being paused + * @locked: is the rtnl_lock already held + */ +void ice_dis_vsi(struct ice_vsi *vsi, bool locked) +{ + if (test_bit(__ICE_DOWN, vsi->state)) + return; + + set_bit(__ICE_NEEDS_RESTART, vsi->state); + + if (vsi->type == ICE_VSI_PF && vsi->netdev) { + if (netif_running(vsi->netdev)) { + if (!locked) + rtnl_lock(); + + ice_stop(vsi->netdev); + + if (!locked) + rtnl_unlock(); + } else { + ice_vsi_close(vsi); + } + } +} + /** * ice_free_res - free a block of resources * @res: pointer to the resource diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 8d5a7978e066..2c5c01b7a582 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -62,6 +62,10 @@ int ice_vsi_release(struct ice_vsi *vsi); void ice_vsi_close(struct ice_vsi *vsi); +int ice_ena_vsi(struct ice_vsi *vsi, bool locked); + +void ice_dis_vsi(struct ice_vsi *vsi, bool locked); + int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); int diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 32684fce7de6..5f3a692f28e6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -435,43 +435,12 @@ static void ice_sync_fltr_subtask(struct ice_pf *pf) } } -/** - * ice_dis_vsi - pause a VSI - * @vsi: the VSI being paused - * @locked: is the rtnl_lock already held - */ -static void ice_dis_vsi(struct ice_vsi *vsi, bool locked) -{ - if (test_bit(__ICE_DOWN, vsi->state)) - return; - - set_bit(__ICE_NEEDS_RESTART, vsi->state); - - if (vsi->type == ICE_VSI_PF && vsi->netdev) { - if (netif_running(vsi->netdev)) { - if (!locked) - rtnl_lock(); - - ice_stop(vsi->netdev); - - if (!locked) - rtnl_unlock(); - } else { - ice_vsi_close(vsi); - } - } -} - /** * ice_pf_dis_all_vsi - Pause all VSIs on a PF * @pf: the PF * @locked: is the rtnl_lock already held */ -#ifdef CONFIG_DCB -void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked) -#else static void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked) -#endif /* CONFIG_DCB */ { int v; @@ -4440,54 +4409,6 @@ static void ice_vsi_release_all(struct ice_pf *pf) } } -/** - * ice_ena_vsi - resume a VSI - * @vsi: the VSI being resume - * @locked: is the rtnl_lock already held - */ -static int ice_ena_vsi(struct ice_vsi *vsi, bool locked) -{ - int err = 0; - - if (!test_bit(__ICE_NEEDS_RESTART, vsi->state)) - return 0; - - clear_bit(__ICE_NEEDS_RESTART, vsi->state); - - if (vsi->netdev && vsi->type == ICE_VSI_PF) { - if (netif_running(vsi->netdev)) { - if (!locked) - rtnl_lock(); - - err = ice_open(vsi->netdev); - - if (!locked) - rtnl_unlock(); - } - } - - return err; -} - -/** - * ice_pf_ena_all_vsi - Resume all VSIs on a PF - * @pf: the PF - * @locked: is the rtnl_lock already held - */ -#ifdef CONFIG_DCB -int ice_pf_ena_all_vsi(struct ice_pf *pf, bool locked) -{ - int v; - - ice_for_each_vsi(pf, v) - if (pf->vsi[v]) - if (ice_ena_vsi(pf->vsi[v], locked)) - return -EIO; - - return 0; -} -#endif /* CONFIG_DCB */ - /** * ice_vsi_rebuild_by_type - Rebuild VSI of a given type * @pf: pointer to the PF instance -- cgit v1.2.3-59-g8ed1b From 1ddef455f4a8ba6374ce6a3ec88c815b3d4a4ad2 Mon Sep 17 00:00:00 2001 From: Usha Ketineni Date: Wed, 6 Nov 2019 02:05:28 -0800 Subject: ice: Add NDO callback to set the maximum per-queue bitrate Allow for rate limiting Tx queues. Bitrate is set in Mbps(megabits per second). Mbps max-rate is set for the queue via sysfs: /sys/class/net//queues/tx-/tx_maxrate ex: echo 100 >/sys/class/net/ens7/queues/tx-0/tx_maxrate echo 200 >/sys/class/net/ens7/queues/tx-1/tx_maxrate Note: A value of zero for tx_maxrate means disabled, default is disabled. Signed-off-by: Usha Ketineni Co-developed-by: Tarun Singh Signed-off-by: Tarun Singh Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 46 + drivers/net/ethernet/intel/ice/ice_common.c | 10 +- drivers/net/ethernet/intel/ice/ice_common.h | 2 + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 10 + drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 8 + drivers/net/ethernet/intel/ice/ice_main.c | 43 + drivers/net/ethernet/intel/ice/ice_sched.c | 1264 ++++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_sched.h | 39 + drivers/net/ethernet/intel/ice/ice_switch.h | 5 - drivers/net/ethernet/intel/ice/ice_type.h | 63 +- 10 files changed, 1480 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index 622c666399fd..5421fc413f94 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -742,6 +742,10 @@ struct ice_aqc_add_elem { struct ice_aqc_txsched_elem_data generic[1]; }; +struct ice_aqc_conf_elem { + struct ice_aqc_txsched_elem_data generic[1]; +}; + struct ice_aqc_get_elem { struct ice_aqc_txsched_elem_data generic[1]; }; @@ -783,6 +787,44 @@ struct ice_aqc_port_ets_elem { __le32 tc_node_teid[8]; /* Used for response, reserved in command */ }; +/* Rate limiting profile for + * Add RL profile (indirect 0x0410) + * Query RL profile (indirect 0x0411) + * Remove RL profile (indirect 0x0415) + * These indirect commands acts on single or multiple + * RL profiles with specified data. + */ +struct ice_aqc_rl_profile { + __le16 num_profiles; + __le16 num_processed; /* Only for response. Reserved in Command. */ + u8 reserved[4]; + __le32 addr_high; + __le32 addr_low; +}; + +struct ice_aqc_rl_profile_elem { + u8 level; + u8 flags; +#define ICE_AQC_RL_PROFILE_TYPE_S 0x0 +#define ICE_AQC_RL_PROFILE_TYPE_M (0x3 << ICE_AQC_RL_PROFILE_TYPE_S) +#define ICE_AQC_RL_PROFILE_TYPE_CIR 0 +#define ICE_AQC_RL_PROFILE_TYPE_EIR 1 +#define ICE_AQC_RL_PROFILE_TYPE_SRL 2 +/* The following flag is used for Query RL Profile Data */ +#define ICE_AQC_RL_PROFILE_INVAL_S 0x7 +#define ICE_AQC_RL_PROFILE_INVAL_M (0x1 << ICE_AQC_RL_PROFILE_INVAL_S) + + __le16 profile_id; + __le16 max_burst_size; + __le16 rl_multiply; + __le16 wake_up_calc; + __le16 rl_encode; +}; + +struct ice_aqc_rl_profile_generic_elem { + struct ice_aqc_rl_profile_elem generic[1]; +}; + /* Query Scheduler Resource Allocation (indirect 0x0412) * This indirect command retrieves the scheduler resources allocated by * EMP Firmware to the given PF. @@ -1657,6 +1699,7 @@ struct ice_aq_desc { struct ice_aqc_sched_elem_cmd sched_elem_cmd; struct ice_aqc_query_txsched_res query_sched_res; struct ice_aqc_query_port_ets port_ets; + struct ice_aqc_rl_profile rl_profile; struct ice_aqc_nvm nvm; struct ice_aqc_nvm_checksum nvm_checksum; struct ice_aqc_pf_vf_msg virt; @@ -1758,12 +1801,15 @@ enum ice_adminq_opc { /* transmit scheduler commands */ ice_aqc_opc_get_dflt_topo = 0x0400, ice_aqc_opc_add_sched_elems = 0x0401, + ice_aqc_opc_cfg_sched_elems = 0x0403, ice_aqc_opc_get_sched_elems = 0x0404, ice_aqc_opc_suspend_sched_elems = 0x0409, ice_aqc_opc_resume_sched_elems = 0x040A, ice_aqc_opc_query_port_ets = 0x040E, ice_aqc_opc_delete_sched_elems = 0x040F, + ice_aqc_opc_add_rl_profiles = 0x0410, ice_aqc_opc_query_sched_res = 0x0412, + ice_aqc_opc_remove_rl_profiles = 0x0415, /* PHY commands */ ice_aqc_opc_get_phy_caps = 0x0600, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 9972929053aa..3e0d50c1bc7a 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -855,6 +855,9 @@ enum ice_status ice_init_hw(struct ice_hw *hw) goto err_unroll_sched; } INIT_LIST_HEAD(&hw->agg_list); + /* Initialize max burst size */ + if (!hw->max_burst_size) + ice_cfg_rl_burst_size(hw, ICE_SCHED_DFLT_BURST_SIZE); status = ice_init_fltr_mgmt_struct(hw); if (status) @@ -3260,7 +3263,7 @@ ice_set_ctx(u8 *src_ctx, u8 *dest_ctx, const struct ice_ctx_ele *ce_info) * @tc: TC number * @q_handle: software queue handle */ -static struct ice_q_ctx * +struct ice_q_ctx * ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle) { struct ice_vsi_ctx *vsi; @@ -3357,9 +3360,12 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle, node.node_teid = buf->txqs[0].q_teid; node.data.elem_type = ICE_AQC_ELEM_TYPE_LEAF; q_ctx->q_handle = q_handle; + q_ctx->q_teid = le32_to_cpu(node.node_teid); - /* add a leaf node into schduler tree queue layer */ + /* add a leaf node into scheduler tree queue layer */ status = ice_sched_add_node(pi, hw->num_tx_sched_layers - 1, &node); + if (!status) + status = ice_sched_replay_q_bw(pi, q_ctx); ena_txq_exit: mutex_unlock(&pi->sched_lock); diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index db9a2d48202f..5a52f3b3e688 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -141,6 +141,8 @@ ice_ena_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 q_handle, enum ice_status ice_replay_vsi(struct ice_hw *hw, u16 vsi_handle); void ice_replay_post(struct ice_hw *hw); void ice_output_fw_log(struct ice_hw *hw, struct ice_aq_desc *desc, void *buf); +struct ice_q_ctx * +ice_get_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 q_handle); void ice_stat_update40(struct ice_hw *hw, u32 reg, bool prev_stat_loaded, u64 *prev_stat, u64 *cur_stat); diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index baea28c712ee..c00c68bacadb 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -101,6 +101,16 @@ u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg) return ret; } +/** + * ice_dcb_get_tc - Get the TC associated with the queue + * @vsi: ptr to the VSI + * @queue_index: queue number associated with VSI + */ +u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index) +{ + return vsi->tx_rings[queue_index]->dcb_tc; +} + /** * ice_vsi_cfg_dcb_rings - Update rings to reflect DCB TC * @vsi: VSI owner of rings being updated diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index d11a0aab01ac..59e40cf2dd73 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -14,6 +14,7 @@ void ice_dcb_rebuild(struct ice_pf *pf); u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg); u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg); +u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); int ice_init_pf_dcb(struct ice_pf *pf, bool locked); void ice_update_dcb_stats(struct ice_pf *pf); @@ -42,6 +43,13 @@ static inline u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg __always_unused *dcbcfg) return 1; } +static inline u8 +ice_dcb_get_tc(struct ice_vsi __always_unused *vsi, + int __always_unused queue_index) +{ + return 0; +} + static inline int ice_init_pf_dcb(struct ice_pf *pf, bool __always_unused locked) { diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5f3a692f28e6..cacbe2103b28 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3648,6 +3648,48 @@ static void ice_set_rx_mode(struct net_device *netdev) ice_service_task_schedule(vsi->back); } +/** + * ice_set_tx_maxrate - NDO callback to set the maximum per-queue bitrate + * @netdev: network interface device structure + * @queue_index: Queue ID + * @maxrate: maximum bandwidth in Mbps + */ +static int +ice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate) +{ + struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_vsi *vsi = np->vsi; + enum ice_status status; + u16 q_handle; + u8 tc; + + /* Validate maxrate requested is within permitted range */ + if (maxrate && (maxrate > (ICE_SCHED_MAX_BW / 1000))) { + netdev_err(netdev, + "Invalid max rate %d specified for the queue %d\n", + maxrate, queue_index); + return -EINVAL; + } + + q_handle = vsi->tx_rings[queue_index]->q_handle; + tc = ice_dcb_get_tc(vsi, queue_index); + + /* Set BW back to default, when user set maxrate to 0 */ + if (!maxrate) + status = ice_cfg_q_bw_dflt_lmt(vsi->port_info, vsi->idx, tc, + q_handle, ICE_MAX_BW); + else + status = ice_cfg_q_bw_lmt(vsi->port_info, vsi->idx, tc, + q_handle, ICE_MAX_BW, maxrate * 1000); + if (status) { + netdev_err(netdev, + "Unable to set Tx max rate, error %d\n", status); + return -EIO; + } + + return 0; +} + /** * ice_fdb_add - add an entry to the hardware database * @ndm: the input from the stack @@ -5159,6 +5201,7 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ice_change_mtu, .ndo_get_stats64 = ice_get_stats64, + .ndo_set_tx_maxrate = ice_set_tx_maxrate, .ndo_set_vf_spoofchk = ice_set_vf_spoofchk, .ndo_set_vf_mac = ice_set_vf_mac, .ndo_get_vf_config = ice_get_vf_cfg, diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index fc624b73d05d..6f8a83f92c8d 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -410,6 +410,27 @@ ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req, grps_added, cd); } +/** + * ice_aq_cfg_sched_elems - configures scheduler elements + * @hw: pointer to the HW struct + * @elems_req: number of elements to configure + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @elems_cfgd: returns total number of elements configured + * @cd: pointer to command details structure or NULL + * + * Configure scheduling elements (0x0403) + */ +static enum ice_status +ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req, + struct ice_aqc_conf_elem *buf, u16 buf_size, + u16 *elems_cfgd, struct ice_sq_cd *cd) +{ + return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems, + elems_req, (void *)buf, buf_size, + elems_cfgd, cd); +} + /** * ice_aq_suspend_sched_elems - suspend scheduler elements * @hw: pointer to the HW struct @@ -556,6 +577,149 @@ ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs) return 0; } +/** + * ice_aq_rl_profile - performs a rate limiting task + * @hw: pointer to the HW struct + * @opcode:opcode for add, query, or remove profile(s) + * @num_profiles: the number of profiles + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @num_processed: number of processed add or remove profile(s) to return + * @cd: pointer to command details structure + * + * RL profile function to add, query, or remove profile(s) + */ +static enum ice_status +ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode, + u16 num_profiles, struct ice_aqc_rl_profile_generic_elem *buf, + u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd) +{ + struct ice_aqc_rl_profile *cmd; + struct ice_aq_desc desc; + enum ice_status status; + + cmd = &desc.params.rl_profile; + + ice_fill_dflt_direct_cmd_desc(&desc, opcode); + desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); + cmd->num_profiles = cpu_to_le16(num_profiles); + status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); + if (!status && num_processed) + *num_processed = le16_to_cpu(cmd->num_processed); + return status; +} + +/** + * ice_aq_add_rl_profile - adds rate limiting profile(s) + * @hw: pointer to the HW struct + * @num_profiles: the number of profile(s) to be add + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @num_profiles_added: total number of profiles added to return + * @cd: pointer to command details structure + * + * Add RL profile (0x0410) + */ +static enum ice_status +ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles, + struct ice_aqc_rl_profile_generic_elem *buf, + u16 buf_size, u16 *num_profiles_added, + struct ice_sq_cd *cd) +{ + return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, + num_profiles, buf, + buf_size, num_profiles_added, cd); +} + +/** + * ice_aq_remove_rl_profile - removes RL profile(s) + * @hw: pointer to the HW struct + * @num_profiles: the number of profile(s) to remove + * @buf: pointer to buffer + * @buf_size: buffer size in bytes + * @num_profiles_removed: total number of profiles removed to return + * @cd: pointer to command details structure or NULL + * + * Remove RL profile (0x0415) + */ +static enum ice_status +ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles, + struct ice_aqc_rl_profile_generic_elem *buf, + u16 buf_size, u16 *num_profiles_removed, + struct ice_sq_cd *cd) +{ + return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles, + num_profiles, buf, + buf_size, num_profiles_removed, cd); +} + +/** + * ice_sched_del_rl_profile - remove RL profile + * @hw: pointer to the HW struct + * @rl_info: rate limit profile information + * + * If the profile ID is not referenced anymore, it removes profile ID with + * its associated parameters from HW DB,and locally. The caller needs to + * hold scheduler lock. + */ +static enum ice_status +ice_sched_del_rl_profile(struct ice_hw *hw, + struct ice_aqc_rl_profile_info *rl_info) +{ + struct ice_aqc_rl_profile_generic_elem *buf; + u16 num_profiles_removed; + enum ice_status status; + u16 num_profiles = 1; + + if (rl_info->prof_id_ref != 0) + return ICE_ERR_IN_USE; + + /* Safe to remove profile ID */ + buf = (struct ice_aqc_rl_profile_generic_elem *) + &rl_info->profile; + status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf), + &num_profiles_removed, NULL); + if (status || num_profiles_removed != num_profiles) + return ICE_ERR_CFG; + + /* Delete stale entry now */ + list_del(&rl_info->list_entry); + devm_kfree(ice_hw_to_dev(hw), rl_info); + return status; +} + +/** + * ice_sched_clear_rl_prof - clears RL prof entries + * @pi: port information structure + * + * This function removes all RL profile from HW as well as from SW DB. + */ +static void ice_sched_clear_rl_prof(struct ice_port_info *pi) +{ + u16 ln; + + for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) { + struct ice_aqc_rl_profile_info *rl_prof_elem; + struct ice_aqc_rl_profile_info *rl_prof_tmp; + + list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp, + &pi->rl_prof_list[ln], list_entry) { + struct ice_hw *hw = pi->hw; + enum ice_status status; + + rl_prof_elem->prof_id_ref = 0; + status = ice_sched_del_rl_profile(hw, rl_prof_elem); + if (status) { + ice_debug(hw, ICE_DBG_SCHED, + "Remove rl profile failed\n"); + /* On error, free mem required */ + list_del(&rl_prof_elem->list_entry); + devm_kfree(ice_hw_to_dev(hw), rl_prof_elem); + } + } + } +} + /** * ice_sched_clear_agg - clears the aggregator related information * @hw: pointer to the hardware structure @@ -592,6 +756,8 @@ static void ice_sched_clear_tx_topo(struct ice_port_info *pi) { if (!pi) return; + /* remove RL profiles related lists */ + ice_sched_clear_rl_prof(pi); if (pi->root) { ice_free_sched_node(pi, pi->root); pi->root = NULL; @@ -1014,6 +1180,8 @@ enum ice_status ice_sched_init_port(struct ice_port_info *pi) /* initialize the port for handling the scheduler tree */ pi->port_state = ICE_SCHED_PORT_STATE_READY; mutex_init(&pi->sched_lock); + for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++) + INIT_LIST_HEAD(&pi->rl_prof_list[i]); err_init_port: if (status && pi->root) { @@ -1062,8 +1230,8 @@ enum ice_status ice_sched_query_res_alloc(struct ice_hw *hw) * and so on. This array will be populated from root (index 0) to * qgroup layer 7. Leaf node has no children. */ - for (i = 0; i < hw->num_tx_sched_layers; i++) { - max_sibl = buf->layer_props[i].max_sibl_grp_sz; + for (i = 0; i < hw->num_tx_sched_layers - 1; i++) { + max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz; hw->max_children[i] = le16_to_cpu(max_sibl); } @@ -1670,3 +1838,1095 @@ enum ice_status ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle) { return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN); } + +/** + * ice_sched_rm_unused_rl_prof - remove unused RL profile + * @pi: port information structure + * + * This function removes unused rate limit profiles from the HW and + * SW DB. The caller needs to hold scheduler lock. + */ +static void ice_sched_rm_unused_rl_prof(struct ice_port_info *pi) +{ + u16 ln; + + for (ln = 0; ln < pi->hw->num_tx_sched_layers; ln++) { + struct ice_aqc_rl_profile_info *rl_prof_elem; + struct ice_aqc_rl_profile_info *rl_prof_tmp; + + list_for_each_entry_safe(rl_prof_elem, rl_prof_tmp, + &pi->rl_prof_list[ln], list_entry) { + if (!ice_sched_del_rl_profile(pi->hw, rl_prof_elem)) + ice_debug(pi->hw, ICE_DBG_SCHED, + "Removed rl profile\n"); + } + } +} + +/** + * ice_sched_update_elem - update element + * @hw: pointer to the HW struct + * @node: pointer to node + * @info: node info to update + * + * It updates the HW DB, and local SW DB of node. It updates the scheduling + * parameters of node from argument info data buffer (Info->data buf) and + * returns success or error on config sched element failure. The caller + * needs to hold scheduler lock. + */ +static enum ice_status +ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node, + struct ice_aqc_txsched_elem_data *info) +{ + struct ice_aqc_conf_elem buf; + enum ice_status status; + u16 elem_cfgd = 0; + u16 num_elems = 1; + + buf.generic[0] = *info; + /* Parent TEID is reserved field in this aq call */ + buf.generic[0].parent_teid = 0; + /* Element type is reserved field in this aq call */ + buf.generic[0].data.elem_type = 0; + /* Flags is reserved field in this aq call */ + buf.generic[0].data.flags = 0; + + /* Update HW DB */ + /* Configure element node */ + status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf), + &elem_cfgd, NULL); + if (status || elem_cfgd != num_elems) { + ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n"); + return ICE_ERR_CFG; + } + + /* Config success case */ + /* Now update local SW DB */ + /* Only copy the data portion of info buffer */ + node->info.data = info->data; + return status; +} + +/** + * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params + * @hw: pointer to the HW struct + * @node: sched node to configure + * @rl_type: rate limit type CIR, EIR, or shared + * @bw_alloc: BW weight/allocation + * + * This function configures node element's BW allocation. + */ +static enum ice_status +ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node, + enum ice_rl_type rl_type, u8 bw_alloc) +{ + struct ice_aqc_txsched_elem_data buf; + struct ice_aqc_txsched_elem *data; + enum ice_status status; + + buf = node->info; + data = &buf.data; + if (rl_type == ICE_MIN_BW) { + data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; + data->cir_bw.bw_alloc = cpu_to_le16(bw_alloc); + } else if (rl_type == ICE_MAX_BW) { + data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; + data->eir_bw.bw_alloc = cpu_to_le16(bw_alloc); + } else { + return ICE_ERR_PARAM; + } + + /* Configure element */ + status = ice_sched_update_elem(hw, node, &buf); + return status; +} + +/** + * ice_set_clear_cir_bw - set or clear CIR BW + * @bw_t_info: bandwidth type information structure + * @bw: bandwidth in Kbps - Kilo bits per sec + * + * Save or clear CIR bandwidth (BW) in the passed param bw_t_info. + */ +static void +ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) +{ + if (bw == ICE_SCHED_DFLT_BW) { + clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); + bw_t_info->cir_bw.bw = 0; + } else { + /* Save type of BW information */ + set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); + bw_t_info->cir_bw.bw = bw; + } +} + +/** + * ice_set_clear_eir_bw - set or clear EIR BW + * @bw_t_info: bandwidth type information structure + * @bw: bandwidth in Kbps - Kilo bits per sec + * + * Save or clear EIR bandwidth (BW) in the passed param bw_t_info. + */ +static void +ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) +{ + if (bw == ICE_SCHED_DFLT_BW) { + clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); + bw_t_info->eir_bw.bw = 0; + } else { + /* EIR BW and Shared BW profiles are mutually exclusive and + * hence only one of them may be set for any given element. + * First clear earlier saved shared BW information. + */ + clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); + bw_t_info->shared_bw = 0; + /* save EIR BW information */ + set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); + bw_t_info->eir_bw.bw = bw; + } +} + +/** + * ice_set_clear_shared_bw - set or clear shared BW + * @bw_t_info: bandwidth type information structure + * @bw: bandwidth in Kbps - Kilo bits per sec + * + * Save or clear shared bandwidth (BW) in the passed param bw_t_info. + */ +static void +ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw) +{ + if (bw == ICE_SCHED_DFLT_BW) { + clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); + bw_t_info->shared_bw = 0; + } else { + /* EIR BW and Shared BW profiles are mutually exclusive and + * hence only one of them may be set for any given element. + * First clear earlier saved EIR BW information. + */ + clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); + bw_t_info->eir_bw.bw = 0; + /* save shared BW information */ + set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); + bw_t_info->shared_bw = bw; + } +} + +/** + * ice_sched_calc_wakeup - calculate RL profile wakeup parameter + * @bw: bandwidth in Kbps + * + * This function calculates the wakeup parameter of RL profile. + */ +static u16 ice_sched_calc_wakeup(s32 bw) +{ + s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f; + s32 wakeup_f_int; + u16 wakeup = 0; + + /* Get the wakeup integer value */ + bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE); + wakeup_int = div64_long(ICE_RL_PROF_FREQUENCY, bytes_per_sec); + if (wakeup_int > 63) { + wakeup = (u16)((1 << 15) | wakeup_int); + } else { + /* Calculate fraction value up to 4 decimals + * Convert Integer value to a constant multiplier + */ + wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int; + wakeup_a = div64_long((s64)ICE_RL_PROF_MULTIPLIER * + ICE_RL_PROF_FREQUENCY, + bytes_per_sec); + + /* Get Fraction value */ + wakeup_f = wakeup_a - wakeup_b; + + /* Round up the Fractional value via Ceil(Fractional value) */ + if (wakeup_f > div64_long(ICE_RL_PROF_MULTIPLIER, 2)) + wakeup_f += 1; + + wakeup_f_int = (s32)div64_long(wakeup_f * ICE_RL_PROF_FRACTION, + ICE_RL_PROF_MULTIPLIER); + wakeup |= (u16)(wakeup_int << 9); + wakeup |= (u16)(0x1ff & wakeup_f_int); + } + + return wakeup; +} + +/** + * ice_sched_bw_to_rl_profile - convert BW to profile parameters + * @bw: bandwidth in Kbps + * @profile: profile parameters to return + * + * This function converts the BW to profile structure format. + */ +static enum ice_status +ice_sched_bw_to_rl_profile(u32 bw, struct ice_aqc_rl_profile_elem *profile) +{ + enum ice_status status = ICE_ERR_PARAM; + s64 bytes_per_sec, ts_rate, mv_tmp; + bool found = false; + s32 encode = 0; + s64 mv = 0; + s32 i; + + /* Bw settings range is from 0.5Mb/sec to 100Gb/sec */ + if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW) + return status; + + /* Bytes per second from Kbps */ + bytes_per_sec = div64_long(((s64)bw * 1000), BITS_PER_BYTE); + + /* encode is 6 bits but really useful are 5 bits */ + for (i = 0; i < 64; i++) { + u64 pow_result = BIT_ULL(i); + + ts_rate = div64_long((s64)ICE_RL_PROF_FREQUENCY, + pow_result * ICE_RL_PROF_TS_MULTIPLIER); + if (ts_rate <= 0) + continue; + + /* Multiplier value */ + mv_tmp = div64_long(bytes_per_sec * ICE_RL_PROF_MULTIPLIER, + ts_rate); + + /* Round to the nearest ICE_RL_PROF_MULTIPLIER */ + mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER); + + /* First multiplier value greater than the given + * accuracy bytes + */ + if (mv > ICE_RL_PROF_ACCURACY_BYTES) { + encode = i; + found = true; + break; + } + } + if (found) { + u16 wm; + + wm = ice_sched_calc_wakeup(bw); + profile->rl_multiply = cpu_to_le16(mv); + profile->wake_up_calc = cpu_to_le16(wm); + profile->rl_encode = cpu_to_le16(encode); + status = 0; + } else { + status = ICE_ERR_DOES_NOT_EXIST; + } + + return status; +} + +/** + * ice_sched_add_rl_profile - add RL profile + * @pi: port information structure + * @rl_type: type of rate limit BW - min, max, or shared + * @bw: bandwidth in Kbps - Kilo bits per sec + * @layer_num: specifies in which layer to create profile + * + * This function first checks the existing list for corresponding BW + * parameter. If it exists, it returns the associated profile otherwise + * it creates a new rate limit profile for requested BW, and adds it to + * the HW DB and local list. It returns the new profile or null on error. + * The caller needs to hold the scheduler lock. + */ +static struct ice_aqc_rl_profile_info * +ice_sched_add_rl_profile(struct ice_port_info *pi, + enum ice_rl_type rl_type, u32 bw, u8 layer_num) +{ + struct ice_aqc_rl_profile_generic_elem *buf; + struct ice_aqc_rl_profile_info *rl_prof_elem; + u16 profiles_added = 0, num_profiles = 1; + enum ice_status status; + struct ice_hw *hw; + u8 profile_type; + + if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM) + return NULL; + switch (rl_type) { + case ICE_MIN_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; + break; + case ICE_MAX_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; + break; + case ICE_SHARED_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; + break; + default: + return NULL; + } + + if (!pi) + return NULL; + hw = pi->hw; + list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num], + list_entry) + if (rl_prof_elem->profile.flags == profile_type && + rl_prof_elem->bw == bw) + /* Return existing profile ID info */ + return rl_prof_elem; + + /* Create new profile ID */ + rl_prof_elem = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rl_prof_elem), + GFP_KERNEL); + + if (!rl_prof_elem) + return NULL; + + status = ice_sched_bw_to_rl_profile(bw, &rl_prof_elem->profile); + if (status) + goto exit_add_rl_prof; + + rl_prof_elem->bw = bw; + /* layer_num is zero relative, and fw expects level from 1 to 9 */ + rl_prof_elem->profile.level = layer_num + 1; + rl_prof_elem->profile.flags = profile_type; + rl_prof_elem->profile.max_burst_size = cpu_to_le16(hw->max_burst_size); + + /* Create new entry in HW DB */ + buf = (struct ice_aqc_rl_profile_generic_elem *) + &rl_prof_elem->profile; + status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf), + &profiles_added, NULL); + if (status || profiles_added != num_profiles) + goto exit_add_rl_prof; + + /* Good entry - add in the list */ + rl_prof_elem->prof_id_ref = 0; + list_add(&rl_prof_elem->list_entry, &pi->rl_prof_list[layer_num]); + return rl_prof_elem; + +exit_add_rl_prof: + devm_kfree(ice_hw_to_dev(hw), rl_prof_elem); + return NULL; +} + +/** + * ice_sched_cfg_node_bw_lmt - configure node sched params + * @hw: pointer to the HW struct + * @node: sched node to configure + * @rl_type: rate limit type CIR, EIR, or shared + * @rl_prof_id: rate limit profile ID + * + * This function configures node element's BW limit. + */ +static enum ice_status +ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node, + enum ice_rl_type rl_type, u16 rl_prof_id) +{ + struct ice_aqc_txsched_elem_data buf; + struct ice_aqc_txsched_elem *data; + + buf = node->info; + data = &buf.data; + switch (rl_type) { + case ICE_MIN_BW: + data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; + data->cir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id); + break; + case ICE_MAX_BW: + /* EIR BW and Shared BW profiles are mutually exclusive and + * hence only one of them may be set for any given element + */ + if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED) + return ICE_ERR_CFG; + data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; + data->eir_bw.bw_profile_idx = cpu_to_le16(rl_prof_id); + break; + case ICE_SHARED_BW: + /* Check for removing shared BW */ + if (rl_prof_id == ICE_SCHED_NO_SHARED_RL_PROF_ID) { + /* remove shared profile */ + data->valid_sections &= ~ICE_AQC_ELEM_VALID_SHARED; + data->srl_id = 0; /* clear SRL field */ + + /* enable back EIR to default profile */ + data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; + data->eir_bw.bw_profile_idx = + cpu_to_le16(ICE_SCHED_DFLT_RL_PROF_ID); + break; + } + /* EIR BW and Shared BW profiles are mutually exclusive and + * hence only one of them may be set for any given element + */ + if ((data->valid_sections & ICE_AQC_ELEM_VALID_EIR) && + (le16_to_cpu(data->eir_bw.bw_profile_idx) != + ICE_SCHED_DFLT_RL_PROF_ID)) + return ICE_ERR_CFG; + /* EIR BW is set to default, disable it */ + data->valid_sections &= ~ICE_AQC_ELEM_VALID_EIR; + /* Okay to enable shared BW now */ + data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED; + data->srl_id = cpu_to_le16(rl_prof_id); + break; + default: + /* Unknown rate limit type */ + return ICE_ERR_PARAM; + } + + /* Configure element */ + return ice_sched_update_elem(hw, node, &buf); +} + +/** + * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID + * @node: sched node + * @rl_type: rate limit type + * + * If existing profile matches, it returns the corresponding rate + * limit profile ID, otherwise it returns an invalid ID as error. + */ +static u16 +ice_sched_get_node_rl_prof_id(struct ice_sched_node *node, + enum ice_rl_type rl_type) +{ + u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID; + struct ice_aqc_txsched_elem *data; + + data = &node->info.data; + switch (rl_type) { + case ICE_MIN_BW: + if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR) + rl_prof_id = le16_to_cpu(data->cir_bw.bw_profile_idx); + break; + case ICE_MAX_BW: + if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR) + rl_prof_id = le16_to_cpu(data->eir_bw.bw_profile_idx); + break; + case ICE_SHARED_BW: + if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED) + rl_prof_id = le16_to_cpu(data->srl_id); + break; + default: + break; + } + + return rl_prof_id; +} + +/** + * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer + * @pi: port information structure + * @rl_type: type of rate limit BW - min, max, or shared + * @layer_index: layer index + * + * This function returns requested profile creation layer. + */ +static u8 +ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type, + u8 layer_index) +{ + struct ice_hw *hw = pi->hw; + + if (layer_index >= hw->num_tx_sched_layers) + return ICE_SCHED_INVAL_LAYER_NUM; + switch (rl_type) { + case ICE_MIN_BW: + if (hw->layer_info[layer_index].max_cir_rl_profiles) + return layer_index; + break; + case ICE_MAX_BW: + if (hw->layer_info[layer_index].max_eir_rl_profiles) + return layer_index; + break; + case ICE_SHARED_BW: + /* if current layer doesn't support SRL profile creation + * then try a layer up or down. + */ + if (hw->layer_info[layer_index].max_srl_profiles) + return layer_index; + else if (layer_index < hw->num_tx_sched_layers - 1 && + hw->layer_info[layer_index + 1].max_srl_profiles) + return layer_index + 1; + else if (layer_index > 0 && + hw->layer_info[layer_index - 1].max_srl_profiles) + return layer_index - 1; + break; + default: + break; + } + return ICE_SCHED_INVAL_LAYER_NUM; +} + +/** + * ice_sched_get_srl_node - get shared rate limit node + * @node: tree node + * @srl_layer: shared rate limit layer + * + * This function returns SRL node to be used for shared rate limit purpose. + * The caller needs to hold scheduler lock. + */ +static struct ice_sched_node * +ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer) +{ + if (srl_layer > node->tx_sched_layer) + return node->children[0]; + else if (srl_layer < node->tx_sched_layer) + /* Node can't be created without a parent. It will always + * have a valid parent except root node. + */ + return node->parent; + else + return node; +} + +/** + * ice_sched_rm_rl_profile - remove RL profile ID + * @pi: port information structure + * @layer_num: layer number where profiles are saved + * @profile_type: profile type like EIR, CIR, or SRL + * @profile_id: profile ID to remove + * + * This function removes rate limit profile from layer 'layer_num' of type + * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold + * scheduler lock. + */ +static enum ice_status +ice_sched_rm_rl_profile(struct ice_port_info *pi, u8 layer_num, u8 profile_type, + u16 profile_id) +{ + struct ice_aqc_rl_profile_info *rl_prof_elem; + enum ice_status status = 0; + + if (layer_num >= ICE_AQC_TOPO_MAX_LEVEL_NUM) + return ICE_ERR_PARAM; + /* Check the existing list for RL profile */ + list_for_each_entry(rl_prof_elem, &pi->rl_prof_list[layer_num], + list_entry) + if (rl_prof_elem->profile.flags == profile_type && + le16_to_cpu(rl_prof_elem->profile.profile_id) == + profile_id) { + if (rl_prof_elem->prof_id_ref) + rl_prof_elem->prof_id_ref--; + + /* Remove old profile ID from database */ + status = ice_sched_del_rl_profile(pi->hw, rl_prof_elem); + if (status && status != ICE_ERR_IN_USE) + ice_debug(pi->hw, ICE_DBG_SCHED, + "Remove rl profile failed\n"); + break; + } + if (status == ICE_ERR_IN_USE) + status = 0; + return status; +} + +/** + * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default + * @pi: port information structure + * @node: pointer to node structure + * @rl_type: rate limit type min, max, or shared + * @layer_num: layer number where RL profiles are saved + * + * This function configures node element's BW rate limit profile ID of + * type CIR, EIR, or SRL to default. This function needs to be called + * with the scheduler lock held. + */ +static enum ice_status +ice_sched_set_node_bw_dflt(struct ice_port_info *pi, + struct ice_sched_node *node, + enum ice_rl_type rl_type, u8 layer_num) +{ + enum ice_status status; + struct ice_hw *hw; + u8 profile_type; + u16 rl_prof_id; + u16 old_id; + + hw = pi->hw; + switch (rl_type) { + case ICE_MIN_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; + rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; + break; + case ICE_MAX_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; + rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; + break; + case ICE_SHARED_BW: + profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; + /* No SRL is configured for default case */ + rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID; + break; + default: + return ICE_ERR_PARAM; + } + /* Save existing RL prof ID for later clean up */ + old_id = ice_sched_get_node_rl_prof_id(node, rl_type); + /* Configure BW scheduling parameters */ + status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); + if (status) + return status; + + /* Remove stale RL profile ID */ + if (old_id == ICE_SCHED_DFLT_RL_PROF_ID || + old_id == ICE_SCHED_INVAL_PROF_ID) + return 0; + + return ice_sched_rm_rl_profile(pi, layer_num, profile_type, old_id); +} + +/** + * ice_sched_set_eir_srl_excl - set EIR/SRL exclusiveness + * @pi: port information structure + * @node: pointer to node structure + * @layer_num: layer number where rate limit profiles are saved + * @rl_type: rate limit type min, max, or shared + * @bw: bandwidth value + * + * This function prepares node element's bandwidth to SRL or EIR exclusively. + * EIR BW and Shared BW profiles are mutually exclusive and hence only one of + * them may be set for any given element. This function needs to be called + * with the scheduler lock held. + */ +static enum ice_status +ice_sched_set_eir_srl_excl(struct ice_port_info *pi, + struct ice_sched_node *node, + u8 layer_num, enum ice_rl_type rl_type, u32 bw) +{ + if (rl_type == ICE_SHARED_BW) { + /* SRL node passed in this case, it may be different node */ + if (bw == ICE_SCHED_DFLT_BW) + /* SRL being removed, ice_sched_cfg_node_bw_lmt() + * enables EIR to default. EIR is not set in this + * case, so no additional action is required. + */ + return 0; + + /* SRL being configured, set EIR to default here. + * ice_sched_cfg_node_bw_lmt() disables EIR when it + * configures SRL + */ + return ice_sched_set_node_bw_dflt(pi, node, ICE_MAX_BW, + layer_num); + } else if (rl_type == ICE_MAX_BW && + node->info.data.valid_sections & ICE_AQC_ELEM_VALID_SHARED) { + /* Remove Shared profile. Set default shared BW call + * removes shared profile for a node. + */ + return ice_sched_set_node_bw_dflt(pi, node, + ICE_SHARED_BW, + layer_num); + } + return 0; +} + +/** + * ice_sched_set_node_bw - set node's bandwidth + * @pi: port information structure + * @node: tree node + * @rl_type: rate limit type min, max, or shared + * @bw: bandwidth in Kbps - Kilo bits per sec + * @layer_num: layer number + * + * This function adds new profile corresponding to requested BW, configures + * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile + * ID from local database. The caller needs to hold scheduler lock. + */ +static enum ice_status +ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node, + enum ice_rl_type rl_type, u32 bw, u8 layer_num) +{ + struct ice_aqc_rl_profile_info *rl_prof_info; + enum ice_status status = ICE_ERR_PARAM; + struct ice_hw *hw = pi->hw; + u16 old_id, rl_prof_id; + + rl_prof_info = ice_sched_add_rl_profile(pi, rl_type, bw, layer_num); + if (!rl_prof_info) + return status; + + rl_prof_id = le16_to_cpu(rl_prof_info->profile.profile_id); + + /* Save existing RL prof ID for later clean up */ + old_id = ice_sched_get_node_rl_prof_id(node, rl_type); + /* Configure BW scheduling parameters */ + status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); + if (status) + return status; + + /* New changes has been applied */ + /* Increment the profile ID reference count */ + rl_prof_info->prof_id_ref++; + + /* Check for old ID removal */ + if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) || + old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id) + return 0; + + return ice_sched_rm_rl_profile(pi, layer_num, + rl_prof_info->profile.flags, + old_id); +} + +/** + * ice_sched_set_node_bw_lmt - set node's BW limit + * @pi: port information structure + * @node: tree node + * @rl_type: rate limit type min, max, or shared + * @bw: bandwidth in Kbps - Kilo bits per sec + * + * It updates node's BW limit parameters like BW RL profile ID of type CIR, + * EIR, or SRL. The caller needs to hold scheduler lock. + */ +static enum ice_status +ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node, + enum ice_rl_type rl_type, u32 bw) +{ + struct ice_sched_node *cfg_node = node; + enum ice_status status; + + struct ice_hw *hw; + u8 layer_num; + + if (!pi) + return ICE_ERR_PARAM; + hw = pi->hw; + /* Remove unused RL profile IDs from HW and SW DB */ + ice_sched_rm_unused_rl_prof(pi); + layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, + node->tx_sched_layer); + if (layer_num >= hw->num_tx_sched_layers) + return ICE_ERR_PARAM; + + if (rl_type == ICE_SHARED_BW) { + /* SRL node may be different */ + cfg_node = ice_sched_get_srl_node(node, layer_num); + if (!cfg_node) + return ICE_ERR_CFG; + } + /* EIR BW and Shared BW profiles are mutually exclusive and + * hence only one of them may be set for any given element + */ + status = ice_sched_set_eir_srl_excl(pi, cfg_node, layer_num, rl_type, + bw); + if (status) + return status; + if (bw == ICE_SCHED_DFLT_BW) + return ice_sched_set_node_bw_dflt(pi, cfg_node, rl_type, + layer_num); + return ice_sched_set_node_bw(pi, cfg_node, rl_type, bw, layer_num); +} + +/** + * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default + * @pi: port information structure + * @node: pointer to node structure + * @rl_type: rate limit type min, max, or shared + * + * This function configures node element's BW rate limit profile ID of + * type CIR, EIR, or SRL to default. This function needs to be called + * with the scheduler lock held. + */ +static enum ice_status +ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi, + struct ice_sched_node *node, + enum ice_rl_type rl_type) +{ + return ice_sched_set_node_bw_lmt(pi, node, rl_type, + ICE_SCHED_DFLT_BW); +} + +/** + * ice_sched_validate_srl_node - Check node for SRL applicability + * @node: sched node to configure + * @sel_layer: selected SRL layer + * + * This function checks if the SRL can be applied to a selected layer node on + * behalf of the requested node (first argument). This function needs to be + * called with scheduler lock held. + */ +static enum ice_status +ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer) +{ + /* SRL profiles are not available on all layers. Check if the + * SRL profile can be applied to a node above or below the + * requested node. SRL configuration is possible only if the + * selected layer's node has single child. + */ + if (sel_layer == node->tx_sched_layer || + ((sel_layer == node->tx_sched_layer + 1) && + node->num_children == 1) || + ((sel_layer == node->tx_sched_layer - 1) && + (node->parent && node->parent->num_children == 1))) + return 0; + + return ICE_ERR_CFG; +} + +/** + * ice_sched_save_q_bw - save queue node's BW information + * @q_ctx: queue context structure + * @rl_type: rate limit type min, max, or shared + * @bw: bandwidth in Kbps - Kilo bits per sec + * + * Save BW information of queue type node for post replay use. + */ +static enum ice_status +ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw) +{ + switch (rl_type) { + case ICE_MIN_BW: + ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw); + break; + case ICE_MAX_BW: + ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw); + break; + case ICE_SHARED_BW: + ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw); + break; + default: + return ICE_ERR_PARAM; + } + return 0; +} + +/** + * ice_sched_set_q_bw_lmt - sets queue BW limit + * @pi: port information structure + * @vsi_handle: sw VSI handle + * @tc: traffic class + * @q_handle: software queue handle + * @rl_type: min, max, or shared + * @bw: bandwidth in Kbps + * + * This function sets BW limit of queue scheduling node. + */ +static enum ice_status +ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, + u16 q_handle, enum ice_rl_type rl_type, u32 bw) +{ + enum ice_status status = ICE_ERR_PARAM; + struct ice_sched_node *node; + struct ice_q_ctx *q_ctx; + + if (!ice_is_vsi_valid(pi->hw, vsi_handle)) + return ICE_ERR_PARAM; + mutex_lock(&pi->sched_lock); + q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle); + if (!q_ctx) + goto exit_q_bw_lmt; + node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); + if (!node) { + ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n"); + goto exit_q_bw_lmt; + } + + /* Return error if it is not a leaf node */ + if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) + goto exit_q_bw_lmt; + + /* SRL bandwidth layer selection */ + if (rl_type == ICE_SHARED_BW) { + u8 sel_layer; /* selected layer */ + + sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type, + node->tx_sched_layer); + if (sel_layer >= pi->hw->num_tx_sched_layers) { + status = ICE_ERR_PARAM; + goto exit_q_bw_lmt; + } + status = ice_sched_validate_srl_node(node, sel_layer); + if (status) + goto exit_q_bw_lmt; + } + + if (bw == ICE_SCHED_DFLT_BW) + status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type); + else + status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw); + + if (!status) + status = ice_sched_save_q_bw(q_ctx, rl_type, bw); + +exit_q_bw_lmt: + mutex_unlock(&pi->sched_lock); + return status; +} + +/** + * ice_cfg_q_bw_lmt - configure queue BW limit + * @pi: port information structure + * @vsi_handle: sw VSI handle + * @tc: traffic class + * @q_handle: software queue handle + * @rl_type: min, max, or shared + * @bw: bandwidth in Kbps + * + * This function configures BW limit of queue scheduling node. + */ +enum ice_status +ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, + u16 q_handle, enum ice_rl_type rl_type, u32 bw) +{ + return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, + bw); +} + +/** + * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit + * @pi: port information structure + * @vsi_handle: sw VSI handle + * @tc: traffic class + * @q_handle: software queue handle + * @rl_type: min, max, or shared + * + * This function configures BW default limit of queue scheduling node. + */ +enum ice_status +ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, + u16 q_handle, enum ice_rl_type rl_type) +{ + return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, + ICE_SCHED_DFLT_BW); +} + +/** + * ice_cfg_rl_burst_size - Set burst size value + * @hw: pointer to the HW struct + * @bytes: burst size in bytes + * + * This function configures/set the burst size to requested new value. The new + * burst size value is used for future rate limit calls. It doesn't change the + * existing or previously created RL profiles. + */ +enum ice_status ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes) +{ + u16 burst_size_to_prog; + + if (bytes < ICE_MIN_BURST_SIZE_ALLOWED || + bytes > ICE_MAX_BURST_SIZE_ALLOWED) + return ICE_ERR_PARAM; + if (ice_round_to_num(bytes, 64) <= + ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) { + /* 64 byte granularity case */ + /* Disable MSB granularity bit */ + burst_size_to_prog = ICE_64_BYTE_GRANULARITY; + /* round number to nearest 64 byte granularity */ + bytes = ice_round_to_num(bytes, 64); + /* The value is in 64 byte chunks */ + burst_size_to_prog |= (u16)(bytes / 64); + } else { + /* k bytes granularity case */ + /* Enable MSB granularity bit */ + burst_size_to_prog = ICE_KBYTE_GRANULARITY; + /* round number to nearest 1024 granularity */ + bytes = ice_round_to_num(bytes, 1024); + /* check rounding doesn't go beyond allowed */ + if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY) + bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY; + /* The value is in k bytes */ + burst_size_to_prog |= (u16)(bytes / 1024); + } + hw->max_burst_size = burst_size_to_prog; + return 0; +} + +/** + * ice_sched_replay_node_prio - re-configure node priority + * @hw: pointer to the HW struct + * @node: sched node to configure + * @priority: priority value + * + * This function configures node element's priority value. It + * needs to be called with scheduler lock held. + */ +static enum ice_status +ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node, + u8 priority) +{ + struct ice_aqc_txsched_elem_data buf; + struct ice_aqc_txsched_elem *data; + enum ice_status status; + + buf = node->info; + data = &buf.data; + data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; + data->generic = priority; + + /* Configure element */ + status = ice_sched_update_elem(hw, node, &buf); + return status; +} + +/** + * ice_sched_replay_node_bw - replay node(s) BW + * @hw: pointer to the HW struct + * @node: sched node to configure + * @bw_t_info: BW type information + * + * This function restores node's BW from bw_t_info. The caller needs + * to hold the scheduler lock. + */ +static enum ice_status +ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node, + struct ice_bw_type_info *bw_t_info) +{ + struct ice_port_info *pi = hw->port_info; + enum ice_status status = ICE_ERR_PARAM; + u16 bw_alloc; + + if (!node) + return status; + if (bitmap_empty(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT)) + return 0; + if (test_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap)) { + status = ice_sched_replay_node_prio(hw, node, + bw_t_info->generic); + if (status) + return status; + } + if (test_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap)) { + status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW, + bw_t_info->cir_bw.bw); + if (status) + return status; + } + if (test_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap)) { + bw_alloc = bw_t_info->cir_bw.bw_alloc; + status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW, + bw_alloc); + if (status) + return status; + } + if (test_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap)) { + status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW, + bw_t_info->eir_bw.bw); + if (status) + return status; + } + if (test_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap)) { + bw_alloc = bw_t_info->eir_bw.bw_alloc; + status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW, + bw_alloc); + if (status) + return status; + } + if (test_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap)) + status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW, + bw_t_info->shared_bw); + return status; +} + +/** + * ice_sched_replay_q_bw - replay queue type node BW + * @pi: port information structure + * @q_ctx: queue context structure + * + * This function replays queue type node bandwidth. This function needs to be + * called with scheduler lock held. + */ +enum ice_status +ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx) +{ + struct ice_sched_node *q_node; + + /* Following also checks the presence of node in tree */ + q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); + if (!q_node) + return ICE_ERR_PARAM; + return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info); +} diff --git a/drivers/net/ethernet/intel/ice/ice_sched.h b/drivers/net/ethernet/intel/ice/ice_sched.h index 3902a8ad3025..f0593cfb6521 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.h +++ b/drivers/net/ethernet/intel/ice/ice_sched.h @@ -8,6 +8,36 @@ #define ICE_QGRP_LAYER_OFFSET 2 #define ICE_VSI_LAYER_OFFSET 4 +#define ICE_SCHED_INVAL_LAYER_NUM 0xFF +/* Burst size is a 12 bits register that is configured while creating the RL + * profile(s). MSB is a granularity bit and tells the granularity type + * 0 - LSB bits are in 64 bytes granularity + * 1 - LSB bits are in 1K bytes granularity + */ +#define ICE_64_BYTE_GRANULARITY 0 +#define ICE_KBYTE_GRANULARITY BIT(11) +#define ICE_MIN_BURST_SIZE_ALLOWED 64 /* In Bytes */ +#define ICE_MAX_BURST_SIZE_ALLOWED \ + ((BIT(11) - 1) * 1024) /* In Bytes */ +#define ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY \ + ((BIT(11) - 1) * 64) /* In Bytes */ +#define ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY ICE_MAX_BURST_SIZE_ALLOWED + +#define ICE_RL_PROF_FREQUENCY 446000000 +#define ICE_RL_PROF_ACCURACY_BYTES 128 +#define ICE_RL_PROF_MULTIPLIER 10000 +#define ICE_RL_PROF_TS_MULTIPLIER 32 +#define ICE_RL_PROF_FRACTION 512 + +/* BW rate limit profile parameters list entry along + * with bandwidth maintained per layer in port info + */ +struct ice_aqc_rl_profile_info { + struct ice_aqc_rl_profile_elem profile; + struct list_head list_entry; + u32 bw; /* requested */ + u16 prof_id_ref; /* profile ID to node association ref count */ +}; struct ice_sched_agg_vsi_info { struct list_head list_entry; @@ -48,4 +78,13 @@ enum ice_status ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, u8 owner, bool enable); enum ice_status ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle); +enum ice_status +ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, + u16 q_handle, enum ice_rl_type rl_type, u32 bw); +enum ice_status +ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, + u16 q_handle, enum ice_rl_type rl_type); +enum ice_status ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes); +enum ice_status +ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx); #endif /* _ICE_SCHED_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_switch.h b/drivers/net/ethernet/intel/ice/ice_switch.h index cb123fbe30be..fa14b9545dab 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.h +++ b/drivers/net/ethernet/intel/ice/ice_switch.h @@ -14,11 +14,6 @@ #define ICE_VSI_INVAL_ID 0xffff #define ICE_INVAL_Q_HANDLE 0xFFFF -/* VSI queue context structure */ -struct ice_q_ctx { - u16 q_handle; -}; - /* VSI context structure for add/get/update/free operations */ struct ice_vsi_ctx { u16 vsi_num; diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index 08fe3e5e72d4..d3d7049c97f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -19,6 +19,17 @@ static inline bool ice_is_tc_ena(unsigned long bitmap, u8 tc) return test_bit(tc, &bitmap); } +static inline u64 round_up_64bit(u64 a, u32 b) +{ + return div64_long(((a) + (b) / 2), (b)); +} + +static inline u32 ice_round_to_num(u32 N, u32 R) +{ + return ((((N) % (R)) < ((R) / 2)) ? (((N) / (R)) * (R)) : + ((((N) + (R) - 1) / (R)) * (R))); +} + /* Driver always calls main vsi_handle first */ #define ICE_MAIN_VSI_HANDLE 0 @@ -272,10 +283,56 @@ enum ice_agg_type { ICE_AGG_TYPE_QG }; +/* Rate limit types */ +enum ice_rl_type { + ICE_UNKNOWN_BW = 0, + ICE_MIN_BW, /* for CIR profile */ + ICE_MAX_BW, /* for EIR profile */ + ICE_SHARED_BW /* for shared profile */ +}; + +#define ICE_SCHED_MIN_BW 500 /* in Kbps */ +#define ICE_SCHED_MAX_BW 100000000 /* in Kbps */ +#define ICE_SCHED_DFLT_BW 0xFFFFFFFF /* unlimited */ #define ICE_SCHED_DFLT_RL_PROF_ID 0 +#define ICE_SCHED_NO_SHARED_RL_PROF_ID 0xFFFF #define ICE_SCHED_DFLT_BW_WT 1 +#define ICE_SCHED_INVAL_PROF_ID 0xFFFF +#define ICE_SCHED_DFLT_BURST_SIZE (15 * 1024) /* in bytes (15k) */ -/* VSI type list entry to locate corresponding VSI/ag nodes */ + /* Data structure for saving BW information */ +enum ice_bw_type { + ICE_BW_TYPE_PRIO, + ICE_BW_TYPE_CIR, + ICE_BW_TYPE_CIR_WT, + ICE_BW_TYPE_EIR, + ICE_BW_TYPE_EIR_WT, + ICE_BW_TYPE_SHARED, + ICE_BW_TYPE_CNT /* This must be last */ +}; + +struct ice_bw { + u32 bw; + u16 bw_alloc; +}; + +struct ice_bw_type_info { + DECLARE_BITMAP(bw_t_bitmap, ICE_BW_TYPE_CNT); + u8 generic; + struct ice_bw cir_bw; + struct ice_bw eir_bw; + u32 shared_bw; +}; + +/* VSI queue context structure for given TC */ +struct ice_q_ctx { + u16 q_handle; + u32 q_teid; + /* bw_t_info saves queue BW information */ + struct ice_bw_type_info bw_t_info; +}; + +/* VSI type list entry to locate corresponding VSI/aggregator nodes */ struct ice_sched_vsi_info { struct ice_sched_node *vsi_node[ICE_MAX_TRAFFIC_CLASS]; struct ice_sched_node *ag_node[ICE_MAX_TRAFFIC_CLASS]; @@ -364,6 +421,8 @@ struct ice_port_info { struct mutex sched_lock; /* protect access to TXSched tree */ struct ice_sched_node * sib_head[ICE_MAX_TRAFFIC_CLASS][ICE_AQC_TOPO_MAX_LEVEL_NUM]; + /* List contain profile ID(s) and other params per layer */ + struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM]; struct ice_dcbx_cfg local_dcbx_cfg; /* Oper/Local Cfg */ /* DCBX info */ struct ice_dcbx_cfg remote_dcbx_cfg; /* Peer Cfg */ @@ -415,6 +474,8 @@ struct ice_hw { u8 pf_id; /* device profile info */ + u16 max_burst_size; /* driver sets this value */ + /* Tx Scheduler values */ u16 num_tx_sched_layers; u16 num_tx_sched_phys_layers; -- cgit v1.2.3-59-g8ed1b From b94b013eb6269526eeb3768101666ba6f526313e Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 6 Nov 2019 02:05:29 -0800 Subject: ice: Implement DCBNL support Implement interface layer for the DCBNL subsystem. These are the functions to support the callbacks defined in the dcbnl_rtnl_ops struct. These callbacks are going to be used to interface with the DCB settings of the device. Implementation of dcb_nl set functions and supporting SW DCB functions. Signed-off-by: Dave Ertman Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/Makefile | 2 +- drivers/net/ethernet/intel/ice/ice.h | 2 + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 15 +- drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 15 +- drivers/net/ethernet/intel/ice/ice_dcb_nl.c | 933 ++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_dcb_nl.h | 19 + drivers/net/ethernet/intel/ice/ice_hw_autogen.h | 3 + drivers/net/ethernet/intel/ice/ice_lib.c | 1 + drivers/net/ethernet/intel/ice/ice_main.c | 6 + 9 files changed, 991 insertions(+), 5 deletions(-) create mode 100644 drivers/net/ethernet/intel/ice/ice_dcb_nl.c create mode 100644 drivers/net/ethernet/intel/ice/ice_dcb_nl.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile index df5a9699276a..7cb829132d28 100644 --- a/drivers/net/ethernet/intel/ice/Makefile +++ b/drivers/net/ethernet/intel/ice/Makefile @@ -20,5 +20,5 @@ ice-y := ice_main.o \ ice_flex_pipe.o \ ice_ethtool.o ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o -ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_lib.o +ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_nl.o ice_dcb_lib.o ice-$(CONFIG_XDP_SOCKETS) += ice_xsk.o diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 7da4ae9608c4..8d7e8fc55585 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -180,6 +180,7 @@ enum ice_state { __ICE_NEEDS_RESTART, __ICE_PREPARED_FOR_RESET, /* set by driver when prepared */ __ICE_RESET_OICR_RECV, /* set by driver after rcv reset OICR */ + __ICE_DCBNL_DEVRESET, /* set by dcbnl devreset */ __ICE_PFR_REQ, /* set by driver and peers */ __ICE_CORER_REQ, /* set by driver and peers */ __ICE_GLOBR_REQ, /* set by driver and peers */ @@ -365,6 +366,7 @@ struct ice_pf { struct work_struct serv_task; struct mutex avail_q_mutex; /* protects access to avail_[rx|tx]qs */ struct mutex sw_mutex; /* lock for protecting VSI alloc flow */ + struct mutex tc_mutex; /* lock to protect TC changes */ u32 msg_enable; u32 hw_csum_rx_error; u32 oicr_idx; /* Other interrupt cause MSIX vector index */ diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index c00c68bacadb..9448a289363d 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -2,6 +2,7 @@ /* Copyright (c) 2019, Intel Corporation. */ #include "ice_dcb_lib.h" +#include "ice_dcb_nl.h" static void ice_pf_dcb_recfg(struct ice_pf *pf); @@ -155,16 +156,19 @@ void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi) * @new_cfg: DCBX config to apply * @locked: is the RTNL held */ -static int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) { - struct ice_dcbx_cfg *old_cfg, *curr_cfg; struct ice_aqc_port_ets_elem buf = { 0 }; + struct ice_dcbx_cfg *old_cfg, *curr_cfg; + int ret = ICE_DCB_NO_HW_CHG; struct ice_vsi *pf_vsi; - int ret = 0; curr_cfg = &pf->hw.port_info->local_dcbx_cfg; + /* FW does not care if change happened */ + if (!pf->hw.port_info->is_sw_lldp) + ret = ICE_DCB_HW_CHG_RST; + /* Enable DCB tagging only when more than one TC */ if (ice_dcb_get_num_tc(new_cfg) > 1) { dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n"); @@ -184,6 +188,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) if (!old_cfg) return -ENOMEM; + dev_info(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n"); pf_vsi = ice_get_main_vsi(pf); if (!pf_vsi) { dev_dbg(&pf->pdev->dev, "PF VSI doesn't exist\n"); @@ -200,6 +205,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) memcpy(curr_cfg, new_cfg, sizeof(*curr_cfg)); memcpy(&curr_cfg->etsrec, &curr_cfg->etscfg, sizeof(curr_cfg->etsrec)); + memcpy(&new_cfg->etsrec, &curr_cfg->etscfg, sizeof(curr_cfg->etsrec)); /* Only send new config to HW if we are in SW LLDP mode. Otherwise, * the new config came from the HW in the first place. @@ -559,6 +565,8 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf) } ice_vsi_map_rings_to_vectors(pf->vsi[v]); + if (pf->vsi[v]->type == ICE_VSI_PF) + ice_dcbnl_set_all(pf->vsi[v]); } } @@ -770,6 +778,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, need_reconfig = ice_dcb_need_recfg(pf, &tmp_dcbx_cfg, &pi->local_dcbx_cfg); + ice_dcbnl_flush_apps(pf, &tmp_dcbx_cfg, &pi->local_dcbx_cfg); if (!need_reconfig) return; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index 59e40cf2dd73..e90e25b7da77 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -9,12 +9,17 @@ #include "ice_lib.h" #ifdef CONFIG_DCB -#define ICE_TC_MAX_BW 100 /* Default Max BW percentage */ +#define ICE_TC_MAX_BW 100 /* Default Max BW percentage */ +#define ICE_DCB_HW_CHG_RST 0 /* DCB configuration changed with reset */ +#define ICE_DCB_NO_HW_CHG 1 /* DCB configuration did not change */ +#define ICE_DCB_HW_CHG 2 /* DCB configuration changed, no reset */ void ice_dcb_rebuild(struct ice_pf *pf); u8 ice_dcb_get_ena_tc(struct ice_dcbx_cfg *dcbcfg); u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg); u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index); +int +ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); int ice_init_pf_dcb(struct ice_pf *pf, bool locked); void ice_update_dcb_stats(struct ice_pf *pf); @@ -57,6 +62,14 @@ ice_init_pf_dcb(struct ice_pf *pf, bool __always_unused locked) return -EOPNOTSUPP; } +static inline int +ice_pf_dcb_cfg(struct ice_pf __always_unused *pf, + struct ice_dcbx_cfg __always_unused *new_cfg, + bool __always_unused locked) +{ + return -EOPNOTSUPP; +} + static inline int ice_tx_prepare_vlan_flags_dcb(struct ice_ring __always_unused *tx_ring, struct ice_tx_buf __always_unused *first) diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c new file mode 100644 index 000000000000..3c90fc0a3feb --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c @@ -0,0 +1,933 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019, Intel Corporation. */ + +#include "ice.h" +#include "ice_dcb.h" +#include "ice_dcb_lib.h" +#include "ice_dcb_nl.h" +#include + +#define ICE_APP_PROT_ID_ROCE 0x8915 + +/** + * ice_dcbnl_devreset - perform enough of a ifdown/ifup to sync DCBNL info + * @netdev: device associated with interface that needs reset + */ +static void ice_dcbnl_devreset(struct net_device *netdev) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + while (ice_is_reset_in_progress(pf->state)) + usleep_range(1000, 2000); + + set_bit(__ICE_DCBNL_DEVRESET, pf->state); + dev_close(netdev); + netdev_state_change(netdev); + dev_open(netdev, NULL); + netdev_state_change(netdev); + clear_bit(__ICE_DCBNL_DEVRESET, pf->state); +} + +/** + * ice_dcbnl_getets - retrieve local ETS configuration + * @netdev: the relevant netdev + * @ets: struct to hold ETS configuration + */ +static int ice_dcbnl_getets(struct net_device *netdev, struct ieee_ets *ets) +{ + struct ice_dcbx_cfg *dcbxcfg; + struct ice_port_info *pi; + struct ice_pf *pf; + + pf = ice_netdev_to_pf(netdev); + pi = pf->hw.port_info; + dcbxcfg = &pi->local_dcbx_cfg; + + ets->willing = dcbxcfg->etscfg.willing; + ets->ets_cap = dcbxcfg->etscfg.maxtcs; + ets->cbs = dcbxcfg->etscfg.cbs; + memcpy(ets->tc_tx_bw, dcbxcfg->etscfg.tcbwtable, sizeof(ets->tc_tx_bw)); + memcpy(ets->tc_rx_bw, dcbxcfg->etscfg.tcbwtable, sizeof(ets->tc_rx_bw)); + memcpy(ets->tc_tsa, dcbxcfg->etscfg.tsatable, sizeof(ets->tc_tsa)); + memcpy(ets->prio_tc, dcbxcfg->etscfg.prio_table, sizeof(ets->prio_tc)); + memcpy(ets->tc_reco_bw, dcbxcfg->etsrec.tcbwtable, + sizeof(ets->tc_reco_bw)); + memcpy(ets->tc_reco_tsa, dcbxcfg->etsrec.tsatable, + sizeof(ets->tc_reco_tsa)); + memcpy(ets->reco_prio_tc, dcbxcfg->etscfg.prio_table, + sizeof(ets->reco_prio_tc)); + + return 0; +} + +/** + * ice_dcbnl_setets - set IEEE ETS configuration + * @netdev: pointer to relevant netdev + * @ets: struct to hold ETS configuration + */ +static int ice_dcbnl_setets(struct net_device *netdev, struct ieee_ets *ets) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + int bwcfg = 0, bwrec = 0; + int err, i, max_tc = 0; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) + return -EINVAL; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + mutex_lock(&pf->tc_mutex); + + new_cfg->etscfg.willing = ets->willing; + new_cfg->etscfg.cbs = ets->cbs; + ice_for_each_traffic_class(i) { + new_cfg->etscfg.tcbwtable[i] = ets->tc_tx_bw[i]; + bwcfg += ets->tc_tx_bw[i]; + new_cfg->etscfg.tsatable[i] = ets->tc_tsa[i]; + new_cfg->etscfg.prio_table[i] = ets->prio_tc[i]; + if (ets->prio_tc[i] > max_tc) + max_tc = ets->prio_tc[i]; + new_cfg->etsrec.tcbwtable[i] = ets->tc_reco_bw[i]; + bwrec += ets->tc_reco_bw[i]; + new_cfg->etsrec.tsatable[i] = ets->tc_reco_tsa[i]; + new_cfg->etsrec.prio_table[i] = ets->reco_prio_tc[i]; + } + + /* max_tc is a 1-8 value count of number of TC's, not a 0-7 value + * for the TC's index number. Add one to value if not zero, and + * for zero set it to the FW's default value + */ + if (max_tc) + max_tc++; + else + max_tc = IEEE_8021QAZ_MAX_TCS; + + new_cfg->etscfg.maxtcs = max_tc; + + if (!bwcfg) + new_cfg->etscfg.tcbwtable[0] = 100; + + if (!bwrec) + new_cfg->etsrec.tcbwtable[0] = 100; + + err = ice_pf_dcb_cfg(pf, new_cfg, true); + /* return of zero indicates new cfg applied */ + if (err == ICE_DCB_HW_CHG_RST) + ice_dcbnl_devreset(netdev); + if (err == ICE_DCB_NO_HW_CHG) + err = ICE_DCB_HW_CHG_RST; + + mutex_unlock(&pf->tc_mutex); + return err; +} + +/** + * ice_dcbnl_getnumtcs - Get max number of traffic classes supported + * @dev: pointer to netdev struct + * @tcid: TC ID + * @num: total number of TCs supported by the adapter + * + * Return the total number of TCs supported + */ +static int +ice_dcbnl_getnumtcs(struct net_device *dev, int __always_unused tcid, u8 *num) +{ + struct ice_pf *pf = ice_netdev_to_pf(dev); + + if (!test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags)) + return -EINVAL; + + *num = IEEE_8021QAZ_MAX_TCS; + return 0; +} + +/** + * ice_dcbnl_getdcbx - retrieve current DCBX capability + * @netdev: pointer to the netdev struct + */ +static u8 ice_dcbnl_getdcbx(struct net_device *netdev) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + return pf->dcbx_cap; +} + +/** + * ice_dcbnl_setdcbx - set required DCBX capability + * @netdev: the corresponding netdev + * @mode: required mode + */ +static u8 ice_dcbnl_setdcbx(struct net_device *netdev, u8 mode) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + /* No support for LLD_MANAGED modes or CEE+IEEE */ + if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || + ((mode & DCB_CAP_DCBX_VER_IEEE) && (mode & DCB_CAP_DCBX_VER_CEE)) || + !(mode & DCB_CAP_DCBX_HOST)) + return ICE_DCB_NO_HW_CHG; + + /* Already set to the given mode no change */ + if (mode == pf->dcbx_cap) + return ICE_DCB_NO_HW_CHG; + + pf->dcbx_cap = mode; + if (mode & DCB_CAP_DCBX_VER_CEE) + pf->hw.port_info->local_dcbx_cfg.dcbx_mode = ICE_DCBX_MODE_CEE; + else + pf->hw.port_info->local_dcbx_cfg.dcbx_mode = ICE_DCBX_MODE_IEEE; + + dev_info(&pf->pdev->dev, "DCBx mode = 0x%x\n", mode); + return ICE_DCB_HW_CHG_RST; +} + +/** + * ice_dcbnl_get_perm_hw_addr - MAC address used by DCBX + * @netdev: pointer to netdev struct + * @perm_addr: buffer to return permanent MAC address + */ +static void ice_dcbnl_get_perm_hw_addr(struct net_device *netdev, u8 *perm_addr) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + int i, j; + + memset(perm_addr, 0xff, MAX_ADDR_LEN); + + for (i = 0; i < netdev->addr_len; i++) + perm_addr[i] = pi->mac.perm_addr[i]; + + for (j = 0; j < netdev->addr_len; j++, i++) + perm_addr[i] = pi->mac.perm_addr[j]; +} + +/** + * ice_get_pfc_delay - Retrieve PFC Link Delay + * @hw: pointer to HW struct + * @delay: holds the PFC Link Delay value + */ +static void ice_get_pfc_delay(struct ice_hw *hw, u16 *delay) +{ + u32 val; + + val = rd32(hw, PRTDCB_GENC); + *delay = (u16)((val & PRTDCB_GENC_PFCLDA_M) >> PRTDCB_GENC_PFCLDA_S); +} + +/** + * ice_dcbnl_getpfc - retrieve local IEEE PFC config + * @netdev: pointer to netdev struct + * @pfc: struct to hold PFC info + */ +static int ice_dcbnl_getpfc(struct net_device *netdev, struct ieee_pfc *pfc) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + struct ice_dcbx_cfg *dcbxcfg; + int i; + + dcbxcfg = &pi->local_dcbx_cfg; + pfc->pfc_cap = dcbxcfg->pfc.pfccap; + pfc->pfc_en = dcbxcfg->pfc.pfcena; + pfc->mbc = dcbxcfg->pfc.mbc; + ice_get_pfc_delay(&pf->hw, &pfc->delay); + + ice_for_each_traffic_class(i) { + pfc->requests[i] = pf->stats.priority_xoff_tx[i]; + pfc->indications[i] = pf->stats.priority_xoff_rx[i]; + } + + return 0; +} + +/** + * ice_dcbnl_setpfc - set local IEEE PFC config + * @netdev: pointer to relevant netdev + * @pfc: pointer to struct holding PFC config + */ +static int ice_dcbnl_setpfc(struct net_device *netdev, struct ieee_pfc *pfc) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + int err; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) + return -EINVAL; + + mutex_lock(&pf->tc_mutex); + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + if (pfc->pfc_cap) + new_cfg->pfc.pfccap = pfc->pfc_cap; + else + new_cfg->pfc.pfccap = pf->hw.func_caps.common_cap.maxtc; + + new_cfg->pfc.pfcena = pfc->pfc_en; + + err = ice_pf_dcb_cfg(pf, new_cfg, true); + if (err == ICE_DCB_HW_CHG_RST) + ice_dcbnl_devreset(netdev); + if (err == ICE_DCB_NO_HW_CHG) + err = ICE_DCB_HW_CHG_RST; + mutex_unlock(&pf->tc_mutex); + return err; +} + +/** + * ice_dcbnl_get_pfc_cfg - Get CEE PFC config + * @netdev: pointer to netdev struct + * @prio: corresponding user priority + * @setting: the PFC setting for given priority + */ +static void +ice_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, u8 *setting) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (prio >= ICE_MAX_USER_PRIORITY) + return; + + *setting = (pi->local_dcbx_cfg.pfc.pfcena >> prio) & 0x1; + dev_dbg(&pf->pdev->dev, + "Get PFC Config up=%d, setting=%d, pfcenable=0x%x\n", + prio, *setting, pi->local_dcbx_cfg.pfc.pfcena); +} + +/** + * ice_dcbnl_set_pfc_cfg - Set CEE PFC config + * @netdev: the corresponding netdev + * @prio: User Priority + * @set: PFC setting to apply + */ +static void ice_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, u8 set) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (prio >= ICE_MAX_USER_PRIORITY) + return; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + new_cfg->pfc.pfccap = pf->hw.func_caps.common_cap.maxtc; + if (set) + new_cfg->pfc.pfcena |= BIT(prio); + else + new_cfg->pfc.pfcena &= ~BIT(prio); + + dev_dbg(&pf->pdev->dev, "Set PFC config UP:%d set:%d pfcena:0x%x\n", + prio, set, new_cfg->pfc.pfcena); +} + +/** + * ice_dcbnl_getpfcstate - get CEE PFC mode + * @netdev: pointer to netdev struct + */ +static u8 ice_dcbnl_getpfcstate(struct net_device *netdev) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + + /* Return enabled if any UP enabled for PFC */ + if (pi->local_dcbx_cfg.pfc.pfcena) + return 1; + + return 0; +} + +/** + * ice_dcbnl_getstate - get DCB enabled state + * @netdev: pointer to netdev struct + */ +static u8 ice_dcbnl_getstate(struct net_device *netdev) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + u8 state = 0; + + state = test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); + + dev_dbg(&pf->pdev->dev, "DCB enabled state = %d\n", state); + return state; +} + +/** + * ice_dcbnl_setstate - Set CEE DCB state + * @netdev: pointer to relevant netdev + * @state: state value to set + */ +static u8 ice_dcbnl_setstate(struct net_device *netdev, u8 state) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return ICE_DCB_NO_HW_CHG; + + /* Nothing to do */ + if (!!state == test_bit(ICE_FLAG_DCB_ENA, pf->flags)) + return ICE_DCB_NO_HW_CHG; + + if (state) { + set_bit(ICE_FLAG_DCB_ENA, pf->flags); + memcpy(&pf->hw.port_info->desired_dcbx_cfg, + &pf->hw.port_info->local_dcbx_cfg, + sizeof(struct ice_dcbx_cfg)); + } else { + clear_bit(ICE_FLAG_DCB_ENA, pf->flags); + } + + return ICE_DCB_HW_CHG; +} + +/** + * ice_dcbnl_get_pg_tc_cfg_tx - get CEE PG Tx config + * @netdev: pointer to netdev struct + * @prio: the corresponding user priority + * @prio_type: traffic priority type + * @pgid: the BW group ID the traffic class belongs to + * @bw_pct: BW percentage for the corresponding BWG + * @up_map: prio mapped to corresponding TC + */ +static void +ice_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio, + u8 __always_unused *prio_type, u8 *pgid, + u8 __always_unused *bw_pct, + u8 __always_unused *up_map) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (prio >= ICE_MAX_USER_PRIORITY) + return; + + *pgid = pi->local_dcbx_cfg.etscfg.prio_table[prio]; + dev_dbg(&pf->pdev->dev, + "Get PG config prio=%d tc=%d\n", prio, *pgid); +} + +/** + * ice_dcbnl_set_pg_tc_cfg_tx - set CEE PG Tx config + * @netdev: pointer to relevant netdev + * @tc: the corresponding traffic class + * @prio_type: the traffic priority type + * @bwg_id: the BW group ID the TC belongs to + * @bw_pct: the BW perventage for the BWG + * @up_map: prio mapped to corresponding TC + */ +static void +ice_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, + u8 __always_unused prio_type, + u8 __always_unused bwg_id, + u8 __always_unused bw_pct, u8 up_map) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + int i; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (tc >= ICE_MAX_TRAFFIC_CLASS) + return; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + /* prio_type, bwg_id and bw_pct per UP are not supported */ + + ice_for_each_traffic_class(i) { + if (up_map & BIT(i)) + new_cfg->etscfg.prio_table[i] = tc; + } + new_cfg->etscfg.tsatable[tc] = ICE_IEEE_TSA_ETS; +} + +/** + * ice_dcbnl_get_pg_bwg_cfg_tx - Get CEE PGBW config + * @netdev: pointer to the netdev struct + * @pgid: corresponding traffic class + * @bw_pct: the BW percentage for the corresponding TC + */ +static void +ice_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 *bw_pct) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (pgid >= ICE_MAX_TRAFFIC_CLASS) + return; + + *bw_pct = pi->local_dcbx_cfg.etscfg.tcbwtable[pgid]; + dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n", + pgid, *bw_pct); +} + +/** + * ice_dcbnl_set_pg_bwg_cfg_tx - set CEE PG Tx BW config + * @netdev: the corresponding netdev + * @pgid: Correspongind traffic class + * @bw_pct: the BW percentage for the specified TC + */ +static void +ice_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 bw_pct) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (pgid >= ICE_MAX_TRAFFIC_CLASS) + return; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + new_cfg->etscfg.tcbwtable[pgid] = bw_pct; +} + +/** + * ice_dcbnl_get_pg_tc_cfg_rx - Get CEE PG Rx config + * @netdev: pointer to netdev struct + * @prio: the corresponding user priority + * @prio_type: the traffic priority type + * @pgid: the PG ID + * @bw_pct: the BW percentage for the corresponding BWG + * @up_map: prio mapped to corresponding TC + */ +static void +ice_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int prio, + u8 __always_unused *prio_type, u8 *pgid, + u8 __always_unused *bw_pct, + u8 __always_unused *up_map) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_port_info *pi = pf->hw.port_info; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + if (prio >= ICE_MAX_USER_PRIORITY) + return; + + *pgid = pi->local_dcbx_cfg.etscfg.prio_table[prio]; +} + +/** + * ice_dcbnl_get_pg_bwg_cfg_rx - Get CEE PG BW Rx config + * @netdev: pointer to netdev struct + * @pgid: the corresponding traffic class + * @bw_pct: the BW percentage for the corresponding TC + */ +static void +ice_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int __always_unused pgid, + u8 *bw_pct) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return; + + *bw_pct = 0; +} + +/** + * ice_dcbnl_get_cap - Get DCBX capabilities of adapter + * @netdev: pointer to netdev struct + * @capid: the capability type + * @cap: the capability value + */ +static u8 ice_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + + if (!(test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags))) + return ICE_DCB_NO_HW_CHG; + + switch (capid) { + case DCB_CAP_ATTR_PG: + *cap = true; + break; + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_UP2TC: + *cap = false; + break; + case DCB_CAP_ATTR_PG_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_GSP: + *cap = false; + break; + case DCB_CAP_ATTR_BCN: + *cap = false; + break; + case DCB_CAP_ATTR_DCBX: + *cap = pf->dcbx_cap; + break; + default: + *cap = false; + break; + } + + dev_dbg(&pf->pdev->dev, "DCBX Get Capability cap=%d capval=0x%x\n", + capid, *cap); + return 0; +} + +/** + * ice_dcbnl_getapp - get CEE APP + * @netdev: pointer to netdev struct + * @idtype: the App selector + * @id: the App ethtype or port number + */ +static int ice_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct dcb_app app = { + .selector = idtype, + .protocol = id, + }; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return -EINVAL; + + return dcb_getapp(netdev, &app); +} + +/** + * ice_dcbnl_find_app - Search for APP in given DCB config + * @cfg: struct to hold DCBX config + * @app: struct to hold app data to look for + */ +static bool +ice_dcbnl_find_app(struct ice_dcbx_cfg *cfg, + struct ice_dcb_app_priority_table *app) +{ + int i; + + for (i = 0; i < cfg->numapps; i++) { + if (app->selector == cfg->app[i].selector && + app->prot_id == cfg->app[i].prot_id && + app->priority == cfg->app[i].priority) + return true; + } + + return false; +} + +/** + * ice_dcbnl_setapp - set local IEEE App config + * @netdev: relevant netdev struct + * @app: struct to hold app config info + */ +static int ice_dcbnl_setapp(struct net_device *netdev, struct dcb_app *app) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcb_app_priority_table new_app; + struct ice_dcbx_cfg *old_cfg, *new_cfg; + int ret; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)) + return -EINVAL; + + mutex_lock(&pf->tc_mutex); + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + old_cfg = &pf->hw.port_info->local_dcbx_cfg; + + if (old_cfg->numapps == ICE_DCBX_MAX_APPS) { + ret = -EINVAL; + goto setapp_out; + } + + ret = dcb_ieee_setapp(netdev, app); + if (ret) + goto setapp_out; + + new_app.selector = app->selector; + new_app.prot_id = app->protocol; + new_app.priority = app->priority; + if (ice_dcbnl_find_app(old_cfg, &new_app)) { + ret = 0; + goto setapp_out; + } + + new_cfg->app[new_cfg->numapps++] = new_app; + ret = ice_pf_dcb_cfg(pf, new_cfg, true); + /* return of zero indicates new cfg applied */ + if (ret == ICE_DCB_HW_CHG_RST) + ice_dcbnl_devreset(netdev); + if (ret == ICE_DCB_NO_HW_CHG) + ret = ICE_DCB_HW_CHG_RST; + +setapp_out: + mutex_unlock(&pf->tc_mutex); + return ret; +} + +/** + * ice_dcbnl_delapp - Delete local IEEE App config + * @netdev: relevant netdev + * @app: struct to hold app too delete + * + * Will not delete first application required by the FW + */ +static int ice_dcbnl_delapp(struct net_device *netdev, struct dcb_app *app) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *old_cfg, *new_cfg; + int i, j, ret = 0; + + if (pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) + return -EINVAL; + + mutex_lock(&pf->tc_mutex); + ret = dcb_ieee_delapp(netdev, app); + if (ret) + goto delapp_out; + + old_cfg = &pf->hw.port_info->local_dcbx_cfg; + + if (old_cfg->numapps == 1) + goto delapp_out; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + for (i = 1; i < new_cfg->numapps; i++) { + if (app->selector == new_cfg->app[i].selector && + app->protocol == new_cfg->app[i].prot_id && + app->priority == new_cfg->app[i].priority) { + new_cfg->app[i].selector = 0; + new_cfg->app[i].prot_id = 0; + new_cfg->app[i].priority = 0; + break; + } + } + + /* Did not find DCB App */ + if (i == new_cfg->numapps) { + ret = -EINVAL; + goto delapp_out; + } + + new_cfg->numapps--; + + for (j = i; j < new_cfg->numapps; j++) { + new_cfg->app[i].selector = old_cfg->app[j + 1].selector; + new_cfg->app[i].prot_id = old_cfg->app[j + 1].prot_id; + new_cfg->app[i].priority = old_cfg->app[j + 1].priority; + } + + ret = ice_pf_dcb_cfg(pf, new_cfg, true); + /* return of zero indicates new cfg applied */ + if (ret == ICE_DCB_HW_CHG_RST) + ice_dcbnl_devreset(netdev); + if (ret == ICE_DCB_NO_HW_CHG) + ret = ICE_DCB_HW_CHG_RST; + +delapp_out: + mutex_unlock(&pf->tc_mutex); + return ret; +} + +/** + * ice_dcbnl_cee_set_all - Commit CEE DCB settings to HW + * @netdev: the corresponding netdev + */ +static u8 ice_dcbnl_cee_set_all(struct net_device *netdev) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_dcbx_cfg *new_cfg; + int err; + + if ((pf->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) || + !(pf->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) + return ICE_DCB_NO_HW_CHG; + + new_cfg = &pf->hw.port_info->desired_dcbx_cfg; + + mutex_lock(&pf->tc_mutex); + + err = ice_pf_dcb_cfg(pf, new_cfg, true); + + mutex_unlock(&pf->tc_mutex); + return (err != ICE_DCB_HW_CHG_RST) ? ICE_DCB_NO_HW_CHG : err; +} + +static const struct dcbnl_rtnl_ops dcbnl_ops = { + /* IEEE 802.1Qaz std */ + .ieee_getets = ice_dcbnl_getets, + .ieee_setets = ice_dcbnl_setets, + .ieee_getpfc = ice_dcbnl_getpfc, + .ieee_setpfc = ice_dcbnl_setpfc, + .ieee_setapp = ice_dcbnl_setapp, + .ieee_delapp = ice_dcbnl_delapp, + + /* CEE std */ + .getstate = ice_dcbnl_getstate, + .setstate = ice_dcbnl_setstate, + .getpermhwaddr = ice_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = ice_dcbnl_set_pg_tc_cfg_tx, + .setpgbwgcfgtx = ice_dcbnl_set_pg_bwg_cfg_tx, + .getpgtccfgtx = ice_dcbnl_get_pg_tc_cfg_tx, + .getpgbwgcfgtx = ice_dcbnl_get_pg_bwg_cfg_tx, + .getpgtccfgrx = ice_dcbnl_get_pg_tc_cfg_rx, + .getpgbwgcfgrx = ice_dcbnl_get_pg_bwg_cfg_rx, + .setpfccfg = ice_dcbnl_set_pfc_cfg, + .getpfccfg = ice_dcbnl_get_pfc_cfg, + .setall = ice_dcbnl_cee_set_all, + .getcap = ice_dcbnl_get_cap, + .getnumtcs = ice_dcbnl_getnumtcs, + .getpfcstate = ice_dcbnl_getpfcstate, + .getapp = ice_dcbnl_getapp, + + /* DCBX configuration */ + .getdcbx = ice_dcbnl_getdcbx, + .setdcbx = ice_dcbnl_setdcbx, +}; + +/** + * ice_dcbnl_set_all - set all the apps and ieee data from DCBX config + * @vsi: pointer to VSI struct + */ +void ice_dcbnl_set_all(struct ice_vsi *vsi) +{ + struct net_device *netdev = vsi->netdev; + struct ice_dcbx_cfg *dcbxcfg; + struct ice_port_info *pi; + struct dcb_app sapp; + struct ice_pf *pf; + int i; + + if (!netdev) + return; + + pf = ice_netdev_to_pf(netdev); + pi = pf->hw.port_info; + + /* SW DCB taken care of by SW Default Config */ + if (pf->dcbx_cap & DCB_CAP_DCBX_HOST) + return; + + /* DCB not enabled */ + if (!test_bit(ICE_FLAG_DCB_ENA, pf->flags)) + return; + + dcbxcfg = &pi->local_dcbx_cfg; + + for (i = 0; i < dcbxcfg->numapps; i++) { + u8 prio, tc_map; + + prio = dcbxcfg->app[i].priority; + tc_map = BIT(dcbxcfg->etscfg.prio_table[prio]); + + /* Add APP only if the TC is enabled for this VSI */ + if (tc_map & vsi->tc_cfg.ena_tc) { + sapp.selector = dcbxcfg->app[i].selector; + sapp.protocol = dcbxcfg->app[i].prot_id; + sapp.priority = prio; + dcb_ieee_setapp(netdev, &sapp); + } + } + /* Notify user-space of the changes */ + dcbnl_ieee_notify(netdev, RTM_SETDCB, DCB_CMD_IEEE_SET, 0, 0); +} + +/** + * ice_dcbnl_vsi_del_app - Delete APP on all VSIs + * @vsi: pointer to the main VSI + * @app: APP to delete + * + * Delete given APP from all the VSIs for given PF + */ +static void +ice_dcbnl_vsi_del_app(struct ice_vsi *vsi, + struct ice_dcb_app_priority_table *app) +{ + struct dcb_app sapp; + int err; + + sapp.selector = app->selector; + sapp.protocol = app->prot_id; + sapp.priority = app->priority; + err = ice_dcbnl_delapp(vsi->netdev, &sapp); + dev_dbg(&vsi->back->pdev->dev, + "Deleting app for VSI idx=%d err=%d sel=%d proto=0x%x, prio=%d\n", + vsi->idx, err, app->selector, app->prot_id, app->priority); +} + +/** + * ice_dcbnl_flush_apps - Delete all removed APPs + * @pf: the corresponding PF + * @old_cfg: old DCBX configuration data + * @new_cfg: new DCBX configuration data + * + * Find and delete all APPS that are not present in the passed + * DCB configuration + */ +void +ice_dcbnl_flush_apps(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg, + struct ice_dcbx_cfg *new_cfg) +{ + struct ice_vsi *main_vsi = ice_get_main_vsi(pf); + int i; + + if (!main_vsi) + return; + + for (i = 0; i < old_cfg->numapps; i++) { + struct ice_dcb_app_priority_table app = old_cfg->app[i]; + + /* The APP is not available anymore delete it */ + if (!ice_dcbnl_find_app(new_cfg, &app)) + ice_dcbnl_vsi_del_app(main_vsi, &app); + } +} + +/** + * ice_dcbnl_setup - setup DCBNL + * @vsi: VSI to get associated netdev from + */ +void ice_dcbnl_setup(struct ice_vsi *vsi) +{ + struct net_device *netdev = vsi->netdev; + struct ice_pf *pf; + + pf = ice_netdev_to_pf(netdev); + if (!test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags)) + return; + + netdev->dcbnl_ops = &dcbnl_ops; + ice_dcbnl_set_all(vsi); +} diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.h b/drivers/net/ethernet/intel/ice/ice_dcb_nl.h new file mode 100644 index 000000000000..6c630a362293 --- /dev/null +++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2019, Intel Corporation. */ + +#ifndef _ICE_DCB_NL_H_ +#define _ICE_DCB_NL_H_ + +#ifdef CONFIG_DCB +void ice_dcbnl_setup(struct ice_vsi *vsi); +void ice_dcbnl_set_all(struct ice_vsi *vsi); +void +ice_dcbnl_flush_apps(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg, + struct ice_dcbx_cfg *new_cfg); +#else +#define ice_dcbnl_setup(vsi) do {} while (0) +#define ice_dcbnl_set_all(vsi) do {} while (0) +#define ice_dcbnl_flush_apps(pf, old_cfg, new_cfg) do {} while (0) +#endif /* CONFIG_DCB */ + +#endif /* _ICE_DCB_NL_H_ */ diff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h index 152fbd556e9b..e8f32350fed2 100644 --- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h +++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h @@ -52,6 +52,9 @@ #define PF_MBX_ATQLEN_ATQLEN_M ICE_M(0x3FF, 0) #define PF_MBX_ATQLEN_ATQENABLE_M BIT(31) #define PF_MBX_ATQT 0x0022E300 +#define PRTDCB_GENC 0x00083000 +#define PRTDCB_GENC_PFCLDA_S 16 +#define PRTDCB_GENC_PFCLDA_M ICE_M(0xFFFF, 16) #define PRTDCB_GENS 0x00083020 #define PRTDCB_GENS_DCBX_STATUS_S 0 #define PRTDCB_GENS_DCBX_STATUS_M ICE_M(0x7, 0) diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index f3cfd5017e29..bc37896930f2 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -2487,6 +2487,7 @@ err_vsi: bool ice_is_reset_in_progress(unsigned long *state) { return test_bit(__ICE_RESET_OICR_RECV, state) || + test_bit(__ICE_DCBNL_DEVRESET, state) || test_bit(__ICE_PFR_REQ, state) || test_bit(__ICE_CORER_REQ, state) || test_bit(__ICE_GLOBR_REQ, state); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index cacbe2103b28..d963aec59845 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -9,6 +9,7 @@ #include "ice_base.h" #include "ice_lib.h" #include "ice_dcb_lib.h" +#include "ice_dcb_nl.h" #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 8 @@ -2516,6 +2517,9 @@ static int ice_setup_pf_sw(struct ice_pf *pf) /* netdev has to be configured before setting frame size */ ice_vsi_cfg_frame_size(vsi); + /* Setup DCB netlink interface */ + ice_dcbnl_setup(vsi); + /* registering the NAPI handler requires both the queues and * netdev to be created, which are done in ice_pf_vsi_setup() * and ice_cfg_netdev() respectively @@ -2596,6 +2600,7 @@ static void ice_deinit_pf(struct ice_pf *pf) { ice_service_task_stop(pf); mutex_destroy(&pf->sw_mutex); + mutex_destroy(&pf->tc_mutex); mutex_destroy(&pf->avail_q_mutex); if (pf->avail_txqs) { @@ -2645,6 +2650,7 @@ static int ice_init_pf(struct ice_pf *pf) ice_set_pf_caps(pf); mutex_init(&pf->sw_mutex); + mutex_init(&pf->tc_mutex); /* setup service timer and periodic service task */ timer_setup(&pf->serv_tmr, ice_service_timer, 0); -- cgit v1.2.3-59-g8ed1b From 5f8cc355c4134767aa586920458cc21e01295715 Mon Sep 17 00:00:00 2001 From: Henry Tieman Date: Wed, 6 Nov 2019 02:05:30 -0800 Subject: ice: avoid setting features during reset Certain subsystems behave very badly when called during reset (core dump). This patch returns -EBUSY when reconfiguring some subsystems during reset. With this patch some ethtool functions will not core dump during reset. Signed-off-by: Henry Tieman Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d963aec59845..cb93fe5529f6 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -3776,6 +3776,7 @@ ice_set_features(struct net_device *netdev, netdev_features_t features) { struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; int ret = 0; /* Don't set any netdev advanced features with device in Safe Mode */ @@ -3785,6 +3786,13 @@ ice_set_features(struct net_device *netdev, netdev_features_t features) return ret; } + /* Do not change setting during reset */ + if (ice_is_reset_in_progress(pf->state)) { + dev_err(&vsi->back->pdev->dev, + "Device is resetting, changing advanced netdev features temporarily unavailable.\n"); + return -EBUSY; + } + /* Multiple features can be changed in one call so keep features in * separate if/else statements to guarantee each feature is checked */ -- cgit v1.2.3-59-g8ed1b From c0a3665f71a2f086800abea4d9d14d28269089d6 Mon Sep 17 00:00:00 2001 From: Usha Ketineni Date: Wed, 6 Nov 2019 02:05:31 -0800 Subject: ice: Fix to change Rx/Tx ring descriptor size via ethtool with DCBx This patch fixes the call trace caused by the kernel when the Rx/Tx descriptor size change request is initiated via ethtool when DCB is configured. ice_set_ringparam() should use vsi->num_txq instead of vsi->alloc_txq as it represents the queues that are enabled in the driver when DCB is enabled/disabled. Otherwise, queue index being used can go out of range. For example, when vsi->alloc_txq has 104 queues and with 3 TCS enabled via DCB, each TC gets 34 queues, vsi->num_txq will be 102 and only 102 queues will be enabled. Signed-off-by: Usha Ketineni Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index a8e51bc95198..f85d224f964d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -2654,14 +2654,14 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n", vsi->tx_rings[0]->count, new_tx_cnt); - tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, + tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, sizeof(*tx_rings), GFP_KERNEL); if (!tx_rings) { err = -ENOMEM; goto done; } - for (i = 0; i < vsi->alloc_txq; i++) { + ice_for_each_txq(vsi, i) { /* clone ring and setup updated count */ tx_rings[i] = *vsi->tx_rings[i]; tx_rings[i].count = new_tx_cnt; @@ -2714,14 +2714,14 @@ process_rx: netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n", vsi->rx_rings[0]->count, new_rx_cnt); - rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, + rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_rxq, sizeof(*rx_rings), GFP_KERNEL); if (!rx_rings) { err = -ENOMEM; goto done; } - for (i = 0; i < vsi->alloc_rxq; i++) { + ice_for_each_rxq(vsi, i) { /* clone ring and setup updated count */ rx_rings[i] = *vsi->rx_rings[i]; rx_rings[i].count = new_rx_cnt; @@ -2759,7 +2759,7 @@ process_link: ice_down(vsi); if (tx_rings) { - for (i = 0; i < vsi->alloc_txq; i++) { + ice_for_each_txq(vsi, i) { ice_free_tx_ring(vsi->tx_rings[i]); *vsi->tx_rings[i] = tx_rings[i]; } @@ -2767,7 +2767,7 @@ process_link: } if (rx_rings) { - for (i = 0; i < vsi->alloc_rxq; i++) { + ice_for_each_rxq(vsi, i) { ice_free_rx_ring(vsi->rx_rings[i]); /* copy the real tail offset */ rx_rings[i].tail = vsi->rx_rings[i]->tail; @@ -2801,7 +2801,7 @@ process_link: free_tx: /* error cleanup if the Rx allocations failed after getting Tx */ if (tx_rings) { - for (i = 0; i < vsi->alloc_txq; i++) + ice_for_each_txq(vsi, i) ice_free_tx_ring(&tx_rings[i]); devm_kfree(&pf->pdev->dev, tx_rings); } -- cgit v1.2.3-59-g8ed1b From 241c8cf052e7b1ee32e60bd31214afdaaaa28c55 Mon Sep 17 00:00:00 2001 From: Paul Greenwalt Date: Wed, 6 Nov 2019 02:05:32 -0800 Subject: ice: configure software LLDP in ice_init_pf_dcb Move software LLDP configuration when FW DCBX is disabled to ice_init_pf_dcb, since that is where the FW DCBX state is determined. Remove this software LLDP configuration from ice_vsi_setup and ice_set_priv_flags. Software configuration includes redirecting Rx LLDP packets up the stack, when FW DCBX is not running. Signed-off-by: Paul Greenwalt Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 15 +++++++++++++++ drivers/net/ethernet/intel/ice/ice_ethtool.c | 5 ----- drivers/net/ethernet/intel/ice/ice_lib.c | 14 ++++---------- 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 9448a289363d..1150dbd98d0b 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -594,6 +594,8 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) "DCB is enabled in the hardware, max number of TCs supported on this port are %d\n", pf->hw.func_caps.common_cap.maxtc); if (err) { + struct ice_vsi *pf_vsi; + /* FW LLDP is disabled, activate SW DCBX/LLDP mode */ dev_info(&pf->pdev->dev, "FW LLDP is disabled, DCBx/LLDP in SW mode.\n"); @@ -606,6 +608,19 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) goto dcb_init_err; } + /* If the FW DCBX engine is not running then Rx LLDP packets + * need to be redirected up the stack. + */ + pf_vsi = ice_get_main_vsi(pf); + if (!pf_vsi) { + dev_err(&pf->pdev->dev, + "Failed to set local DCB config\n"); + err = -EIO; + goto dcb_init_err; + } + + ice_cfg_sw_lldp(pf_vsi, false, true); + pf->dcbx_cap = DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index f85d224f964d..1f00091f7906 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1206,11 +1206,6 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) status = ice_init_pf_dcb(pf, true); if (status) dev_warn(&pf->pdev->dev, "Fail to init DCB\n"); - - /* Forward LLDP packets to default VSI so that they - * are passed up the stack - */ - ice_cfg_sw_lldp(vsi, false, true); } else { enum ice_status status; bool dcbx_agent_status; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index bc37896930f2..ebcf81edcb19 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -1881,23 +1881,17 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, * out PAUSE or PFC frames. If enabled, FW can still send FC frames. * The rule is added once for PF VSI in order to create appropriate * recipe, since VSI/VSI list is ignored with drop action... - * Also add rules to handle LLDP Tx and Rx packets. Tx LLDP packets - * need to be dropped so that VFs cannot send LLDP packets to reconfig - * DCB settings in the HW. Also, if the FW DCBX engine is not running - * then Rx LLDP packets need to be redirected up the stack. + * Also add rules to handle LLDP Tx packets. Tx LLDP packets need to + * be dropped so that VFs cannot send LLDP packets to reconfig DCB + * settings in the HW. */ - if (!ice_is_safe_mode(pf)) { + if (!ice_is_safe_mode(pf)) if (vsi->type == ICE_VSI_PF) { ice_vsi_add_rem_eth_mac(vsi, true); /* Tx LLDP packets */ ice_cfg_sw_lldp(vsi, true, true); - - /* Rx LLDP packets */ - if (!test_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags)) - ice_cfg_sw_lldp(vsi, false, true); } - } return vsi; -- cgit v1.2.3-59-g8ed1b From ec4f5a436bdf0e5453ad15c4f34a59b9b675ff48 Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Wed, 6 Nov 2019 02:05:33 -0800 Subject: ice: Check if VF is disabled for Opcode and other operations This patch adds code to check if PF or VF is disabled before honoring mailbox message to configure VF - If it is disabled, and opcode is for resetting VF, the PF driver simply tell VF that all is set. In addition, if reset is ongoing, and Admin intend to configure VF on the host, we can poll the VF enabling bit to make sure it is ready before continue - If after ~250 milliseconds, VF is not in active state, we can bail out with invalid error. Signed-off-by: Akeem G Abodunrin Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 74 ++++++++++++++++++++---- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h | 1 + 2 files changed, 63 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index b4813ccc467d..639d1b2a9e19 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1151,6 +1151,25 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) return true; } +/** + * ice_is_vf_disabled + * @vf: pointer to the VF info + * + * Returns true if the PF or VF is disabled, false otherwise. + */ +static bool ice_is_vf_disabled(struct ice_vf *vf) +{ + struct ice_pf *pf = vf->pf; + + /* If the PF has been disabled, there is no need resetting VF until + * PF is active again. Similarly, if the VF has been disabled, this + * means something else is resetting the VF, so we shouldn't continue. + * Otherwise, set disable VF state bit for actual reset, and continue. + */ + return (test_bit(__ICE_VF_DIS, pf->state) || + test_bit(ICE_VF_STATE_DIS, vf->vf_states)); +} + /** * ice_reset_vf - Reset a particular VF * @vf: pointer to the VF structure @@ -1168,19 +1187,15 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) u32 reg; int i; - /* If the PF has been disabled, there is no need resetting VF until - * PF is active again. - */ - if (test_bit(__ICE_VF_DIS, pf->state)) - return false; - - /* If the VF has been disabled, this means something else is - * resetting the VF, so we shouldn't continue. Otherwise, set - * disable VF state bit for actual reset, and continue. - */ - if (test_and_set_bit(ICE_VF_STATE_DIS, vf->vf_states)) - return false; + if (ice_is_vf_disabled(vf)) { + dev_dbg(&pf->pdev->dev, + "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n", + vf->vf_id); + return true; + } + /* Set VF disable bit state here, before triggering reset */ + set_bit(ICE_VF_STATE_DIS, vf->vf_states); ice_trigger_vf_reset(vf, is_vflr, false); vsi = pf->vsi[vf->lan_vsi_idx]; @@ -3122,6 +3137,23 @@ out: return ret; } +/** + * ice_wait_on_vf_reset + * @vf: The VF being resseting + * + * Poll to make sure a given VF is ready after reset + */ +static void ice_wait_on_vf_reset(struct ice_vf *vf) +{ + int i; + + for (i = 0; i < ICE_MAX_VF_RESET_WAIT; i++) { + if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) + break; + msleep(20); + } +} + /** * ice_set_vf_mac * @netdev: network interface device structure @@ -3145,6 +3177,15 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } vf = &pf->vf[vf_id]; + /* Don't set MAC on disabled VF */ + if (ice_is_vf_disabled(vf)) + return -EINVAL; + + /* In case VF is in reset mode, wait until it is completed. Depending + * on factors like queue disabling routine, this could take ~250ms + */ + ice_wait_on_vf_reset(vf); + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); return -EBUSY; @@ -3192,6 +3233,15 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) } vf = &pf->vf[vf_id]; + /* Don't set Trusted Mode on disabled VF */ + if (ice_is_vf_disabled(vf)) + return -EINVAL; + + /* In case VF is in reset mode, wait until it is completed. Depending + * on factors like queue disabling routine, this could take ~250ms + */ + ice_wait_on_vf_reset(vf); + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); return -EBUSY; diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index 0d9880c8bba3..2e867ad2e81d 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -38,6 +38,7 @@ #define ICE_MAX_POLICY_INTR_PER_VF 33 #define ICE_MIN_INTR_PER_VF (ICE_MIN_QS_PER_VF + 1) #define ICE_DFLT_INTR_PER_VF (ICE_DFLT_QS_PER_VF + 1) +#define ICE_MAX_VF_RESET_WAIT 15 /* Specific VF states */ enum ice_vf_states { -- cgit v1.2.3-59-g8ed1b From b791cdd5c78c74a165ee8da69d6c8ae683d17c38 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 6 Nov 2019 02:05:34 -0800 Subject: ice: Change max MSI-x vector_id check in cfg_irq_map Currently we check to make sure the vector_id passed down from iavf is less than or equal to pf->hw.func_caps.common_caps.num_msix_vectors. This is incorrect because the vector_id is always 0-based and never greater than or equal to the ICE_MAX_INTR_PER_VF. Fix this by checking to make sure the vector_id is less than the max allowed interrupts per VF (ICE_MAX_INTR_PER_VF). Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 639d1b2a9e19..2ac83ad3d1a6 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -2173,9 +2173,11 @@ static int ice_vc_cfg_irq_map_msg(struct ice_vf *vf, u8 *msg) vector_id = map->vector_id; vsi_id = map->vsi_id; - /* validate msg params */ - if (!(vector_id < pf->hw.func_caps.common_cap - .num_msix_vectors) || !ice_vc_isvalid_vsi_id(vf, vsi_id) || + /* vector_id is always 0-based for each VF, and can never be + * larger than or equal to the max allowed interrupts per VF + */ + if (!(vector_id < ICE_MAX_INTR_PER_VF) || + !ice_vc_isvalid_vsi_id(vf, vsi_id) || (!vector_id && (map->rxq_map || map->txq_map))) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; -- cgit v1.2.3-59-g8ed1b From e000248ec870b2e5e2c9934191b057b5d136f267 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 6 Nov 2019 02:05:35 -0800 Subject: ice: use pkg_dwnld_status instead of sq_last_status Since the return value from the Download Package AQ command is stored in hw->pkg_dwnld_status, use that instead of sq_last_status since that may have the return value from some other AQ command leading to unexpected results. Signed-off-by: Bruce Allan Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index cb93fe5529f6..4f4ebb499559 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2900,7 +2900,7 @@ ice_log_pkg_init(struct ice_hw *hw, enum ice_status *status) ICE_PKG_SUPP_VER_MAJ, ICE_PKG_SUPP_VER_MNR); break; case ICE_ERR_AQ_ERROR: - switch (hw->adminq.sq_last_status) { + switch (hw->pkg_dwnld_status) { case ICE_AQ_RC_ENOSEC: case ICE_AQ_RC_EBADSIG: dev_err(dev, -- cgit v1.2.3-59-g8ed1b From 88bb432a55de8ae62106305083a8bfbb23b01ad2 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Wed, 6 Nov 2019 02:05:36 -0800 Subject: ice: delay less Shorten the delay for SQ responses, but increase the number of loops. Max delay time is unchanged, but some operations complete much more quickly. In the process, add a new define to make the delay count and delay time more explicit. Add comments to make things more explicit. This fixes a problem with VF resets failing on with many VFs. Signed-off-by: Mitch Williams Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 2 +- drivers/net/ethernet/intel/ice/ice_controlq.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 2353166c654e..c68709c7ef81 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -948,7 +948,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, if (ice_sq_done(hw, cq)) break; - mdelay(1); + udelay(ICE_CTL_Q_SQ_CMD_USEC); total_delay++; } while (total_delay < cq->sq_cmd_timeout); diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index 44945c2165d8..4df9da359135 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -31,8 +31,9 @@ enum ice_ctl_q { ICE_CTL_Q_MAILBOX, }; -/* Control Queue default settings */ -#define ICE_CTL_Q_SQ_CMD_TIMEOUT 250 /* msecs */ +/* Control Queue timeout settings - max delay 250ms */ +#define ICE_CTL_Q_SQ_CMD_TIMEOUT 2500 /* Count 2500 times */ +#define ICE_CTL_Q_SQ_CMD_USEC 100 /* Check every 100usec */ struct ice_ctl_q_ring { void *dma_head; /* Virtual address to DMA head */ -- cgit v1.2.3-59-g8ed1b From 893869d5d0c922c41d044e92ddd79fff28a27fc1 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Wed, 6 Nov 2019 02:05:37 -0800 Subject: ice: Update enum ice_flg64_bits to current specification Currently the VLAN ice_flg64_bits are off by 1. Fix this by setting the ICE_FLG_EVLAN_x8100 flag to 14, which also updates ICE_FLG_EVLAN_x9100 to 15 and ICE_FLG_VLAN_x8100 to 16. Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h index 2aac8f13daeb..ad34f22d44ef 100644 --- a/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h +++ b/drivers/net/ethernet/intel/ice/ice_lan_tx_rx.h @@ -211,7 +211,7 @@ enum ice_flex_rx_mdid { /* Rx/Tx Flag64 packet flag bits */ enum ice_flg64_bits { ICE_FLG_PKT_DSI = 0, - ICE_FLG_EVLAN_x8100 = 15, + ICE_FLG_EVLAN_x8100 = 14, ICE_FLG_EVLAN_x9100, ICE_FLG_VLAN_x8100, ICE_FLG_TNL_MAC = 22, -- cgit v1.2.3-59-g8ed1b From 87a2e4988994df699f674af33e5cc30db5bf0690 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Wed, 6 Nov 2019 02:05:38 -0800 Subject: ice: remove unnecessary conditional check There is no reason to do this conditional check before the assignment so simply remove it. Signed-off-by: Bruce Allan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 1acdd43a2edd..77d211ea3aae 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -416,8 +416,7 @@ ice_add_vsi(struct ice_hw *hw, u16 vsi_handle, struct ice_vsi_ctx *vsi_ctx, ice_save_vsi_ctx(hw, vsi_handle, tmp_vsi_ctx); } else { /* update with new HW VSI num */ - if (tmp_vsi_ctx->vsi_num != vsi_ctx->vsi_num) - tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; + tmp_vsi_ctx->vsi_num = vsi_ctx->vsi_num; } return 0; -- cgit v1.2.3-59-g8ed1b From 964674f1ddc10a27702be63b241618570c611e9d Mon Sep 17 00:00:00 2001 From: Anirudh Venkataramanan Date: Wed, 6 Nov 2019 02:05:39 -0800 Subject: ice: Introduce and use ice_vsi_type_str ice_vsi_type_str converts an ice_vsi_type enum value to its string equivalent. This is expected to help easily identify VSI types from module print statements. Signed-off-by: Anirudh Venkataramanan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_lib.c | 21 ++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_lib.h | 2 ++ drivers/net/ethernet/intel/ice/ice_main.c | 16 ++++++++-------- 3 files changed, 30 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index ebcf81edcb19..d71f7ce0a265 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -6,6 +6,24 @@ #include "ice_lib.h" #include "ice_dcb_lib.h" +/** + * ice_vsi_type_str - maps VSI type enum to string equivalents + * @type: VSI type enum + */ +const char *ice_vsi_type_str(enum ice_vsi_type type) +{ + switch (type) { + case ICE_VSI_PF: + return "ICE_VSI_PF"; + case ICE_VSI_VF: + return "ICE_VSI_VF"; + case ICE_VSI_LB: + return "ICE_VSI_LB"; + default: + return "unknown"; + } +} + /** * ice_vsi_ctrl_rx_rings - Start or stop a VSI's Rx rings * @vsi: the VSI being configured @@ -700,7 +718,8 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; break; case ICE_VSI_LB: - dev_dbg(&pf->pdev->dev, "Unsupported VSI type %d\n", vsi->type); + dev_dbg(&pf->pdev->dev, "Unsupported VSI type %s\n", + ice_vsi_type_str(vsi->type)); return; default: dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index 2c5c01b7a582..e86aa60c0254 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -6,6 +6,8 @@ #include "ice.h" +const char *ice_vsi_type_str(enum ice_vsi_type type); + int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, const u8 *macaddr); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 4f4ebb499559..5681e3be81f2 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4487,8 +4487,8 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) err = ice_vsi_rebuild(vsi); if (err) { dev_err(&pf->pdev->dev, - "rebuild VSI failed, err %d, VSI index %d, type %d\n", - err, vsi->idx, type); + "rebuild VSI failed, err %d, VSI index %d, type %s\n", + err, vsi->idx, ice_vsi_type_str(type)); return err; } @@ -4496,8 +4496,8 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) status = ice_replay_vsi(&pf->hw, vsi->idx); if (status) { dev_err(&pf->pdev->dev, - "replay VSI failed, status %d, VSI index %d, type %d\n", - status, vsi->idx, type); + "replay VSI failed, status %d, VSI index %d, type %s\n", + status, vsi->idx, ice_vsi_type_str(type)); return -EIO; } @@ -4510,13 +4510,13 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) err = ice_ena_vsi(vsi, false); if (err) { dev_err(&pf->pdev->dev, - "enable VSI failed, err %d, VSI index %d, type %d\n", - err, vsi->idx, type); + "enable VSI failed, err %d, VSI index %d, type %s\n", + err, vsi->idx, ice_vsi_type_str(type)); return err; } - dev_info(&pf->pdev->dev, "VSI rebuilt. VSI index %d, type %d\n", - vsi->idx, type); + dev_info(&pf->pdev->dev, "VSI rebuilt. VSI index %d, type %s\n", + vsi->idx, ice_vsi_type_str(type)); } return 0; -- cgit v1.2.3-59-g8ed1b From faa01721ced5952e05e3baa8d375a9d37e81285b Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 6 Nov 2019 02:05:40 -0800 Subject: ice: use more accurate ICE_DBG mask types ice_debug_cq is passed a mask which is always ICE_DBG_AQ_CMD. Modify this function, removing the mask parameter entirely, and directly use the more appropriate ICE_DBG_AQ_DESC and ICE_DBG_AQ_DESC_BUF. The function is only called from ice_controlq.c, and has no other callers outside of that file. Move it and mark it static to avoid namespace pollution. Signed-off-by: Jacob Keller Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 50 ----------------------- drivers/net/ethernet/intel/ice/ice_common.h | 2 - drivers/net/ethernet/intel/ice/ice_controlq.c | 57 ++++++++++++++++++++++++--- drivers/net/ethernet/intel/ice/ice_type.h | 2 + 4 files changed, 53 insertions(+), 58 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 3e0d50c1bc7a..36be501ae623 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1251,56 +1251,6 @@ const struct ice_ctx_ele ice_tlan_ctx_info[] = { { 0 } }; -/** - * ice_debug_cq - * @hw: pointer to the hardware structure - * @mask: debug mask - * @desc: pointer to control queue descriptor - * @buf: pointer to command buffer - * @buf_len: max length of buf - * - * Dumps debug log about control command with descriptor contents. - */ -void -ice_debug_cq(struct ice_hw *hw, u32 __maybe_unused mask, void *desc, void *buf, - u16 buf_len) -{ - struct ice_aq_desc *cq_desc = (struct ice_aq_desc *)desc; - u16 len; - -#ifndef CONFIG_DYNAMIC_DEBUG - if (!(mask & hw->debug_mask)) - return; -#endif - - if (!desc) - return; - - len = le16_to_cpu(cq_desc->datalen); - - ice_debug(hw, mask, - "CQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", - le16_to_cpu(cq_desc->opcode), - le16_to_cpu(cq_desc->flags), - le16_to_cpu(cq_desc->datalen), le16_to_cpu(cq_desc->retval)); - ice_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n", - le32_to_cpu(cq_desc->cookie_high), - le32_to_cpu(cq_desc->cookie_low)); - ice_debug(hw, mask, "\tparam (0,1) 0x%08X 0x%08X\n", - le32_to_cpu(cq_desc->params.generic.param0), - le32_to_cpu(cq_desc->params.generic.param1)); - ice_debug(hw, mask, "\taddr (h,l) 0x%08X 0x%08X\n", - le32_to_cpu(cq_desc->params.generic.addr_high), - le32_to_cpu(cq_desc->params.generic.addr_low)); - if (buf && cq_desc->datalen != 0) { - ice_debug(hw, mask, "Buffer:\n"); - if (buf_len < len) - len = buf_len; - - ice_debug_array(hw, mask, 16, 1, (u8 *)buf, len); - } -} - /* FW Admin Queue command wrappers */ /* Software lock/mutex that is meant to be held while the Global Config Lock diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 5a52f3b3e688..b22aa561e253 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -13,8 +13,6 @@ enum ice_status ice_nvm_validate_checksum(struct ice_hw *hw); -void -ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf, u16 buf_len); enum ice_status ice_init_hw(struct ice_hw *hw); void ice_deinit_hw(struct ice_hw *hw); enum ice_status diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index c68709c7ef81..947728aada46 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -809,6 +809,52 @@ static u16 ice_clean_sq(struct ice_hw *hw, struct ice_ctl_q_info *cq) return ICE_CTL_Q_DESC_UNUSED(sq); } +/** + * ice_debug_cq + * @hw: pointer to the hardware structure + * @desc: pointer to control queue descriptor + * @buf: pointer to command buffer + * @buf_len: max length of buf + * + * Dumps debug log about control command with descriptor contents. + */ +static void ice_debug_cq(struct ice_hw *hw, void *desc, void *buf, u16 buf_len) +{ + struct ice_aq_desc *cq_desc = (struct ice_aq_desc *)desc; + u16 len; + + if (!IS_ENABLED(CONFIG_DYNAMIC_DEBUG) && + !((ICE_DBG_AQ_DESC | ICE_DBG_AQ_DESC_BUF) & hw->debug_mask)) + return; + + if (!desc) + return; + + len = le16_to_cpu(cq_desc->datalen); + + ice_debug(hw, ICE_DBG_AQ_DESC, + "CQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n", + le16_to_cpu(cq_desc->opcode), + le16_to_cpu(cq_desc->flags), + le16_to_cpu(cq_desc->datalen), le16_to_cpu(cq_desc->retval)); + ice_debug(hw, ICE_DBG_AQ_DESC, "\tcookie (h,l) 0x%08X 0x%08X\n", + le32_to_cpu(cq_desc->cookie_high), + le32_to_cpu(cq_desc->cookie_low)); + ice_debug(hw, ICE_DBG_AQ_DESC, "\tparam (0,1) 0x%08X 0x%08X\n", + le32_to_cpu(cq_desc->params.generic.param0), + le32_to_cpu(cq_desc->params.generic.param1)); + ice_debug(hw, ICE_DBG_AQ_DESC, "\taddr (h,l) 0x%08X 0x%08X\n", + le32_to_cpu(cq_desc->params.generic.addr_high), + le32_to_cpu(cq_desc->params.generic.addr_low)); + if (buf && cq_desc->datalen != 0) { + ice_debug(hw, ICE_DBG_AQ_DESC_BUF, "Buffer:\n"); + if (buf_len < len) + len = buf_len; + + ice_debug_array(hw, ICE_DBG_AQ_DESC_BUF, 16, 1, (u8 *)buf, len); + } +} + /** * ice_sq_done - check if FW has processed the Admin Send Queue (ATQ) * @hw: pointer to the HW struct @@ -934,10 +980,10 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, } /* Debug desc and buffer */ - ice_debug(hw, ICE_DBG_AQ_MSG, + ice_debug(hw, ICE_DBG_AQ_DESC, "ATQ: Control Send queue desc and buffer:\n"); - ice_debug_cq(hw, ICE_DBG_AQ_CMD, (void *)desc_on_ring, buf, buf_size); + ice_debug_cq(hw, (void *)desc_on_ring, buf, buf_size); (cq->sq.next_to_use)++; if (cq->sq.next_to_use == cq->sq.count) @@ -986,7 +1032,7 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, ice_debug(hw, ICE_DBG_AQ_MSG, "ATQ: desc and buffer writeback:\n"); - ice_debug_cq(hw, ICE_DBG_AQ_CMD, (void *)desc, buf, buf_size); + ice_debug_cq(hw, (void *)desc, buf, buf_size); /* save writeback AQ if requested */ if (details->wb_desc) @@ -1084,10 +1130,9 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, if (e->msg_buf && e->msg_len) memcpy(e->msg_buf, cq->rq.r.rq_bi[desc_idx].va, e->msg_len); - ice_debug(hw, ICE_DBG_AQ_MSG, "ARQ: desc and buffer:\n"); + ice_debug(hw, ICE_DBG_AQ_DESC, "ARQ: desc and buffer:\n"); - ice_debug_cq(hw, ICE_DBG_AQ_CMD, (void *)desc, e->msg_buf, - cq->rq_buf_size); + ice_debug_cq(hw, (void *)desc, e->msg_buf, cq->rq_buf_size); /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message size diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index d3d7049c97f0..eba8b04b8cbd 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -46,6 +46,8 @@ static inline u32 ice_round_to_num(u32 N, u32 R) #define ICE_DBG_PKG BIT_ULL(16) #define ICE_DBG_RES BIT_ULL(17) #define ICE_DBG_AQ_MSG BIT_ULL(24) +#define ICE_DBG_AQ_DESC BIT_ULL(25) +#define ICE_DBG_AQ_DESC_BUF BIT_ULL(26) #define ICE_DBG_AQ_CMD BIT_ULL(27) #define ICE_DBG_USER BIT_ULL(31) -- cgit v1.2.3-59-g8ed1b From fb0254b28434697dc7edd986b0811813ac862368 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 6 Nov 2019 02:05:41 -0800 Subject: ice: print opcode when printing controlq errors To help aid in debugging, display the command opcode in debug messages that print an error code. This makes it easier to see what command failed if only ICE_DBG_AQ_MSG is enabled. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c index 947728aada46..dd946866d7b8 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.c +++ b/drivers/net/ethernet/intel/ice/ice_controlq.c @@ -1017,7 +1017,8 @@ ice_sq_send_cmd(struct ice_hw *hw, struct ice_ctl_q_info *cq, retval = le16_to_cpu(desc->retval); if (retval) { ice_debug(hw, ICE_DBG_AQ_MSG, - "Control Send Queue command completed with error 0x%x\n", + "Control Send Queue command 0x%04X completed with error 0x%X\n", + le16_to_cpu(desc->opcode), retval); /* strip off FW internal code */ @@ -1121,7 +1122,8 @@ ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq, if (flags & ICE_AQ_FLAG_ERR) { ret_code = ICE_ERR_AQ_ERROR; ice_debug(hw, ICE_DBG_AQ_MSG, - "Control Receive Queue Event received with error 0x%x\n", + "Control Receive Queue Event 0x%04X received with error 0x%X\n", + le16_to_cpu(desc->opcode), cq->rq_last_status); } memcpy(&e->desc, desc, sizeof(e->desc)); -- cgit v1.2.3-59-g8ed1b From a0c76345e3d3dbc40c39de2e00d15a3b7eef7885 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 8 Nov 2019 21:42:43 +0100 Subject: devlink: disallow reload operation during device cleanup There is a race between driver code that does setup/cleanup of device and devlink reload operation that in some drivers works with the same code. Use after free could we easily obtained by running: while true; do echo 10 > /sys/bus/netdevsim/new_device devlink dev reload netdevsim/netdevsim10 & echo 10 > /sys/bus/netdevsim/del_device done Fix this by enabling reload only after setup of device is complete and disabling it at the beginning of the cleanup process. Reported-by: Ido Schimmel Fixes: 2d8dc5bbf4e7 ("devlink: Add support for reload") Signed-off-by: Jiri Pirko Acked-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 3 +++ drivers/net/ethernet/mellanox/mlxsw/core.c | 6 ++++- drivers/net/netdevsim/dev.c | 3 +++ include/net/devlink.h | 7 +++-- net/core/devlink.c | 42 +++++++++++++++++++++++++++++- 5 files changed, 57 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 22c72fb7206a..77f056b0895e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -4015,6 +4015,7 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) goto err_params_unregister; devlink_params_publish(devlink); + devlink_reload_enable(devlink); pci_save_state(pdev); return 0; @@ -4126,6 +4127,8 @@ static void mlx4_remove_one(struct pci_dev *pdev) struct devlink *devlink = priv_to_devlink(priv); int active_vfs = 0; + devlink_reload_disable(devlink); + if (mlx4_is_slave(dev)) persist->interface_state |= MLX4_INTERFACE_STATE_NOWAIT; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index e1a90f5bddd0..da436a6aad2f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1198,8 +1198,10 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, if (err) goto err_thermal_init; - if (mlxsw_driver->params_register) + if (mlxsw_driver->params_register) { devlink_params_publish(devlink); + devlink_reload_enable(devlink); + } return 0; @@ -1263,6 +1265,8 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, { struct devlink *devlink = priv_to_devlink(mlxsw_core); + if (!reload) + devlink_reload_disable(devlink); if (devlink_is_reload_failed(devlink)) { if (!reload) /* Only the parts that were not de-initialized in the diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 3da96c7e8265..059711edfc61 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -820,6 +820,7 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) goto err_bpf_dev_exit; devlink_params_publish(devlink); + devlink_reload_enable(devlink); return 0; err_bpf_dev_exit: @@ -865,6 +866,8 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); struct devlink *devlink = priv_to_devlink(nsim_dev); + devlink_reload_disable(devlink); + nsim_dev_reload_destroy(nsim_dev); nsim_bpf_dev_exit(nsim_dev); diff --git a/include/net/devlink.h b/include/net/devlink.h index 8d6b5846822c..7891611868e4 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -38,8 +38,9 @@ struct devlink { struct device *dev; possible_net_t _net; struct mutex lock; - bool reload_failed; - bool registered; + u8 reload_failed:1, + reload_enabled:1, + registered:1; char priv[0] __aligned(NETDEV_ALIGN); }; @@ -824,6 +825,8 @@ void devlink_net_set(struct devlink *devlink, struct net *net); struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size); int devlink_register(struct devlink *devlink, struct device *dev); void devlink_unregister(struct devlink *devlink); +void devlink_reload_enable(struct devlink *devlink); +void devlink_reload_disable(struct devlink *devlink); void devlink_free(struct devlink *devlink); int devlink_port_register(struct devlink *devlink, struct devlink_port *devlink_port, diff --git a/net/core/devlink.c b/net/core/devlink.c index ff53f7d29dea..2e027c9436e0 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2791,6 +2791,9 @@ static int devlink_reload(struct devlink *devlink, struct net *dest_net, { int err; + if (!devlink->reload_enabled) + return -EOPNOTSUPP; + err = devlink->ops->reload_down(devlink, !!dest_net, extack); if (err) return err; @@ -6308,12 +6311,49 @@ EXPORT_SYMBOL_GPL(devlink_register); void devlink_unregister(struct devlink *devlink) { mutex_lock(&devlink_mutex); + WARN_ON(devlink_reload_supported(devlink) && + devlink->reload_enabled); devlink_notify(devlink, DEVLINK_CMD_DEL); list_del(&devlink->list); mutex_unlock(&devlink_mutex); } EXPORT_SYMBOL_GPL(devlink_unregister); +/** + * devlink_reload_enable - Enable reload of devlink instance + * + * @devlink: devlink + * + * Should be called at end of device initialization + * process when reload operation is supported. + */ +void devlink_reload_enable(struct devlink *devlink) +{ + mutex_lock(&devlink_mutex); + devlink->reload_enabled = true; + mutex_unlock(&devlink_mutex); +} +EXPORT_SYMBOL_GPL(devlink_reload_enable); + +/** + * devlink_reload_disable - Disable reload of devlink instance + * + * @devlink: devlink + * + * Should be called at the beginning of device cleanup + * process when reload operation is supported. + */ +void devlink_reload_disable(struct devlink *devlink) +{ + mutex_lock(&devlink_mutex); + /* Mutex is taken which ensures that no reload operation is in + * progress while setting up forbidded flag. + */ + devlink->reload_enabled = false; + mutex_unlock(&devlink_mutex); +} +EXPORT_SYMBOL_GPL(devlink_reload_disable); + /** * devlink_free - Free devlink instance resources * @@ -8201,7 +8241,7 @@ static void __net_exit devlink_pernet_pre_exit(struct net *net) if (WARN_ON(!devlink_reload_supported(devlink))) continue; err = devlink_reload(devlink, &init_net, NULL); - if (err) + if (err && err != -EOPNOTSUPP) pr_warn("Failed to reload devlink instance into init_net\n"); } } -- cgit v1.2.3-59-g8ed1b From 727b3668b730634228fc65c336c2a7a080e02885 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 8 Nov 2019 17:39:29 +0000 Subject: net: sfp: rework upstream interface The current upstream interface is an all-or-nothing, which is sub-optimal for future changes, as it doesn't allow the upstream driver to prepare for the SFP module becoming available, as it is at boot. Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus interface structure instead, which allows the upstream driver to prepare for a module being available as soon as add-upstream is called. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 10 +++--- drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++++++++-------------- include/linux/sfp.h | 25 ++++++++----- 3 files changed, 88 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index f16d9e92a81a..e3fbc8e93317 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -567,7 +567,7 @@ static int phylink_register_sfp(struct phylink *pl, struct sfp_bus *bus; int ret; - bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops); + bus = sfp_bus_find_fwnode(fwnode); if (IS_ERR(bus)) { ret = PTR_ERR(bus); phylink_err(pl, "unable to attach SFP bus: %d\n", ret); @@ -576,7 +576,10 @@ static int phylink_register_sfp(struct phylink *pl, pl->sfp_bus = bus; - return 0; + ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops); + sfp_bus_put(bus); + + return ret; } /** @@ -670,8 +673,7 @@ EXPORT_SYMBOL_GPL(phylink_create); */ void phylink_destroy(struct phylink *pl) { - if (pl->sfp_bus) - sfp_unregister_upstream(pl->sfp_bus); + sfp_bus_del_upstream(pl->sfp_bus); if (pl->link_gpio) gpiod_put(pl->link_gpio); diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index d037aab6a71d..715d45214e18 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -329,10 +329,19 @@ static void sfp_bus_release(struct kref *kref) kfree(bus); } -static void sfp_bus_put(struct sfp_bus *bus) +/** + * sfp_bus_put() - put a reference on the &struct sfp_bus + * bus: the &struct sfp_bus found via sfp_bus_find_fwnode() + * + * Put a reference on the &struct sfp_bus and free the underlying structure + * if this was the last reference. + */ +void sfp_bus_put(struct sfp_bus *bus) { - kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex); + if (bus) + kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex); } +EXPORT_SYMBOL_GPL(sfp_bus_put); static int sfp_register_bus(struct sfp_bus *bus) { @@ -348,11 +357,11 @@ static int sfp_register_bus(struct sfp_bus *bus) return ret; } } + bus->registered = true; bus->socket_ops->attach(bus->sfp); if (bus->started) bus->socket_ops->start(bus->sfp); bus->upstream_ops->attach(bus->upstream, bus); - bus->registered = true; return 0; } @@ -446,13 +455,12 @@ static void sfp_upstream_clear(struct sfp_bus *bus) } /** - * sfp_register_upstream_node() - parse and register the neighbouring device + * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode * @fwnode: firmware node for the parent device (MAC or PHY) - * @upstream: the upstream private data - * @ops: the upstream's &struct sfp_upstream_ops * - * Parse the parent device's firmware node for a SFP bus, and register the - * SFP bus using sfp_register_upstream(). + * Parse the parent device's firmware node for a SFP bus, and locate + * the sfp_bus structure, incrementing its reference count. This must + * be put via sfp_bus_put() when done. * * Returns: on success, a pointer to the sfp_bus structure, * %NULL if no SFP is specified, @@ -462,9 +470,7 @@ static void sfp_upstream_clear(struct sfp_bus *bus) * %-ENOMEM if we failed to allocate the bus. * an error from the upstream's connect_phy() method. */ -struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, - void *upstream, - const struct sfp_upstream_ops *ops) +struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode) { struct fwnode_reference_args ref; struct sfp_bus *bus; @@ -482,7 +488,39 @@ struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, if (!bus) return ERR_PTR(-ENOMEM); + return bus; +} +EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode); + +/** + * sfp_bus_add_upstream() - parse and register the neighbouring device + * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode() + * @upstream: the upstream private data + * @ops: the upstream's &struct sfp_upstream_ops + * + * Add upstream driver for the SFP bus, and if the bus is complete, register + * the SFP bus using sfp_register_upstream(). This takes a reference on the + * bus, so it is safe to put the bus after this call. + * + * Returns: on success, a pointer to the sfp_bus structure, + * %NULL if no SFP is specified, + * on failure, an error pointer value: + * corresponding to the errors detailed for + * fwnode_property_get_reference_args(). + * %-ENOMEM if we failed to allocate the bus. + * an error from the upstream's connect_phy() method. + */ +int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, + const struct sfp_upstream_ops *ops) +{ + int ret; + + /* If no bus, return success */ + if (!bus) + return 0; + rtnl_lock(); + kref_get(&bus->kref); bus->upstream_ops = ops; bus->upstream = upstream; @@ -495,33 +533,33 @@ struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, } rtnl_unlock(); - if (ret) { + if (ret) sfp_bus_put(bus); - bus = ERR_PTR(ret); - } - return bus; + return ret; } -EXPORT_SYMBOL_GPL(sfp_register_upstream_node); +EXPORT_SYMBOL_GPL(sfp_bus_add_upstream); /** - * sfp_unregister_upstream() - Unregister sfp bus + * sfp_bus_del_upstream() - Delete a sfp bus * @bus: a pointer to the &struct sfp_bus structure for the sfp module * - * Unregister a previously registered upstream connection for the SFP - * module. @bus is returned from sfp_register_upstream(). + * Delete a previously registered upstream connection for the SFP + * module. @bus should have been added by sfp_bus_add_upstream(). */ -void sfp_unregister_upstream(struct sfp_bus *bus) +void sfp_bus_del_upstream(struct sfp_bus *bus) { - rtnl_lock(); - if (bus->sfp) - sfp_unregister_bus(bus); - sfp_upstream_clear(bus); - rtnl_unlock(); + if (bus) { + rtnl_lock(); + if (bus->sfp) + sfp_unregister_bus(bus); + sfp_upstream_clear(bus); + rtnl_unlock(); - sfp_bus_put(bus); + sfp_bus_put(bus); + } } -EXPORT_SYMBOL_GPL(sfp_unregister_upstream); +EXPORT_SYMBOL_GPL(sfp_bus_del_upstream); /* Socket driver entry points */ int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev) diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 355a08a76fd4..c8464de7cff5 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, u8 *data); void sfp_upstream_start(struct sfp_bus *bus); void sfp_upstream_stop(struct sfp_bus *bus); -struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode, - void *upstream, - const struct sfp_upstream_ops *ops); -void sfp_unregister_upstream(struct sfp_bus *bus); +void sfp_bus_put(struct sfp_bus *bus); +struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode); +int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, + const struct sfp_upstream_ops *ops); +void sfp_bus_del_upstream(struct sfp_bus *bus); #else static inline int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, @@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(struct sfp_bus *bus) { } -static inline struct sfp_bus *sfp_register_upstream_node( - struct fwnode_handle *fwnode, void *upstream, - const struct sfp_upstream_ops *ops) +static inline void sfp_bus_put(struct sfp_bus *bus) +{ +} + +static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode) { return NULL; } -static inline void sfp_unregister_upstream(struct sfp_bus *bus) +static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, + const struct sfp_upstream_ops *ops) +{ + return 0; +} + +static inline void sfp_bus_del_upstream(struct sfp_bus *bus) { } #endif -- cgit v1.2.3-59-g8ed1b From 8bfdce1defb1fb62bcc0e4929abd756585dabd0d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2019 21:59:43 +0100 Subject: r8169: add helper r8168g_phy_param Integrated PHY's from RTL8168g support an indirect access method for PHY parameters. On page 0x0a43 parameter number is written to register 0x13, then the parameter can be accessed via register 0x14. Add a helper for this to improve readability and simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 285 ++++++++++-------------------- 1 file changed, 98 insertions(+), 187 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 8a7b22301296..dbdb77d71c29 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1086,6 +1086,17 @@ static void rtl_w0w1_phy(struct rtl8169_private *tp, int reg_addr, int p, int m) rtl_writephy(tp, reg_addr, (val & ~m) | p); } +static void r8168g_phy_param(struct phy_device *phydev, u16 parm, + u16 mask, u16 val) +{ + int oldpage = phy_select_page(phydev, 0x0a43); + + __phy_write(phydev, 0x13, parm); + __phy_modify(phydev, 0x14, mask, val); + + phy_restore_page(phydev, oldpage, 0); +} + DECLARE_RTL_COND(rtl_ephyar_cond) { return RTL_R32(tp, EPHYAR) & EPHYAR_FLAG; @@ -3222,12 +3233,8 @@ static void rtl8168g_phy_adjust_10m_aldps(struct rtl8169_private *tp) phy_modify_paged(phydev, 0x0bcc, 0x14, BIT(8), 0); phy_modify_paged(phydev, 0x0a44, 0x11, 0, BIT(7) | BIT(6)); - phy_write(phydev, 0x1f, 0x0a43); - phy_write(phydev, 0x13, 0x8084); - phy_clear_bits(phydev, 0x14, BIT(14) | BIT(13)); - phy_set_bits(phydev, 0x10, BIT(12) | BIT(1) | BIT(0)); - - phy_write(phydev, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x8084, 0x6000, 0x0000); + phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x1003); } static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) @@ -3257,9 +3264,7 @@ static void rtl8168g_1_hw_phy_config(struct rtl8169_private *tp) phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2)); /* Enable UC LPF tune function */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8012); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); + r8168g_phy_param(tp->phydev, 0x8012, 0x0000, 0x8000); phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14)); @@ -3289,73 +3294,48 @@ static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp) static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) { + struct phy_device *phydev = tp->phydev; u16 dout_tapbin; u32 data; rtl_apply_firmware(tp); /* CHN EST parameters adjust - giga master */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x809b); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0xf800); - rtl_writephy(tp, 0x13, 0x80a2); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0xff00); - rtl_writephy(tp, 0x13, 0x80a4); - rtl_w0w1_phy(tp, 0x14, 0x8500, 0xff00); - rtl_writephy(tp, 0x13, 0x809c); - rtl_w0w1_phy(tp, 0x14, 0xbd00, 0xff00); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x809b, 0xf800, 0x8000); + r8168g_phy_param(phydev, 0x80a2, 0xff00, 0x8000); + r8168g_phy_param(phydev, 0x80a4, 0xff00, 0x8500); + r8168g_phy_param(phydev, 0x809c, 0xff00, 0xbd00); /* CHN EST parameters adjust - giga slave */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x80ad); - rtl_w0w1_phy(tp, 0x14, 0x7000, 0xf800); - rtl_writephy(tp, 0x13, 0x80b4); - rtl_w0w1_phy(tp, 0x14, 0x5000, 0xff00); - rtl_writephy(tp, 0x13, 0x80ac); - rtl_w0w1_phy(tp, 0x14, 0x4000, 0xff00); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x80ad, 0xf800, 0x7000); + r8168g_phy_param(phydev, 0x80b4, 0xff00, 0x5000); + r8168g_phy_param(phydev, 0x80ac, 0xff00, 0x4000); /* CHN EST parameters adjust - fnet */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x808e); - rtl_w0w1_phy(tp, 0x14, 0x1200, 0xff00); - rtl_writephy(tp, 0x13, 0x8090); - rtl_w0w1_phy(tp, 0x14, 0xe500, 0xff00); - rtl_writephy(tp, 0x13, 0x8092); - rtl_w0w1_phy(tp, 0x14, 0x9f00, 0xff00); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x808e, 0xff00, 0x1200); + r8168g_phy_param(phydev, 0x8090, 0xff00, 0xe500); + r8168g_phy_param(phydev, 0x8092, 0xff00, 0x9f00); /* enable R-tune & PGA-retune function */ dout_tapbin = 0; - rtl_writephy(tp, 0x1f, 0x0a46); - data = rtl_readphy(tp, 0x13); + data = phy_read_paged(phydev, 0x0a46, 0x13); data &= 3; data <<= 2; dout_tapbin |= data; - data = rtl_readphy(tp, 0x12); + data = phy_read_paged(phydev, 0x0a46, 0x12); data &= 0xc000; data >>= 14; dout_tapbin |= data; dout_tapbin = ~(dout_tapbin^0x08); dout_tapbin <<= 12; dout_tapbin &= 0xf000; - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x827a); - rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); - rtl_writephy(tp, 0x13, 0x827b); - rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); - rtl_writephy(tp, 0x13, 0x827c); - rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); - rtl_writephy(tp, 0x13, 0x827d); - rtl_w0w1_phy(tp, 0x14, dout_tapbin, 0xf000); - - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x0811); - rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a42); - rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + + r8168g_phy_param(phydev, 0x827a, 0xf000, dout_tapbin); + r8168g_phy_param(phydev, 0x827b, 0xf000, dout_tapbin); + r8168g_phy_param(phydev, 0x827c, 0xf000, dout_tapbin); + r8168g_phy_param(phydev, 0x827d, 0xf000, dout_tapbin); + r8168g_phy_param(phydev, 0x0811, 0x0000, 0x0800); + phy_modify_paged(phydev, 0x0a42, 0x16, 0x0000, 0x0002); /* enable GPHY 10M */ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11)); @@ -3363,22 +3343,13 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) /* SAR ADC performance */ phy_modify_paged(tp->phydev, 0x0bca, 0x17, BIT(12) | BIT(13), BIT(14)); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x803f); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x8047); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x804f); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x8057); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x805f); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x8067); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x13, 0x806f); - rtl_w0w1_phy(tp, 0x14, 0x0000, 0x3000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x803f, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x8047, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x804f, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x8057, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x805f, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x8067, 0x3000, 0x0000); + r8168g_phy_param(phydev, 0x806f, 0x3000, 0x0000); /* disable phy pfm mode */ phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0); @@ -3391,24 +3362,18 @@ static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp) static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) { u16 ioffset_p3, ioffset_p2, ioffset_p1, ioffset_p0; + struct phy_device *phydev = tp->phydev; u16 rlen; u32 data; rtl_apply_firmware(tp); /* CHIN EST parameter update */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x808a); - rtl_w0w1_phy(tp, 0x14, 0x000a, 0x003f); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x808a, 0x003f, 0x000a); /* enable R-tune & PGA-retune function */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x0811); - rtl_w0w1_phy(tp, 0x14, 0x0800, 0x0000); - rtl_writephy(tp, 0x1f, 0x0a42); - rtl_w0w1_phy(tp, 0x16, 0x0002, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x0811, 0x0000, 0x0800); + phy_modify_paged(phydev, 0x0a42, 0x16, 0x0000, 0x0002); /* enable GPHY 10M */ phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11)); @@ -3428,26 +3393,20 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) data = (ioffset_p3<<12)|(ioffset_p2<<8)|(ioffset_p1<<4)|(ioffset_p0); if ((ioffset_p3 != 0x0f) || (ioffset_p2 != 0x0f) || - (ioffset_p1 != 0x0f) || (ioffset_p0 != 0x0f)) { - rtl_writephy(tp, 0x1f, 0x0bcf); - rtl_writephy(tp, 0x16, data); - rtl_writephy(tp, 0x1f, 0x0000); - } + (ioffset_p1 != 0x0f) || (ioffset_p0 != 0x0f)) + phy_write_paged(phydev, 0x0bcf, 0x16, data); /* Modify rlen (TX LPF corner frequency) level */ - rtl_writephy(tp, 0x1f, 0x0bcd); - data = rtl_readphy(tp, 0x16); + data = phy_read_paged(phydev, 0x0bcd, 0x16); data &= 0x000f; rlen = 0; if (data > 3) rlen = data - 3; data = rlen | (rlen<<4) | (rlen<<8) | (rlen<<12); - rtl_writephy(tp, 0x17, data); - rtl_writephy(tp, 0x1f, 0x0bcd); - rtl_writephy(tp, 0x1f, 0x0000); + phy_write_paged(phydev, 0x0bcd, 0x17, data); /* disable phy pfm mode */ - phy_modify_paged(tp->phydev, 0x0a44, 0x11, BIT(7), 0); + phy_modify_paged(phydev, 0x0a44, 0x11, BIT(7), 0); rtl8168g_disable_aldps(tp); rtl8168g_config_eee_phy(tp); @@ -3456,22 +3415,21 @@ static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp) static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp) { + struct phy_device *phydev = tp->phydev; + /* Enable PHY auto speed down */ - phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2)); + phy_modify_paged(phydev, 0x0a44, 0x11, 0, BIT(3) | BIT(2)); rtl8168g_phy_adjust_10m_aldps(tp); /* Enable EEE auto-fallback function */ - phy_modify_paged(tp->phydev, 0x0a4b, 0x11, 0, BIT(2)); + phy_modify_paged(phydev, 0x0a4b, 0x11, 0, BIT(2)); /* Enable UC LPF tune function */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8012); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x8000); /* set rg_sel_sdm_rate */ - phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14)); + phy_modify_paged(phydev, 0x0c42, 0x11, BIT(13), BIT(14)); rtl8168g_disable_aldps(tp); rtl8168g_config_eee_phy(tp); @@ -3480,63 +3438,38 @@ static void rtl8168ep_1_hw_phy_config(struct rtl8169_private *tp) static void rtl8168ep_2_hw_phy_config(struct rtl8169_private *tp) { + struct phy_device *phydev = tp->phydev; + rtl8168g_phy_adjust_10m_aldps(tp); /* Enable UC LPF tune function */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8012); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x8000); /* Set rg_sel_sdm_rate */ phy_modify_paged(tp->phydev, 0x0c42, 0x11, BIT(13), BIT(14)); /* Channel estimation parameters */ - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x80f3); - rtl_w0w1_phy(tp, 0x14, 0x8b00, ~0x8bff); - rtl_writephy(tp, 0x13, 0x80f0); - rtl_w0w1_phy(tp, 0x14, 0x3a00, ~0x3aff); - rtl_writephy(tp, 0x13, 0x80ef); - rtl_w0w1_phy(tp, 0x14, 0x0500, ~0x05ff); - rtl_writephy(tp, 0x13, 0x80f6); - rtl_w0w1_phy(tp, 0x14, 0x6e00, ~0x6eff); - rtl_writephy(tp, 0x13, 0x80ec); - rtl_w0w1_phy(tp, 0x14, 0x6800, ~0x68ff); - rtl_writephy(tp, 0x13, 0x80ed); - rtl_w0w1_phy(tp, 0x14, 0x7c00, ~0x7cff); - rtl_writephy(tp, 0x13, 0x80f2); - rtl_w0w1_phy(tp, 0x14, 0xf400, ~0xf4ff); - rtl_writephy(tp, 0x13, 0x80f4); - rtl_w0w1_phy(tp, 0x14, 0x8500, ~0x85ff); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x8110); - rtl_w0w1_phy(tp, 0x14, 0xa800, ~0xa8ff); - rtl_writephy(tp, 0x13, 0x810f); - rtl_w0w1_phy(tp, 0x14, 0x1d00, ~0x1dff); - rtl_writephy(tp, 0x13, 0x8111); - rtl_w0w1_phy(tp, 0x14, 0xf500, ~0xf5ff); - rtl_writephy(tp, 0x13, 0x8113); - rtl_w0w1_phy(tp, 0x14, 0x6100, ~0x61ff); - rtl_writephy(tp, 0x13, 0x8115); - rtl_w0w1_phy(tp, 0x14, 0x9200, ~0x92ff); - rtl_writephy(tp, 0x13, 0x810e); - rtl_w0w1_phy(tp, 0x14, 0x0400, ~0x04ff); - rtl_writephy(tp, 0x13, 0x810c); - rtl_w0w1_phy(tp, 0x14, 0x7c00, ~0x7cff); - rtl_writephy(tp, 0x13, 0x810b); - rtl_w0w1_phy(tp, 0x14, 0x5a00, ~0x5aff); - rtl_writephy(tp, 0x1f, 0x0a43); - rtl_writephy(tp, 0x13, 0x80d1); - rtl_w0w1_phy(tp, 0x14, 0xff00, ~0xffff); - rtl_writephy(tp, 0x13, 0x80cd); - rtl_w0w1_phy(tp, 0x14, 0x9e00, ~0x9eff); - rtl_writephy(tp, 0x13, 0x80d3); - rtl_w0w1_phy(tp, 0x14, 0x0e00, ~0x0eff); - rtl_writephy(tp, 0x13, 0x80d5); - rtl_w0w1_phy(tp, 0x14, 0xca00, ~0xcaff); - rtl_writephy(tp, 0x13, 0x80d7); - rtl_w0w1_phy(tp, 0x14, 0x8400, ~0x84ff); + r8168g_phy_param(phydev, 0x80f3, 0xff00, 0x8b00); + r8168g_phy_param(phydev, 0x80f0, 0xff00, 0x3a00); + r8168g_phy_param(phydev, 0x80ef, 0xff00, 0x0500); + r8168g_phy_param(phydev, 0x80f6, 0xff00, 0x6e00); + r8168g_phy_param(phydev, 0x80ec, 0xff00, 0x6800); + r8168g_phy_param(phydev, 0x80ed, 0xff00, 0x7c00); + r8168g_phy_param(phydev, 0x80f2, 0xff00, 0xf400); + r8168g_phy_param(phydev, 0x80f4, 0xff00, 0x8500); + r8168g_phy_param(phydev, 0x8110, 0xff00, 0xa800); + r8168g_phy_param(phydev, 0x810f, 0xff00, 0x1d00); + r8168g_phy_param(phydev, 0x8111, 0xff00, 0xf500); + r8168g_phy_param(phydev, 0x8113, 0xff00, 0x6100); + r8168g_phy_param(phydev, 0x8115, 0xff00, 0x9200); + r8168g_phy_param(phydev, 0x810e, 0xff00, 0x0400); + r8168g_phy_param(phydev, 0x810c, 0xff00, 0x7c00); + r8168g_phy_param(phydev, 0x810b, 0xff00, 0x5a00); + r8168g_phy_param(phydev, 0x80d1, 0xff00, 0xff00); + r8168g_phy_param(phydev, 0x80cd, 0xff00, 0x9e00); + r8168g_phy_param(phydev, 0x80d3, 0xff00, 0x0e00); + r8168g_phy_param(phydev, 0x80d5, 0xff00, 0xca00); + r8168g_phy_param(phydev, 0x80d7, 0xff00, 0x8400); /* Force PWM-mode */ rtl_writephy(tp, 0x1f, 0x0bcd); @@ -3651,38 +3584,22 @@ static void rtl8125_1_hw_phy_config(struct rtl8169_private *tp) phy_modify_paged(phydev, 0xad1, 0x15, 0x0000, 0x03ff); phy_modify_paged(phydev, 0xad1, 0x16, 0x0000, 0x03ff); - phy_write(phydev, 0x1f, 0x0a43); - phy_write(phydev, 0x13, 0x80ea); - phy_modify(phydev, 0x14, 0xff00, 0xc400); - phy_write(phydev, 0x13, 0x80eb); - phy_modify(phydev, 0x14, 0x0700, 0x0300); - phy_write(phydev, 0x13, 0x80f8); - phy_modify(phydev, 0x14, 0xff00, 0x1c00); - phy_write(phydev, 0x13, 0x80f1); - phy_modify(phydev, 0x14, 0xff00, 0x3000); - phy_write(phydev, 0x13, 0x80fe); - phy_modify(phydev, 0x14, 0xff00, 0xa500); - phy_write(phydev, 0x13, 0x8102); - phy_modify(phydev, 0x14, 0xff00, 0x5000); - phy_write(phydev, 0x13, 0x8105); - phy_modify(phydev, 0x14, 0xff00, 0x3300); - phy_write(phydev, 0x13, 0x8100); - phy_modify(phydev, 0x14, 0xff00, 0x7000); - phy_write(phydev, 0x13, 0x8104); - phy_modify(phydev, 0x14, 0xff00, 0xf000); - phy_write(phydev, 0x13, 0x8106); - phy_modify(phydev, 0x14, 0xff00, 0x6500); - phy_write(phydev, 0x13, 0x80dc); - phy_modify(phydev, 0x14, 0xff00, 0xed00); - phy_write(phydev, 0x13, 0x80df); - phy_set_bits(phydev, 0x14, BIT(8)); - phy_write(phydev, 0x13, 0x80e1); - phy_clear_bits(phydev, 0x14, BIT(8)); - phy_write(phydev, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x80ea, 0xff00, 0xc400); + r8168g_phy_param(phydev, 0x80eb, 0x0700, 0x0300); + r8168g_phy_param(phydev, 0x80f8, 0xff00, 0x1c00); + r8168g_phy_param(phydev, 0x80f1, 0xff00, 0x3000); + r8168g_phy_param(phydev, 0x80fe, 0xff00, 0xa500); + r8168g_phy_param(phydev, 0x8102, 0xff00, 0x5000); + r8168g_phy_param(phydev, 0x8105, 0xff00, 0x3300); + r8168g_phy_param(phydev, 0x8100, 0xff00, 0x7000); + r8168g_phy_param(phydev, 0x8104, 0xff00, 0xf000); + r8168g_phy_param(phydev, 0x8106, 0xff00, 0x6500); + r8168g_phy_param(phydev, 0x80dc, 0xff00, 0xed00); + r8168g_phy_param(phydev, 0x80df, 0x0000, 0x0100); + r8168g_phy_param(phydev, 0x80e1, 0x0100, 0x0000); phy_modify_paged(phydev, 0xbf0, 0x13, 0x003f, 0x0038); - phy_write_paged(phydev, 0xa43, 0x13, 0x819f); - phy_write_paged(phydev, 0xa43, 0x14, 0xd0b6); + r8168g_phy_param(phydev, 0x819f, 0xffff, 0xd0b6); phy_write_paged(phydev, 0xbc3, 0x12, 0x5555); phy_modify_paged(phydev, 0xbf0, 0x15, 0x0e00, 0x0a00); @@ -3737,22 +3654,16 @@ static void rtl8125_2_hw_phy_config(struct rtl8169_private *tp) phy_write(phydev, 0x14, 0x0002); for (i = 0; i < 25; i++) phy_write(phydev, 0x14, 0x0000); - - phy_write(phydev, 0x13, 0x8257); - phy_write(phydev, 0x14, 0x020F); - - phy_write(phydev, 0x13, 0x80EA); - phy_write(phydev, 0x14, 0x7843); phy_write(phydev, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x8257, 0xffff, 0x020F); + r8168g_phy_param(phydev, 0x80ea, 0xffff, 0x7843); + rtl_apply_firmware(tp); phy_modify_paged(phydev, 0xd06, 0x14, 0x0000, 0x2000); - phy_write(phydev, 0x1f, 0x0a43); - phy_write(phydev, 0x13, 0x81a2); - phy_set_bits(phydev, 0x14, BIT(8)); - phy_write(phydev, 0x1f, 0x0000); + r8168g_phy_param(phydev, 0x81a2, 0x0000, 0x0100); phy_modify_paged(phydev, 0xb54, 0x16, 0xff00, 0xdb00); phy_modify_paged(phydev, 0xa45, 0x12, 0x0001, 0x0000); -- cgit v1.2.3-59-g8ed1b From b5e189b4f5902ec92dba769fc88ebdef44a68941 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2019 22:00:13 +0100 Subject: r8169: add helper r8168d_phy_param Integrated PHY's from RTL8168d support an indirect access method for PHY parameters. On page 0x0005 parameter number is written to register 0x05, then the parameter can be accessed via register 0x06. Add a helper for this to improve readability and simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 249 ++++++++++-------------------- 1 file changed, 85 insertions(+), 164 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index dbdb77d71c29..fa4b3d71f4fb 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1086,6 +1086,17 @@ static void rtl_w0w1_phy(struct rtl8169_private *tp, int reg_addr, int p, int m) rtl_writephy(tp, reg_addr, (val & ~m) | p); } +static void r8168d_phy_param(struct phy_device *phydev, u16 parm, + u16 mask, u16 val) +{ + int oldpage = phy_select_page(phydev, 0x0005); + + __phy_write(phydev, 0x05, parm); + __phy_modify(phydev, 0x06, mask, val); + + phy_restore_page(phydev, oldpage, 0); +} + static void r8168g_phy_param(struct phy_device *phydev, u16 parm, u16 mask, u16 val) { @@ -2295,12 +2306,9 @@ static void rtl8168f_config_eee_phy(struct rtl8169_private *tp) phy_write(phydev, 0x1f, 0x0007); phy_write(phydev, 0x1e, 0x0020); phy_set_bits(phydev, 0x15, BIT(8)); - - phy_write(phydev, 0x1f, 0x0005); - phy_write(phydev, 0x05, 0x8b85); - phy_set_bits(phydev, 0x06, BIT(13)); - phy_write(phydev, 0x1f, 0x0000); + + r8168d_phy_param(phydev, 0x8b85, 0, BIT(13)); } static void rtl8168g_config_eee_phy(struct rtl8169_private *tp) @@ -2738,15 +2746,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x0d, val | set[i]); } } else { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0002 }, - { 0x05, 0x6662 }, - { 0x1f, 0x0005 }, - { 0x05, 0x8330 }, - { 0x06, 0x6662 } - }; - - rtl_writephy_batch(tp, phy_reg_init); + phy_write_paged(tp->phydev, 0x0002, 0x05, 0x6662); + r8168d_phy_param(tp->phydev, 0x8330, 0xffff, 0x6662); } /* RSET couple improve */ @@ -2791,15 +2792,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x0d, val | set[i]); } } else { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0002 }, - { 0x05, 0x2642 }, - { 0x1f, 0x0005 }, - { 0x05, 0x8330 }, - { 0x06, 0x2642 } - }; - - rtl_writephy_batch(tp, phy_reg_init); + phy_write_paged(tp->phydev, 0x0002, 0x05, 0x2642); + r8168d_phy_param(tp->phydev, 0x8330, 0xffff, 0x2642); } /* Fine tune PLL performance */ @@ -2899,12 +2893,6 @@ static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp) static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { - /* Enable Delay cap */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b80 }, - { 0x06, 0xc896 }, - { 0x1f, 0x0000 }, - /* Channel estimation fine tune */ { 0x1f, 0x0001 }, { 0x0b, 0x6c20 }, @@ -2925,9 +2913,13 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) { 0x18, 0x0006 }, { 0x1f, 0x0000 } }; + struct phy_device *phydev = tp->phydev; rtl_apply_firmware(tp); + /* Enable Delay cap */ + r8168d_phy_param(phydev, 0x8b80, 0xffff, 0xc896); + rtl_writephy_batch(tp, phy_reg_init); /* DCO enable for 10M IDLE Power */ @@ -2948,25 +2940,17 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0000); rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b86); - rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); + r8168d_phy_param(phydev, 0x8b85, 0x2000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x2000); rtl_writephy(tp, 0x1f, 0x0007); rtl_writephy(tp, 0x1e, 0x0020); rtl_w0w1_phy(tp, 0x15, 0x0000, 0x1100); rtl_writephy(tp, 0x1f, 0x0006); rtl_writephy(tp, 0x00, 0x5a00); rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x0d, 0x0007); - rtl_writephy(tp, 0x0e, 0x003c); - rtl_writephy(tp, 0x0d, 0x4007); - rtl_writephy(tp, 0x0e, 0x0000); - rtl_writephy(tp, 0x0d, 0x0000); + + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0000); } static void rtl_rar_exgmac_set(struct rtl8169_private *tp, u8 *addr) @@ -3000,22 +2984,18 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) { 0x09, 0xa20f }, { 0x1f, 0x0000 }, { 0x1f, 0x0000 }, - - /* Green Setting */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b5b }, - { 0x06, 0x9222 }, - { 0x05, 0x8b6d }, - { 0x06, 0x8000 }, - { 0x05, 0x8b76 }, - { 0x06, 0x8000 }, - { 0x1f, 0x0000 } }; + struct phy_device *phydev = tp->phydev; rtl_apply_firmware(tp); rtl_writephy_batch(tp, phy_reg_init); + /* Green Setting */ + r8168d_phy_param(phydev, 0x8b5b, 0xffff, 0x9222); + r8168d_phy_param(phydev, 0x8b6d, 0xffff, 0x8000); + r8168d_phy_param(phydev, 0x8b76, 0xffff, 0x8000); + /* For 4-corner performance improve */ rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x8b80); @@ -3032,16 +3012,10 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); /* improve 10M EEE waveform */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b86); - rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); /* Improve 2-pair detection performance */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b85, 0x0000, 0x4000); rtl8168f_config_eee_phy(tp); rtl_enable_eee(tp); @@ -3061,11 +3035,10 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) { + struct phy_device *phydev = tp->phydev; + /* For 4-corner performance improve */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b80); - rtl_w0w1_phy(tp, 0x06, 0x0006, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b80, 0x0000, 0x0006); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0007); @@ -3075,10 +3048,7 @@ static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); /* Improve 10M EEE waveform */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b86); - rtl_w0w1_phy(tp, 0x06, 0x0001, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); rtl8168f_config_eee_phy(tp); rtl_enable_eee(tp); @@ -3086,52 +3056,34 @@ static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - /* Channel estimation fine tune */ - { 0x1f, 0x0003 }, - { 0x09, 0xa20f }, - { 0x1f, 0x0000 }, + struct phy_device *phydev = tp->phydev; - /* Modify green table for giga & fnet */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b55 }, - { 0x06, 0x0000 }, - { 0x05, 0x8b5e }, - { 0x06, 0x0000 }, - { 0x05, 0x8b67 }, - { 0x06, 0x0000 }, - { 0x05, 0x8b70 }, - { 0x06, 0x0000 }, - { 0x1f, 0x0000 }, - { 0x1f, 0x0007 }, - { 0x1e, 0x0078 }, - { 0x17, 0x0000 }, - { 0x19, 0x00fb }, - { 0x1f, 0x0000 }, + rtl_apply_firmware(tp); - /* Modify green table for 10M */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b79 }, - { 0x06, 0xaa00 }, - { 0x1f, 0x0000 }, + /* Channel estimation fine tune */ + phy_write_paged(phydev, 0x0003, 0x09, 0xa20f); - /* Disable hiimpedance detection (RTCT) */ - { 0x1f, 0x0003 }, - { 0x01, 0x328a }, - { 0x1f, 0x0000 } - }; + /* Modify green table for giga & fnet */ + r8168d_phy_param(phydev, 0x8b55, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b5e, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b67, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b70, 0xffff, 0x0000); + phy_write(phydev, 0x1f, 0x0007); + phy_write(phydev, 0x1e, 0x0078); + phy_write(phydev, 0x17, 0x0000); + phy_write(phydev, 0x19, 0x00fb); + phy_write(phydev, 0x1f, 0x0000); - rtl_apply_firmware(tp); + /* Modify green table for 10M */ + r8168d_phy_param(phydev, 0x8b79, 0xffff, 0xaa00); - rtl_writephy_batch(tp, phy_reg_init); + /* Disable hiimpedance detection (RTCT) */ + phy_write_paged(phydev, 0x0003, 0x01, 0x328a); rtl8168f_hw_phy_config(tp); /* Improve 2-pair detection performance */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b85, 0x0000, 0x4000); } static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) @@ -3143,77 +3095,46 @@ static void rtl8168f_2_hw_phy_config(struct rtl8169_private *tp) static void rtl8411_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - /* Channel estimation fine tune */ - { 0x1f, 0x0003 }, - { 0x09, 0xa20f }, - { 0x1f, 0x0000 }, - - /* Modify green table for giga & fnet */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b55 }, - { 0x06, 0x0000 }, - { 0x05, 0x8b5e }, - { 0x06, 0x0000 }, - { 0x05, 0x8b67 }, - { 0x06, 0x0000 }, - { 0x05, 0x8b70 }, - { 0x06, 0x0000 }, - { 0x1f, 0x0000 }, - { 0x1f, 0x0007 }, - { 0x1e, 0x0078 }, - { 0x17, 0x0000 }, - { 0x19, 0x00aa }, - { 0x1f, 0x0000 }, - - /* Modify green table for 10M */ - { 0x1f, 0x0005 }, - { 0x05, 0x8b79 }, - { 0x06, 0xaa00 }, - { 0x1f, 0x0000 }, - - /* Disable hiimpedance detection (RTCT) */ - { 0x1f, 0x0003 }, - { 0x01, 0x328a }, - { 0x1f, 0x0000 } - }; - + struct phy_device *phydev = tp->phydev; rtl_apply_firmware(tp); rtl8168f_hw_phy_config(tp); /* Improve 2-pair detection performance */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x4000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b85, 0x0000, 0x4000); - rtl_writephy_batch(tp, phy_reg_init); + /* Channel estimation fine tune */ + phy_write_paged(phydev, 0x0003, 0x09, 0xa20f); + + /* Modify green table for giga & fnet */ + r8168d_phy_param(phydev, 0x8b55, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b5e, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b67, 0xffff, 0x0000); + r8168d_phy_param(phydev, 0x8b70, 0xffff, 0x0000); + phy_write(phydev, 0x1f, 0x0007); + phy_write(phydev, 0x1e, 0x0078); + phy_write(phydev, 0x17, 0x0000); + phy_write(phydev, 0x19, 0x00aa); + phy_write(phydev, 0x1f, 0x0000); + + /* Modify green table for 10M */ + r8168d_phy_param(phydev, 0x8b79, 0xffff, 0xaa00); + + /* Disable hiimpedance detection (RTCT) */ + phy_write_paged(phydev, 0x0003, 0x01, 0x328a); /* Modify green table for giga */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b54); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0800); - rtl_writephy(tp, 0x05, 0x8b5d); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0800); - rtl_writephy(tp, 0x05, 0x8a7c); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); - rtl_writephy(tp, 0x05, 0x8a7f); - rtl_w0w1_phy(tp, 0x06, 0x0100, 0x0000); - rtl_writephy(tp, 0x05, 0x8a82); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); - rtl_writephy(tp, 0x05, 0x8a85); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); - rtl_writephy(tp, 0x05, 0x8a88); - rtl_w0w1_phy(tp, 0x06, 0x0000, 0x0100); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b54, 0x0800, 0x0000); + r8168d_phy_param(phydev, 0x8b5d, 0x0800, 0x0000); + r8168d_phy_param(phydev, 0x8a7c, 0x0100, 0x0000); + r8168d_phy_param(phydev, 0x8a7f, 0x0000, 0x0100); + r8168d_phy_param(phydev, 0x8a82, 0x0100, 0x0000); + r8168d_phy_param(phydev, 0x8a85, 0x0100, 0x0000); + r8168d_phy_param(phydev, 0x8a88, 0x0100, 0x0000); /* uc same-seed solution */ - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x8b85); - rtl_w0w1_phy(tp, 0x06, 0x8000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_phy_param(phydev, 0x8b85, 0x0000, 0x8000); /* Green feature */ rtl_writephy(tp, 0x1f, 0x0003); -- cgit v1.2.3-59-g8ed1b From 3a129e3f9ac4fc2f977af1ad8f17ab343a468cc1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2019 22:00:51 +0100 Subject: r8169: switch to phylib functions in more places Use the phylib MDIO access functions in more places to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 85 +++++++------------------------ 1 file changed, 17 insertions(+), 68 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index fa4b3d71f4fb..b3263a8870ba 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2405,13 +2405,7 @@ static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0002 }, - { 0x01, 0x90d0 }, - { 0x1f, 0x0000 } - }; - - rtl_writephy_batch(tp, phy_reg_init); + phy_write_paged(tp->phydev, 0x0002, 0x01, 0x90d0); } static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp) @@ -2422,9 +2416,7 @@ static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp) (pdev->subsystem_device != 0xe000)) return; - rtl_writephy(tp, 0x1f, 0x0001); - rtl_writephy(tp, 0x10, 0xf01b); - rtl_writephy(tp, 0x1f, 0x0000); + phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b); } static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp) @@ -2529,54 +2521,28 @@ static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp) static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x10, 0xf41b }, - { 0x1f, 0x0000 } - }; - rtl_writephy(tp, 0x1f, 0x0001); rtl_patchphy(tp, 0x16, 1 << 0); - - rtl_writephy_batch(tp, phy_reg_init); + rtl_writephy(tp, 0x10, 0xf41b); + rtl_writephy(tp, 0x1f, 0x0000); } static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x10, 0xf41b }, - { 0x1f, 0x0000 } - }; - - rtl_writephy_batch(tp, phy_reg_init); + phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf41b); } static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0000 }, - { 0x1d, 0x0f00 }, - { 0x1f, 0x0002 }, - { 0x0c, 0x1ec8 }, - { 0x1f, 0x0000 } - }; - - rtl_writephy_batch(tp, phy_reg_init); + phy_write(tp->phydev, 0x1d, 0x0f00); + phy_write_paged(tp->phydev, 0x0002, 0x0c, 0x1ec8); } static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x1d, 0x3d98 }, - { 0x1f, 0x0000 } - }; - - rtl_writephy(tp, 0x1f, 0x0000); - rtl_patchphy(tp, 0x14, 1 << 5); - rtl_patchphy(tp, 0x0d, 1 << 5); - - rtl_writephy_batch(tp, phy_reg_init); + phy_set_bits(tp->phydev, 0x14, BIT(5)); + phy_set_bits(tp->phydev, 0x0d, BIT(5)); + phy_write_paged(tp->phydev, 0x0001, 0x1d, 0x3d98); } static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp) @@ -2929,9 +2895,7 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0000); /* For impedance matching */ - rtl_writephy(tp, 0x1f, 0x0002); - rtl_w0w1_phy(tp, 0x08, 0x8000, 0x7f00); - rtl_writephy(tp, 0x1f, 0x0000); + phy_modify_paged(phydev, 0x0002, 0x08, 0x7f00, 0x8000); /* PHY auto speed down */ rtl_writephy(tp, 0x1f, 0x0007); @@ -3428,35 +3392,21 @@ static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0005 }, - { 0x1a, 0x0000 }, - { 0x1f, 0x0000 }, - - { 0x1f, 0x0004 }, - { 0x1c, 0x0000 }, - { 0x1f, 0x0000 }, - - { 0x1f, 0x0001 }, - { 0x15, 0x7701 }, - { 0x1f, 0x0000 } - }; - /* Disable ALDPS before ram code */ - rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x18, 0x0310); + phy_write(tp->phydev, 0x18, 0x0310); msleep(100); rtl_apply_firmware(tp); - rtl_writephy_batch(tp, phy_reg_init); + phy_write_paged(tp->phydev, 0x0005, 0x1a, 0x0000); + phy_write_paged(tp->phydev, 0x0004, 0x1c, 0x0000); + phy_write_paged(tp->phydev, 0x0001, 0x15, 0x7701); } static void rtl8402_hw_phy_config(struct rtl8169_private *tp) { /* Disable ALDPS before setting firmware */ - rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x18, 0x0310); + phy_write(tp->phydev, 0x18, 0x0310); msleep(20); rtl_apply_firmware(tp); @@ -3479,8 +3429,7 @@ static void rtl8106e_hw_phy_config(struct rtl8169_private *tp) }; /* Disable ALDPS before ram code */ - rtl_writephy(tp, 0x1f, 0x0000); - rtl_writephy(tp, 0x18, 0x0310); + phy_write(tp->phydev, 0x18, 0x0310); msleep(100); rtl_apply_firmware(tp); -- cgit v1.2.3-59-g8ed1b From 0721914a3d2bc31b5c6bd4b0c10cecab939b315e Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2019 22:01:36 +0100 Subject: r8169: add helper r8168d_modify_extpage Certain integrated PHY's from RTL8168d support extended pages. On page 0x0007 the number of the extended page is written to register 0x1e, then the registers on the extended page can be accessed. Add a helper for this to improve readability and simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 121 ++++++++++-------------------- 1 file changed, 39 insertions(+), 82 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index b3263a8870ba..8aa681dfeac6 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1086,6 +1086,17 @@ static void rtl_w0w1_phy(struct rtl8169_private *tp, int reg_addr, int p, int m) rtl_writephy(tp, reg_addr, (val & ~m) | p); } +static void r8168d_modify_extpage(struct phy_device *phydev, int extpage, + int reg, u16 mask, u16 val) +{ + int oldpage = phy_select_page(phydev, 0x0007); + + __phy_write(phydev, 0x1e, extpage); + __phy_modify(phydev, reg, mask, val); + + phy_restore_page(phydev, oldpage, 0); +} + static void r8168d_phy_param(struct phy_device *phydev, u16 parm, u16 mask, u16 val) { @@ -2830,30 +2841,18 @@ static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp) { 0x04, 0xf800 }, { 0x04, 0xf000 }, { 0x1f, 0x0000 }, - - { 0x1f, 0x0007 }, - { 0x1e, 0x0023 }, - { 0x16, 0x0000 }, - { 0x1f, 0x0000 } }; rtl_writephy_batch(tp, phy_reg_init); + + r8168d_modify_extpage(tp->phydev, 0x0023, 0x16, 0xffff, 0x0000); } static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x17, 0x0cc0 }, - - { 0x1f, 0x0007 }, - { 0x1e, 0x002d }, - { 0x18, 0x0040 }, - { 0x1f, 0x0000 } - }; - - rtl_writephy_batch(tp, phy_reg_init); - rtl_patchphy(tp, 0x0d, 1 << 5); + phy_write_paged(tp->phydev, 0x0001, 0x17, 0x0cc0); + r8168d_modify_extpage(tp->phydev, 0x002d, 0x18, 0xffff, 0x0040); + phy_set_bits(tp->phydev, 0x0d, BIT(5)); } static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) @@ -2867,17 +2866,6 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) { 0x1f, 0x0003 }, { 0x14, 0x6420 }, { 0x1f, 0x0000 }, - - /* Update PFM & 10M TX idle timer */ - { 0x1f, 0x0007 }, - { 0x1e, 0x002f }, - { 0x15, 0x1919 }, - { 0x1f, 0x0000 }, - - { 0x1f, 0x0007 }, - { 0x1e, 0x00ac }, - { 0x18, 0x0006 }, - { 0x1f, 0x0000 } }; struct phy_device *phydev = tp->phydev; @@ -2888,31 +2876,26 @@ static void rtl8168e_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy_batch(tp, phy_reg_init); + /* Update PFM & 10M TX idle timer */ + r8168d_modify_extpage(phydev, 0x002f, 0x15, 0xffff, 0x1919); + + r8168d_modify_extpage(phydev, 0x00ac, 0x18, 0xffff, 0x0006); + /* DCO enable for 10M IDLE Power */ - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x0023); - rtl_w0w1_phy(tp, 0x17, 0x0006, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_modify_extpage(phydev, 0x0023, 0x17, 0x0000, 0x0006); /* For impedance matching */ phy_modify_paged(phydev, 0x0002, 0x08, 0x7f00, 0x8000); /* PHY auto speed down */ - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x002d); - rtl_w0w1_phy(tp, 0x18, 0x0050, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); + r8168d_modify_extpage(phydev, 0x002d, 0x18, 0x0000, 0x0050); + phy_set_bits(phydev, 0x14, BIT(15)); r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); r8168d_phy_param(phydev, 0x8b85, 0x2000, 0x0000); - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x0020); - rtl_w0w1_phy(tp, 0x15, 0x0000, 0x1100); - rtl_writephy(tp, 0x1f, 0x0006); - rtl_writephy(tp, 0x00, 0x5a00); - rtl_writephy(tp, 0x1f, 0x0000); + r8168d_modify_extpage(phydev, 0x0020, 0x15, 0x1100, 0x0000); + phy_write_paged(phydev, 0x0006, 0x00, 0x5a00); phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0000); } @@ -2933,27 +2916,15 @@ static void rtl_rar_exgmac_set(struct rtl8169_private *tp, u8 *addr) static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) { - static const struct phy_reg phy_reg_init[] = { - /* Enable Delay cap */ - { 0x1f, 0x0004 }, - { 0x1f, 0x0007 }, - { 0x1e, 0x00ac }, - { 0x18, 0x0006 }, - { 0x1f, 0x0002 }, - { 0x1f, 0x0000 }, - { 0x1f, 0x0000 }, - - /* Channel estimation fine tune */ - { 0x1f, 0x0003 }, - { 0x09, 0xa20f }, - { 0x1f, 0x0000 }, - { 0x1f, 0x0000 }, - }; struct phy_device *phydev = tp->phydev; rtl_apply_firmware(tp); - rtl_writephy_batch(tp, phy_reg_init); + /* Enable Delay cap */ + r8168d_modify_extpage(phydev, 0x00ac, 0x18, 0xffff, 0x0006); + + /* Channel estimation fine tune */ + phy_write_paged(phydev, 0x0003, 0x09, 0xa20f); /* Green Setting */ r8168d_phy_param(phydev, 0x8b5b, 0xffff, 0x9222); @@ -2967,13 +2938,8 @@ static void rtl8168e_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0000); /* PHY auto speed down */ - rtl_writephy(tp, 0x1f, 0x0004); - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x002d); - rtl_w0w1_phy(tp, 0x18, 0x0010, 0x0000); - rtl_writephy(tp, 0x1f, 0x0002); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); + r8168d_modify_extpage(phydev, 0x002d, 0x18, 0x0000, 0x0010); + phy_set_bits(phydev, 0x14, BIT(15)); /* improve 10M EEE waveform */ r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); @@ -3005,11 +2971,8 @@ static void rtl8168f_hw_phy_config(struct rtl8169_private *tp) r8168d_phy_param(phydev, 0x8b80, 0x0000, 0x0006); /* PHY auto speed down */ - rtl_writephy(tp, 0x1f, 0x0007); - rtl_writephy(tp, 0x1e, 0x002d); - rtl_w0w1_phy(tp, 0x18, 0x0010, 0x0000); - rtl_writephy(tp, 0x1f, 0x0000); - rtl_w0w1_phy(tp, 0x14, 0x8000, 0x0000); + r8168d_modify_extpage(phydev, 0x002d, 0x18, 0x0000, 0x0010); + phy_set_bits(phydev, 0x14, BIT(15)); /* Improve 10M EEE waveform */ r8168d_phy_param(phydev, 0x8b86, 0x0000, 0x0001); @@ -3032,11 +2995,8 @@ static void rtl8168f_1_hw_phy_config(struct rtl8169_private *tp) r8168d_phy_param(phydev, 0x8b5e, 0xffff, 0x0000); r8168d_phy_param(phydev, 0x8b67, 0xffff, 0x0000); r8168d_phy_param(phydev, 0x8b70, 0xffff, 0x0000); - phy_write(phydev, 0x1f, 0x0007); - phy_write(phydev, 0x1e, 0x0078); - phy_write(phydev, 0x17, 0x0000); - phy_write(phydev, 0x19, 0x00fb); - phy_write(phydev, 0x1f, 0x0000); + r8168d_modify_extpage(phydev, 0x0078, 0x17, 0xffff, 0x0000); + r8168d_modify_extpage(phydev, 0x0078, 0x19, 0xffff, 0x00fb); /* Modify green table for 10M */ r8168d_phy_param(phydev, 0x8b79, 0xffff, 0xaa00); @@ -3076,11 +3036,8 @@ static void rtl8411_hw_phy_config(struct rtl8169_private *tp) r8168d_phy_param(phydev, 0x8b5e, 0xffff, 0x0000); r8168d_phy_param(phydev, 0x8b67, 0xffff, 0x0000); r8168d_phy_param(phydev, 0x8b70, 0xffff, 0x0000); - phy_write(phydev, 0x1f, 0x0007); - phy_write(phydev, 0x1e, 0x0078); - phy_write(phydev, 0x17, 0x0000); - phy_write(phydev, 0x19, 0x00aa); - phy_write(phydev, 0x1f, 0x0000); + r8168d_modify_extpage(phydev, 0x0078, 0x17, 0xffff, 0x0000); + r8168d_modify_extpage(phydev, 0x0078, 0x19, 0xffff, 0x00aa); /* Modify green table for 10M */ r8168d_phy_param(phydev, 0x8b79, 0xffff, 0xaa00); -- cgit v1.2.3-59-g8ed1b From afa2642778f3cbe99a6c315800c6ed429b6017c8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 9 Nov 2019 22:02:30 +0100 Subject: r8169: remove rtl8168c_4_hw_phy_config rtl8168c_4_hw_phy_config() duplicates rtl8168c_3_hw_phy_config(), so we can remove the function. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 8aa681dfeac6..d4345493fdba 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2635,11 +2635,6 @@ static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0000); } -static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp) -{ - rtl8168c_3_hw_phy_config(tp); -} - static const struct phy_reg rtl8168d_1_phy_reg_init_0[] = { /* Channel Estimation */ { 0x1f, 0x0001 }, @@ -3528,7 +3523,7 @@ static void rtl_hw_phy_config(struct net_device *dev) [RTL_GIGA_MAC_VER_19] = rtl8168c_1_hw_phy_config, [RTL_GIGA_MAC_VER_20] = rtl8168c_2_hw_phy_config, [RTL_GIGA_MAC_VER_21] = rtl8168c_3_hw_phy_config, - [RTL_GIGA_MAC_VER_22] = rtl8168c_4_hw_phy_config, + [RTL_GIGA_MAC_VER_22] = rtl8168c_3_hw_phy_config, [RTL_GIGA_MAC_VER_23] = rtl8168cp_2_hw_phy_config, [RTL_GIGA_MAC_VER_24] = rtl8168cp_2_hw_phy_config, [RTL_GIGA_MAC_VER_25] = rtl8168d_1_hw_phy_config, -- cgit v1.2.3-59-g8ed1b From cc9defcbb8fae52810f7795b039223edae51ef95 Mon Sep 17 00:00:00 2001 From: Michael Guralnik Date: Fri, 8 Nov 2019 23:45:24 +0000 Subject: net/mlx5: Handle "enable_roce" devlink param Register "enable_roce" param, default value is RoCE enabled. Current configuration is stored on mlx5_core_dev and exposed to user through the cmode runtime devlink param. Changing configuration requires changing the cmode driverinit devlink param and calling devlink reload. Signed-off-by: Michael Guralnik Acked-by: Jiri Pirko Signed-off-by: Saeed Mahameed --- .../networking/device_drivers/mellanox/mlx5.rst | 21 +++++++++++++++++++++ Documentation/networking/devlink-params-mlx5.txt | 5 +++++ drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 22 ++++++++++++++++++++++ include/linux/mlx5/driver.h | 11 +++++++++++ 4 files changed, 59 insertions(+) (limited to 'drivers/net') diff --git a/Documentation/networking/device_drivers/mellanox/mlx5.rst b/Documentation/networking/device_drivers/mellanox/mlx5.rst index d071c6b49e1f..7599dceba9f1 100644 --- a/Documentation/networking/device_drivers/mellanox/mlx5.rst +++ b/Documentation/networking/device_drivers/mellanox/mlx5.rst @@ -154,6 +154,27 @@ User command examples: values: cmode runtime value smfs +enable_roce: RoCE enablement state +---------------------------------- +RoCE enablement state controls driver support for RoCE traffic. +When RoCE is disabled, there is no gid table, only raw ethernet QPs are supported and traffic on the well known UDP RoCE port is handled as raw ethernet traffic. + +To change RoCE enablement state a user must change the driverinit cmode value and run devlink reload. + +User command examples: + +- Disable RoCE:: + + $ devlink dev param set pci/0000:06:00.0 name enable_roce value false cmode driverinit + $ devlink dev reload pci/0000:06:00.0 + +- Read RoCE enablement state:: + + $ devlink dev param show pci/0000:06:00.0 name enable_roce + pci/0000:06:00.0: + name enable_roce type generic + values: + cmode driverinit value true Devlink health reporters ======================== diff --git a/Documentation/networking/devlink-params-mlx5.txt b/Documentation/networking/devlink-params-mlx5.txt index 8c0b82d655dc..5071467118bd 100644 --- a/Documentation/networking/devlink-params-mlx5.txt +++ b/Documentation/networking/devlink-params-mlx5.txt @@ -10,3 +10,8 @@ flow_steering_mode [DEVICE, DRIVER-SPECIFIC] without firmware intervention. Type: String Configuration mode: runtime + +enable_roce [DEVICE, GENERIC] + Enable handling of RoCE traffic in the device. + Defaultly enabled. + Configuration mode: driverinit diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 381925c90d94..b2c26388edb1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -177,12 +177,29 @@ enum mlx5_devlink_param_id { MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, }; +static int mlx5_devlink_enable_roce_validate(struct devlink *devlink, u32 id, + union devlink_param_value val, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + bool new_state = val.vbool; + + if (new_state && !MLX5_CAP_GEN(dev, roce)) { + NL_SET_ERR_MSG_MOD(extack, "Device doesn't support RoCE"); + return -EOPNOTSUPP; + } + + return 0; +} + static const struct devlink_param mlx5_devlink_params[] = { DEVLINK_PARAM_DRIVER(MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, "flow_steering_mode", DEVLINK_PARAM_TYPE_STRING, BIT(DEVLINK_PARAM_CMODE_RUNTIME), mlx5_devlink_fs_mode_get, mlx5_devlink_fs_mode_set, mlx5_devlink_fs_mode_validate), + DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), + NULL, NULL, mlx5_devlink_enable_roce_validate), }; static void mlx5_devlink_set_params_init_values(struct devlink *devlink) @@ -197,6 +214,11 @@ static void mlx5_devlink_set_params_init_values(struct devlink *devlink) devlink_param_driverinit_value_set(devlink, MLX5_DEVLINK_PARAM_FLOW_STEERING_MODE, value); + + value.vbool = MLX5_CAP_GEN(dev, roce); + devlink_param_driverinit_value_set(devlink, + DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, + value); } int mlx5_devlink_register(struct devlink *devlink, struct device *dev) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 7b4801e96feb..1884513aac90 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -1191,4 +1191,15 @@ enum { MLX5_TRIGGERED_CMD_COMP = (u64)1 << 32, }; +static inline bool mlx5_is_roce_enabled(struct mlx5_core_dev *dev) +{ + struct devlink *devlink = priv_to_devlink(dev); + union devlink_param_value val; + + devlink_param_driverinit_value_get(devlink, + DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE, + &val); + return val.vbool; +} + #endif /* MLX5_DRIVER_H */ -- cgit v1.2.3-59-g8ed1b From 34d76e9fa846a87e7924ab974e4cb70394a4fcac Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 13:32:22 +0200 Subject: net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 6 +++-- drivers/net/dsa/sja1105/sja1105_main.c | 3 ++- drivers/net/dsa/sja1105/sja1105_ptp.c | 26 +++++++++++------- drivers/net/dsa/sja1105/sja1105_spi.c | 48 +++++++++++++++++++++++++++------- 4 files changed, 61 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 91063ed3ef1b..64b3ee7b9771 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -122,9 +122,11 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf, size_t len); int sja1105_xfer_u32(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value); + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value, + struct ptp_system_timestamp *ptp_sts); int sja1105_xfer_u64(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value); + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value, + struct ptp_system_timestamp *ptp_sts); int sja1105_static_config_upload(struct sja1105_private *priv); int sja1105_inhibit_tx(const struct sja1105_private *priv, unsigned long port_bitmap, bool tx_inhibited); diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d5dfda335aa1..d545edbbef9e 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1973,7 +1973,8 @@ static int sja1105_check_device_id(struct sja1105_private *priv) u64 part_no; int rc; - rc = sja1105_xfer_u32(priv, SPI_READ, regs->device_id, &device_id); + rc = sja1105_xfer_u32(priv, SPI_READ, regs->device_id, &device_id, + NULL); if (rc < 0) return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 783100397f8a..fac72af24baf 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2019, Vladimir Oltean */ +#include #include "sja1105.h" /* The adjfine API clamps ppb between [-32,768,000, 32,768,000], and @@ -335,11 +336,13 @@ static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts) } /* Caller must hold ptp_data->lock */ -static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks) +static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; - return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks); + return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks, + ptp_sts); } /* Caller must hold ptp_data->lock */ @@ -347,7 +350,8 @@ static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) { const struct sja1105_regs *regs = priv->info->regs; - return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks); + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks, + NULL); } #define rxtstamp_to_tagger(d) \ @@ -370,7 +374,7 @@ static void sja1105_rxtstamp_work(struct work_struct *work) u64 ticks, ts; int rc; - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, NULL); if (rc < 0) { dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); kfree_skb(skb); @@ -441,8 +445,9 @@ int sja1105_ptp_reset(struct dsa_switch *ds) return rc; } -static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, - struct timespec64 *ts) +static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, + struct timespec64 *ts, + struct ptp_system_timestamp *ptp_sts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); @@ -451,7 +456,7 @@ static int sja1105_ptp_gettime(struct ptp_clock_info *ptp, mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); mutex_unlock(&ptp_data->lock); @@ -516,7 +521,8 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) mutex_lock(&ptp_data->lock); - rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32); + rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32, + NULL); mutex_unlock(&ptp_data->lock); @@ -558,7 +564,7 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds) .name = "SJA1105 PHC", .adjfine = sja1105_ptp_adjfine, .adjtime = sja1105_ptp_adjtime, - .gettime64 = sja1105_ptp_gettime, + .gettimex64 = sja1105_ptp_gettimex, .settime64 = sja1105_ptp_settime, .max_adj = SJA1105_MAX_ADJ_PPB, }; @@ -604,7 +610,7 @@ void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks); + rc = sja1105_ptpclkval_read(priv, &ticks, NULL); if (rc < 0) { dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); kfree_skb(skb); diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index ed02410a9366..691cd250e50a 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -42,9 +42,9 @@ sja1105_spi_message_pack(void *buf, const struct sja1105_spi_message *msg) * - SPI_READ: creates and sends an SPI read message from absolute * address reg_addr, writing @len bytes into *buf */ -int sja1105_xfer_buf(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, - u8 *buf, size_t len) +static int sja1105_xfer(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, u8 *buf, + size_t len, struct ptp_system_timestamp *ptp_sts) { struct sja1105_chunk chunk = { .len = min_t(size_t, len, SJA1105_SIZE_SPI_MSG_MAXLEN), @@ -81,6 +81,7 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, struct spi_transfer *chunk_xfer = sja1105_chunk_xfer(xfers, i); struct spi_transfer *hdr_xfer = sja1105_hdr_xfer(xfers, i); u8 *hdr_buf = sja1105_hdr_buf(hdr_bufs, i); + struct spi_transfer *ptp_sts_xfer; struct sja1105_spi_message msg; /* Populate the transfer's header buffer */ @@ -102,6 +103,26 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, chunk_xfer->tx_buf = chunk.buf; chunk_xfer->len = chunk.len; + /* Request timestamping for the transfer. Instead of letting + * callers specify which byte they want to timestamp, we can + * make certain assumptions: + * - A read operation will request a software timestamp when + * what's being read is the PTP time. That is snapshotted by + * the switch hardware at the end of the command portion + * (hdr_xfer). + * - A write operation will request a software timestamp on + * actions that modify the PTP time. Taking clock stepping as + * an example, the switch writes the PTP time at the end of + * the data portion (chunk_xfer). + */ + if (rw == SPI_READ) + ptp_sts_xfer = hdr_xfer; + else + ptp_sts_xfer = chunk_xfer; + ptp_sts_xfer->ptp_sts_word_pre = ptp_sts_xfer->len - 1; + ptp_sts_xfer->ptp_sts_word_post = ptp_sts_xfer->len - 1; + ptp_sts_xfer->ptp_sts = ptp_sts; + /* Calculate next chunk */ chunk.buf += chunk.len; chunk.reg_addr += chunk.len / 4; @@ -123,6 +144,13 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, return rc; } +int sja1105_xfer_buf(const struct sja1105_private *priv, + sja1105_spi_rw_mode_t rw, u64 reg_addr, + u8 *buf, size_t len) +{ + return sja1105_xfer(priv, rw, reg_addr, buf, len, NULL); +} + /* If @rw is: * - SPI_WRITE: creates and sends an SPI write message at absolute * address reg_addr @@ -133,7 +161,8 @@ int sja1105_xfer_buf(const struct sja1105_private *priv, * CPU endianness and directly usable by software running on the core. */ int sja1105_xfer_u64(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value) + sja1105_spi_rw_mode_t rw, u64 reg_addr, u64 *value, + struct ptp_system_timestamp *ptp_sts) { u8 packed_buf[8]; int rc; @@ -141,7 +170,7 @@ int sja1105_xfer_u64(const struct sja1105_private *priv, if (rw == SPI_WRITE) sja1105_pack(packed_buf, value, 63, 0, 8); - rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 8); + rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 8, ptp_sts); if (rw == SPI_READ) sja1105_unpack(packed_buf, value, 63, 0, 8); @@ -151,7 +180,8 @@ int sja1105_xfer_u64(const struct sja1105_private *priv, /* Same as above, but transfers only a 4 byte word */ int sja1105_xfer_u32(const struct sja1105_private *priv, - sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value) + sja1105_spi_rw_mode_t rw, u64 reg_addr, u32 *value, + struct ptp_system_timestamp *ptp_sts) { u8 packed_buf[4]; u64 tmp; @@ -165,7 +195,7 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, sja1105_pack(packed_buf, &tmp, 31, 0, 4); } - rc = sja1105_xfer_buf(priv, rw, reg_addr, packed_buf, 4); + rc = sja1105_xfer(priv, rw, reg_addr, packed_buf, 4, ptp_sts); if (rw == SPI_READ) { sja1105_unpack(packed_buf, &tmp, 31, 0, 4); @@ -293,7 +323,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, int rc; rc = sja1105_xfer_u32(priv, SPI_READ, regs->port_control, - &inhibit_cmd); + &inhibit_cmd, NULL); if (rc < 0) return rc; @@ -303,7 +333,7 @@ int sja1105_inhibit_tx(const struct sja1105_private *priv, inhibit_cmd &= ~port_bitmap; return sja1105_xfer_u32(priv, SPI_WRITE, regs->port_control, - &inhibit_cmd); + &inhibit_cmd, NULL); } struct sja1105_status { -- cgit v1.2.3-59-g8ed1b From 6cf99c13ea07b5cb345d83598adea60823cea576 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 13:32:23 +0200 Subject: net: dsa: sja1105: Restore PTP time after switch reset The PTP time of the switch is not preserved when uploading a new static configuration. Work around this hardware oddity by reading its PTP time before a static config upload, and restoring it afterwards. Static config changes are expected to occur at runtime even in scenarios directly related to PTP, i.e. the Time-Aware Scheduler of the switch is programmed in this way. Perhaps the larger implication of this patch is that the PTP .gettimex64 and .settime functions need to be exposed to sja1105_main.c, where the PTP lock needs to be held during this entire process. So their core implementation needs to move to some common functions which get exposed in sja1105_ptp.h. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 35 ++++++++++++++- drivers/net/dsa/sja1105/sja1105_ptp.c | 81 +++++++++++++++++++++++++--------- drivers/net/dsa/sja1105/sja1105_ptp.h | 24 ++++++++-- drivers/net/dsa/sja1105/sja1105_spi.c | 6 --- 4 files changed, 114 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index d545edbbef9e..2b8919a25392 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1349,9 +1349,15 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, */ int sja1105_static_config_reload(struct sja1105_private *priv) { + struct ptp_system_timestamp ptp_sts_before; + struct ptp_system_timestamp ptp_sts_after; struct sja1105_mac_config_entry *mac; int speed_mbps[SJA1105_NUM_PORTS]; + struct dsa_switch *ds = priv->ds; + s64 t1, t2, t3, t4; + s64 t12, t34; int rc, i; + s64 now; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; @@ -1365,10 +1371,37 @@ int sja1105_static_config_reload(struct sja1105_private *priv) mac[i].speed = SJA1105_SPEED_AUTO; } + /* No PTP operations can run right now */ + mutex_lock(&priv->ptp_data.lock); + + rc = __sja1105_ptp_gettimex(ds, &now, &ptp_sts_before); + if (rc < 0) + goto out_unlock_ptp; + /* Reset switch and send updated static configuration */ rc = sja1105_static_config_upload(priv); if (rc < 0) - goto out; + goto out_unlock_ptp; + + rc = __sja1105_ptp_settime(ds, 0, &ptp_sts_after); + if (rc < 0) + goto out_unlock_ptp; + + t1 = timespec64_to_ns(&ptp_sts_before.pre_ts); + t2 = timespec64_to_ns(&ptp_sts_before.post_ts); + t3 = timespec64_to_ns(&ptp_sts_after.pre_ts); + t4 = timespec64_to_ns(&ptp_sts_after.post_ts); + /* Mid point, corresponds to pre-reset PTPCLKVAL */ + t12 = t1 + (t2 - t1) / 2; + /* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */ + t34 = t3 + (t4 - t3) / 2; + /* Advance PTPCLKVAL by the time it took since its readout */ + now += (t34 - t12); + + __sja1105_ptp_adjtime(ds, now); + +out_unlock_ptp: + mutex_unlock(&priv->ptp_data.lock); /* Configure the CGU (PLLs) for MII and RMII PHYs. * For these interfaces there is no dynamic configuration diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index fac72af24baf..0a35813f9328 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -346,12 +346,13 @@ static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks, } /* Caller must hold ptp_data->lock */ -static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks) +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks, - NULL); + ptp_sts); } #define rxtstamp_to_tagger(d) \ @@ -427,7 +428,7 @@ bool sja1105_port_txtstamp(struct dsa_switch *ds, int port, return true; } -int sja1105_ptp_reset(struct dsa_switch *ds) +static int sja1105_ptp_reset(struct dsa_switch *ds) { struct sja1105_private *priv = ds->priv; struct sja1105_ptp_data *ptp_data = &priv->ptp_data; @@ -445,19 +446,38 @@ int sja1105_ptp_reset(struct dsa_switch *ds) return rc; } +/* Caller must hold ptp_data->lock */ +int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *ptp_sts) +{ + struct sja1105_private *priv = ds->priv; + u64 ticks; + int rc; + + rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); + if (rc < 0) { + dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc); + return rc; + } + + *ns = sja1105_ticks_to_ns(ticks); + + return 0; +} + static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *ptp_sts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - u64 ticks = 0; + u64 now = 0; int rc; mutex_lock(&ptp_data->lock); - rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts); - *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + rc = __sja1105_ptp_gettimex(priv->ds, &now, ptp_sts); + *ts = ns_to_timespec64(now); mutex_unlock(&ptp_data->lock); @@ -479,24 +499,34 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ +int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + struct sja1105_private *priv = ds->priv; + u64 ticks = ns_to_sja1105_ticks(ns); + int rc; + + rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); + if (rc < 0) { + dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); + return rc; + } + + return sja1105_ptpclkval_write(priv, ticks, ptp_sts); +} + static int sja1105_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); - u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); + u64 ns = timespec64_to_ns(ts); int rc; mutex_lock(&ptp_data->lock); - rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); - if (rc < 0) { - dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); - goto out; - } + rc = __sja1105_ptp_settime(priv->ds, ns, NULL); - rc = sja1105_ptpclkval_write(priv, ticks); -out: mutex_unlock(&ptp_data->lock); return rc; @@ -530,24 +560,31 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) } /* Write to PTPCLKVAL while PTPCLKADD is 1 */ -static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) { - struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); - struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + struct sja1105_private *priv = ds->priv; s64 ticks = ns_to_sja1105_ticks(delta); int rc; - mutex_lock(&ptp_data->lock); - rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); if (rc < 0) { dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); - goto out; + return rc; } - rc = sja1105_ptpclkval_write(priv, ticks); + return sja1105_ptpclkval_write(priv, ticks, NULL); +} + +static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data); + int rc; + + mutex_lock(&ptp_data->lock); + + rc = __sja1105_ptp_adjtime(priv->ds, delta); -out: mutex_unlock(&ptp_data->lock); return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 243f130374d2..19e707db7e8c 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -51,8 +51,6 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, struct sk_buff *clone); -int sja1105_ptp_reset(struct dsa_switch *ds); - bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb, unsigned int type); @@ -63,6 +61,14 @@ int sja1105_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr); int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr); +int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *sts); + +int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts); + +int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta); + #else struct sja1105_ptp_cmd; @@ -87,7 +93,19 @@ static inline void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int slot, { } -static inline int sja1105_ptp_reset(struct dsa_switch *ds) +static inline int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns, + struct ptp_system_timestamp *sts) +{ + return 0; +} + +static inline int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + return 0; +} + +static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) { return 0; } diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 691cd250e50a..cb48e77f63fd 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -511,12 +511,6 @@ int sja1105_static_config_upload(struct sja1105_private *priv) dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); } - rc = sja1105_ptp_reset(priv->ds); - if (rc < 0) - dev_err(dev, "Failed to reset PTP clock: %d\n", rc); - - dev_info(dev, "Reset switch and programmed static config\n"); - out: kfree(config_buf); return rc; -- cgit v1.2.3-59-g8ed1b From af580ae2dcb250719857b4b7024bd4bb0c2e05fb Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 13:32:24 +0200 Subject: net: dsa: sja1105: Disallow management xmit during switch reset The purpose here is to avoid ptp4l fail due to this condition: timed out while polling for tx timestamp increasing tx_timestamp_timeout may correct this issue, but it is likely caused by a driver bug port 1: send peer delay request failed So either reset the switch before the management frame was sent, or after it was timestamped as well, but not in the middle. The condition may arise either due to a true timeout (i.e. because re-uploading the static config takes time), or due to the TX timestamp actually getting lost due to reset. For the former we can increase tx_timestamp_timeout in userspace, for the latter we need this patch. Locking all traffic during switch reset does not make sense at all, though. Forcing all CPU-originated traffic to potentially block waiting for a sleepable context to send > 800 bytes over SPI is not a good idea. Flows that are autonomously forwarded by the switch will get dropped anyway during switch reset no matter what. So just let all other CPU-originated traffic be dropped as well. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 2b8919a25392..475cc2d8b0e8 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1359,6 +1359,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv) int rc, i; s64 now; + mutex_lock(&priv->mgmt_lock); + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; /* Back up the dynamic link speed changed by sja1105_adjust_port_config @@ -1417,6 +1419,8 @@ out_unlock_ptp: goto out; } out: + mutex_unlock(&priv->mgmt_lock); + return rc; } -- cgit v1.2.3-59-g8ed1b From 228200179213bfc9b4d6097e1c26de30bd18c1e6 Mon Sep 17 00:00:00 2001 From: John Efstathiades Date: Thu, 7 Nov 2019 17:08:33 +0000 Subject: Support LAN743x PTP periodic output on any GPIO The LAN743x Ethernet controller provides two independent PTP event channels. Each one can be used to generate a periodic output from the PTP clock. The output can be routed to any one of the available GPIO pins on the device. The PTP clock API can now be used to: - select any LAN743x GPIO pin to function as a periodic output - select either LAN743x PTP event channel to generate the output The LAN7430 has 4 GPIO pins that are multiplexed with its internal PHY LED control signals. A pin assigned to the LED control function will be assigned to the GPIO function if selected for PTP periodic output. Signed-off-by: John Efstathiades Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/lan743x_ptp.c | 299 +++++++++++++++++++-------- drivers/net/ethernet/microchip/lan743x_ptp.h | 27 ++- 2 files changed, 230 insertions(+), 96 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index 57b26c2acf87..e177b1ae03f1 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -11,7 +11,9 @@ #include "lan743x_ptp.h" -#define LAN743X_NUMBER_OF_GPIO (12) +#define LAN743X_LED0_ENABLE 20 /* LED0 offset in HW_CFG */ +#define LAN743X_LED_ENABLE(pin) BIT(LAN743X_LED0_ENABLE + (pin)) + #define LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB (31249999) #define LAN743X_PTP_MAX_FINE_ADJ_IN_SCALED_PPM (2047999934) @@ -139,19 +141,20 @@ done: spin_unlock_bh(&ptp->tx_ts_lock); } -static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter) +static int lan743x_ptp_reserve_event_ch(struct lan743x_adapter *adapter, + int event_channel) { struct lan743x_ptp *ptp = &adapter->ptp; int result = -ENODEV; - int index = 0; mutex_lock(&ptp->command_lock); - for (index = 0; index < LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS; index++) { - if (!(test_bit(index, &ptp->used_event_ch))) { - ptp->used_event_ch |= BIT(index); - result = index; - break; - } + if (!(test_bit(event_channel, &ptp->used_event_ch))) { + ptp->used_event_ch |= BIT(event_channel); + result = event_channel; + } else { + netif_warn(adapter, drv, adapter->netdev, + "attempted to reserved a used event_channel = %d\n", + event_channel); } mutex_unlock(&ptp->command_lock); return result; @@ -179,12 +182,62 @@ static void lan743x_ptp_clock_get(struct lan743x_adapter *adapter, static void lan743x_ptp_clock_step(struct lan743x_adapter *adapter, s64 time_step_ns); +static void lan743x_led_mux_enable(struct lan743x_adapter *adapter, + int pin, bool enable) +{ + struct lan743x_ptp *ptp = &adapter->ptp; + + if (ptp->leds_multiplexed && + ptp->led_enabled[pin]) { + u32 val = lan743x_csr_read(adapter, HW_CFG); + + if (enable) + val |= LAN743X_LED_ENABLE(pin); + else + val &= ~LAN743X_LED_ENABLE(pin); + + lan743x_csr_write(adapter, HW_CFG, val); + } +} + +static void lan743x_led_mux_save(struct lan743x_adapter *adapter) +{ + struct lan743x_ptp *ptp = &adapter->ptp; + u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; + + if (id_rev == ID_REV_ID_LAN7430_) { + int i; + u32 val = lan743x_csr_read(adapter, HW_CFG); + + for (i = 0; i < LAN7430_N_LED; i++) { + bool led_enabled = (val & LAN743X_LED_ENABLE(i)) != 0; + + ptp->led_enabled[i] = led_enabled; + } + ptp->leds_multiplexed = true; + } else { + ptp->leds_multiplexed = false; + } +} + +static void lan743x_led_mux_restore(struct lan743x_adapter *adapter) +{ + u32 id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_; + + if (id_rev == ID_REV_ID_LAN7430_) { + int i; + + for (i = 0; i < LAN7430_N_LED; i++) + lan743x_led_mux_enable(adapter, i, true); + } +} + static int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter, - int bit, int ptp_channel) + int pin, int event_channel) { struct lan743x_gpio *gpio = &adapter->gpio; unsigned long irq_flags = 0; - int bit_mask = BIT(bit); + int bit_mask = BIT(pin); int ret = -EBUSY; spin_lock_irqsave(&gpio->gpio_lock, irq_flags); @@ -194,41 +247,44 @@ static int lan743x_gpio_rsrv_ptp_out(struct lan743x_adapter *adapter, gpio->output_bits |= bit_mask; gpio->ptp_bits |= bit_mask; + /* assign pin to GPIO function */ + lan743x_led_mux_enable(adapter, pin, false); + /* set as output, and zero initial value */ - gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(bit); - gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit); + gpio->gpio_cfg0 |= GPIO_CFG0_GPIO_DIR_BIT_(pin); + gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); /* enable gpio, and set buffer type to push pull */ - gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(bit); - gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(bit); + gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOEN_BIT_(pin); + gpio->gpio_cfg1 |= GPIO_CFG1_GPIOBUF_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); /* set 1588 polarity to high */ - gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(bit); + gpio->gpio_cfg2 |= GPIO_CFG2_1588_POL_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG2, gpio->gpio_cfg2); - if (!ptp_channel) { + if (event_channel == 0) { /* use channel A */ - gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(bit); + gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_CH_SEL_BIT_(pin); } else { /* use channel B */ - gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(bit); + gpio->gpio_cfg3 |= GPIO_CFG3_1588_CH_SEL_BIT_(pin); } - gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(bit); + gpio->gpio_cfg3 |= GPIO_CFG3_1588_OE_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); - ret = bit; + ret = pin; } spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); return ret; } -static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit) +static void lan743x_gpio_release(struct lan743x_adapter *adapter, int pin) { struct lan743x_gpio *gpio = &adapter->gpio; unsigned long irq_flags = 0; - int bit_mask = BIT(bit); + int bit_mask = BIT(pin); spin_lock_irqsave(&gpio->gpio_lock, irq_flags); if (gpio->used_bits & bit_mask) { @@ -239,21 +295,24 @@ static void lan743x_gpio_release(struct lan743x_adapter *adapter, int bit) if (gpio->ptp_bits & bit_mask) { gpio->ptp_bits &= ~bit_mask; /* disable ptp output */ - gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(bit); + gpio->gpio_cfg3 &= ~GPIO_CFG3_1588_OE_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG3, gpio->gpio_cfg3); } /* release gpio output */ /* disable gpio */ - gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(bit); - gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(bit); + gpio->gpio_cfg1 |= GPIO_CFG1_GPIOEN_BIT_(pin); + gpio->gpio_cfg1 &= ~GPIO_CFG1_GPIOBUF_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG1, gpio->gpio_cfg1); /* reset back to input */ - gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(bit); - gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(bit); + gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DIR_BIT_(pin); + gpio->gpio_cfg0 &= ~GPIO_CFG0_GPIO_DATA_BIT_(pin); lan743x_csr_write(adapter, GPIO_CFG0, gpio->gpio_cfg0); + + /* assign pin to original function */ + lan743x_led_mux_enable(adapter, pin, true); } } spin_unlock_irqrestore(&gpio->gpio_lock, irq_flags); @@ -391,89 +450,91 @@ static int lan743x_ptpci_settime64(struct ptp_clock_info *ptpci, return 0; } -static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter) +static void lan743x_ptp_perout_off(struct lan743x_adapter *adapter, + unsigned int index) { struct lan743x_ptp *ptp = &adapter->ptp; u32 general_config = 0; + struct lan743x_ptp_perout *perout = &ptp->perout[index]; - if (ptp->perout_gpio_bit >= 0) { - lan743x_gpio_release(adapter, ptp->perout_gpio_bit); - ptp->perout_gpio_bit = -1; + if (perout->gpio_pin >= 0) { + lan743x_gpio_release(adapter, perout->gpio_pin); + perout->gpio_pin = -1; } - if (ptp->perout_event_ch >= 0) { + if (perout->event_ch >= 0) { /* set target to far in the future, effectively disabling it */ lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 0xFFFF0000); lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0); general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); general_config |= PTP_GENERAL_CONFIG_RELOAD_ADD_X_ - (ptp->perout_event_ch); + (perout->event_ch); lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); - lan743x_ptp_release_event_ch(adapter, ptp->perout_event_ch); - ptp->perout_event_ch = -1; + lan743x_ptp_release_event_ch(adapter, perout->event_ch); + perout->event_ch = -1; } } static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, - struct ptp_perout_request *perout) + struct ptp_perout_request *perout_request) { struct lan743x_ptp *ptp = &adapter->ptp; u32 period_sec = 0, period_nsec = 0; u32 start_sec = 0, start_nsec = 0; u32 general_config = 0; int pulse_width = 0; - int perout_bit = 0; - - if (!on) { - lan743x_ptp_perout_off(adapter); + int perout_pin = 0; + unsigned int index = perout_request->index; + struct lan743x_ptp_perout *perout = &ptp->perout[index]; + + if (on) { + perout_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT, + perout_request->index); + if (perout_pin < 0) + return -EBUSY; + } else { + lan743x_ptp_perout_off(adapter, index); return 0; } - if (ptp->perout_event_ch >= 0 || - ptp->perout_gpio_bit >= 0) { + if (perout->event_ch >= 0 || + perout->gpio_pin >= 0) { /* already on, turn off first */ - lan743x_ptp_perout_off(adapter); + lan743x_ptp_perout_off(adapter, index); } - ptp->perout_event_ch = lan743x_ptp_reserve_event_ch(adapter); - if (ptp->perout_event_ch < 0) { + perout->event_ch = lan743x_ptp_reserve_event_ch(adapter, index); + + if (perout->event_ch < 0) { netif_warn(adapter, drv, adapter->netdev, - "Failed to reserve event channel for PEROUT\n"); + "Failed to reserve event channel %d for PEROUT\n", + index); goto failed; } - switch (adapter->csr.id_rev & ID_REV_ID_MASK_) { - case ID_REV_ID_LAN7430_: - perout_bit = 2;/* GPIO 2 is preferred on EVB LAN7430 */ - break; - case ID_REV_ID_LAN7431_: - perout_bit = 4;/* GPIO 4 is preferred on EVB LAN7431 */ - break; - } + perout->gpio_pin = lan743x_gpio_rsrv_ptp_out(adapter, + perout_pin, + perout->event_ch); - ptp->perout_gpio_bit = lan743x_gpio_rsrv_ptp_out(adapter, - perout_bit, - ptp->perout_event_ch); - - if (ptp->perout_gpio_bit < 0) { + if (perout->gpio_pin < 0) { netif_warn(adapter, drv, adapter->netdev, "Failed to reserve gpio %d for PEROUT\n", - perout_bit); + perout_pin); goto failed; } - start_sec = perout->start.sec; - start_sec += perout->start.nsec / 1000000000; - start_nsec = perout->start.nsec % 1000000000; + start_sec = perout_request->start.sec; + start_sec += perout_request->start.nsec / 1000000000; + start_nsec = perout_request->start.nsec % 1000000000; - period_sec = perout->period.sec; - period_sec += perout->period.nsec / 1000000000; - period_nsec = perout->period.nsec % 1000000000; + period_sec = perout_request->period.sec; + period_sec += perout_request->period.nsec / 1000000000; + period_nsec = perout_request->period.nsec % 1000000000; if (period_sec == 0) { if (period_nsec >= 400000000) { @@ -499,41 +560,41 @@ static int lan743x_ptp_perout(struct lan743x_adapter *adapter, int on, /* turn off by setting target far in future */ lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_SEC_X(perout->event_ch), 0xFFFF0000); lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch), 0); + PTP_CLOCK_TARGET_NS_X(perout->event_ch), 0); /* Configure to pulse every period */ general_config = lan743x_csr_read(adapter, PTP_GENERAL_CONFIG); general_config &= ~(PTP_GENERAL_CONFIG_CLOCK_EVENT_X_MASK_ - (ptp->perout_event_ch)); + (perout->event_ch)); general_config |= PTP_GENERAL_CONFIG_CLOCK_EVENT_X_SET_ - (ptp->perout_event_ch, pulse_width); + (perout->event_ch, pulse_width); general_config &= ~PTP_GENERAL_CONFIG_RELOAD_ADD_X_ - (ptp->perout_event_ch); + (perout->event_ch); lan743x_csr_write(adapter, PTP_GENERAL_CONFIG, general_config); /* set the reload to one toggle cycle */ lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_RELOAD_SEC_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_RELOAD_SEC_X(perout->event_ch), period_sec); lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_RELOAD_NS_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_RELOAD_NS_X(perout->event_ch), period_nsec); /* set the start time */ lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_SEC_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_SEC_X(perout->event_ch), start_sec); lan743x_csr_write(adapter, - PTP_CLOCK_TARGET_NS_X(ptp->perout_event_ch), + PTP_CLOCK_TARGET_NS_X(perout->event_ch), start_nsec); return 0; failed: - lan743x_ptp_perout_off(adapter); + lan743x_ptp_perout_off(adapter, index); return -ENODEV; } @@ -550,7 +611,7 @@ static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci, case PTP_CLK_REQ_EXTTS: return -EINVAL; case PTP_CLK_REQ_PEROUT: - if (request->perout.index == 0) + if (request->perout.index < ptpci->n_per_out) return lan743x_ptp_perout(adapter, on, &request->perout); return -EINVAL; @@ -568,6 +629,29 @@ static int lan743x_ptpci_enable(struct ptp_clock_info *ptpci, return 0; } +static int lan743x_ptpci_verify_pin_config(struct ptp_clock_info *ptp, + unsigned int pin, + enum ptp_pin_function func, + unsigned int chan) +{ + int result = 0; + + /* Confirm the requested function is supported. Parameter + * validation is done by the caller. + */ + switch (func) { + case PTP_PF_NONE: + case PTP_PF_PEROUT: + break; + case PTP_PF_EXTTS: + case PTP_PF_PHYSYNC: + default: + result = -1; + break; + } + return result; +} + static long lan743x_ptpci_do_aux_work(struct ptp_clock_info *ptpci) { struct lan743x_ptp *ptp = @@ -861,12 +945,19 @@ void lan743x_ptp_update_latency(struct lan743x_adapter *adapter, int lan743x_ptp_init(struct lan743x_adapter *adapter) { struct lan743x_ptp *ptp = &adapter->ptp; + int i; mutex_init(&ptp->command_lock); spin_lock_init(&ptp->tx_ts_lock); ptp->used_event_ch = 0; - ptp->perout_event_ch = -1; - ptp->perout_gpio_bit = -1; + + for (i = 0; i < LAN743X_PTP_N_EVENT_CHAN; i++) { + ptp->perout[i].event_ch = -1; + ptp->perout[i].gpio_pin = -1; + } + + lan743x_led_mux_save(adapter); + return 0; } @@ -875,6 +966,8 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter) struct lan743x_ptp *ptp = &adapter->ptp; int ret = -ENODEV; u32 temp; + int i; + int n_pins; lan743x_ptp_reset(adapter); lan743x_ptp_sync_to_system_clock(adapter); @@ -890,10 +983,32 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter) if (!IS_ENABLED(CONFIG_PTP_1588_CLOCK)) return 0; - snprintf(ptp->pin_config[0].name, 32, "lan743x_ptp_pin_0"); - ptp->pin_config[0].index = 0; - ptp->pin_config[0].func = PTP_PF_PEROUT; - ptp->pin_config[0].chan = 0; + switch (adapter->csr.id_rev & ID_REV_ID_MASK_) { + case ID_REV_ID_LAN7430_: + n_pins = LAN7430_N_GPIO; + break; + case ID_REV_ID_LAN7431_: + n_pins = LAN7431_N_GPIO; + break; + default: + netif_warn(adapter, drv, adapter->netdev, + "Unknown LAN743x (%08x). Assuming no GPIO\n", + adapter->csr.id_rev); + n_pins = 0; + break; + } + + if (n_pins > LAN743X_PTP_N_GPIO) + n_pins = LAN743X_PTP_N_GPIO; + + for (i = 0; i < n_pins; i++) { + struct ptp_pin_desc *ptp_pin = &ptp->pin_config[i]; + + snprintf(ptp_pin->name, + sizeof(ptp_pin->name), "lan743x_ptp_pin_%02d", i); + ptp_pin->index = i; + ptp_pin->func = PTP_PF_NONE; + } ptp->ptp_clock_info.owner = THIS_MODULE; snprintf(ptp->ptp_clock_info.name, 16, "%pm", @@ -901,10 +1016,10 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter) ptp->ptp_clock_info.max_adj = LAN743X_PTP_MAX_FREQ_ADJ_IN_PPB; ptp->ptp_clock_info.n_alarm = 0; ptp->ptp_clock_info.n_ext_ts = 0; - ptp->ptp_clock_info.n_per_out = 1; - ptp->ptp_clock_info.n_pins = 0; + ptp->ptp_clock_info.n_per_out = LAN743X_PTP_N_EVENT_CHAN; + ptp->ptp_clock_info.n_pins = n_pins; ptp->ptp_clock_info.pps = 0; - ptp->ptp_clock_info.pin_config = NULL; + ptp->ptp_clock_info.pin_config = ptp->pin_config; ptp->ptp_clock_info.adjfine = lan743x_ptpci_adjfine; ptp->ptp_clock_info.adjfreq = lan743x_ptpci_adjfreq; ptp->ptp_clock_info.adjtime = lan743x_ptpci_adjtime; @@ -913,7 +1028,7 @@ int lan743x_ptp_open(struct lan743x_adapter *adapter) ptp->ptp_clock_info.settime64 = lan743x_ptpci_settime64; ptp->ptp_clock_info.enable = lan743x_ptpci_enable; ptp->ptp_clock_info.do_aux_work = lan743x_ptpci_do_aux_work; - ptp->ptp_clock_info.verify = NULL; + ptp->ptp_clock_info.verify = lan743x_ptpci_verify_pin_config; ptp->ptp_clock = ptp_clock_register(&ptp->ptp_clock_info, &adapter->pdev->dev); @@ -939,7 +1054,7 @@ void lan743x_ptp_close(struct lan743x_adapter *adapter) int index; if (IS_ENABLED(CONFIG_PTP_1588_CLOCK) && - ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED) { + (ptp->flags & PTP_FLAG_PTP_CLOCK_REGISTERED)) { ptp_clock_unregister(ptp->ptp_clock); ptp->ptp_clock = NULL; ptp->flags &= ~PTP_FLAG_PTP_CLOCK_REGISTERED; @@ -973,6 +1088,8 @@ void lan743x_ptp_close(struct lan743x_adapter *adapter) ptp->pending_tx_timestamps = 0; spin_unlock_bh(&ptp->tx_ts_lock); + lan743x_led_mux_restore(adapter); + lan743x_ptp_disable(adapter); } diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h index 5fc1b3cd5e33..7663bf5d2e33 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.h +++ b/drivers/net/ethernet/microchip/lan743x_ptp.h @@ -7,6 +7,18 @@ #include "linux/ptp_clock_kernel.h" #include "linux/netdevice.h" +#define LAN7430_N_LED 4 +#define LAN7430_N_GPIO 4 /* multiplexed with PHY LEDs */ +#define LAN7431_N_GPIO 12 + +#define LAN743X_PTP_N_GPIO LAN7431_N_GPIO + +/* the number of periodic outputs is limited by number of + * PTP clock event channels + */ +#define LAN743X_PTP_N_EVENT_CHAN 2 +#define LAN743X_PTP_N_PEROUT LAN743X_PTP_N_EVENT_CHAN + struct lan743x_adapter; /* GPIO */ @@ -40,9 +52,14 @@ int lan743x_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); #define LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS (4) -#define PTP_FLAG_PTP_CLOCK_REGISTERED BIT(1) +#define PTP_FLAG_PTP_CLOCK_REGISTERED BIT(1) #define PTP_FLAG_ISR_ENABLED BIT(2) +struct lan743x_ptp_perout { + int event_ch; /* PTP event channel (0=channel A, 1=channel B) */ + int gpio_pin; /* GPIO pin where output appears */ +}; + struct lan743x_ptp { int flags; @@ -51,13 +68,13 @@ struct lan743x_ptp { struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_clock_info; - struct ptp_pin_desc pin_config[1]; + struct ptp_pin_desc pin_config[LAN743X_PTP_N_GPIO]; -#define LAN743X_PTP_NUMBER_OF_EVENT_CHANNELS (2) unsigned long used_event_ch; + struct lan743x_ptp_perout perout[LAN743X_PTP_N_PEROUT]; - int perout_event_ch; - int perout_gpio_bit; + bool leds_multiplexed; + bool led_enabled[LAN7430_N_LED]; /* tx_ts_lock: used to prevent concurrent access to timestamp arrays */ spinlock_t tx_ts_lock; -- cgit v1.2.3-59-g8ed1b From 5c74c54ce6fff719999ff48f128cf4150ee4ff59 Mon Sep 17 00:00:00 2001 From: Iwan R Timmer Date: Thu, 7 Nov 2019 22:11:13 +0100 Subject: net: dsa: mv88e6xxx: Split monitor port configuration Separate the configuration of the egress and ingress monitor port. This allows the port mirror functionality to do ingress and egress port mirroring to separate ports. Signed-off-by: Iwan R Timmer Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 9 +++++++- drivers/net/dsa/mv88e6xxx/chip.h | 9 +++++++- drivers/net/dsa/mv88e6xxx/global1.c | 42 ++++++++++++++++++++++++++----------- drivers/net/dsa/mv88e6xxx/global1.h | 8 +++++-- 4 files changed, 52 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0dbe6c8b9dc0..dfca0ec35145 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2390,7 +2390,14 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) if (chip->info->ops->set_egress_port) { err = chip->info->ops->set_egress_port(chip, - upstream_port); + MV88E6XXX_EGRESS_DIR_INGRESS, + upstream_port); + if (err) + return err; + + err = chip->info->ops->set_egress_port(chip, + MV88E6XXX_EGRESS_DIR_EGRESS, + upstream_port); if (err) return err; } diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 65ce09bdcbcf..9fc93b1a9f74 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -33,6 +33,11 @@ enum mv88e6xxx_egress_mode { MV88E6XXX_EGRESS_MODE_ETHERTYPE, }; +enum mv88e6xxx_egress_direction { + MV88E6XXX_EGRESS_DIR_INGRESS, + MV88E6XXX_EGRESS_DIR_EGRESS, +}; + enum mv88e6xxx_frame_mode { MV88E6XXX_FRAME_MODE_NORMAL, MV88E6XXX_FRAME_MODE_DSA, @@ -465,7 +470,9 @@ struct mv88e6xxx_ops { int (*stats_get_stats)(struct mv88e6xxx_chip *chip, int port, uint64_t *data); int (*set_cpu_port)(struct mv88e6xxx_chip *chip, int port); - int (*set_egress_port)(struct mv88e6xxx_chip *chip, int port); + int (*set_egress_port)(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port); #define MV88E6XXX_CASCADE_PORT_NONE 0xe #define MV88E6XXX_CASCADE_PORT_MULTIPLE 0xf diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 25ec4c0ac589..36b88db22946 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -263,7 +263,9 @@ int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip) /* Offset 0x1a: Monitor Control */ /* Offset 0x1a: Monitor & MGMT Control on some devices */ -int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) +int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port) { u16 reg; int err; @@ -272,11 +274,20 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) if (err) return err; - reg &= ~(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK | - MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); - - reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK) | - port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: + reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK); + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: + reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; + reg |= port << + __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); + break; + default: + return -EINVAL; + } return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); } @@ -310,17 +321,24 @@ static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg); } -int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) +int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port) { u16 ptr; int err; - ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; - err = mv88e6390_g1_monitor_write(chip, ptr, port); - if (err) - return err; + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: + ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; + break; + default: + return -EINVAL; + } - ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; err = mv88e6390_g1_monitor_write(chip, ptr, port); if (err) return err; diff --git a/drivers/net/dsa/mv88e6xxx/global1.h b/drivers/net/dsa/mv88e6xxx/global1.h index 342172275841..bc5a6b2bb1e4 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.h +++ b/drivers/net/dsa/mv88e6xxx/global1.h @@ -288,8 +288,12 @@ int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip); int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip); void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val); int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip); -int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port); -int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port); +int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port); +int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, + enum mv88e6xxx_egress_direction direction, + int port); int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port); int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip); -- cgit v1.2.3-59-g8ed1b From f0942e00a1abb6404ca4302c66497fc623676c11 Mon Sep 17 00:00:00 2001 From: Iwan R Timmer Date: Thu, 7 Nov 2019 22:11:14 +0100 Subject: net: dsa: mv88e6xxx: Add support for port mirroring Add support for configuring port mirroring through the cls_matchall classifier. We do a full ingress and/or egress capture towards a capture port. It allows setting a different capture port for ingress and egress traffic. It keeps track of the mirrored ports and the destination ports to prevent changes to the capture port while other ports are being mirrored. Signed-off-by: Iwan R Timmer Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 76 +++++++++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 6 +++ drivers/net/dsa/mv88e6xxx/global1.c | 18 +++++++-- drivers/net/dsa/mv88e6xxx/port.c | 37 ++++++++++++++++++ drivers/net/dsa/mv88e6xxx/port.h | 3 ++ 5 files changed, 136 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index dfca0ec35145..e8bf6ac1e0f4 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5250,6 +5250,80 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, return err; } +static int mv88e6xxx_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, + bool ingress) +{ + enum mv88e6xxx_egress_direction direction = ingress ? + MV88E6XXX_EGRESS_DIR_INGRESS : + MV88E6XXX_EGRESS_DIR_EGRESS; + struct mv88e6xxx_chip *chip = ds->priv; + bool other_mirrors = false; + int i; + int err; + + if (!chip->info->ops->set_egress_port) + return -EOPNOTSUPP; + + mutex_lock(&chip->reg_lock); + if ((ingress ? chip->ingress_dest_port : chip->egress_dest_port) != + mirror->to_local_port) { + for (i = 0; i < mv88e6xxx_num_ports(chip); i++) + other_mirrors |= ingress ? + chip->ports[i].mirror_ingress : + chip->ports[i].mirror_egress; + + /* Can't change egress port when other mirror is active */ + if (other_mirrors) { + err = -EBUSY; + goto out; + } + + err = chip->info->ops->set_egress_port(chip, + direction, + mirror->to_local_port); + if (err) + goto out; + } + + err = mv88e6xxx_port_set_mirror(chip, port, direction, true); +out: + mutex_unlock(&chip->reg_lock); + + return err; +} + +static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror) +{ + enum mv88e6xxx_egress_direction direction = mirror->ingress ? + MV88E6XXX_EGRESS_DIR_INGRESS : + MV88E6XXX_EGRESS_DIR_EGRESS; + struct mv88e6xxx_chip *chip = ds->priv; + bool other_mirrors = false; + int i; + + mutex_lock(&chip->reg_lock); + if (mv88e6xxx_port_set_mirror(chip, port, direction, false)) + dev_err(ds->dev, "p%d: failed to disable mirroring\n", port); + + for (i = 0; i < mv88e6xxx_num_ports(chip); i++) + other_mirrors |= mirror->ingress ? + chip->ports[i].mirror_ingress : + chip->ports[i].mirror_egress; + + /* Reset egress port when no other mirror is active */ + if (!other_mirrors) { + if (chip->info->ops->set_egress_port(chip, + direction, + dsa_upstream_port(ds, + port))); + dev_err(ds->dev, "failed to set egress port\n"); + } + + mutex_unlock(&chip->reg_lock); +} + static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, bool unicast, bool multicast) { @@ -5305,6 +5379,8 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .port_mdb_prepare = mv88e6xxx_port_mdb_prepare, .port_mdb_add = mv88e6xxx_port_mdb_add, .port_mdb_del = mv88e6xxx_port_mdb_del, + .port_mirror_add = mv88e6xxx_port_mirror_add, + .port_mirror_del = mv88e6xxx_port_mirror_del, .crosschip_bridge_join = mv88e6xxx_crosschip_bridge_join, .crosschip_bridge_leave = mv88e6xxx_crosschip_bridge_leave, .port_hwtstamp_set = mv88e6xxx_port_hwtstamp_set, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 9fc93b1a9f74..8a8e38bfb161 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -233,6 +233,8 @@ struct mv88e6xxx_port { u64 vtu_member_violation; u64 vtu_miss_violation; u8 cmode; + bool mirror_ingress; + bool mirror_egress; unsigned int serdes_irq; }; @@ -316,6 +318,10 @@ struct mv88e6xxx_chip { u16 evcap_config; u16 enable_count; + /* Current ingress and egress monitor ports */ + int egress_dest_port; + int ingress_dest_port; + /* Per-port timestamping resources. */ struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS]; diff --git a/drivers/net/dsa/mv88e6xxx/global1.c b/drivers/net/dsa/mv88e6xxx/global1.c index 36b88db22946..120a65d3e3ef 100644 --- a/drivers/net/dsa/mv88e6xxx/global1.c +++ b/drivers/net/dsa/mv88e6xxx/global1.c @@ -267,6 +267,7 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, enum mv88e6xxx_egress_direction direction, int port) { + int *dest_port_chip; u16 reg; int err; @@ -276,11 +277,13 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, switch (direction) { case MV88E6XXX_EGRESS_DIR_INGRESS: + dest_port_chip = &chip->ingress_dest_port; reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK; reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK); break; case MV88E6XXX_EGRESS_DIR_EGRESS: + dest_port_chip = &chip->egress_dest_port; reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK; reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); @@ -289,7 +292,11 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, return -EINVAL; } - return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); + err = mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); + if (!err) + *dest_port_chip = port; + + return err; } /* Older generations also call this the ARP destination. It has been @@ -325,14 +332,17 @@ int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, enum mv88e6xxx_egress_direction direction, int port) { + int *dest_port_chip; u16 ptr; int err; switch (direction) { case MV88E6XXX_EGRESS_DIR_INGRESS: + dest_port_chip = &chip->ingress_dest_port; ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; break; case MV88E6XXX_EGRESS_DIR_EGRESS: + dest_port_chip = &chip->egress_dest_port; ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; break; default: @@ -340,10 +350,10 @@ int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, } err = mv88e6390_g1_monitor_write(chip, ptr, port); - if (err) - return err; + if (!err) + *dest_port_chip = port; - return 0; + return err; } int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 15ef81654b67..7fe256c5739d 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -1181,6 +1181,43 @@ int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } +int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_egress_direction direction, + bool mirror) +{ + bool *mirror_port; + u16 reg; + u16 bit; + int err; + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, ®); + if (err) + return err; + + switch (direction) { + case MV88E6XXX_EGRESS_DIR_INGRESS: + bit = MV88E6XXX_PORT_CTL2_INGRESS_MONITOR; + mirror_port = &chip->ports[port].mirror_ingress; + break; + case MV88E6XXX_EGRESS_DIR_EGRESS: + bit = MV88E6XXX_PORT_CTL2_EGRESS_MONITOR; + mirror_port = &chip->ports[port].mirror_egress; + break; + default: + return -EINVAL; + } + + reg &= ~bit; + if (mirror) + reg |= bit; + + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); + if (!err) + *mirror_port = mirror; + + return err; +} + int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port, u16 mode) { diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 03a480cd71b9..0ec4327c2b42 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -368,6 +368,9 @@ int mv88e6352_port_link_state(struct mv88e6xxx_chip *chip, int port, int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port); int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, int upstream_port); +int mv88e6xxx_port_set_mirror(struct mv88e6xxx_chip *chip, int port, + enum mv88e6xxx_egress_direction direction, + bool mirror); int mv88e6xxx_port_disable_learn_limit(struct mv88e6xxx_chip *chip, int port); int mv88e6xxx_port_disable_pri_override(struct mv88e6xxx_chip *chip, int port); -- cgit v1.2.3-59-g8ed1b From 371fd7baa81d2adb05c390f8f8a42a4f02173cbd Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Oct 2017 22:36:52 -0500 Subject: can: dev: can_restart(): remove unused code Value assigned to variable err is overwritten at line 562: err = priv->do_set_mode(dev, CAN_MODE_START); before it can be used. Also, notice that this code has been there since 2014. Addresses-Coverity-ID: 1227031 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Marc Kleine-Budde --- drivers/net/can/dev.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 1c88c361938c..6ee06a49fb4c 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -553,10 +553,9 @@ static void can_restart(struct net_device *dev) /* send restart message upstream */ skb = alloc_can_err_skb(dev, &cf); - if (!skb) { - err = -ENOMEM; + if (!skb) goto restart; - } + cf->can_id |= CAN_ERR_RESTARTED; netif_rx(skb); -- cgit v1.2.3-59-g8ed1b From 50ec88120ea16cf8b9aabf8422c364166ce3ee17 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 8 Oct 2019 19:20:39 +0300 Subject: can: mcp251x: get rid of legacy platform data Instead of using legacy platform data, switch to use device properties. For clock frequency we are using well established clock-frequency property. Users, two for now, are also converted here. Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Russell King Signed-off-by: Andy Shevchenko Signed-off-by: Marc Kleine-Budde --- arch/arm/mach-pxa/icontrol.c | 9 +++++---- arch/arm/mach-pxa/zeus.c | 9 +++++---- drivers/net/can/spi/mcp251x.c | 9 ++++----- include/linux/can/platform/mcp251x.h | 22 ---------------------- 4 files changed, 14 insertions(+), 35 deletions(-) delete mode 100644 include/linux/can/platform/mcp251x.h (limited to 'drivers/net') diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c index 865b10344ea2..0474a4b1394d 100644 --- a/arch/arm/mach-pxa/icontrol.c +++ b/arch/arm/mach-pxa/icontrol.c @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -22,7 +23,6 @@ #include #include -#include #include #include "generic.h" @@ -69,8 +69,9 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = { .gpio_cs = ICONTROL_MCP251x_nCS4 }; -static struct mcp251x_platform_data mcp251x_info = { - .oscillator_frequency = 16E6, +static const struct property_entry mcp251x_properties[] = { + PROPERTY_ENTRY_U32("clock-frequency", 16000000), + {} }; static struct spi_board_info mcp251x_board_info[] = { @@ -79,7 +80,7 @@ static struct spi_board_info mcp251x_board_info[] = { .max_speed_hz = 6500000, .bus_num = 3, .chip_select = 0, - .platform_data = &mcp251x_info, + .properties = mcp251x_properties, .controller_data = &mcp251x_chip_info1, .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ1) }, diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c index da113c8eefbf..b27fc7ac9cea 100644 --- a/arch/arm/mach-pxa/zeus.c +++ b/arch/arm/mach-pxa/zeus.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #include #include @@ -428,14 +428,15 @@ static struct gpiod_lookup_table can_regulator_gpiod_table = { }, }; -static struct mcp251x_platform_data zeus_mcp2515_pdata = { - .oscillator_frequency = 16*1000*1000, +static const struct property_entry mcp251x_properties[] = { + PROPERTY_ENTRY_U32("clock-frequency", 16000000), + {} }; static struct spi_board_info zeus_spi_board_info[] = { [0] = { .modalias = "mcp2515", - .platform_data = &zeus_mcp2515_pdata, + .properties = mcp251x_properties, .irq = PXA_GPIO_TO_IRQ(ZEUS_CAN_GPIO), .max_speed_hz = 1*1000*1000, .bus_num = 3, diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index bb20a9b75cc6..ee2e97da4e1d 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -986,19 +985,19 @@ MODULE_DEVICE_TABLE(spi, mcp251x_id_table); static int mcp251x_can_probe(struct spi_device *spi) { const void *match = device_get_match_data(&spi->dev); - struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev); struct net_device *net; struct mcp251x_priv *priv; struct clk *clk; - int freq, ret; + u32 freq; + int ret; clk = devm_clk_get_optional(&spi->dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); freq = clk_get_rate(clk); - if (freq == 0 && pdata) - freq = pdata->oscillator_frequency; + if (freq == 0) + device_property_read_u32(&spi->dev, "clock-frequency", &freq); /* Sanity check */ if (freq < 1000000 || freq > 25000000) diff --git a/include/linux/can/platform/mcp251x.h b/include/linux/can/platform/mcp251x.h deleted file mode 100644 index 9e5ac27fb6c1..000000000000 --- a/include/linux/can/platform/mcp251x.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _CAN_PLATFORM_MCP251X_H -#define _CAN_PLATFORM_MCP251X_H - -/* - * - * CAN bus driver for Microchip 251x CAN Controller with SPI Interface - * - */ - -#include - -/* - * struct mcp251x_platform_data - MCP251X SPI CAN controller platform data - * @oscillator_frequency: - oscillator frequency in Hz - */ - -struct mcp251x_platform_data { - unsigned long oscillator_frequency; -}; - -#endif /* !_CAN_PLATFORM_MCP251X_H */ -- cgit v1.2.3-59-g8ed1b From 877a902103fd3ed15872a5d740fca8aa3f5fa33f Mon Sep 17 00:00:00 2001 From: Timo Schlüßler Date: Fri, 11 Oct 2019 15:38:20 +0200 Subject: can: mcp251x: add mcp251x_write_2regs() and make use of it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces the function mcp251x_write_2regs() to write two registers with one SPI transfer and converts the disabling of pending interrupts in mcp251x_stop() to it. Signed-off-by: Timo Schlüßler Signed-off-by: Marc Kleine-Budde --- drivers/net/can/spi/mcp251x.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index ee2e97da4e1d..d371d3868a66 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -320,6 +320,18 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val) mcp251x_spi_trans(spi, 3); } +static void mcp251x_write_2regs(struct spi_device *spi, u8 reg, u8 v1, u8 v2) +{ + struct mcp251x_priv *priv = spi_get_drvdata(spi); + + priv->spi_tx_buf[0] = INSTRUCTION_WRITE; + priv->spi_tx_buf[1] = reg; + priv->spi_tx_buf[2] = v1; + priv->spi_tx_buf[3] = v2; + + mcp251x_spi_trans(spi, 4); +} + static void mcp251x_write_bits(struct spi_device *spi, u8 reg, u8 mask, u8 val) { @@ -645,8 +657,7 @@ static int mcp251x_stop(struct net_device *net) mutex_lock(&priv->mcp_lock); /* Disable and clear pending interrupts */ - mcp251x_write_reg(spi, CANINTE, 0x00); - mcp251x_write_reg(spi, CANINTF, 0x00); + mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00); mcp251x_write_reg(spi, TXBCTRL(0), 0); mcp251x_clean(net); -- cgit v1.2.3-59-g8ed1b From 8ce8c0abcba314e1fe954a1840f6568bf5aef2ef Mon Sep 17 00:00:00 2001 From: Timo Schlüßler Date: Fri, 11 Oct 2019 15:38:20 +0200 Subject: can: mcp251x: only reset hardware as required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents unwanted glitches on the outputs when changing the link state of the can interface or when resuming from suspend. Only if the device is powered off during suspend it needs to be resetted as required by the specs. Signed-off-by: Timo Schlüßler Signed-off-by: Marc Kleine-Budde --- drivers/net/can/spi/mcp251x.c | 51 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index d371d3868a66..5009ff294941 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -468,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi) mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); } +/* May only be called when device is sleeping! */ +static int mcp251x_hw_wake(struct spi_device *spi) +{ + unsigned long timeout; + + /* Force wakeup interrupt to wake device, but don't execute IST */ + disable_irq(spi->irq); + mcp251x_write_2regs(spi, CANINTE, CANINTE_WAKIE, CANINTF_WAKIF); + + /* Wait for oscillator startup timer after wake up */ + mdelay(MCP251X_OST_DELAY_MS); + + /* Put device into config mode */ + mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF); + + /* Wait for the device to enter config mode */ + timeout = jiffies + HZ; + while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) != + CANCTRL_REQOP_CONF) { + schedule(); + if (time_after(jiffies, timeout)) { + dev_err(&spi->dev, "MCP251x didn't enter in config mode\n"); + return -EBUSY; + } + } + + /* Disable and clear pending interrupts */ + mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00); + enable_irq(spi->irq); + + return 0; +} + static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -725,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) mutex_lock(&priv->mcp_lock); if (priv->after_suspend) { - mcp251x_hw_reset(spi); - mcp251x_setup(net, spi); + if (priv->after_suspend & AFTER_SUSPEND_POWER) { + mcp251x_hw_reset(spi); + mcp251x_setup(net, spi); + } else { + mcp251x_hw_wake(spi); + } priv->force_quit = 0; if (priv->after_suspend & AFTER_SUSPEND_RESTART) { mcp251x_set_normal_mode(spi); @@ -923,7 +960,7 @@ static int mcp251x_open(struct net_device *net) INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); - ret = mcp251x_hw_reset(spi); + ret = mcp251x_hw_wake(spi); if (ret) goto out_free_wq; ret = mcp251x_setup(net, spi); @@ -1165,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev) if (priv->after_suspend & AFTER_SUSPEND_POWER) mcp251x_power_enable(priv->power, 1); - - if (priv->after_suspend & AFTER_SUSPEND_UP) { + if (priv->after_suspend & AFTER_SUSPEND_UP) mcp251x_power_enable(priv->transceiver, 1); + + if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP)) queue_work(priv->wq, &priv->restart_work); - } else { + else priv->after_suspend = 0; - } priv->force_quit = 0; enable_irq(spi->irq); -- cgit v1.2.3-59-g8ed1b From e577ba728bf50ea0b6b9b9a833d75fa45ed9a26a Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 8 Oct 2019 10:16:48 +0200 Subject: can: c_can: c_can_plaform: fix checkpatch warnings This patch fixes several checkpatch warnings in the c_can_platform driver glue code. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/c_can/c_can_platform.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index b5145a7f874c..05f425ceb53a 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -39,10 +39,11 @@ #include "c_can.h" -#define DCAN_RAM_INIT_BIT (1 << 3) +#define DCAN_RAM_INIT_BIT BIT(3) + static DEFINE_SPINLOCK(raminit_lock); -/* - * 16-bit c_can registers can be arranged differently in the memory + +/* 16-bit c_can registers can be arranged differently in the memory * architecture of different implementations. For example: 16-bit * registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * Handle the same by providing a common read/write interface. @@ -54,7 +55,7 @@ static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv, } static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv, - enum reg index, u16 val) + enum reg index, u16 val) { writew(val, priv->base + priv->regs[index]); } @@ -66,7 +67,7 @@ static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv, } static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv, - enum reg index, u16 val) + enum reg index, u16 val) { writew(val, priv->base + 2 * priv->regs[index]); } @@ -144,13 +145,13 @@ static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index) u32 val; val = priv->read_reg(priv, index); - val |= ((u32) priv->read_reg(priv, index + 1)) << 16; + val |= ((u32)priv->read_reg(priv, index + 1)) << 16; return val; } -static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, - u32 val) +static void c_can_plat_write_reg32(const struct c_can_priv *priv, + enum reg index, u32 val) { priv->write_reg(priv, index + 1, val >> 16); priv->write_reg(priv, index, val); @@ -161,8 +162,8 @@ static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index) return readl(priv->base + priv->regs[index]); } -static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, - u32 val) +static void d_can_plat_write_reg32(const struct c_can_priv *priv, + enum reg index, u32 val) { writel(val, priv->base + priv->regs[index]); } -- cgit v1.2.3-59-g8ed1b From 3cc9358fb51f160e78746fce4adb60b913fb5cc1 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Tue, 1 Oct 2019 21:50:20 +0200 Subject: can: peak_canfd: fix checkpatch warnings This patch fixes checkpatch warnings in the peak_canfd driver. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/peak_canfd/peak_canfd.c | 7 +++---- drivers/net/can/peak_canfd/peak_canfd_user.h | 3 +-- drivers/net/can/peak_canfd/peak_pciefd_main.c | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 6b0c6a99fc8d..1ffcd63f5a86 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007, 2011 Wolfgang Grandegger +/* Copyright (C) 2007, 2011 Wolfgang Grandegger * Copyright (C) 2012 Stephane Grosjean * * Copyright (C) 2016 PEAK System-Technik GmbH @@ -122,7 +121,8 @@ static int pucan_set_timing_slow(struct peak_canfd_priv *priv, cmd = pucan_add_cmd(pucan_init_cmd(priv), PUCAN_CMD_TIMING_SLOW); cmd->sjw_t = PUCAN_TSLOW_SJW_T(pbt->sjw - 1, - priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES); + priv->can.ctrlmode & + CAN_CTRLMODE_3_SAMPLES); cmd->tseg1 = PUCAN_TSLOW_TSEG1(pbt->prop_seg + pbt->phase_seg1 - 1); cmd->tseg2 = PUCAN_TSLOW_TSEG2(pbt->phase_seg2 - 1); cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(pbt->brp - 1)); @@ -325,7 +325,6 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, /* this STATUS is the CNF of the RX_BARRIER: Tx path can be setup */ if (pucan_status_is_rx_barrier(msg)) { - if (priv->enable_tx_path) { int err = priv->enable_tx_path(priv); diff --git a/drivers/net/can/peak_canfd/peak_canfd_user.h b/drivers/net/can/peak_canfd/peak_canfd_user.h index 95b23caa7dd6..a72719dc3b74 100644 --- a/drivers/net/can/peak_canfd/peak_canfd_user.h +++ b/drivers/net/can/peak_canfd/peak_canfd_user.h @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* - * CAN driver for PEAK System micro-CAN based adapters +/* CAN driver for PEAK System micro-CAN based adapters * * Copyright (C) 2003-2011 PEAK System-Technik GmbH * Copyright (C) 2011-2013 Stephane Grosjean diff --git a/drivers/net/can/peak_canfd/peak_pciefd_main.c b/drivers/net/can/peak_canfd/peak_pciefd_main.c index 13b10cbf236a..d08a3d559114 100644 --- a/drivers/net/can/peak_canfd/peak_pciefd_main.c +++ b/drivers/net/can/peak_canfd/peak_pciefd_main.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007, 2011 Wolfgang Grandegger +/* Copyright (C) 2007, 2011 Wolfgang Grandegger * Copyright (C) 2012 Stephane Grosjean * * Derived from the PCAN project file driver/src/pcan_pci.c: @@ -841,7 +840,8 @@ err_disable_pci: /* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while * the probe() function must return a negative errno in case of failure - * (err is unchanged if negative) */ + * (err is unchanged if negative) + */ return pcibios_err_to_errno(err); } -- cgit v1.2.3-59-g8ed1b From 2b1a4547c122dcb9999e1a876236b44408c7d01c Mon Sep 17 00:00:00 2001 From: Stephane Grosjean Date: Mon, 16 Sep 2019 16:15:44 +0200 Subject: can: peak_canfd: provide hw timestamps in rx skbs PEAK-System's CAN FD interfaces based on an IP core provide a timestamp for each CAN and STATUS message received. This patch transfers these received timestamps (clocked in microseconds) to hardware timestamps (clocked in nanoseconds) in the corresponding skbs raised to the network layer. Signed-off-by: Stephane Grosjean Signed-off-by: Marc Kleine-Budde --- drivers/net/can/peak_canfd/peak_canfd.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/peak_canfd/peak_canfd.c b/drivers/net/can/peak_canfd/peak_canfd.c index 1ffcd63f5a86..10aa3e457c33 100644 --- a/drivers/net/can/peak_canfd/peak_canfd.c +++ b/drivers/net/can/peak_canfd/peak_canfd.c @@ -232,6 +232,20 @@ static int pucan_setup_rx_barrier(struct peak_canfd_priv *priv) return pucan_write_cmd(priv); } +static int pucan_netif_rx(struct sk_buff *skb, __le32 ts_low, __le32 ts_high) +{ + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + u64 ts_us; + + ts_us = (u64)le32_to_cpu(ts_high) << 32; + ts_us |= le32_to_cpu(ts_low); + + /* IP core timestamps are µs. */ + hwts->hwtstamp = ns_to_ktime(ts_us * NSEC_PER_USEC); + + return netif_rx(skb); +} + /* handle the reception of one CAN frame */ static int pucan_handle_can_rx(struct peak_canfd_priv *priv, struct pucan_rx_msg *msg) @@ -299,7 +313,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv, stats->rx_bytes += cf->len; stats->rx_packets++; - netif_rx(skb); + pucan_netif_rx(skb, msg->ts_low, msg->ts_high); return 0; } @@ -392,7 +406,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, stats->rx_packets++; stats->rx_bytes += cf->can_dlc; - netif_rx(skb); + pucan_netif_rx(skb, msg->ts_low, msg->ts_high); return 0; } -- cgit v1.2.3-59-g8ed1b From b687a7792b9c28778f1d4359fafcec3c17147c58 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 4 Oct 2019 20:22:22 +0200 Subject: can: xilinx_can: fix checkpatch warnings This patch fixes several checkpatch warnings. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 7c482b2d78d2..b6fa735e47f1 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -194,7 +194,7 @@ struct xcan_devtype_data { */ struct xcan_priv { struct can_priv can; - spinlock_t tx_lock; + spinlock_t tx_lock; /* Lock for synchronizing TX interrupt handling */ unsigned int tx_head; unsigned int tx_tail; unsigned int tx_max; @@ -400,7 +400,7 @@ static int xcan_set_bittiming(struct net_device *ndev) XCAN_SR_CONFIG_MASK; if (!is_config_mode) { netdev_alert(ndev, - "BUG! Cannot set bittiming - CAN is not in config mode\n"); + "BUG! Cannot set bittiming - CAN is not in config mode\n"); return -EPERM; } @@ -482,11 +482,10 @@ static int xcan_chip_start(struct net_device *ndev) priv->write_reg(priv, XCAN_IER_OFFSET, ier); /* Check whether it is loopback mode or normal mode */ - if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) { + if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) reg_msr = XCAN_MSR_LBACK_MASK; - } else { + else reg_msr = 0x0; - } /* enable the first extended filter, if any, as cores with extended * filtering default to non-receipt if all filters are disabled -- cgit v1.2.3-59-g8ed1b From 91e9f2c0e7a49ec6a6673b4d97d535b838396fc9 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Fri, 4 Oct 2019 12:02:56 +0300 Subject: can: xilinx_can: avoid non-requested bus error frames Userspace can signal with CAN_CTRLMODE_BERR_REPORTING whether they need reporting of bus errors (CAN_ERR_BUSERROR) or not. However, xilinx_can driver currently always sends CAN_ERR_BUSERROR frames to userspace on bus errors. To improve performance on error conditions when bus error reporting is not needed, avoid sending CAN_ERR_BUSERROR frames unless requested via CAN_CTRLMODE_BERR_REPORTING. The error interrupt is still kept enabled as there is no dedicated state transition interrupt, but just disabling error frame submission still yields a significant performance improvement. In a simple test with continuous bus errors and no userspace programs reading/writing CAN I saw system CPU load reduced by 1/3. Tested on a ZynqMP board with CAN-FD v1.0. Signed-off-by: Anssi Hannula Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 89 ++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index b6fa735e47f1..f33863379036 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -470,7 +470,13 @@ static int xcan_chip_start(struct net_device *ndev) if (err < 0) return err; - /* Enable interrupts */ + /* Enable interrupts + * + * We enable the ERROR interrupt even with + * CAN_CTRLMODE_BERR_REPORTING disabled as there is no + * dedicated interrupt for a state change to + * ERROR_WARNING/ERROR_PASSIVE. + */ ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK | XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | @@ -980,12 +986,9 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) { struct xcan_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; - struct can_frame *cf; - struct sk_buff *skb; + struct can_frame cf = { }; u32 err_status; - skb = alloc_can_err_skb(ndev, &cf); - err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); @@ -995,32 +998,27 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) /* Leave device in Config Mode in bus-off state */ priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); can_bus_off(ndev); - if (skb) - cf->can_id |= CAN_ERR_BUSOFF; + cf.can_id |= CAN_ERR_BUSOFF; } else { enum can_state new_state = xcan_current_error_state(ndev); if (new_state != priv->can.state) - xcan_set_error_state(ndev, new_state, skb ? cf : NULL); + xcan_set_error_state(ndev, new_state, &cf); } /* Check for Arbitration lost interrupt */ if (isr & XCAN_IXR_ARBLST_MASK) { priv->can.can_stats.arbitration_lost++; - if (skb) { - cf->can_id |= CAN_ERR_LOSTARB; - cf->data[0] = CAN_ERR_LOSTARB_UNSPEC; - } + cf.can_id |= CAN_ERR_LOSTARB; + cf.data[0] = CAN_ERR_LOSTARB_UNSPEC; } /* Check for RX FIFO Overflow interrupt */ if (isr & XCAN_IXR_RXOFLW_MASK) { stats->rx_over_errors++; stats->rx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; - } + cf.can_id |= CAN_ERR_CRTL; + cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; } /* Check for RX Match Not Finished interrupt */ @@ -1028,68 +1026,77 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) stats->rx_dropped++; stats->rx_errors++; netdev_err(ndev, "RX match not finished, frame discarded\n"); - if (skb) { - cf->can_id |= CAN_ERR_CRTL; - cf->data[1] |= CAN_ERR_CRTL_UNSPEC; - } + cf.can_id |= CAN_ERR_CRTL; + cf.data[1] |= CAN_ERR_CRTL_UNSPEC; } /* Check for error interrupt */ if (isr & XCAN_IXR_ERROR_MASK) { - if (skb) - cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + bool berr_reporting = false; + + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) { + berr_reporting = true; + cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; + } /* Check for Ack error interrupt */ if (err_status & XCAN_ESR_ACKER_MASK) { stats->tx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_ACK; - cf->data[3] = CAN_ERR_PROT_LOC_ACK; + if (berr_reporting) { + cf.can_id |= CAN_ERR_ACK; + cf.data[3] = CAN_ERR_PROT_LOC_ACK; } } /* Check for Bit error interrupt */ if (err_status & XCAN_ESR_BERR_MASK) { stats->tx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_BIT; + if (berr_reporting) { + cf.can_id |= CAN_ERR_PROT; + cf.data[2] = CAN_ERR_PROT_BIT; } } /* Check for Stuff error interrupt */ if (err_status & XCAN_ESR_STER_MASK) { stats->rx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_STUFF; + if (berr_reporting) { + cf.can_id |= CAN_ERR_PROT; + cf.data[2] = CAN_ERR_PROT_STUFF; } } /* Check for Form error interrupt */ if (err_status & XCAN_ESR_FMER_MASK) { stats->rx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_PROT; - cf->data[2] = CAN_ERR_PROT_FORM; + if (berr_reporting) { + cf.can_id |= CAN_ERR_PROT; + cf.data[2] = CAN_ERR_PROT_FORM; } } /* Check for CRC error interrupt */ if (err_status & XCAN_ESR_CRCER_MASK) { stats->rx_errors++; - if (skb) { - cf->can_id |= CAN_ERR_PROT; - cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; + if (berr_reporting) { + cf.can_id |= CAN_ERR_PROT; + cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; } } priv->can.can_stats.bus_error++; } - if (skb) { - stats->rx_packets++; - stats->rx_bytes += cf->can_dlc; - netif_rx(skb); + if (cf.can_id) { + struct can_frame *skb_cf; + struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf); + + if (skb) { + skb_cf->can_id |= cf.can_id; + memcpy(skb_cf->data, cf.data, CAN_ERR_DLC); + stats->rx_packets++; + stats->rx_bytes += CAN_ERR_DLC; + netif_rx(skb); + } } netdev_dbg(ndev, "%s: error status register:0x%x\n", -- cgit v1.2.3-59-g8ed1b From 0ff8ee89624aaa74ee48a3015b4c1305b357e401 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 15 Oct 2019 22:26:19 +0800 Subject: can: xilinx_can: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Marc Kleine-Budde --- drivers/net/can/xilinx_can.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index f33863379036..4a96e2dd7d77 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -1657,7 +1657,6 @@ MODULE_DEVICE_TABLE(of, xcan_of_match); */ static int xcan_probe(struct platform_device *pdev) { - struct resource *res; /* IO mem resources */ struct net_device *ndev; struct xcan_priv *priv; const struct of_device_id *of_id; @@ -1669,8 +1668,7 @@ static int xcan_probe(struct platform_device *pdev) const char *hw_tx_max_property; /* Get the virtual base address for the device */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(&pdev->dev, res); + addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(addr)) { ret = PTR_ERR(addr); goto err; -- cgit v1.2.3-59-g8ed1b From fb7d6a81c220178851badef9dd6eeba88264320a Mon Sep 17 00:00:00 2001 From: Pankaj Sharma Date: Mon, 21 Oct 2019 17:34:40 +0530 Subject: can: m_can: add support for one shot mode According to the CAN Specification (see ISO 11898-1:2015, 8.3.4 Recovery Management), the M_CAN provides means for automatic retransmission of frames that have lost arbitration or that have been disturbed by errors during transmission. By default automatic retransmission is enabled. The Bosch MCAN controller has support for disabling automatic retransmission. To support time-triggered communication as described in ISO 11898-1:2015, chapter 9.2, the automatic retransmission may be disabled via CCCR.DAR. CAN_CTRLMODE_ONE_SHOT is used for disabling automatic retransmission. Signed-off-by: Pankaj Sharma Signed-off-by: Sriram Dash Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 562c8317e3aa..75e7490c4299 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -123,6 +123,7 @@ enum m_can_reg { #define CCCR_CME_CANFD_BRS 0x2 #define CCCR_TXP BIT(14) #define CCCR_TEST BIT(7) +#define CCCR_DAR BIT(6) #define CCCR_MON BIT(5) #define CCCR_CSR BIT(4) #define CCCR_CSA BIT(3) @@ -1135,7 +1136,7 @@ static void m_can_chip_config(struct net_device *dev) if (cdev->version == 30) { /* Version 3.0.x */ - cccr &= ~(CCCR_TEST | CCCR_MON | + cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) | (CCCR_CME_MASK << CCCR_CME_SHIFT)); @@ -1145,7 +1146,7 @@ static void m_can_chip_config(struct net_device *dev) } else { /* Version 3.1.x or 3.2.x */ cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | - CCCR_NISO); + CCCR_NISO | CCCR_DAR); /* Only 3.2.x has NISO Bit implemented */ if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) @@ -1165,6 +1166,10 @@ static void m_can_chip_config(struct net_device *dev) if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) cccr |= CCCR_MON; + /* Disable Auto Retransmission (all versions) */ + if (cdev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) + cccr |= CCCR_DAR; + /* Write config */ m_can_write(cdev, M_CAN_CCCR, cccr); m_can_write(cdev, M_CAN_TEST, test); @@ -1310,7 +1315,8 @@ static int m_can_dev_setup(struct m_can_classdev *m_can_dev) m_can_dev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | - CAN_CTRLMODE_FD; + CAN_CTRLMODE_FD | + CAN_CTRLMODE_ONE_SHOT; /* Set properties depending on M_CAN version */ switch (m_can_dev->version) { -- cgit v1.2.3-59-g8ed1b From 6b43a2650806ca59e9ac2554cfd1cf23ed491879 Mon Sep 17 00:00:00 2001 From: Pankaj Sharma Date: Wed, 30 Oct 2019 17:08:59 +0530 Subject: can: m_can: add support for handling arbitration error The Bosch MCAN hardware (3.1.0 and above) supports interrupt flag to detect Protocol error in arbitration phase. Transmit error statistics is currently not updated from the MCAN driver. Protocol error in arbitration phase is a TX error and the network statistics should be updated accordingly. The member "tx_error" of "struct net_device_stats" should be incremented as arbitration is a transmit protocol error. Also "arbitration_lost" of "struct can_device_stats" should be incremented to report arbitration lost. Signed-off-by: Pankaj Sharma Signed-off-by: Sriram Dash Signed-off-by: Marc Kleine-Budde --- drivers/net/can/m_can/m_can.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 75e7490c4299..02c5795b7393 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -778,6 +778,43 @@ static inline bool is_lec_err(u32 psr) return psr && (psr != LEC_UNUSED); } +static inline bool m_can_is_protocol_err(u32 irqstatus) +{ + return irqstatus & IR_ERR_LEC_31X; +} + +static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus) +{ + struct net_device_stats *stats = &dev->stats; + struct m_can_classdev *cdev = netdev_priv(dev); + struct can_frame *cf; + struct sk_buff *skb; + + /* propagate the error condition to the CAN stack */ + skb = alloc_can_err_skb(dev, &cf); + + /* update tx error stats since there is protocol error */ + stats->tx_errors++; + + /* update arbitration lost status */ + if (cdev->version >= 31 && (irqstatus & IR_PEA)) { + netdev_dbg(dev, "Protocol error in Arbitration fail\n"); + cdev->can.can_stats.arbitration_lost++; + if (skb) { + cf->can_id |= CAN_ERR_LOSTARB; + cf->data[0] |= CAN_ERR_LOSTARB_UNSPEC; + } + } + + if (unlikely(!skb)) { + netdev_dbg(dev, "allocation of skb failed\n"); + return 0; + } + netif_receive_skb(skb); + + return 1; +} + static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, u32 psr) { @@ -792,6 +829,11 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, is_lec_err(psr)) work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); + /* handle protocol errors in arbitration phase */ + if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && + m_can_is_protocol_err(irqstatus)) + work_done += m_can_handle_protocol_error(dev, irqstatus); + /* other unproccessed error interrupts */ m_can_handle_other_err(dev, irqstatus); -- cgit v1.2.3-59-g8ed1b From 65725aa8829f0042db888c2b7e6cc8f1d79e7131 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 30 Sep 2019 17:49:09 +0800 Subject: can: grcan: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Reviewed-by: Sean Nyekjaer Signed-off-by: Marc Kleine-Budde --- drivers/net/can/grcan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c index b8f1f2b69dd3..378200b682fa 100644 --- a/drivers/net/can/grcan.c +++ b/drivers/net/can/grcan.c @@ -1652,7 +1652,6 @@ exit_free_candev: static int grcan_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; - struct resource *res; u32 sysid, ambafreq; int irq, err; void __iomem *base; @@ -1672,8 +1671,7 @@ static int grcan_probe(struct platform_device *ofdev) goto exit_error; } - res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&ofdev->dev, res); + base = devm_platform_ioremap_resource(ofdev, 0); if (IS_ERR(base)) { err = PTR_ERR(base); goto exit_error; -- cgit v1.2.3-59-g8ed1b From 8dab8c65d1b519aa6466dbd433b7062382d24ade Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 15 Oct 2019 22:20:46 +0800 Subject: can: ifi: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Signed-off-by: YueHaibing Reviewed-by: Simon Horman Signed-off-by: Marc Kleine-Budde --- drivers/net/can/ifi_canfd/ifi_canfd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index fedd927ba6ed..04d59bede5ea 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -942,13 +942,11 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct net_device *ndev; struct ifi_canfd_priv *priv; - struct resource *res; void __iomem *addr; int irq, ret; u32 id, rev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(dev, res); + addr = devm_platform_ioremap_resource(pdev, 0); irq = platform_get_irq(pdev, 0); if (IS_ERR(addr) || irq < 0) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From ac9921ded292bf3e8c201387bbbc0c3e171cae26 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 15 Oct 2019 22:30:47 +0800 Subject: can: rcar: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rcar/rcar_can.c | 4 +--- drivers/net/can/rcar/rcar_canfd.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rcar/rcar_can.c b/drivers/net/can/rcar/rcar_can.c index bf5adea9c0a3..48575900adb7 100644 --- a/drivers/net/can/rcar/rcar_can.c +++ b/drivers/net/can/rcar/rcar_can.c @@ -744,7 +744,6 @@ static int rcar_can_probe(struct platform_device *pdev) { struct rcar_can_priv *priv; struct net_device *ndev; - struct resource *mem; void __iomem *addr; u32 clock_select = CLKR_CLKP1; int err = -ENODEV; @@ -759,8 +758,7 @@ static int rcar_can_probe(struct platform_device *pdev) goto fail; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(&pdev->dev, mem); + addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(addr)) { err = PTR_ERR(addr); goto fail; diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index edaa1ca972c1..de59dd6aad29 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -1630,7 +1630,6 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch) static int rcar_canfd_probe(struct platform_device *pdev) { - struct resource *mem; void __iomem *addr; u32 sts, ch, fcan_freq; struct rcar_canfd_global *gpriv; @@ -1704,8 +1703,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) /* CANFD clock is further divided by (1/2) within the IP */ fcan_freq /= 2; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(&pdev->dev, mem); + addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(addr)) { err = PTR_ERR(addr); goto fail_dev; -- cgit v1.2.3-59-g8ed1b From 0767bbe530c123e0945f4c4c60639005ce44fede Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 15 Oct 2019 22:27:44 +0800 Subject: can: sun4i: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Marc Kleine-Budde --- drivers/net/can/sun4i_can.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index f4cd88196404..e3ba8ab0cbf4 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -771,7 +771,6 @@ static int sun4ican_remove(struct platform_device *pdev) static int sun4ican_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource *mem; struct clk *clk; void __iomem *addr; int err, irq; @@ -791,8 +790,7 @@ static int sun4ican_probe(struct platform_device *pdev) goto exit; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = devm_ioremap_resource(&pdev->dev, mem); + addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(addr)) { err = -EBUSY; goto exit; -- cgit v1.2.3-59-g8ed1b From 54dd0b8904ac4c70df7616d39b80390835fede80 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 7 Oct 2019 09:59:49 +0200 Subject: can: rx-offload: fix long lines This patch fixes the checkpatch warnings about too long lines. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rx-offload.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index 84cae167e42f..62393b029e4e 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2014 David Jander, Protonic Holland - * Copyright (C) 2014-2017 Pengutronix, Marc Kleine-Budde +/* Copyright (c) 2014 Protonic Holland, + * David Jander + * Copyright (C) 2014-2017 Pengutronix, + * Marc Kleine-Budde */ #include @@ -11,14 +12,17 @@ struct can_rx_offload_cb { u32 timestamp; }; -static inline struct can_rx_offload_cb *can_rx_offload_get_cb(struct sk_buff *skb) +static inline struct can_rx_offload_cb * +can_rx_offload_get_cb(struct sk_buff *skb) { BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb)); return (struct can_rx_offload_cb *)skb->cb; } -static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned int a, unsigned int b) +static inline bool +can_rx_offload_le(struct can_rx_offload *offload, + unsigned int a, unsigned int b) { if (offload->inc) return a <= b; @@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned in return a >= b; } -static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val) +static inline unsigned int +can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val) { if (offload->inc) return (*val)++; @@ -36,7 +41,9 @@ static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, un static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota) { - struct can_rx_offload *offload = container_of(napi, struct can_rx_offload, napi); + struct can_rx_offload *offload = container_of(napi, + struct can_rx_offload, + napi); struct net_device *dev = offload->dev; struct net_device_stats *stats = &dev->stats; struct sk_buff *skb; @@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota) return work_done; } -static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new, - int (*compare)(struct sk_buff *a, struct sk_buff *b)) +static inline void +__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new, + int (*compare)(struct sk_buff *a, struct sk_buff *b)) { struct sk_buff *pos, *insert = NULL; @@ -199,7 +207,8 @@ can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n) return skb; } -int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pending) +int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, + u64 pending) { struct sk_buff_head skb_queue; unsigned int i; @@ -328,7 +337,9 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload, } EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail); -static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight) +static int can_rx_offload_init_queue(struct net_device *dev, + struct can_rx_offload *offload, + unsigned int weight) { offload->dev = dev; @@ -346,7 +357,8 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo return 0; } -int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *offload) +int can_rx_offload_add_timestamp(struct net_device *dev, + struct can_rx_offload *offload) { unsigned int weight; @@ -366,7 +378,8 @@ int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload * } EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp); -int can_rx_offload_add_fifo(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight) +int can_rx_offload_add_fifo(struct net_device *dev, + struct can_rx_offload *offload, unsigned int weight) { if (!offload->mailbox_read) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From a7b70e2d62d86fcb3f665d325dbc6f0303ee3c51 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 7 Oct 2019 10:00:25 +0200 Subject: can: rx-offload: can_rx_offload_compare(): fix typo This patch fixes a typo found by checkpatch. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rx-offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index 62393b029e4e..c277c5151153 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -109,7 +109,7 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b) cb_a = can_rx_offload_get_cb(a); cb_b = can_rx_offload_get_cb(b); - /* Substract two u32 and return result as int, to keep + /* Subtract two u32 and return result as int, to keep * difference steady around the u32 overflow. */ return cb_b->timestamp - cb_a->timestamp; -- cgit v1.2.3-59-g8ed1b From f1242cd981e36385169281bf7b978e2bfa942eb5 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 7 Oct 2019 10:00:52 +0200 Subject: can: rx-offload: can_rx_offload_irq_offload_timestamp(): don't use assignment in if condition This patch moves the assignment of queue_len out of the if condition. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rx-offload.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index c277c5151153..412a8cec5d18 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -238,8 +238,8 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, skb_queue_splice_tail(&skb_queue, &offload->skb_queue); spin_unlock_irqrestore(&offload->skb_queue.lock, flags); - if ((queue_len = skb_queue_len(&offload->skb_queue)) > - (offload->skb_queue_len_max / 8)) + queue_len = skb_queue_len(&offload->skb_queue); + if (queue_len > offload->skb_queue_len_max / 8) netdev_dbg(offload->dev, "%s: queue_len=%d\n", __func__, queue_len); -- cgit v1.2.3-59-g8ed1b From 61d2350615c2c42f7af65d9a575f5dbf9738a10e Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 7 Oct 2019 13:36:58 +0200 Subject: can: rx-offload: can_rx_offload_reset(): remove no-op function This patch removes the function can_rx_offload_reset(), as it does nothing. If we ever need this function, add it back again. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rx-offload.c | 7 ------- include/linux/can/rx-offload.h | 1 - 2 files changed, 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index 412a8cec5d18..8d120a3750fa 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -348,7 +348,6 @@ static int can_rx_offload_init_queue(struct net_device *dev, offload->skb_queue_len_max *= 4; skb_queue_head_init(&offload->skb_queue); - can_rx_offload_reset(offload); netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight); dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n", @@ -390,7 +389,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo); void can_rx_offload_enable(struct can_rx_offload *offload) { - can_rx_offload_reset(offload); napi_enable(&offload->napi); } EXPORT_SYMBOL_GPL(can_rx_offload_enable); @@ -401,8 +399,3 @@ void can_rx_offload_del(struct can_rx_offload *offload) skb_queue_purge(&offload->skb_queue); } EXPORT_SYMBOL_GPL(can_rx_offload_del); - -void can_rx_offload_reset(struct can_rx_offload *offload) -{ -} -EXPORT_SYMBOL_GPL(can_rx_offload_reset); diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h index 01219f2902bf..fc75e9a7ad2f 100644 --- a/include/linux/can/rx-offload.h +++ b/include/linux/can/rx-offload.h @@ -44,7 +44,6 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, unsigned int idx, u32 timestamp); int can_rx_offload_queue_tail(struct can_rx_offload *offload, struct sk_buff *skb); -void can_rx_offload_reset(struct can_rx_offload *offload); void can_rx_offload_del(struct can_rx_offload *offload); void can_rx_offload_enable(struct can_rx_offload *offload); -- cgit v1.2.3-59-g8ed1b From 4e9c9484b085dbba60b299182dd490eaeb84d18a Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Fri, 12 Jul 2019 08:02:38 +0000 Subject: can: rx-offload: Prepare for CAN FD support The skbs for classic CAN and CAN FD frames are allocated with seperate functions: alloc_can_skb() and alloc_canfd_skb(). In order to support CAN FD frames via the rx-offload helper, the driver itself has to allocate the skb (depending whether it received a classic CAN or CAN FD frame), as the rx-offload helper cannot know which kind of CAN frame the driver has received. This patch moves the allocation of the skb into the struct can_rx_offload::mailbox_read callbacks of the the flexcan and ti_hecc driver and adjusts the rx-offload helper accordingly. Signed-off-by: Joakim Zhang Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 27 +++++++++++----- drivers/net/can/rx-offload.c | 70 ++++++++++-------------------------------- drivers/net/can/ti_hecc.c | 26 ++++++++++++---- include/linux/can/rx-offload.h | 6 ++-- 4 files changed, 60 insertions(+), 69 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 57f9a2f51085..1a8198163b80 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -783,16 +783,23 @@ static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *off return container_of(offload, struct flexcan_priv, offload); } -static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, - struct can_frame *cf, - u32 *timestamp, unsigned int n) +static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, + unsigned int n, u32 *timestamp, + bool drop) { struct flexcan_priv *priv = rx_offload_to_priv(offload); struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_mb __iomem *mb; + struct sk_buff *skb; + struct can_frame *cf; u32 reg_ctrl, reg_id, reg_iflag1; int i; + if (unlikely(drop)) { + skb = ERR_PTR(-ENOBUFS); + goto mark_as_read; + } + mb = flexcan_get_mb(priv, n); if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { @@ -806,7 +813,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, code = reg_ctrl & FLEXCAN_MB_CODE_MASK; if ((code != FLEXCAN_MB_CODE_RX_FULL) && (code != FLEXCAN_MB_CODE_RX_OVERRUN)) - return 0; + return NULL; if (code == FLEXCAN_MB_CODE_RX_OVERRUN) { /* This MB was overrun, we lost data */ @@ -816,11 +823,17 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, } else { reg_iflag1 = priv->read(®s->iflag1); if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE)) - return 0; + return NULL; reg_ctrl = priv->read(&mb->can_ctrl); } + skb = alloc_can_skb(offload->dev, &cf); + if (!skb) { + skb = ERR_PTR(-ENOMEM); + goto mark_as_read; + } + /* increase timstamp to full 32 bit */ *timestamp = reg_ctrl << 16; @@ -839,7 +852,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, *(__be32 *)(cf->data + i) = data; } - /* mark as read */ + mark_as_read: if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { /* Clear IRQ */ if (n < 32) @@ -856,7 +869,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, */ priv->read(®s->timer); - return 1; + return skb; } diff --git a/drivers/net/can/rx-offload.c b/drivers/net/can/rx-offload.c index 8d120a3750fa..e8328910a234 100644 --- a/drivers/net/can/rx-offload.c +++ b/drivers/net/can/rx-offload.c @@ -139,71 +139,35 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b) static struct sk_buff * can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n) { - struct sk_buff *skb = NULL, *skb_error = NULL; + struct sk_buff *skb; struct can_rx_offload_cb *cb; - struct can_frame *cf; - int ret; - - if (likely(skb_queue_len(&offload->skb_queue) < - offload->skb_queue_len_max)) { - skb = alloc_can_skb(offload->dev, &cf); - if (unlikely(!skb)) - skb_error = ERR_PTR(-ENOMEM); /* skb alloc failed */ - } else { - skb_error = ERR_PTR(-ENOBUFS); /* skb_queue is full */ - } - - /* If queue is full or skb not available, drop by reading into - * overflow buffer. - */ - if (unlikely(skb_error)) { - struct can_frame cf_overflow; - u32 timestamp; - - ret = offload->mailbox_read(offload, &cf_overflow, - ×tamp, n); - - /* Mailbox was empty. */ - if (unlikely(!ret)) - return NULL; - - /* Mailbox has been read and we're dropping it or - * there was a problem reading the mailbox. - * - * Increment error counters in any case. - */ - offload->dev->stats.rx_dropped++; - offload->dev->stats.rx_fifo_errors++; - - /* There was a problem reading the mailbox, propagate - * error value. - */ - if (unlikely(ret < 0)) - return ERR_PTR(ret); - - return skb_error; - } + bool drop = false; + u32 timestamp; - cb = can_rx_offload_get_cb(skb); - ret = offload->mailbox_read(offload, cf, &cb->timestamp, n); + /* If queue is full drop frame */ + if (unlikely(skb_queue_len(&offload->skb_queue) > + offload->skb_queue_len_max)) + drop = true; + skb = offload->mailbox_read(offload, n, ×tamp, drop); /* Mailbox was empty. */ - if (unlikely(!ret)) { - kfree_skb(skb); + if (unlikely(!skb)) return NULL; - } - - /* There was a problem reading the mailbox, propagate error value. */ - if (unlikely(ret < 0)) { - kfree_skb(skb); + /* There was a problem reading the mailbox, propagate + * error value. + */ + if (unlikely(IS_ERR(skb))) { offload->dev->stats.rx_dropped++; offload->dev->stats.rx_fifo_errors++; - return ERR_PTR(ret); + return skb; } /* Mailbox was read. */ + cb = can_rx_offload_get_cb(skb); + cb->timestamp = timestamp; + return skb; } diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 31ad364a89bb..94b1491b569f 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -535,15 +535,28 @@ struct ti_hecc_priv *rx_offload_to_priv(struct can_rx_offload *offload) return container_of(offload, struct ti_hecc_priv, offload); } -static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload, - struct can_frame *cf, - u32 *timestamp, unsigned int mbxno) +static struct sk_buff *ti_hecc_mailbox_read(struct can_rx_offload *offload, + unsigned int mbxno, u32 *timestamp, + bool drop) { struct ti_hecc_priv *priv = rx_offload_to_priv(offload); + struct sk_buff *skb; + struct can_frame *cf; u32 data, mbx_mask; - int ret = 1; mbx_mask = BIT(mbxno); + + if (unlikely(drop)) { + skb = ERR_PTR(-ENOBUFS); + goto mark_as_read; + } + + skb = alloc_can_skb(offload->dev, &cf); + if (unlikely(!skb)) { + skb = ERR_PTR(-ENOMEM); + goto mark_as_read; + } + data = hecc_read_mbx(priv, mbxno, HECC_CANMID); if (data & HECC_CANMID_IDE) cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; @@ -578,11 +591,12 @@ static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload, */ if (unlikely(mbxno == HECC_RX_LAST_MBOX && hecc_read(priv, HECC_CANRML) & mbx_mask)) - ret = -ENOBUFS; + skb = ERR_PTR(-ENOBUFS); + mark_as_read: hecc_write(priv, HECC_CANRMP, mbx_mask); - return ret; + return skb; } static int ti_hecc_error(struct net_device *ndev, int int_status, diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h index fc75e9a7ad2f..1b78a0cfb615 100644 --- a/include/linux/can/rx-offload.h +++ b/include/linux/can/rx-offload.h @@ -15,9 +15,9 @@ struct can_rx_offload { struct net_device *dev; - unsigned int (*mailbox_read)(struct can_rx_offload *offload, - struct can_frame *cf, - u32 *timestamp, unsigned int mb); + struct sk_buff *(*mailbox_read)(struct can_rx_offload *offload, + unsigned int mb, u32 *timestamp, + bool drop); struct sk_buff_head skb_queue; u32 skb_queue_len_max; -- cgit v1.2.3-59-g8ed1b From a4721f27b94a807205d96a24c9f70fe7caf81b3b Mon Sep 17 00:00:00 2001 From: Joakim Zhang Date: Sun, 29 Sep 2019 08:32:09 +0000 Subject: can: flexcan: use devm_platform_ioremap_resource() to simplify code Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together to simplify the code. Signed-off-by: Joakim Zhang Reviewed-by: Sean Nyekjaer Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 1a8198163b80..362ed90c701f 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -1547,7 +1547,6 @@ static int flexcan_probe(struct platform_device *pdev) struct net_device *dev; struct flexcan_priv *priv; struct regulator *reg_xceiver; - struct resource *mem; struct clk *clk_ipg = NULL, *clk_per = NULL; struct flexcan_regs __iomem *regs; int err, irq; @@ -1582,12 +1581,11 @@ static int flexcan_probe(struct platform_device *pdev) clock_freq = clk_get_rate(clk_per); } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (irq <= 0) return -ENODEV; - regs = devm_ioremap_resource(&pdev->dev, mem); + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); -- cgit v1.2.3-59-g8ed1b From 58ed8e77d3123acb6ece7d016c8db393d5c0d488 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 9 Oct 2019 15:15:37 +0200 Subject: can: flexcan: flexcan_irq_state(): only read timestamp if needed The function flexcan_irq_state() checks the controller for CAN state changes and pushes a skb with the new state and a timestamp into the rx-offload framework. This patch optimizes the function by only reading the timestamp, if a state change is detected. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 362ed90c701f..148c0a3fab24 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -743,8 +743,6 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) u32 timestamp; int err; - timestamp = priv->read(®s->timer) << 16; - flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ? @@ -764,6 +762,8 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) if (likely(new_state == priv->can.state)) return; + timestamp = priv->read(®s->timer) << 16; + skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) return; -- cgit v1.2.3-59-g8ed1b From b36d3c0f7e70dff646b87e2c3d4ee0ac953d8b49 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 11:12:13 +0100 Subject: can: flexcan: rename macro FLEXCAN_IFLAG_MB() -> FLEXCAN_IFLAG2_MB() The macro FLEXCAN_IFLAG_MB() is always used for the iflag2 register, so rename it to FLEXCAN_IFLAG2_MB() Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 148c0a3fab24..4b2275b3c8e0 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -142,7 +142,7 @@ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) -#define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f) +#define FLEXCAN_IFLAG2_MB(x) BIT((x) & 0x1f) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) @@ -879,7 +879,7 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) u32 iflag1, iflag2; iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default & - ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default; return (u64)iflag2 << 32 | iflag1; @@ -929,7 +929,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) reg_iflag2 = priv->read(®s->iflag2); /* transmission complete interrupt */ - if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) { + if (reg_iflag2 & FLEXCAN_IFLAG2_MB(priv->tx_mb_idx)) { u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl); handled = IRQ_HANDLED; @@ -941,7 +941,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* after sending a RTR frame MB is in RX mode */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, &priv->tx_mb->can_ctrl); - priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), ®s->iflag2); + priv->write(FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), ®s->iflag2); netif_wake_queue(dev); } @@ -1298,7 +1298,7 @@ static int flexcan_open(struct net_device *dev) priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); priv->reg_imask1_default = 0; - priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + priv->reg_imask2_default = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); priv->offload.mailbox_read = flexcan_mailbox_read; -- cgit v1.2.3-59-g8ed1b From 4e26598a7d3cd1bf6a0843042997963f9828a6ba Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 16:29:47 +0100 Subject: can: flexcan: flexcan_irq(): rename variable reg_iflag -> reg_iflag_rx This patch renames the variable reg_iflag in the flexcan_irq() function to reg_iflag_rx. This better reflects the contents of the varibale. It does not hold the unmodified iflag registers, instead all non RX interrupts have been masked. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 4b2275b3c8e0..be81c8439a32 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -897,13 +897,13 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* reception interrupt */ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { - u64 reg_iflag; + u64 reg_iflag_rx; int ret; - while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) { + while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) { handled = IRQ_HANDLED; ret = can_rx_offload_irq_offload_timestamp(&priv->offload, - reg_iflag); + reg_iflag_rx); if (!ret) break; } -- cgit v1.2.3-59-g8ed1b From 07c054d3e53fe27025dae5e232465c8ecf658ebf Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 09:18:54 +0100 Subject: can: flexcan: rename struct flexcan_priv::reg_imask{1,2}_default to rx_mask{1,2} The flexcan IP core has up to 64 mailboxes, each one has a corresponding interrupt bit in the iflag1 or iflag2 registers and a mask bit in the imask1 or imask2 registers. In the timestamp (i.e. non FIFO) mode the driver needs to mask out all non RX interrupt sources and uses the precomputed values reg_imask1_default and reg_imask2_default of struct flexcan_priv for this. However in the current driver the reg_imask{1,2}_default cannot be used directly to get the pending RX interrupts. The TX interrupt is part of these variables, so it needs to be masked out, too. This is a preparation patch to clean up calculation of the pending RX interrupts, it only renames the variables from reg_imask{1,2}_default to rx_mask{1,2} To better reflect their meaning after the complete conversion. This change is done with the following sed command: sed -i -e "s/reg_imask\(1\|2\)_default/rx_mask\1/" drivers/net/can/flexcan.c Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index be81c8439a32..44ac211af7eb 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -278,8 +278,8 @@ struct flexcan_priv { u8 clk_src; /* clock source of CAN Protocol Engine */ u32 reg_ctrl_default; - u32 reg_imask1_default; - u32 reg_imask2_default; + u32 rx_mask1; + u32 rx_mask2; struct clk *clk_ipg; struct clk *clk_per; @@ -878,9 +878,9 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) struct flexcan_regs __iomem *regs = priv->regs; u32 iflag1, iflag2; - iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default & + iflag2 = priv->read(®s->iflag2) & priv->rx_mask2 & ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); - iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default; + iflag1 = priv->read(®s->iflag1) & priv->rx_mask1; return (u64)iflag2 << 32 | iflag1; } @@ -1227,8 +1227,8 @@ static int flexcan_chip_start(struct net_device *dev) /* enable interrupts atomically */ disable_irq(dev->irq); priv->write(priv->reg_ctrl_default, ®s->ctrl); - priv->write(priv->reg_imask1_default, ®s->imask1); - priv->write(priv->reg_imask2_default, ®s->imask2); + priv->write(priv->rx_mask1, ®s->imask1); + priv->write(priv->rx_mask2, ®s->imask2); enable_irq(dev->irq); /* print chip status */ @@ -1297,8 +1297,8 @@ static int flexcan_open(struct net_device *dev) priv->tx_mb_idx = priv->mb_count - 1; priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); - priv->reg_imask1_default = 0; - priv->reg_imask2_default = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); + priv->rx_mask1 = 0; + priv->rx_mask2 = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); priv->offload.mailbox_read = flexcan_mailbox_read; @@ -1310,12 +1310,12 @@ static int flexcan_open(struct net_device *dev) imask = GENMASK_ULL(priv->offload.mb_last, priv->offload.mb_first); - priv->reg_imask1_default |= imask; - priv->reg_imask2_default |= imask >> 32; + priv->rx_mask1 |= imask; + priv->rx_mask2 |= imask >> 32; err = can_rx_offload_add_timestamp(dev, &priv->offload); } else { - priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | + priv->rx_mask1 |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; err = can_rx_offload_add_fifo(dev, &priv->offload, FLEXCAN_NAPI_WEIGHT); -- cgit v1.2.3-59-g8ed1b From 9ed63c60c9e3ace16e4307866cc01e8ddf296155 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 10:22:26 +0100 Subject: can: flexcan: remove TX mailbox bit from struct flexcan_priv::rx_mask{1,2} The flexcan IP core has up to 64 mailboxes, each one has a corresponding interrupt bit in the iflag1 or iflag2 registers and a mask bit in the imask1 or imask2 registers. In the timestamp (i.e. non FIFO) mode the driver needs to mask out all non RX interrupt sources and uses the precomputed values rx_mask1 and rx_mask2 of struct flexcan_priv for this. Currently these values cannot be used directly, as they contain the TX mailbox flag. This patch removes the TX flag from flexcan_priv::rx_mask1 and flexcan_priv::rx_mask2, and sets the TX flag directly when writing the regs->iflag1 and regs->iflag2 into the hardware. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 44ac211af7eb..29d1dbe89351 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -878,8 +878,7 @@ static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) struct flexcan_regs __iomem *regs = priv->regs; u32 iflag1, iflag2; - iflag2 = priv->read(®s->iflag2) & priv->rx_mask2 & - ~FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); + iflag2 = priv->read(®s->iflag2) & priv->rx_mask2; iflag1 = priv->read(®s->iflag1) & priv->rx_mask1; return (u64)iflag2 << 32 | iflag1; @@ -1228,7 +1227,7 @@ static int flexcan_chip_start(struct net_device *dev) disable_irq(dev->irq); priv->write(priv->reg_ctrl_default, ®s->ctrl); priv->write(priv->rx_mask1, ®s->imask1); - priv->write(priv->rx_mask2, ®s->imask2); + priv->write(priv->rx_mask2 | FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), ®s->imask2); enable_irq(dev->irq); /* print chip status */ @@ -1297,9 +1296,6 @@ static int flexcan_open(struct net_device *dev) priv->tx_mb_idx = priv->mb_count - 1; priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); - priv->rx_mask1 = 0; - priv->rx_mask2 = FLEXCAN_IFLAG2_MB(priv->tx_mb_idx); - priv->offload.mailbox_read = flexcan_mailbox_read; if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { @@ -1310,12 +1306,12 @@ static int flexcan_open(struct net_device *dev) imask = GENMASK_ULL(priv->offload.mb_last, priv->offload.mb_first); - priv->rx_mask1 |= imask; - priv->rx_mask2 |= imask >> 32; + priv->rx_mask1 = imask; + priv->rx_mask2 = imask >> 32; err = can_rx_offload_add_timestamp(dev, &priv->offload); } else { - priv->rx_mask1 |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | + priv->rx_mask1 = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; err = can_rx_offload_add_fifo(dev, &priv->offload, FLEXCAN_NAPI_WEIGHT); -- cgit v1.2.3-59-g8ed1b From 8ce5139e3db829d53c2f33ff812cea4f1f075e9c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 12:17:30 +0100 Subject: can: flexcan: convert struct flexcan_priv::rx_mask{1,2} to rx_mask The flexcan IP core has up to 64 mailboxes, each one has a corresponding interrupt bit in the iflag1 or iflag2 registers and a mask bit in the imask1 or imask2 registers. In the timestamp (i.e. non FIFO) mode the driver needs to mask out all non RX interrupt sources and uses the precomputed values rx_mask1 and rx_mask2 of struct flexcan_priv for this. This patch merges the two u32 rx_mask1 and rx_mask2 to a single u64 rx_mask variable, which simplifies the code a bit. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 29d1dbe89351..c3fdd47c5cdb 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -142,6 +142,7 @@ #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) +#define FLEXCAN_IFLAG_MB(x) BIT_ULL(x) #define FLEXCAN_IFLAG2_MB(x) BIT((x) & 0x1f) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) @@ -277,9 +278,8 @@ struct flexcan_priv { u8 mb_size; u8 clk_src; /* clock source of CAN Protocol Engine */ + u64 rx_mask; u32 reg_ctrl_default; - u32 rx_mask1; - u32 rx_mask2; struct clk *clk_ipg; struct clk *clk_per; @@ -872,16 +872,15 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, return skb; } - static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->regs; - u32 iflag1, iflag2; + u64 iflag; - iflag2 = priv->read(®s->iflag2) & priv->rx_mask2; - iflag1 = priv->read(®s->iflag1) & priv->rx_mask1; + iflag = (u64)priv->read(®s->iflag2) << 32 | + priv->read(®s->iflag1); - return (u64)iflag2 << 32 | iflag1; + return iflag & priv->rx_mask; } static irqreturn_t flexcan_irq(int irq, void *dev_id) @@ -1052,6 +1051,7 @@ static int flexcan_chip_start(struct net_device *dev) struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->regs; u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; + u64 reg_imask; int err, i; struct flexcan_mb __iomem *mb; @@ -1226,8 +1226,9 @@ static int flexcan_chip_start(struct net_device *dev) /* enable interrupts atomically */ disable_irq(dev->irq); priv->write(priv->reg_ctrl_default, ®s->ctrl); - priv->write(priv->rx_mask1, ®s->imask1); - priv->write(priv->rx_mask2 | FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), ®s->imask2); + reg_imask = priv->rx_mask | FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + priv->write(upper_32_bits(reg_imask), ®s->imask2); + priv->write(lower_32_bits(reg_imask), ®s->imask1); enable_irq(dev->irq); /* print chip status */ @@ -1299,19 +1300,14 @@ static int flexcan_open(struct net_device *dev) priv->offload.mailbox_read = flexcan_mailbox_read; if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { - u64 imask; - priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST; priv->offload.mb_last = priv->mb_count - 2; - imask = GENMASK_ULL(priv->offload.mb_last, - priv->offload.mb_first); - priv->rx_mask1 = imask; - priv->rx_mask2 = imask >> 32; - + priv->rx_mask = GENMASK_ULL(priv->offload.mb_last, + priv->offload.mb_first); err = can_rx_offload_add_timestamp(dev, &priv->offload); } else { - priv->rx_mask1 = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | + priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; err = can_rx_offload_add_fifo(dev, &priv->offload, FLEXCAN_NAPI_WEIGHT); -- cgit v1.2.3-59-g8ed1b From 0ca64f02de380e0b75b9555d325e6dcfe36470ef Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 13:54:19 +0100 Subject: can: flexcan: introduce struct flexcan_priv::tx_mask and make use of it The current driver uses FLEXCAN_IFLAG2_MB() to generate the mask to check for the TX complete interrupt. This works well, as the driver will always use the last mailbox for TX, which falls into the iflag2 register. To support CANFD the payload size has to increase to 64 bytes and the number of mailboxes will decrease so much that the TX mailbox will be handled in the iflag1 register. This patch introduces a tx_mask in the struct flexcan_priv (similar to rx_mask) and makes use of it. The actual support to handle the TX mailbox in iflag1 will be added in the next patches. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index c3fdd47c5cdb..c2843571b46e 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -143,7 +143,6 @@ #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) #define FLEXCAN_IFLAG_MB(x) BIT_ULL(x) -#define FLEXCAN_IFLAG2_MB(x) BIT((x) & 0x1f) #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) @@ -279,6 +278,7 @@ struct flexcan_priv { u8 clk_src; /* clock source of CAN Protocol Engine */ u64 rx_mask; + u64 tx_mask; u32 reg_ctrl_default; struct clk *clk_ipg; @@ -890,7 +890,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->regs; irqreturn_t handled = IRQ_NONE; - u32 reg_iflag2, reg_esr; + u64 reg_iflag_tx; + u32 reg_esr; enum can_state last_state = priv->can.state; /* reception interrupt */ @@ -924,10 +925,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) } } - reg_iflag2 = priv->read(®s->iflag2); + reg_iflag_tx = (u64)priv->read(®s->iflag2) << 32; /* transmission complete interrupt */ - if (reg_iflag2 & FLEXCAN_IFLAG2_MB(priv->tx_mb_idx)) { + if (reg_iflag_tx & priv->tx_mask) { u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl); handled = IRQ_HANDLED; @@ -939,7 +940,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* after sending a RTR frame MB is in RX mode */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, &priv->tx_mb->can_ctrl); - priv->write(FLEXCAN_IFLAG2_MB(priv->tx_mb_idx), ®s->iflag2); + priv->write(priv->tx_mask >> 32, ®s->iflag2); netif_wake_queue(dev); } @@ -1226,7 +1227,7 @@ static int flexcan_chip_start(struct net_device *dev) /* enable interrupts atomically */ disable_irq(dev->irq); priv->write(priv->reg_ctrl_default, ®s->ctrl); - reg_imask = priv->rx_mask | FLEXCAN_IFLAG_MB(priv->tx_mb_idx); + reg_imask = priv->rx_mask | priv->tx_mask; priv->write(upper_32_bits(reg_imask), ®s->imask2); priv->write(lower_32_bits(reg_imask), ®s->imask1); enable_irq(dev->irq); @@ -1296,6 +1297,7 @@ static int flexcan_open(struct net_device *dev) flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO); priv->tx_mb_idx = priv->mb_count - 1; priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); + priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx); priv->offload.mailbox_read = flexcan_mailbox_read; -- cgit v1.2.3-59-g8ed1b From d3a51507e45e06b22ea892fccfba4b42f704f859 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 15:38:05 +0100 Subject: can: flexcan: flexcan_read_reg_iflag_rx(): optimize reading The flexcan IP core has up to 64 mailboxes, each one has a corresponding interrupt bit in the iflag1 or iflag2 registers and a mask bit in the imask1 or imask2 registers. In the timestamp (i.e. non FIFO) mode the driver needs to mask all non RX interrupt sources, it uses the precomputed value rx_mask of struct flexcan_priv for this. In certain use cases, for example the CANFD mode, the contents of the iflag2 register is completely masked. This patch optimizes the flexcan_read_reg_iflag_rx() function by not reading the iflag1 or iflag2 register if the contents is masked. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index c2843571b46e..f6c3613485af 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -778,6 +778,23 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) dev->stats.rx_fifo_errors++; } +static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask) +{ + u64 reg = 0; + + if (upper_32_bits(mask)) + reg = (u64)priv->read(addr - 4) << 32; + if (lower_32_bits(mask)) + reg |= priv->read(addr); + + return reg & mask; +} + +static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) +{ + return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask); +} + static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload) { return container_of(offload, struct flexcan_priv, offload); @@ -872,17 +889,6 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, return skb; } -static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) -{ - struct flexcan_regs __iomem *regs = priv->regs; - u64 iflag; - - iflag = (u64)priv->read(®s->iflag2) << 32 | - priv->read(®s->iflag1); - - return iflag & priv->rx_mask; -} - static irqreturn_t flexcan_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; -- cgit v1.2.3-59-g8ed1b From b87c28b726daaa5ac315b59a0ae04282c265580b Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 15:38:05 +0100 Subject: can: flexcan: flexcan_irq(): add support for TX mailbox in iflag1 The flexcan IP core has up to 64 mailboxes, each one has a corresponding interrupt bit in the iflag1 or iflag2 registers and a mask bit in the imask1 or imask2 registers. The driver will always use the last mailbox for TX, which falls into the iflag2 register. To support CANFD the payload size has to increase to 64 bytes and the number of mailboxes will decrease so much that the TX mailbox will be handled in the iflag1 register. This patch add support to handle the TX mailbox independent whether it's in iflag1 or iflag2 by introducing th flexcan_read_reg_iflag_tx() function, similar to flexcan_read_reg_iflag_rx(), for the read path. For the write path the function flexcan_write64() is added. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index f6c3613485af..79696430dedf 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -790,11 +790,24 @@ static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *a return reg & mask; } +static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr) +{ + if (upper_32_bits(val)) + priv->write(upper_32_bits(val), addr - 4); + if (lower_32_bits(val)) + priv->write(lower_32_bits(val), addr); +} + static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv) { return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask); } +static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv) +{ + return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask); +} + static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload) { return container_of(offload, struct flexcan_priv, offload); @@ -931,7 +944,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) } } - reg_iflag_tx = (u64)priv->read(®s->iflag2) << 32; + reg_iflag_tx = flexcan_read_reg_iflag_tx(priv); /* transmission complete interrupt */ if (reg_iflag_tx & priv->tx_mask) { @@ -946,7 +959,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) /* after sending a RTR frame MB is in RX mode */ priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, &priv->tx_mb->can_ctrl); - priv->write(priv->tx_mask >> 32, ®s->iflag2); + flexcan_write64(priv, priv->tx_mask, ®s->iflag1); netif_wake_queue(dev); } -- cgit v1.2.3-59-g8ed1b From b9468ad8ff65e6dcfeb69cab15deecafdb883643 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 1 Mar 2019 16:27:59 +0100 Subject: can: flexcan: flexcan_mailbox_read() make use of flexcan_write64() to mark the mailbox as read In the previous patch the function flexcan_write64() was introduced. This patch replaces the open coded variant in flexcan_mailbox_read() that marks a mailbox as read, by a single call to flexcan_write64(). Signed-off-by: Marc Kleine-Budde --- drivers/net/can/flexcan.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 79696430dedf..a929cdda9ab2 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -883,15 +883,10 @@ static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload, } mark_as_read: - if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { - /* Clear IRQ */ - if (n < 32) - priv->write(BIT(n), ®s->iflag1); - else - priv->write(BIT(n - 32), ®s->iflag2); - } else { + if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) + flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), ®s->iflag1); + else priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1); - } /* Read the Free Running Timer. It is optional but recommended * to unlock Mailbox as soon as possible and make it available -- cgit v1.2.3-59-g8ed1b From 97bb69e1e36e960b0ecfa2be5ea75ec357a61c3f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:47 +0200 Subject: net: mscc: ocelot: break apart ocelot_vlan_port_apply This patch transforms the ocelot_vlan_port_apply function ("apply what?") into 3 standalone functions: - ocelot_port_vlan_filtering - ocelot_port_set_native_vlan - ocelot_port_set_pvid These functions have a prototype that is better aligned to the DSA API. The function also had some static initialization (TPID, drop frames with multicast source MAC) which was not being changed from any place, so that was just moved to ocelot_probe_port (one of the 6 callers of ocelot_vlan_port_apply). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 168 ++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 68 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 672ea1342add..029c5ea59e35 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -185,65 +185,97 @@ static void ocelot_vlan_mode(struct ocelot_port *port, ocelot_write(ocelot, val, ANA_VLANMASK); } -static void ocelot_vlan_port_apply(struct ocelot *ocelot, - struct ocelot_port *port) +static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + bool vlan_aware) { + struct ocelot_port *ocelot_port = ocelot->ports[port]; u32 val; - /* Ingress clasification (ANA_PORT_VLAN_CFG) */ - /* Default vlan to clasify for untagged frames (may be zero) */ - val = ANA_PORT_VLAN_CFG_VLAN_VID(port->pvid); - if (port->vlan_aware) - val |= ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | - ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1); - + if (vlan_aware) + val = ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | + ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1); + else + val = 0; ocelot_rmw_gix(ocelot, val, - ANA_PORT_VLAN_CFG_VLAN_VID_M | ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M, - ANA_PORT_VLAN_CFG, port->chip_port); + ANA_PORT_VLAN_CFG, port); - /* Drop frames with multicast source address */ - val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA; - if (port->vlan_aware && !port->vid) + if (vlan_aware && !ocelot_port->vid) /* If port is vlan-aware and tagged, drop untagged and priority * tagged frames. */ - val |= ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | + val = ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | + ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | + ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA; + else + val = 0; + ocelot_rmw_gix(ocelot, val, + ANA_PORT_DROP_CFG_DROP_UNTAGGED_ENA | ANA_PORT_DROP_CFG_DROP_PRIO_S_TAGGED_ENA | - ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA; - ocelot_write_gix(ocelot, val, ANA_PORT_DROP_CFG, port->chip_port); - - /* Egress configuration (REW_TAG_CFG): VLAN tag type to 8021Q. */ - val = REW_TAG_CFG_TAG_TPID_CFG(0); + ANA_PORT_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, + ANA_PORT_DROP_CFG, port); - if (port->vlan_aware) { - if (port->vid) + if (vlan_aware) { + if (ocelot_port->vid) /* Tag all frames except when VID == DEFAULT_VLAN */ val |= REW_TAG_CFG_TAG_CFG(1); else /* Tag all frames */ val |= REW_TAG_CFG_TAG_CFG(3); + } else { + /* Port tagging disabled. */ + val = REW_TAG_CFG_TAG_CFG(0); } ocelot_rmw_gix(ocelot, val, - REW_TAG_CFG_TAG_TPID_CFG_M | REW_TAG_CFG_TAG_CFG_M, - REW_TAG_CFG, port->chip_port); + REW_TAG_CFG, port); - /* Set default VLAN and tag type to 8021Q. */ - val = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q) | - REW_PORT_VLAN_CFG_PORT_VID(port->vid); - ocelot_rmw_gix(ocelot, val, - REW_PORT_VLAN_CFG_PORT_TPID_M | + ocelot_port->vlan_aware = vlan_aware; +} + +static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, + u16 vid) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + if (ocelot_port->vid != vid) { + /* Always permit deleting the native VLAN (vid = 0) */ + if (ocelot_port->vid && vid) { + dev_err(ocelot->dev, + "Port already has a native VLAN: %d\n", + ocelot_port->vid); + return -EBUSY; + } + ocelot_port->vid = vid; + } + + ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_VID(vid), REW_PORT_VLAN_CFG_PORT_VID_M, - REW_PORT_VLAN_CFG, port->chip_port); + REW_PORT_VLAN_CFG, port); + + return 0; +} + +/* Default vlan to clasify for untagged frames (may be zero) */ +static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + ocelot_rmw_gix(ocelot, + ANA_PORT_VLAN_CFG_VLAN_VID(pvid), + ANA_PORT_VLAN_CFG_VLAN_VID_M, + ANA_PORT_VLAN_CFG, port); + + ocelot_port->pvid = pvid; } static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, bool untagged) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; int ret; /* Add the port MAC address to with the right VLAN information */ @@ -251,35 +283,30 @@ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, ENTRYTYPE_LOCKED); /* Make the port a member of the VLAN */ - ocelot->vlan_mask[vid] |= BIT(port->chip_port); + ocelot->vlan_mask[vid] |= BIT(port); ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); if (ret) return ret; /* Default ingress vlan classification */ if (pvid) - port->pvid = vid; + ocelot_port_set_pvid(ocelot, port, vid); /* Untagged egress vlan clasification */ - if (untagged && port->vid != vid) { - if (port->vid) { - dev_err(ocelot->dev, - "Port already has a native VLAN: %d\n", - port->vid); - return -EBUSY; - } - port->vid = vid; + if (untagged) { + ret = ocelot_port_set_native_vlan(ocelot, port, vid); + if (ret) + return ret; } - ocelot_vlan_port_apply(ocelot, port); - return 0; } static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; int ret; /* 8021q removes VID 0 on module unload for all interfaces @@ -293,20 +320,18 @@ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) ocelot_mact_forget(ocelot, dev->dev_addr, vid); /* Stop the port from being a member of the vlan */ - ocelot->vlan_mask[vid] &= ~BIT(port->chip_port); + ocelot->vlan_mask[vid] &= ~BIT(port); ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); if (ret) return ret; /* Ingress */ - if (port->pvid == vid) - port->pvid = 0; + if (ocelot_port->pvid == vid) + ocelot_port_set_pvid(ocelot, port, 0); /* Egress */ - if (port->vid == vid) - port->vid = 0; - - ocelot_vlan_port_apply(ocelot, port); + if (ocelot_port->vid == vid) + ocelot_port_set_native_vlan(ocelot, port, 0); return 0; } @@ -1306,6 +1331,7 @@ static int ocelot_port_attr_set(struct net_device *dev, struct switchdev_trans *trans) { struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; int err = 0; switch (attr->id) { @@ -1317,8 +1343,8 @@ static int ocelot_port_attr_set(struct net_device *dev, ocelot_port_attr_ageing_set(ocelot_port, attr->u.ageing_time); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - ocelot_port->vlan_aware = attr->u.vlan_filtering; - ocelot_vlan_port_apply(ocelot_port->ocelot, ocelot_port); + ocelot_port_vlan_filtering(ocelot, ocelot_port->chip_port, + attr->u.vlan_filtering); break; case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled); @@ -1520,20 +1546,20 @@ static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port, return 0; } -static void ocelot_port_bridge_leave(struct ocelot_port *ocelot_port, - struct net_device *bridge) +static int ocelot_port_bridge_leave(struct ocelot_port *ocelot_port, + struct net_device *bridge) { struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; - ocelot->bridge_mask &= ~BIT(ocelot_port->chip_port); + ocelot->bridge_mask &= ~BIT(port); if (!ocelot->bridge_mask) ocelot->hw_bridge_dev = NULL; - /* Clear bridge vlan settings before calling ocelot_vlan_port_apply */ - ocelot_port->vlan_aware = 0; - ocelot_port->pvid = 0; - ocelot_port->vid = 0; + ocelot_port_vlan_filtering(ocelot, port, 0); + ocelot_port_set_pvid(ocelot, port, 0); + return ocelot_port_set_native_vlan(ocelot, port, 0); } static void ocelot_set_aggr_pgids(struct ocelot *ocelot) @@ -1687,11 +1713,8 @@ static int ocelot_netdevice_port_event(struct net_device *dev, err = ocelot_port_bridge_join(ocelot_port, info->upper_dev); else - ocelot_port_bridge_leave(ocelot_port, - info->upper_dev); - - ocelot_vlan_port_apply(ocelot_port->ocelot, - ocelot_port); + err = ocelot_port_bridge_leave(ocelot_port, + info->upper_dev); } if (netif_is_lag_master(info->upper_dev)) { if (info->linking) @@ -2007,6 +2030,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, { struct ocelot_port *ocelot_port; struct net_device *dev; + u32 val; int err; dev = alloc_etherdev(sizeof(struct ocelot_port)); @@ -2042,7 +2066,15 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, } /* Basic L2 initialization */ - ocelot_vlan_port_apply(ocelot, ocelot_port); + + /* Drop frames with multicast source address */ + val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA; + ocelot_rmw_gix(ocelot, val, val, ANA_PORT_DROP_CFG, port); + + /* Set default VLAN and tag type to 8021Q. */ + ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q), + REW_PORT_VLAN_CFG_PORT_TPID_M, + REW_PORT_VLAN_CFG, port); /* Enable vcap lookups */ ocelot_vcap_enable(ocelot, ocelot_port); -- cgit v1.2.3-59-g8ed1b From 9855934c27855002aa977bb879c6e1fe74ee5f03 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:48 +0200 Subject: net: mscc: ocelot: break apart vlan operations into ocelot_vlan_{add, del} We need an implementation of these functions that is agnostic to the higher layer (switchdev or dsa). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 60 ++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 029c5ea59e35..5b9cde6d3e38 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -270,18 +270,11 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid) ocelot_port->pvid = pvid; } -static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, - bool untagged) +static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + bool untagged) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; int ret; - /* Add the port MAC address to with the right VLAN information */ - ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid, - ENTRYTYPE_LOCKED); - /* Make the port a member of the VLAN */ ocelot->vlan_mask[vid] |= BIT(port); ret = ocelot_vlant_set_mask(ocelot, vid, ocelot->vlan_mask[vid]); @@ -302,22 +295,29 @@ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, return 0; } -static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) +static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, + bool untagged) { struct ocelot_port *ocelot_port = netdev_priv(dev); struct ocelot *ocelot = ocelot_port->ocelot; int port = ocelot_port->chip_port; int ret; - /* 8021q removes VID 0 on module unload for all interfaces - * with VLAN filtering feature. We need to keep it to receive - * untagged traffic. - */ - if (vid == 0) - return 0; + ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged); + if (ret) + return ret; - /* Del the port MAC address to with the right VLAN information */ - ocelot_mact_forget(ocelot, dev->dev_addr, vid); + /* Add the port MAC address to with the right VLAN information */ + ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, vid, + ENTRYTYPE_LOCKED); + + return 0; +} + +static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + int ret; /* Stop the port from being a member of the vlan */ ocelot->vlan_mask[vid] &= ~BIT(port); @@ -336,6 +336,30 @@ static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) return 0; } +static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) +{ + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; + int ret; + + /* 8021q removes VID 0 on module unload for all interfaces + * with VLAN filtering feature. We need to keep it to receive + * untagged traffic. + */ + if (vid == 0) + return 0; + + ret = ocelot_vlan_del(ocelot, port, vid); + if (ret) + return ret; + + /* Del the port MAC address to with the right VLAN information */ + ocelot_mact_forget(ocelot, dev->dev_addr, vid); + + return 0; +} + static void ocelot_vlan_init(struct ocelot *ocelot) { u16 port, vid; -- cgit v1.2.3-59-g8ed1b From 531ee1a6a325c877b069a186999c1b9c911027b3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:49 +0200 Subject: net: mscc: ocelot: break out fdb operations into abstract implementations To be able to implement a DSA front-end over ocelot_fdb_add, ocelot_fdb_del, ocelot_fdb_dump, these need to have a simple function prototype that is independent of struct net_device, netlink skb, etc. So rename the ndo ops of the ocelot driver into ocelot_port_fdb_{add,del,dump}, and have them all call the abstract implementations. At the same time, refactor ocelot_port_fdb_do_dump into a function whose prototype is compatible with dsa_fdb_dump_cb_t, so that the do_dump implementations can live together and be called by the ocelot_fdb_dump through a function pointer. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 124 +++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 5b9cde6d3e38..3e03c4dd80a0 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "ocelot.h" #include "ocelot_ace.h" @@ -814,21 +815,18 @@ static void ocelot_get_stats64(struct net_device *dev, stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION); } -static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, const unsigned char *addr, - u16 vid, u16 flags, - struct netlink_ext_ack *extack) +static int ocelot_fdb_add(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = ocelot->ports[port]; if (!vid) { - if (!port->vlan_aware) + if (!ocelot_port->vlan_aware) /* If the bridge is not VLAN aware and no VID was * provided, set it to pvid to ensure the MAC entry * matches incoming untagged packets */ - vid = port->pvid; + vid = ocelot_port->pvid; else /* If the bridge is VLAN aware a VID must be provided as * otherwise the learnt entry wouldn't match any frame. @@ -836,20 +834,37 @@ static int ocelot_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EINVAL; } - return ocelot_mact_learn(ocelot, port->chip_port, addr, vid, - ENTRYTYPE_LOCKED); + return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED); } -static int ocelot_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid) +static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, + u16 vid, u16 flags, + struct netlink_ext_ack *extack) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + + return ocelot_fdb_add(ocelot, ocelot_port->chip_port, addr, vid); +} +static int ocelot_fdb_del(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid) +{ return ocelot_mact_forget(ocelot, addr, vid); } +static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, u16 vid) +{ + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + + return ocelot_fdb_del(ocelot, ocelot_port->chip_port, addr, vid); +} + struct ocelot_dump_ctx { struct net_device *dev; struct sk_buff *skb; @@ -857,9 +872,10 @@ struct ocelot_dump_ctx { int idx; }; -static int ocelot_fdb_do_dump(struct ocelot_mact_entry *entry, - struct ocelot_dump_ctx *dump) +static int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid, + bool is_static, void *data) { + struct ocelot_dump_ctx *dump = data; u32 portid = NETLINK_CB(dump->cb->skb).portid; u32 seq = dump->cb->nlh->nlmsg_seq; struct nlmsghdr *nlh; @@ -880,12 +896,12 @@ static int ocelot_fdb_do_dump(struct ocelot_mact_entry *entry, ndm->ndm_flags = NTF_SELF; ndm->ndm_type = 0; ndm->ndm_ifindex = dump->dev->ifindex; - ndm->ndm_state = NUD_REACHABLE; + ndm->ndm_state = is_static ? NUD_NOARP : NUD_REACHABLE; - if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, entry->mac)) + if (nla_put(dump->skb, NDA_LLADDR, ETH_ALEN, addr)) goto nla_put_failure; - if (entry->vid && nla_put_u16(dump->skb, NDA_VLAN, entry->vid)) + if (vid && nla_put_u16(dump->skb, NDA_VLAN, vid)) goto nla_put_failure; nlmsg_end(dump->skb, nlh); @@ -899,12 +915,11 @@ nla_put_failure: return -EMSGSIZE; } -static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col, - struct ocelot_mact_entry *entry) +static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col, + struct ocelot_mact_entry *entry) { - struct ocelot *ocelot = port->ocelot; - char mac[ETH_ALEN]; u32 val, dst, macl, mach; + char mac[ETH_ALEN]; /* Set row and column to read from */ ocelot_field_write(ocelot, ANA_TABLES_MACTINDX_M_INDEX, row); @@ -927,7 +942,7 @@ static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col, * do not report it. */ dst = (val & ANA_TABLES_MACACCESS_DEST_IDX_M) >> 3; - if (dst != port->chip_port) + if (dst != port) return -EINVAL; /* Get the entry's MAC address and VLAN id */ @@ -947,43 +962,60 @@ static inline int ocelot_mact_read(struct ocelot_port *port, int row, int col, return 0; } -static int ocelot_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, int *idx) +static int ocelot_fdb_dump(struct ocelot *ocelot, int port, + dsa_fdb_dump_cb_t *cb, void *data) { - struct ocelot_port *port = netdev_priv(dev); - int i, j, ret = 0; - struct ocelot_dump_ctx dump = { - .dev = dev, - .skb = skb, - .cb = cb, - .idx = *idx, - }; - - struct ocelot_mact_entry entry; + int i, j; /* Loop through all the mac tables entries. There are 1024 rows of 4 * entries. */ for (i = 0; i < 1024; i++) { for (j = 0; j < 4; j++) { - ret = ocelot_mact_read(port, i, j, &entry); + struct ocelot_mact_entry entry; + bool is_static; + int ret; + + ret = ocelot_mact_read(ocelot, port, i, j, &entry); /* If the entry is invalid (wrong port, invalid...), * skip it. */ if (ret == -EINVAL) continue; else if (ret) - goto end; + return ret; + + is_static = (entry.type == ENTRYTYPE_LOCKED); - ret = ocelot_fdb_do_dump(&entry, &dump); + ret = cb(entry.mac, entry.vid, is_static, data); if (ret) - goto end; + return ret; } } -end: + return 0; +} + +static int ocelot_port_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct net_device *dev, + struct net_device *filter_dev, int *idx) +{ + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_dump_ctx dump = { + .dev = dev, + .skb = skb, + .cb = cb, + .idx = *idx, + }; + int ret; + + ret = ocelot_fdb_dump(ocelot, ocelot_port->chip_port, + ocelot_port_fdb_do_dump, &dump); + *idx = dump.idx; + return ret; } @@ -1129,9 +1161,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = { .ndo_get_phys_port_name = ocelot_port_get_phys_port_name, .ndo_set_mac_address = ocelot_port_set_mac_address, .ndo_get_stats64 = ocelot_get_stats64, - .ndo_fdb_add = ocelot_fdb_add, - .ndo_fdb_del = ocelot_fdb_del, - .ndo_fdb_dump = ocelot_fdb_dump, + .ndo_fdb_add = ocelot_port_fdb_add, + .ndo_fdb_del = ocelot_port_fdb_del, + .ndo_fdb_dump = ocelot_port_fdb_dump, .ndo_vlan_rx_add_vid = ocelot_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ocelot_vlan_rx_kill_vid, .ndo_set_features = ocelot_set_features, -- cgit v1.2.3-59-g8ed1b From 306fd44b1af9b2a5c245b0f14979cfe62e50fae3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:50 +0200 Subject: net: mscc: ocelot: change prototypes of hwtstamping ioctls This is needed in order to present a simpler prototype to the DSA front-end of ocelot. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 3e03c4dd80a0..8b7d46693e49 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1062,17 +1062,17 @@ static int ocelot_get_port_parent_id(struct net_device *dev, return 0; } -static int ocelot_hwstamp_get(struct ocelot_port *port, struct ifreq *ifr) +static int ocelot_hwstamp_get(struct ocelot *ocelot, int port, + struct ifreq *ifr) { - struct ocelot *ocelot = port->ocelot; - return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config, sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0; } -static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr) +static int ocelot_hwstamp_set(struct ocelot *ocelot, int port, + struct ifreq *ifr) { - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = ocelot->ports[port]; struct hwtstamp_config cfg; if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) @@ -1085,16 +1085,16 @@ static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr) /* Tx type sanity check */ switch (cfg.tx_type) { case HWTSTAMP_TX_ON: - port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; + ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; break; case HWTSTAMP_TX_ONESTEP_SYNC: /* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we * need to update the origin time. */ - port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP; + ocelot_port->ptp_cmd = IFH_REW_OP_ORIGIN_PTP; break; case HWTSTAMP_TX_OFF: - port->ptp_cmd = 0; + ocelot_port->ptp_cmd = 0; break; default: return -ERANGE; @@ -1136,8 +1136,9 @@ static int ocelot_hwstamp_set(struct ocelot_port *port, struct ifreq *ifr) static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; /* The function is only used for PTP operations for now */ if (!ocelot->ptp) @@ -1145,9 +1146,9 @@ static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCSHWTSTAMP: - return ocelot_hwstamp_set(port, ifr); + return ocelot_hwstamp_set(ocelot, port, ifr); case SIOCGHWTSTAMP: - return ocelot_hwstamp_get(port, ifr); + return ocelot_hwstamp_get(ocelot, port, ifr); default: return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From 4bda14156ee22af4825c2dd140e76d0b301bcd1b Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:51 +0200 Subject: net: mscc: ocelot: change prototypes of switchdev port attribute handlers This is needed so that the Felix DSA front-end can call the Ocelot implementations. The implementation of the "mc_disabled" switchdev attribute has also been simplified by using the read-modify-write macro instead of open-coding that operation. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 88 +++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 8b7d46693e49..ba8996bf995e 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1285,26 +1285,20 @@ static const struct ethtool_ops ocelot_ethtool_ops = { .get_ts_info = ocelot_get_ts_info, }; -static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port, - struct switchdev_trans *trans, - u8 state) +static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, + u8 state) { - struct ocelot *ocelot = ocelot_port->ocelot; u32 port_cfg; - int port, i; - - if (switchdev_trans_ph_prepare(trans)) - return 0; + int p, i; - if (!(BIT(ocelot_port->chip_port) & ocelot->bridge_mask)) - return 0; + if (!(BIT(port) & ocelot->bridge_mask)) + return; - port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, - ocelot_port->chip_port); + port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port); switch (state) { case BR_STATE_FORWARDING: - ocelot->bridge_fwd_mask |= BIT(ocelot_port->chip_port); + ocelot->bridge_fwd_mask |= BIT(port); /* Fallthrough */ case BR_STATE_LEARNING: port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA; @@ -1312,19 +1306,18 @@ static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port, default: port_cfg &= ~ANA_PORT_PORT_CFG_LEARN_ENA; - ocelot->bridge_fwd_mask &= ~BIT(ocelot_port->chip_port); + ocelot->bridge_fwd_mask &= ~BIT(port); break; } - ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, - ocelot_port->chip_port); + ocelot_write_gix(ocelot, port_cfg, ANA_PORT_PORT_CFG, port); /* Apply FWD mask. The loop is needed to add/remove the current port as * a source for the other ports. */ - for (port = 0; port < ocelot->num_phys_ports; port++) { - if (ocelot->bridge_fwd_mask & BIT(port)) { - unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(port); + for (p = 0; p < ocelot->num_phys_ports; p++) { + if (ocelot->bridge_fwd_mask & BIT(p)) { + unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p); for (i = 0; i < ocelot->num_phys_ports; i++) { unsigned long bond_mask = ocelot->lags[i]; @@ -1332,7 +1325,7 @@ static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port, if (!bond_mask) continue; - if (bond_mask & BIT(port)) { + if (bond_mask & BIT(p)) { mask &= ~bond_mask; break; } @@ -1340,47 +1333,55 @@ static int ocelot_port_attr_stp_state_set(struct ocelot_port *ocelot_port, ocelot_write_rix(ocelot, BIT(ocelot->num_phys_ports) | mask, - ANA_PGID_PGID, PGID_SRC + port); + ANA_PGID_PGID, PGID_SRC + p); } else { /* Only the CPU port, this is compatible with link * aggregation. */ ocelot_write_rix(ocelot, BIT(ocelot->num_phys_ports), - ANA_PGID_PGID, PGID_SRC + port); + ANA_PGID_PGID, PGID_SRC + p); } } +} - return 0; +static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port, + struct switchdev_trans *trans, + u8 state) +{ + if (switchdev_trans_ph_prepare(trans)) + return; + + ocelot_bridge_stp_state_set(ocelot, port, state); +} + +static void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs) +{ + ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(msecs / 2), + ANA_AUTOAGE); } -static void ocelot_port_attr_ageing_set(struct ocelot_port *ocelot_port, +static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port, unsigned long ageing_clock_t) { - struct ocelot *ocelot = ocelot_port->ocelot; unsigned long ageing_jiffies = clock_t_to_jiffies(ageing_clock_t); u32 ageing_time = jiffies_to_msecs(ageing_jiffies) / 1000; - ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(ageing_time / 2), - ANA_AUTOAGE); + ocelot_set_ageing_time(ocelot, ageing_time); } -static void ocelot_port_attr_mc_set(struct ocelot_port *port, bool mc) +static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc) { - struct ocelot *ocelot = port->ocelot; - u32 val = ocelot_read_gix(ocelot, ANA_PORT_CPU_FWD_CFG, - port->chip_port); + u32 cpu_fwd_mcast = ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA | + ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA | + ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA; + u32 val = 0; if (mc) - val |= ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA | - ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA | - ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA; - else - val &= ~(ANA_PORT_CPU_FWD_CFG_CPU_IGMP_REDIR_ENA | - ANA_PORT_CPU_FWD_CFG_CPU_MLD_REDIR_ENA | - ANA_PORT_CPU_FWD_CFG_CPU_IPMC_CTRL_COPY_ENA); + val = cpu_fwd_mcast; - ocelot_write_gix(ocelot, val, ANA_PORT_CPU_FWD_CFG, port->chip_port); + ocelot_rmw_gix(ocelot, val, cpu_fwd_mcast, + ANA_PORT_CPU_FWD_CFG, port); } static int ocelot_port_attr_set(struct net_device *dev, @@ -1389,22 +1390,23 @@ static int ocelot_port_attr_set(struct net_device *dev, { struct ocelot_port *ocelot_port = netdev_priv(dev); struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; int err = 0; switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: - ocelot_port_attr_stp_state_set(ocelot_port, trans, + ocelot_port_attr_stp_state_set(ocelot, port, trans, attr->u.stp_state); break; case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: - ocelot_port_attr_ageing_set(ocelot_port, attr->u.ageing_time); + ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - ocelot_port_vlan_filtering(ocelot, ocelot_port->chip_port, + ocelot_port_vlan_filtering(ocelot, port, attr->u.vlan_filtering); break; case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: - ocelot_port_attr_mc_set(ocelot_port, !attr->u.mc_disabled); + ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled); break; default: err = -EOPNOTSUPP; -- cgit v1.2.3-59-g8ed1b From f270dbfab8799f9fd9cfb275df1cabd36c06e918 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:52 +0200 Subject: net: mscc: ocelot: refactor struct ocelot_port out of function prototypes The ocelot_port structure has a net_device embedded in it, which makes it unsuitable for leaving it in the driver implementation functions. Leave ocelot_flower.c untouched. In that file, ocelot_port is used as an interface to the tc shared blocks. That will be addressed in the next patch. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 79 ++++++++++++++----------------- drivers/net/ethernet/mscc/ocelot_police.c | 36 +++++++------- drivers/net/ethernet/mscc/ocelot_police.h | 4 +- drivers/net/ethernet/mscc/ocelot_tc.c | 5 +- 4 files changed, 59 insertions(+), 65 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index ba8996bf995e..492193af2f73 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -133,11 +133,11 @@ static void ocelot_mact_init(struct ocelot *ocelot) ocelot_write(ocelot, MACACCESS_CMD_INIT, ANA_TABLES_MACACCESS); } -static void ocelot_vcap_enable(struct ocelot *ocelot, struct ocelot_port *port) +static void ocelot_vcap_enable(struct ocelot *ocelot, int port) { ocelot_write_gix(ocelot, ANA_PORT_VCAP_S2_CFG_S2_ENA | ANA_PORT_VCAP_S2_CFG_S2_IP6_CFG(0xa), - ANA_PORT_VCAP_S2_CFG, port->chip_port); + ANA_PORT_VCAP_S2_CFG, port); } static inline u32 ocelot_vlant_read_vlanaccess(struct ocelot *ocelot) @@ -170,19 +170,17 @@ static int ocelot_vlant_set_mask(struct ocelot *ocelot, u16 vid, u32 mask) return ocelot_vlant_wait_for_completion(ocelot); } -static void ocelot_vlan_mode(struct ocelot_port *port, +static void ocelot_vlan_mode(struct ocelot *ocelot, int port, netdev_features_t features) { - struct ocelot *ocelot = port->ocelot; - u8 p = port->chip_port; u32 val; /* Filtering */ val = ocelot_read(ocelot, ANA_VLANMASK); if (features & NETIF_F_HW_VLAN_CTAG_FILTER) - val |= BIT(p); + val |= BIT(port); else - val &= ~BIT(p); + val &= ~BIT(port); ocelot_write(ocelot, val, ANA_VLANMASK); } @@ -1034,18 +1032,20 @@ static int ocelot_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, static int ocelot_set_features(struct net_device *dev, netdev_features_t features) { - struct ocelot_port *port = netdev_priv(dev); netdev_features_t changed = dev->features ^ features; + struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && - port->tc.offload_cnt) { + ocelot_port->tc.offload_cnt) { netdev_err(dev, "Cannot disable HW TC offload while offloads active\n"); return -EBUSY; } if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) - ocelot_vlan_mode(port, features); + ocelot_vlan_mode(ocelot, port, features); return 0; } @@ -1586,11 +1586,9 @@ static int ocelot_port_obj_del(struct net_device *dev, return ret; } -static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port, +static int ocelot_port_bridge_join(struct ocelot *ocelot, int port, struct net_device *bridge) { - struct ocelot *ocelot = ocelot_port->ocelot; - if (!ocelot->bridge_mask) { ocelot->hw_bridge_dev = bridge; } else { @@ -1600,17 +1598,14 @@ static int ocelot_port_bridge_join(struct ocelot_port *ocelot_port, return -ENODEV; } - ocelot->bridge_mask |= BIT(ocelot_port->chip_port); + ocelot->bridge_mask |= BIT(port); return 0; } -static int ocelot_port_bridge_leave(struct ocelot_port *ocelot_port, +static int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, struct net_device *bridge) { - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; - ocelot->bridge_mask &= ~BIT(port); if (!ocelot->bridge_mask) @@ -1679,14 +1674,12 @@ static void ocelot_setup_lag(struct ocelot *ocelot, int lag) } } -static int ocelot_port_lag_join(struct ocelot_port *ocelot_port, +static int ocelot_port_lag_join(struct ocelot *ocelot, int port, struct net_device *bond) { - struct ocelot *ocelot = ocelot_port->ocelot; - int p = ocelot_port->chip_port; - int lag, lp; struct net_device *ndev; u32 bond_mask = 0; + int lag, lp; rcu_read_lock(); for_each_netdev_in_bond_rcu(bond, ndev) { @@ -1701,17 +1694,17 @@ static int ocelot_port_lag_join(struct ocelot_port *ocelot_port, /* If the new port is the lowest one, use it as the logical port from * now on */ - if (p == lp) { - lag = p; - ocelot->lags[p] = bond_mask; - bond_mask &= ~BIT(p); + if (port == lp) { + lag = port; + ocelot->lags[port] = bond_mask; + bond_mask &= ~BIT(port); if (bond_mask) { lp = __ffs(bond_mask); ocelot->lags[lp] = 0; } } else { lag = lp; - ocelot->lags[lp] |= BIT(p); + ocelot->lags[lp] |= BIT(port); } ocelot_setup_lag(ocelot, lag); @@ -1720,34 +1713,32 @@ static int ocelot_port_lag_join(struct ocelot_port *ocelot_port, return 0; } -static void ocelot_port_lag_leave(struct ocelot_port *ocelot_port, +static void ocelot_port_lag_leave(struct ocelot *ocelot, int port, struct net_device *bond) { - struct ocelot *ocelot = ocelot_port->ocelot; - int p = ocelot_port->chip_port; u32 port_cfg; int i; /* Remove port from any lag */ for (i = 0; i < ocelot->num_phys_ports; i++) - ocelot->lags[i] &= ~BIT(ocelot_port->chip_port); + ocelot->lags[i] &= ~BIT(port); /* if it was the logical port of the lag, move the lag config to the * next port */ - if (ocelot->lags[p]) { - int n = __ffs(ocelot->lags[p]); + if (ocelot->lags[port]) { + int n = __ffs(ocelot->lags[port]); - ocelot->lags[n] = ocelot->lags[p]; - ocelot->lags[p] = 0; + ocelot->lags[n] = ocelot->lags[port]; + ocelot->lags[port] = 0; ocelot_setup_lag(ocelot, n); } - port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, p); + port_cfg = ocelot_read_gix(ocelot, ANA_PORT_PORT_CFG, port); port_cfg &= ~ANA_PORT_PORT_CFG_PORTID_VAL_M; - ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(p), - ANA_PORT_PORT_CFG, p); + ocelot_write_gix(ocelot, port_cfg | ANA_PORT_PORT_CFG_PORTID_VAL(port), + ANA_PORT_PORT_CFG, port); ocelot_set_aggr_pgids(ocelot); } @@ -1763,24 +1754,26 @@ static int ocelot_netdevice_port_event(struct net_device *dev, struct netdev_notifier_changeupper_info *info) { struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot *ocelot = ocelot_port->ocelot; + int port = ocelot_port->chip_port; int err = 0; switch (event) { case NETDEV_CHANGEUPPER: if (netif_is_bridge_master(info->upper_dev)) { if (info->linking) - err = ocelot_port_bridge_join(ocelot_port, + err = ocelot_port_bridge_join(ocelot, port, info->upper_dev); else - err = ocelot_port_bridge_leave(ocelot_port, + err = ocelot_port_bridge_leave(ocelot, port, info->upper_dev); } if (netif_is_lag_master(info->upper_dev)) { if (info->linking) - err = ocelot_port_lag_join(ocelot_port, + err = ocelot_port_lag_join(ocelot, port, info->upper_dev); else - ocelot_port_lag_leave(ocelot_port, + ocelot_port_lag_leave(ocelot, port, info->upper_dev); } break; @@ -2136,7 +2129,7 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, REW_PORT_VLAN_CFG, port); /* Enable vcap lookups */ - ocelot_vcap_enable(ocelot, ocelot_port); + ocelot_vcap_enable(ocelot, port); return 0; diff --git a/drivers/net/ethernet/mscc/ocelot_police.c b/drivers/net/ethernet/mscc/ocelot_police.c index 701e82dd749a..faddce43f2e3 100644 --- a/drivers/net/ethernet/mscc/ocelot_police.c +++ b/drivers/net/ethernet/mscc/ocelot_police.c @@ -40,13 +40,12 @@ struct qos_policer_conf { u8 ipg; /* Size of IPG when MSCC_QOS_RATE_MODE_LINE is chosen */ }; -static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix, +static int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, struct qos_policer_conf *conf) { u32 cf = 0, cir_ena = 0, frm_mode = POL_MODE_LINERATE; u32 cir = 0, cbs = 0, pir = 0, pbs = 0; bool cir_discard = 0, pir_discard = 0; - struct ocelot *ocelot = port->ocelot; u32 pbs_max = 0, cbs_max = 0; u8 ipg = 20; u32 value; @@ -123,22 +122,26 @@ static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix, /* Check limits */ if (pir > GENMASK(15, 0)) { - netdev_err(port->dev, "Invalid pir\n"); + dev_err(ocelot->dev, "Invalid pir for port %d: %u (max %lu)\n", + port, pir, GENMASK(15, 0)); return -EINVAL; } if (cir > GENMASK(15, 0)) { - netdev_err(port->dev, "Invalid cir\n"); + dev_err(ocelot->dev, "Invalid cir for port %d: %u (max %lu)\n", + port, cir, GENMASK(15, 0)); return -EINVAL; } if (pbs > pbs_max) { - netdev_err(port->dev, "Invalid pbs\n"); + dev_err(ocelot->dev, "Invalid pbs for port %d: %u (max %u)\n", + port, pbs, pbs_max); return -EINVAL; } if (cbs > cbs_max) { - netdev_err(port->dev, "Invalid cbs\n"); + dev_err(ocelot->dev, "Invalid cbs for port %d: %u (max %u)\n", + port, cbs, cbs_max); return -EINVAL; } @@ -171,10 +174,9 @@ static int qos_policer_conf_set(struct ocelot_port *port, u32 pol_ix, return 0; } -int ocelot_port_policer_add(struct ocelot_port *port, +int ocelot_port_policer_add(struct ocelot *ocelot, int port, struct ocelot_policer *pol) { - struct ocelot *ocelot = port->ocelot; struct qos_policer_conf pp = { 0 }; int err; @@ -185,11 +187,10 @@ int ocelot_port_policer_add(struct ocelot_port *port, pp.pir = pol->rate; pp.pbs = pol->burst; - netdev_dbg(port->dev, - "%s: port %u pir %u kbps, pbs %u bytes\n", - __func__, port->chip_port, pp.pir, pp.pbs); + dev_dbg(ocelot->dev, "%s: port %u pir %u kbps, pbs %u bytes\n", + __func__, port, pp.pir, pp.pbs); - err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp); + err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); if (err) return err; @@ -198,22 +199,21 @@ int ocelot_port_policer_add(struct ocelot_port *port, ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), ANA_PORT_POL_CFG_PORT_POL_ENA | ANA_PORT_POL_CFG_POL_ORDER_M, - ANA_PORT_POL_CFG, port->chip_port); + ANA_PORT_POL_CFG, port); return 0; } -int ocelot_port_policer_del(struct ocelot_port *port) +int ocelot_port_policer_del(struct ocelot *ocelot, int port) { - struct ocelot *ocelot = port->ocelot; struct qos_policer_conf pp = { 0 }; int err; - netdev_dbg(port->dev, "%s: port %u\n", __func__, port->chip_port); + dev_dbg(ocelot->dev, "%s: port %u\n", __func__, port); pp.mode = MSCC_QOS_RATE_MODE_DISABLED; - err = qos_policer_conf_set(port, POL_IX_PORT + port->chip_port, &pp); + err = qos_policer_conf_set(ocelot, port, POL_IX_PORT + port, &pp); if (err) return err; @@ -221,7 +221,7 @@ int ocelot_port_policer_del(struct ocelot_port *port) ANA_PORT_POL_CFG_POL_ORDER(POL_ORDER), ANA_PORT_POL_CFG_PORT_POL_ENA | ANA_PORT_POL_CFG_POL_ORDER_M, - ANA_PORT_POL_CFG, port->chip_port); + ANA_PORT_POL_CFG, port); return 0; } diff --git a/drivers/net/ethernet/mscc/ocelot_police.h b/drivers/net/ethernet/mscc/ocelot_police.h index d1137f79efda..ae9509229463 100644 --- a/drivers/net/ethernet/mscc/ocelot_police.h +++ b/drivers/net/ethernet/mscc/ocelot_police.h @@ -14,9 +14,9 @@ struct ocelot_policer { u32 burst; /* bytes */ }; -int ocelot_port_policer_add(struct ocelot_port *port, +int ocelot_port_policer_add(struct ocelot *ocelot, int port, struct ocelot_policer *pol); -int ocelot_port_policer_del(struct ocelot_port *port); +int ocelot_port_policer_del(struct ocelot *ocelot, int port); #endif /* _MSCC_OCELOT_POLICE_H_ */ diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c index 16a6db71ca5e..9be8e7369d6a 100644 --- a/drivers/net/ethernet/mscc/ocelot_tc.c +++ b/drivers/net/ethernet/mscc/ocelot_tc.c @@ -58,7 +58,8 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, PSCHED_NS2TICKS(action->police.burst), PSCHED_TICKS_PER_SEC); - err = ocelot_port_policer_add(port, &pol); + err = ocelot_port_policer_add(port->ocelot, port->chip_port, + &pol); if (err) { NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n"); return err; @@ -71,7 +72,7 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, if (port->tc.police_id != f->cookie) return -ENOENT; - err = ocelot_port_policer_del(port); + err = ocelot_port_policer_del(port->ocelot, port->chip_port); if (err) { NL_SET_ERR_MSG_MOD(extack, "Could not delete policer\n"); -- cgit v1.2.3-59-g8ed1b From 004d44f6e5a80429424632467cabba34ccdb79f3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:53 +0200 Subject: net: mscc: ocelot: separate net_device related items out of ocelot_port The ocelot and ocelot_port structures will be used by a new DSA driver, so the ocelot_board.c file will have to allocate and work with a private structure (ocelot_port_private), which embeds the generic struct ocelot_port. This is because in DSA, at least one interface does not have a net_device, and the DSA driver API does not interact with that anyway. The ocelot_port structure is equivalent to dsa_port, and ocelot to dsa_switch. The members of ocelot_port which have an equivalent in dsa_port (such as dp->vlan_filtering) have been moved to ocelot_port_private. We want to enforce the coding convention that "ocelot_port" refers to the structure, and "port" refers to the integer index. One can retrieve the structure at any time from ocelot->ports[port]. The patch is large but only contains variable renaming and mechanical movement of fields from one structure to another. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 288 ++++++++++++++++-------------- drivers/net/ethernet/mscc/ocelot.h | 21 ++- drivers/net/ethernet/mscc/ocelot_ace.h | 4 +- drivers/net/ethernet/mscc/ocelot_board.c | 21 ++- drivers/net/ethernet/mscc/ocelot_flower.c | 32 ++-- drivers/net/ethernet/mscc/ocelot_tc.c | 57 +++--- 6 files changed, 233 insertions(+), 190 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 492193af2f73..ad808344e33b 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -229,8 +229,6 @@ static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, ocelot_rmw_gix(ocelot, val, REW_TAG_CFG_TAG_CFG_M, REW_TAG_CFG, port); - - ocelot_port->vlan_aware = vlan_aware; } static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, @@ -297,9 +295,10 @@ static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, bool untagged) { - struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + int port = priv->chip_port; int ret; ret = ocelot_vlan_add(ocelot, port, vid, pvid, untagged); @@ -337,9 +336,9 @@ static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; int ret; /* 8021q removes VID 0 on module unload for all interfaces @@ -412,10 +411,11 @@ static u16 ocelot_wm_enc(u16 value) static void ocelot_port_adjust_link(struct net_device *dev) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; - u8 p = port->chip_port; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; int speed, atop_wm, mode = 0; + u8 port = priv->chip_port; switch (dev->phydev->speed) { case SPEED_10: @@ -444,62 +444,66 @@ static void ocelot_port_adjust_link(struct net_device *dev) return; /* Only full duplex supported for now */ - ocelot_port_writel(port, DEV_MAC_MODE_CFG_FDX_ENA | + ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA | mode, DEV_MAC_MODE_CFG); /* Set MAC IFG Gaps * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0 * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5 */ - ocelot_port_writel(port, DEV_MAC_IFG_CFG_TX_IFG(5), DEV_MAC_IFG_CFG); + ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5), + DEV_MAC_IFG_CFG); /* Load seed (0) and set MAC HDX late collision */ - ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) | + ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) | DEV_MAC_HDX_CFG_SEED_LOAD, DEV_MAC_HDX_CFG); mdelay(1); - ocelot_port_writel(port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), + ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), DEV_MAC_HDX_CFG); /* Disable HDX fast control */ - ocelot_port_writel(port, DEV_PORT_MISC_HDX_FAST_DIS, DEV_PORT_MISC); + ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS, + DEV_PORT_MISC); /* SGMII only for now */ - ocelot_port_writel(port, PCS1G_MODE_CFG_SGMII_MODE_ENA, PCS1G_MODE_CFG); - ocelot_port_writel(port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); + ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA, + PCS1G_MODE_CFG); + ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); /* Enable PCS */ - ocelot_port_writel(port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); + ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); /* No aneg on SGMII */ - ocelot_port_writel(port, 0, PCS1G_ANEG_CFG); + ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG); /* No loopback */ - ocelot_port_writel(port, 0, PCS1G_LB_CFG); + ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); /* Set Max Length and maximum tags allowed */ - ocelot_port_writel(port, VLAN_ETH_FRAME_LEN, DEV_MAC_MAXLEN_CFG); - ocelot_port_writel(port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | + ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN, + DEV_MAC_MAXLEN_CFG); + ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | DEV_MAC_TAGS_CFG_VLAN_AWR_ENA | DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, DEV_MAC_TAGS_CFG); /* Enable MAC module */ - ocelot_port_writel(port, DEV_MAC_ENA_CFG_RX_ENA | + ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of * reset */ - ocelot_port_writel(port, DEV_CLOCK_CFG_LINK_SPEED(speed), + ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed), DEV_CLOCK_CFG); /* Set SMAC of Pause frame (00:00:00:00:00:00) */ - ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_HIGH_CFG); - ocelot_port_writel(port, 0, DEV_MAC_FC_MAC_LOW_CFG); + ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); + ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); /* No PFC */ ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed), - ANA_PFC_PFC_CFG, p); + ANA_PFC_PFC_CFG, port); /* Set Pause WM hysteresis * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ @@ -507,13 +511,13 @@ static void ocelot_port_adjust_link(struct net_device *dev) */ ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | SYS_PAUSE_CFG_PAUSE_STOP(101) | - SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, p); + SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); /* Core: Enable port for frame transfer */ ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, p); + QSYS_SWITCH_PORT_MODE, port); /* Flow control */ ocelot_write_rix(ocelot, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | @@ -521,20 +525,21 @@ static void ocelot_port_adjust_link(struct net_device *dev) SYS_MAC_FC_CFG_ZERO_PAUSE_ENA | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | SYS_MAC_FC_CFG_FC_LINK_SPEED(speed), - SYS_MAC_FC_CFG, p); - ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, p); + SYS_MAC_FC_CFG, port); + ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); /* Tail dropping watermark */ atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ; ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN), - SYS_ATOP, p); + SYS_ATOP, port); ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); } static int ocelot_port_open(struct net_device *dev) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; int err; /* Enable receiving frames on the port, and activate auto-learning of @@ -542,43 +547,44 @@ static int ocelot_port_open(struct net_device *dev) */ ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | ANA_PORT_PORT_CFG_RECV_ENA | - ANA_PORT_PORT_CFG_PORTID_VAL(port->chip_port), - ANA_PORT_PORT_CFG, port->chip_port); + ANA_PORT_PORT_CFG_PORTID_VAL(port), + ANA_PORT_PORT_CFG, port); - if (port->serdes) { - err = phy_set_mode_ext(port->serdes, PHY_MODE_ETHERNET, - port->phy_mode); + if (priv->serdes) { + err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET, + priv->phy_mode); if (err) { netdev_err(dev, "Could not set mode of SerDes\n"); return err; } } - err = phy_connect_direct(dev, port->phy, &ocelot_port_adjust_link, - port->phy_mode); + err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link, + priv->phy_mode); if (err) { netdev_err(dev, "Could not attach to PHY\n"); return err; } - dev->phydev = port->phy; + dev->phydev = priv->phy; - phy_attached_info(port->phy); - phy_start(port->phy); + phy_attached_info(priv->phy); + phy_start(priv->phy); return 0; } static int ocelot_port_stop(struct net_device *dev) { - struct ocelot_port *port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *port = &priv->port; - phy_disconnect(port->phy); + phy_disconnect(priv->phy); dev->phydev = NULL; ocelot_port_writel(port, 0, DEV_MAC_ENA_CFG); ocelot_rmw_rix(port->ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, port->chip_port); + QSYS_SWITCH_PORT_MODE, priv->chip_port); return 0; } @@ -604,13 +610,15 @@ static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info) static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) { + struct ocelot_port_private *priv = netdev_priv(dev); struct skb_shared_info *shinfo = skb_shinfo(skb); - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; - u32 val, ifh[IFH_LEN]; + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; struct frame_info info = {}; u8 grp = 0; /* Send everything on CPU group 0 */ unsigned int i, count, last; + int port = priv->chip_port; + u32 val, ifh[IFH_LEN]; val = ocelot_read(ocelot, QS_INJ_STATUS); if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) || @@ -620,15 +628,15 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) ocelot_write_rix(ocelot, QS_INJ_CTRL_GAP_SIZE(1) | QS_INJ_CTRL_SOF, QS_INJ_CTRL, grp); - info.port = BIT(port->chip_port); + info.port = BIT(port); info.tag_type = IFH_TAG_TYPE_C; info.vid = skb_vlan_tag_get(skb); /* Check if timestamping is needed */ if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP) { - info.rew_op = port->ptp_cmd; - if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) - info.rew_op |= (port->ts_id % 4) << 3; + info.rew_op = ocelot_port->ptp_cmd; + if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) + info.rew_op |= (ocelot_port->ts_id % 4) << 3; } ocelot_gen_ifh(ifh, &info); @@ -663,7 +671,7 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_bytes += skb->len; if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && - port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { + ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { struct ocelot_skb *oskb = kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC); @@ -673,10 +681,10 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; oskb->skb = skb; - oskb->id = port->ts_id % 4; - port->ts_id++; + oskb->id = ocelot_port->ts_id % 4; + ocelot_port->ts_id++; - list_add_tail(&oskb->head, &port->skbs); + list_add_tail(&oskb->head, &ocelot_port->skbs); return NETDEV_TX_OK; } @@ -715,25 +723,29 @@ EXPORT_SYMBOL(ocelot_get_hwtimestamp); static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr) { - struct ocelot_port *port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; - return ocelot_mact_forget(port->ocelot, addr, port->pvid); + return ocelot_mact_forget(ocelot, addr, ocelot_port->pvid); } static int ocelot_mc_sync(struct net_device *dev, const unsigned char *addr) { - struct ocelot_port *port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; - return ocelot_mact_learn(port->ocelot, PGID_CPU, addr, port->pvid, + return ocelot_mact_learn(ocelot, PGID_CPU, addr, ocelot_port->pvid, ENTRYTYPE_LOCKED); } static void ocelot_set_rx_mode(struct net_device *dev) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; - int i; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; u32 val; + int i; /* This doesn't handle promiscuous mode because the bridge core is * setting IFF_PROMISC on all slave interfaces and all frames would be @@ -749,10 +761,11 @@ static void ocelot_set_rx_mode(struct net_device *dev) static int ocelot_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { - struct ocelot_port *port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + int port = priv->chip_port; int ret; - ret = snprintf(buf, len, "p%d", port->chip_port); + ret = snprintf(buf, len, "p%d", port); if (ret >= len) return -EINVAL; @@ -761,15 +774,16 @@ static int ocelot_port_get_phys_port_name(struct net_device *dev, static int ocelot_port_set_mac_address(struct net_device *dev, void *p) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; const struct sockaddr *addr = p; /* Learn the new net device MAC address in the mac table. */ - ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, port->pvid, + ocelot_mact_learn(ocelot, PGID_CPU, addr->sa_data, ocelot_port->pvid, ENTRYTYPE_LOCKED); /* Then forget the previous one. */ - ocelot_mact_forget(ocelot, dev->dev_addr, port->pvid); + ocelot_mact_forget(ocelot, dev->dev_addr, ocelot_port->pvid); ether_addr_copy(dev->dev_addr, addr->sa_data); return 0; @@ -778,11 +792,12 @@ static int ocelot_port_set_mac_address(struct net_device *dev, void *p) static void ocelot_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; /* Configure the port to read the stats from */ - ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port->chip_port), + ocelot_write(ocelot, SYS_STAT_CFG_STAT_VIEW(port), SYS_STAT_CFG); /* Get Rx stats */ @@ -814,12 +829,13 @@ static void ocelot_get_stats64(struct net_device *dev, } static int ocelot_fdb_add(struct ocelot *ocelot, int port, - const unsigned char *addr, u16 vid) + const unsigned char *addr, u16 vid, + bool vlan_aware) { struct ocelot_port *ocelot_port = ocelot->ports[port]; if (!vid) { - if (!ocelot_port->vlan_aware) + if (!vlan_aware) /* If the bridge is not VLAN aware and no VID was * provided, set it to pvid to ensure the MAC entry * matches incoming untagged packets @@ -841,10 +857,11 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], u16 vid, u16 flags, struct netlink_ext_ack *extack) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; - return ocelot_fdb_add(ocelot, ocelot_port->chip_port, addr, vid); + return ocelot_fdb_add(ocelot, port, addr, vid, priv->vlan_aware); } static int ocelot_fdb_del(struct ocelot *ocelot, int port, @@ -857,10 +874,11 @@ static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, const unsigned char *addr, u16 vid) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; - return ocelot_fdb_del(ocelot, ocelot_port->chip_port, addr, vid); + return ocelot_fdb_del(ocelot, port, addr, vid); } struct ocelot_dump_ctx { @@ -999,18 +1017,18 @@ static int ocelot_port_fdb_dump(struct sk_buff *skb, struct net_device *dev, struct net_device *filter_dev, int *idx) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; struct ocelot_dump_ctx dump = { .dev = dev, .skb = skb, .cb = cb, .idx = *idx, }; + int port = priv->chip_port; int ret; - ret = ocelot_fdb_dump(ocelot, ocelot_port->chip_port, - ocelot_port_fdb_do_dump, &dump); + ret = ocelot_fdb_dump(ocelot, port, ocelot_port_fdb_do_dump, &dump); *idx = dump.idx; @@ -1033,12 +1051,12 @@ static int ocelot_set_features(struct net_device *dev, netdev_features_t features) { netdev_features_t changed = dev->features ^ features; - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; if ((dev->features & NETIF_F_HW_TC) > (features & NETIF_F_HW_TC) && - ocelot_port->tc.offload_cnt) { + priv->tc.offload_cnt) { netdev_err(dev, "Cannot disable HW TC offload while offloads active\n"); return -EBUSY; @@ -1053,8 +1071,8 @@ static int ocelot_set_features(struct net_device *dev, static int ocelot_get_port_parent_id(struct net_device *dev, struct netdev_phys_item_id *ppid) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; ppid->id_len = sizeof(ocelot->base_mac); memcpy(&ppid->id, &ocelot->base_mac, ppid->id_len); @@ -1136,9 +1154,9 @@ static int ocelot_hwstamp_set(struct ocelot *ocelot, int port, static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; /* The function is only used for PTP operations for now */ if (!ocelot->ptp) @@ -1175,8 +1193,8 @@ static const struct net_device_ops ocelot_port_netdev_ops = { static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data) { - struct ocelot_port *port = netdev_priv(netdev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(netdev); + struct ocelot *ocelot = priv->port.ocelot; int i; if (sset != ETH_SS_STATS) @@ -1230,8 +1248,9 @@ static void ocelot_check_stats_work(struct work_struct *work) static void ocelot_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; int i; /* check and update now */ @@ -1239,13 +1258,13 @@ static void ocelot_get_ethtool_stats(struct net_device *dev, /* Copy all counters */ for (i = 0; i < ocelot->num_stats; i++) - *data++ = ocelot->stats[port->chip_port * ocelot->num_stats + i]; + *data++ = ocelot->stats[port * ocelot->num_stats + i]; } static int ocelot_get_sset_count(struct net_device *dev, int sset) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; if (sset != ETH_SS_STATS) return -EOPNOTSUPP; @@ -1255,8 +1274,8 @@ static int ocelot_get_sset_count(struct net_device *dev, int sset) static int ocelot_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; if (!ocelot->ptp) return ethtool_op_get_ts_info(dev, info); @@ -1388,9 +1407,9 @@ static int ocelot_port_attr_set(struct net_device *dev, const struct switchdev_attr *attr, struct switchdev_trans *trans) { - struct ocelot_port *ocelot_port = netdev_priv(dev); - struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; int err = 0; switch (attr->id) { @@ -1402,8 +1421,8 @@ static int ocelot_port_attr_set(struct net_device *dev, ocelot_port_attr_ageing_set(ocelot, port, attr->u.ageing_time); break; case SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING: - ocelot_port_vlan_filtering(ocelot, port, - attr->u.vlan_filtering); + priv->vlan_aware = attr->u.vlan_filtering; + ocelot_port_vlan_filtering(ocelot, port, priv->vlan_aware); break; case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled); @@ -1468,15 +1487,17 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev, const struct switchdev_obj_port_mdb *mdb, struct switchdev_trans *trans) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; - struct ocelot_multicast *mc; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; unsigned char addr[ETH_ALEN]; + struct ocelot_multicast *mc; + int port = priv->chip_port; u16 vid = mdb->vid; bool new = false; if (!vid) - vid = port->pvid; + vid = ocelot_port->pvid; mc = ocelot_multicast_get(ocelot, mdb->addr, vid); if (!mc) { @@ -1500,7 +1521,7 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev, ocelot_mact_forget(ocelot, addr, vid); } - mc->ports |= BIT(port->chip_port); + mc->ports |= BIT(port); addr[2] = mc->ports << 0; addr[1] = mc->ports << 8; @@ -1510,14 +1531,16 @@ static int ocelot_port_obj_add_mdb(struct net_device *dev, static int ocelot_port_obj_del_mdb(struct net_device *dev, const struct switchdev_obj_port_mdb *mdb) { - struct ocelot_port *port = netdev_priv(dev); - struct ocelot *ocelot = port->ocelot; - struct ocelot_multicast *mc; + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; unsigned char addr[ETH_ALEN]; + struct ocelot_multicast *mc; + int port = priv->chip_port; u16 vid = mdb->vid; if (!vid) - vid = port->pvid; + vid = ocelot_port->pvid; mc = ocelot_multicast_get(ocelot, mdb->addr, vid); if (!mc) @@ -1529,7 +1552,7 @@ static int ocelot_port_obj_del_mdb(struct net_device *dev, addr[0] = 0; ocelot_mact_forget(ocelot, addr, vid); - mc->ports &= ~BIT(port->chip_port); + mc->ports &= ~BIT(port); if (!mc->ports) { list_del(&mc->list); devm_kfree(ocelot->dev, mc); @@ -1683,9 +1706,9 @@ static int ocelot_port_lag_join(struct ocelot *ocelot, int port, rcu_read_lock(); for_each_netdev_in_bond_rcu(bond, ndev) { - struct ocelot_port *port = netdev_priv(ndev); + struct ocelot_port_private *priv = netdev_priv(ndev); - bond_mask |= BIT(port->chip_port); + bond_mask |= BIT(priv->chip_port); } rcu_read_unlock(); @@ -1753,20 +1776,23 @@ static int ocelot_netdevice_port_event(struct net_device *dev, unsigned long event, struct netdev_notifier_changeupper_info *info) { - struct ocelot_port *ocelot_port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; - int port = ocelot_port->chip_port; + int port = priv->chip_port; int err = 0; switch (event) { case NETDEV_CHANGEUPPER: if (netif_is_bridge_master(info->upper_dev)) { - if (info->linking) + if (info->linking) { err = ocelot_port_bridge_join(ocelot, port, info->upper_dev); - else + } else { err = ocelot_port_bridge_leave(ocelot, port, info->upper_dev); + priv->vlan_aware = false; + } } if (netif_is_lag_master(info->upper_dev)) { if (info->linking) @@ -2080,21 +2106,23 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, struct phy_device *phy) { + struct ocelot_port_private *priv; struct ocelot_port *ocelot_port; struct net_device *dev; u32 val; int err; - dev = alloc_etherdev(sizeof(struct ocelot_port)); + dev = alloc_etherdev(sizeof(struct ocelot_port_private)); if (!dev) return -ENOMEM; SET_NETDEV_DEV(dev, ocelot->dev); - ocelot_port = netdev_priv(dev); - ocelot_port->dev = dev; + priv = netdev_priv(dev); + priv->dev = dev; + priv->phy = phy; + priv->chip_port = port; + ocelot_port = &priv->port; ocelot_port->ocelot = ocelot; ocelot_port->regs = regs; - ocelot_port->chip_port = port; - ocelot_port->phy = phy; ocelot->ports[port] = ocelot_port; dev->netdev_ops = &ocelot_port_netdev_ops; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 06ac806052bc..7f3526151fa9 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -479,11 +479,9 @@ struct ocelot { }; struct ocelot_port { - struct net_device *dev; struct ocelot *ocelot; - struct phy_device *phy; + void __iomem *regs; - u8 chip_port; /* Ingress default VLAN (pvid) */ u16 pvid; @@ -491,18 +489,23 @@ struct ocelot_port { /* Egress default VLAN (vid) */ u16 vid; - u8 vlan_aware; + u8 ptp_cmd; + struct list_head skbs; + u8 ts_id; +}; - u64 *stats; +struct ocelot_port_private { + struct ocelot_port port; + struct net_device *dev; + struct phy_device *phy; + u8 chip_port; + + u8 vlan_aware; phy_interface_t phy_mode; struct phy *serdes; struct ocelot_port_tc tc; - - u8 ptp_cmd; - struct list_head skbs; - u8 ts_id; }; struct ocelot_skb { diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h index e98944c87259..c08e3e8482e7 100644 --- a/drivers/net/ethernet/mscc/ocelot_ace.h +++ b/drivers/net/ethernet/mscc/ocelot_ace.h @@ -224,9 +224,9 @@ int ocelot_ace_rule_stats_update(struct ocelot_ace_rule *rule); int ocelot_ace_init(struct ocelot *ocelot); void ocelot_ace_deinit(void); -int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port, +int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv, struct flow_block_offload *f); -void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port, +void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv, struct flow_block_offload *f); #endif /* _MSCC_OCELOT_ACE_H_ */ diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 723724bdc139..4793d275d845 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -95,6 +95,8 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) do { struct skb_shared_hwtstamps *shhwtstamps; + struct ocelot_port_private *priv; + struct ocelot_port *ocelot_port; u64 tod_in_ns, full_ts_in_ns; struct frame_info info = {}; struct net_device *dev; @@ -114,7 +116,10 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) ocelot_parse_ifh(ifh, &info); - dev = ocelot->ports[info.port]->dev; + ocelot_port = ocelot->ports[info.port]; + priv = container_of(ocelot_port, struct ocelot_port_private, + port); + dev = priv->dev; skb = netdev_alloc_skb(dev, info.len); @@ -363,6 +368,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot_init(ocelot); for_each_available_child_of_node(ports, portnp) { + struct ocelot_port_private *priv; + struct ocelot_port *ocelot_port; struct device_node *phy_node; phy_interface_t phy_mode; struct phy_device *phy; @@ -398,13 +405,17 @@ static int mscc_ocelot_probe(struct platform_device *pdev) goto out_put_ports; } + ocelot_port = ocelot->ports[port]; + priv = container_of(ocelot_port, struct ocelot_port_private, + port); + err = of_get_phy_mode(portnp, &phy_mode); if (err && err != -ENODEV) goto out_put_ports; - ocelot->ports[port]->phy_mode = phy_mode; + priv->phy_mode = phy_mode; - switch (ocelot->ports[port]->phy_mode) { + switch (priv->phy_mode) { case PHY_INTERFACE_MODE_NA: continue; case PHY_INTERFACE_MODE_SGMII: @@ -413,7 +424,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) /* Ensure clock signals and speed is set on all * QSGMII links */ - ocelot_port_writel(ocelot->ports[port], + ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED (OCELOT_SPEED_1000), DEV_CLOCK_CFG); @@ -441,7 +452,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) goto out_put_ports; } - ocelot->ports[port]->serdes = serdes; + priv->serdes = serdes; } register_netdevice_notifier(&ocelot_netdevice_nb); diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c index b894bc0c9c16..3d65b99b9734 100644 --- a/drivers/net/ethernet/mscc/ocelot_flower.c +++ b/drivers/net/ethernet/mscc/ocelot_flower.c @@ -10,7 +10,7 @@ struct ocelot_port_block { struct ocelot_acl_block *block; - struct ocelot_port *port; + struct ocelot_port_private *priv; }; static int ocelot_flower_parse_action(struct flow_cls_offload *f, @@ -177,8 +177,8 @@ struct ocelot_ace_rule *ocelot_ace_rule_create(struct flow_cls_offload *f, if (!rule) return NULL; - rule->port = block->port; - rule->chip_port = block->port->chip_port; + rule->port = &block->priv->port; + rule->chip_port = block->priv->chip_port; return rule; } @@ -202,7 +202,7 @@ static int ocelot_flower_replace(struct flow_cls_offload *f, if (ret) return ret; - port_block->port->tc.offload_cnt++; + port_block->priv->tc.offload_cnt++; return 0; } @@ -213,14 +213,14 @@ static int ocelot_flower_destroy(struct flow_cls_offload *f, int ret; rule.prio = f->common.prio; - rule.port = port_block->port; + rule.port = &port_block->priv->port; rule.id = f->cookie; ret = ocelot_ace_rule_offload_del(&rule); if (ret) return ret; - port_block->port->tc.offload_cnt--; + port_block->priv->tc.offload_cnt--; return 0; } @@ -231,7 +231,7 @@ static int ocelot_flower_stats_update(struct flow_cls_offload *f, int ret; rule.prio = f->common.prio; - rule.port = port_block->port; + rule.port = &port_block->priv->port; rule.id = f->cookie; ret = ocelot_ace_rule_stats_update(&rule); if (ret) @@ -261,7 +261,7 @@ static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type, { struct ocelot_port_block *port_block = cb_priv; - if (!tc_cls_can_offload_and_chain0(port_block->port->dev, type_data)) + if (!tc_cls_can_offload_and_chain0(port_block->priv->dev, type_data)) return -EOPNOTSUPP; switch (type) { @@ -275,7 +275,7 @@ static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type, } static struct ocelot_port_block* -ocelot_port_block_create(struct ocelot_port *port) +ocelot_port_block_create(struct ocelot_port_private *priv) { struct ocelot_port_block *port_block; @@ -283,7 +283,7 @@ ocelot_port_block_create(struct ocelot_port *port) if (!port_block) return NULL; - port_block->port = port; + port_block->priv = priv; return port_block; } @@ -300,7 +300,7 @@ static void ocelot_tc_block_unbind(void *cb_priv) ocelot_port_block_destroy(port_block); } -int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port, +int ocelot_setup_tc_block_flower_bind(struct ocelot_port_private *priv, struct flow_block_offload *f) { struct ocelot_port_block *port_block; @@ -311,14 +311,14 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port, return -EOPNOTSUPP; block_cb = flow_block_cb_lookup(f->block, - ocelot_setup_tc_block_cb_flower, port); + ocelot_setup_tc_block_cb_flower, priv); if (!block_cb) { - port_block = ocelot_port_block_create(port); + port_block = ocelot_port_block_create(priv); if (!port_block) return -ENOMEM; block_cb = flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower, - port, port_block, + priv, port_block, ocelot_tc_block_unbind); if (IS_ERR(block_cb)) { ret = PTR_ERR(block_cb); @@ -339,13 +339,13 @@ err_cb_register: return ret; } -void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port, +void ocelot_setup_tc_block_flower_unbind(struct ocelot_port_private *priv, struct flow_block_offload *f) { struct flow_block_cb *block_cb; block_cb = flow_block_cb_lookup(f->block, - ocelot_setup_tc_block_cb_flower, port); + ocelot_setup_tc_block_cb_flower, priv); if (!block_cb) return; diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c index 9be8e7369d6a..a4f7fbd76507 100644 --- a/drivers/net/ethernet/mscc/ocelot_tc.c +++ b/drivers/net/ethernet/mscc/ocelot_tc.c @@ -9,17 +9,19 @@ #include "ocelot_ace.h" #include -static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, +static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv, struct tc_cls_matchall_offload *f, bool ingress) { struct netlink_ext_ack *extack = f->common.extack; + struct ocelot *ocelot = priv->port.ocelot; struct ocelot_policer pol = { 0 }; struct flow_action_entry *action; + int port = priv->chip_port; int err; - netdev_dbg(port->dev, "%s: port %u command %d cookie %lu\n", - __func__, port->chip_port, f->command, f->cookie); + netdev_dbg(priv->dev, "%s: port %u command %d cookie %lu\n", + __func__, port, f->command, f->cookie); if (!ingress) { NL_SET_ERR_MSG_MOD(extack, "Only ingress is supported"); @@ -34,7 +36,7 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, return -EOPNOTSUPP; } - if (port->tc.block_shared) { + if (priv->tc.block_shared) { NL_SET_ERR_MSG_MOD(extack, "Rate limit is not supported on shared blocks"); return -EOPNOTSUPP; @@ -47,7 +49,7 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, return -EOPNOTSUPP; } - if (port->tc.police_id && port->tc.police_id != f->cookie) { + if (priv->tc.police_id && priv->tc.police_id != f->cookie) { NL_SET_ERR_MSG_MOD(extack, "Only one policer per port is supported\n"); return -EEXIST; @@ -58,28 +60,27 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port *port, PSCHED_NS2TICKS(action->police.burst), PSCHED_TICKS_PER_SEC); - err = ocelot_port_policer_add(port->ocelot, port->chip_port, - &pol); + err = ocelot_port_policer_add(ocelot, port, &pol); if (err) { NL_SET_ERR_MSG_MOD(extack, "Could not add policer\n"); return err; } - port->tc.police_id = f->cookie; - port->tc.offload_cnt++; + priv->tc.police_id = f->cookie; + priv->tc.offload_cnt++; return 0; case TC_CLSMATCHALL_DESTROY: - if (port->tc.police_id != f->cookie) + if (priv->tc.police_id != f->cookie) return -ENOENT; - err = ocelot_port_policer_del(port->ocelot, port->chip_port); + err = ocelot_port_policer_del(ocelot, port); if (err) { NL_SET_ERR_MSG_MOD(extack, "Could not delete policer\n"); return err; } - port->tc.police_id = 0; - port->tc.offload_cnt--; + priv->tc.police_id = 0; + priv->tc.offload_cnt--; return 0; case TC_CLSMATCHALL_STATS: /* fall through */ default: @@ -91,21 +92,21 @@ static int ocelot_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv, bool ingress) { - struct ocelot_port *port = cb_priv; + struct ocelot_port_private *priv = cb_priv; - if (!tc_cls_can_offload_and_chain0(port->dev, type_data)) + if (!tc_cls_can_offload_and_chain0(priv->dev, type_data)) return -EOPNOTSUPP; switch (type) { case TC_SETUP_CLSMATCHALL: - netdev_dbg(port->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n", + netdev_dbg(priv->dev, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n", ingress ? "ingress" : "egress"); - return ocelot_setup_tc_cls_matchall(port, type_data, ingress); + return ocelot_setup_tc_cls_matchall(priv, type_data, ingress); case TC_SETUP_CLSFLOWER: return 0; default: - netdev_dbg(port->dev, "tc_block_cb: type %d %s\n", + netdev_dbg(priv->dev, "tc_block_cb: type %d %s\n", type, ingress ? "ingress" : "egress"); @@ -131,19 +132,19 @@ static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type, static LIST_HEAD(ocelot_block_cb_list); -static int ocelot_setup_tc_block(struct ocelot_port *port, +static int ocelot_setup_tc_block(struct ocelot_port_private *priv, struct flow_block_offload *f) { struct flow_block_cb *block_cb; flow_setup_cb_t *cb; int err; - netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n", + netdev_dbg(priv->dev, "tc_block command %d, binder_type %d\n", f->command, f->binder_type); if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) { cb = ocelot_setup_tc_block_cb_ig; - port->tc.block_shared = f->block_shared; + priv->tc.block_shared = f->block_shared; } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { cb = ocelot_setup_tc_block_cb_eg; } else { @@ -154,14 +155,14 @@ static int ocelot_setup_tc_block(struct ocelot_port *port, switch (f->command) { case FLOW_BLOCK_BIND: - if (flow_block_cb_is_busy(cb, port, &ocelot_block_cb_list)) + if (flow_block_cb_is_busy(cb, priv, &ocelot_block_cb_list)) return -EBUSY; - block_cb = flow_block_cb_alloc(cb, port, port, NULL); + block_cb = flow_block_cb_alloc(cb, priv, priv, NULL); if (IS_ERR(block_cb)) return PTR_ERR(block_cb); - err = ocelot_setup_tc_block_flower_bind(port, f); + err = ocelot_setup_tc_block_flower_bind(priv, f); if (err < 0) { flow_block_cb_free(block_cb); return err; @@ -170,11 +171,11 @@ static int ocelot_setup_tc_block(struct ocelot_port *port, list_add_tail(&block_cb->driver_list, f->driver_block_list); return 0; case FLOW_BLOCK_UNBIND: - block_cb = flow_block_cb_lookup(f->block, cb, port); + block_cb = flow_block_cb_lookup(f->block, cb, priv); if (!block_cb) return -ENOENT; - ocelot_setup_tc_block_flower_unbind(port, f); + ocelot_setup_tc_block_flower_unbind(priv, f); flow_block_cb_remove(block_cb, f); list_del(&block_cb->driver_list); return 0; @@ -186,11 +187,11 @@ static int ocelot_setup_tc_block(struct ocelot_port *port, int ocelot_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { - struct ocelot_port *port = netdev_priv(dev); + struct ocelot_port_private *priv = netdev_priv(dev); switch (type) { case TC_SETUP_BLOCK: - return ocelot_setup_tc_block(port, type_data); + return ocelot_setup_tc_block(priv, type_data); default: return -EOPNOTSUPP; } -- cgit v1.2.3-59-g8ed1b From c7282d387695e711b5edc08aa4111b3a4a8a4c23 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:54 +0200 Subject: net: mscc: ocelot: refactor ethtool callbacks Convert them into an implementation that can be called from DSA as well. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 64 ++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index ad808344e33b..58ead0652bce 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1191,10 +1191,9 @@ static const struct net_device_ops ocelot_port_netdev_ops = { .ndo_do_ioctl = ocelot_ioctl, }; -static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data) +static void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, + u8 *data) { - struct ocelot_port_private *priv = netdev_priv(netdev); - struct ocelot *ocelot = priv->port.ocelot; int i; if (sset != ETH_SS_STATS) @@ -1205,6 +1204,16 @@ static void ocelot_get_strings(struct net_device *netdev, u32 sset, u8 *data) ETH_GSTRING_LEN); } +static void ocelot_port_get_strings(struct net_device *netdev, u32 sset, + u8 *data) +{ + struct ocelot_port_private *priv = netdev_priv(netdev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; + + ocelot_get_strings(ocelot, port, sset, data); +} + static void ocelot_update_stats(struct ocelot *ocelot) { int i, j; @@ -1245,12 +1254,8 @@ static void ocelot_check_stats_work(struct work_struct *work) OCELOT_STATS_CHECK_DELAY); } -static void ocelot_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) +static void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) { - struct ocelot_port_private *priv = netdev_priv(dev); - struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; int i; /* check and update now */ @@ -1261,25 +1266,37 @@ static void ocelot_get_ethtool_stats(struct net_device *dev, *data++ = ocelot->stats[port * ocelot->num_stats + i]; } -static int ocelot_get_sset_count(struct net_device *dev, int sset) +static void ocelot_port_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; + ocelot_get_ethtool_stats(ocelot, port, data); +} + +static int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset) +{ if (sset != ETH_SS_STATS) return -EOPNOTSUPP; + return ocelot->num_stats; } -static int ocelot_get_ts_info(struct net_device *dev, - struct ethtool_ts_info *info) +static int ocelot_port_get_sset_count(struct net_device *dev, int sset) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; - if (!ocelot->ptp) - return ethtool_op_get_ts_info(dev, info); + return ocelot_get_sset_count(ocelot, port, sset); +} +static int ocelot_get_ts_info(struct ocelot *ocelot, int port, + struct ethtool_ts_info *info) +{ info->phc_index = ocelot->ptp_clock ? ptp_clock_index(ocelot->ptp_clock) : -1; info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE | @@ -1295,13 +1312,26 @@ static int ocelot_get_ts_info(struct net_device *dev, return 0; } +static int ocelot_port_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; + + if (!ocelot->ptp) + return ethtool_op_get_ts_info(dev, info); + + return ocelot_get_ts_info(ocelot, port, info); +} + static const struct ethtool_ops ocelot_ethtool_ops = { - .get_strings = ocelot_get_strings, - .get_ethtool_stats = ocelot_get_ethtool_stats, - .get_sset_count = ocelot_get_sset_count, + .get_strings = ocelot_port_get_strings, + .get_ethtool_stats = ocelot_port_get_ethtool_stats, + .get_sset_count = ocelot_port_get_sset_count, .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, - .get_ts_info = ocelot_get_ts_info, + .get_ts_info = ocelot_port_get_ts_info, }; static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, -- cgit v1.2.3-59-g8ed1b From 714d0ffabeb21550895ff32a8ba8866b684b5203 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:55 +0200 Subject: net: mscc: ocelot: limit vlan ingress filtering to actual number of ports The VSC7514 switch (Ocelot) is a 10-port device, while VSC9959 (Felix) is 6-port. Therefore the VLAN filtering mask would be out of bounds when calling for this new switch. Fix that. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 58ead0652bce..107a07cfaec9 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -389,7 +389,8 @@ static void ocelot_vlan_init(struct ocelot *ocelot) /* Set vlan ingress filter mask to all ports but the CPU port by * default. */ - ocelot_write(ocelot, GENMASK(9, 0), ANA_VLANMASK); + ocelot_write(ocelot, GENMASK(ocelot->num_phys_ports - 1, 0), + ANA_VLANMASK); for (port = 0; port < ocelot->num_phys_ports; port++) { ocelot_write_gix(ocelot, 0, REW_PORT_VLAN_CFG, port); -- cgit v1.2.3-59-g8ed1b From 31350d7fb985398a61cad8fd7acb6aa3272939d2 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:56 +0200 Subject: net: mscc: ocelot: move port initialization into separate function We need a function for the DSA front-end that does none of the net_device registration, but initializes the hardware ports. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 45 ++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 107a07cfaec9..83ecbbd720fd 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2133,6 +2133,28 @@ static int ocelot_init_timestamp(struct ocelot *ocelot) return 0; } +static void ocelot_init_port(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + INIT_LIST_HEAD(&ocelot_port->skbs); + + /* Basic L2 initialization */ + + /* Drop frames with multicast source address */ + ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, + ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, + ANA_PORT_DROP_CFG, port); + + /* Set default VLAN and tag type to 8021Q. */ + ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q), + REW_PORT_VLAN_CFG_PORT_TPID_M, + REW_PORT_VLAN_CFG, port); + + /* Enable vcap lookups */ + ocelot_vcap_enable(ocelot, port); +} + int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, struct phy_device *phy) @@ -2140,7 +2162,6 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, struct ocelot_port_private *priv; struct ocelot_port *ocelot_port; struct net_device *dev; - u32 val; int err; dev = alloc_etherdev(sizeof(struct ocelot_port_private)); @@ -2168,32 +2189,14 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, ocelot_mact_learn(ocelot, PGID_CPU, dev->dev_addr, ocelot_port->pvid, ENTRYTYPE_LOCKED); - INIT_LIST_HEAD(&ocelot_port->skbs); + ocelot_init_port(ocelot, port); err = register_netdev(dev); if (err) { dev_err(ocelot->dev, "register_netdev failed\n"); - goto err_register_netdev; + free_netdev(dev); } - /* Basic L2 initialization */ - - /* Drop frames with multicast source address */ - val = ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA; - ocelot_rmw_gix(ocelot, val, val, ANA_PORT_DROP_CFG, port); - - /* Set default VLAN and tag type to 8021Q. */ - ocelot_rmw_gix(ocelot, REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q), - REW_PORT_VLAN_CFG_PORT_TPID_M, - REW_PORT_VLAN_CFG, port); - - /* Enable vcap lookups */ - ocelot_vcap_enable(ocelot, port); - - return 0; - -err_register_netdev: - free_netdev(dev); return err; } EXPORT_SYMBOL(ocelot_probe_port); -- cgit v1.2.3-59-g8ed1b From 889b8950d85287e870288c7503870fd11db3d551 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:57 +0200 Subject: net: mscc: ocelot: separate the common implementation of ndo_open and ndo_stop Allow these functions to be called from the .port_enable and .port_disable callbacks of DSA. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 83ecbbd720fd..df8796f05ff9 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -536,13 +536,9 @@ static void ocelot_port_adjust_link(struct net_device *dev) ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); } -static int ocelot_port_open(struct net_device *dev) +static void ocelot_port_enable(struct ocelot *ocelot, int port, + struct phy_device *phy) { - struct ocelot_port_private *priv = netdev_priv(dev); - struct ocelot *ocelot = priv->port.ocelot; - int port = priv->chip_port; - int err; - /* Enable receiving frames on the port, and activate auto-learning of * MAC addresses. */ @@ -550,6 +546,14 @@ static int ocelot_port_open(struct net_device *dev) ANA_PORT_PORT_CFG_RECV_ENA | ANA_PORT_PORT_CFG_PORTID_VAL(port), ANA_PORT_PORT_CFG, port); +} + +static int ocelot_port_open(struct net_device *dev) +{ + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; + int err; if (priv->serdes) { err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET, @@ -571,21 +575,33 @@ static int ocelot_port_open(struct net_device *dev) phy_attached_info(priv->phy); phy_start(priv->phy); + + ocelot_port_enable(ocelot, port, priv->phy); + return 0; } +static void ocelot_port_disable(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); + ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, port); +} + static int ocelot_port_stop(struct net_device *dev) { struct ocelot_port_private *priv = netdev_priv(dev); - struct ocelot_port *port = &priv->port; + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; phy_disconnect(priv->phy); dev->phydev = NULL; - ocelot_port_writel(port, 0, DEV_MAC_ENA_CFG); - ocelot_rmw_rix(port->ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, priv->chip_port); + ocelot_port_disable(ocelot, port); + return 0; } -- cgit v1.2.3-59-g8ed1b From 2b120dded260adc5c6fb4600cd383b2c7f3537e8 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Sat, 9 Nov 2019 15:02:58 +0200 Subject: net: mscc: ocelot: initialize list of multicast addresses in common code This is just common path code that belongs to ocelot_init, it has nothing to do with a specific SoC/board instance. Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 1 + drivers/net/ethernet/mscc/ocelot_board.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index df8796f05ff9..4cb78e14f2fd 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2243,6 +2243,7 @@ int ocelot_init(struct ocelot *ocelot) if (!ocelot->stats_queue) return -ENOMEM; + INIT_LIST_HEAD(&ocelot->multicast); ocelot_mact_init(ocelot); ocelot_vlan_init(ocelot); ocelot_ace_init(ocelot); diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 4793d275d845..9985fb334aac 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -364,7 +364,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports, sizeof(struct ocelot_port *), GFP_KERNEL); - INIT_LIST_HEAD(&ocelot->multicast); ocelot_init(ocelot); for_each_available_child_of_node(ports, portnp) { -- cgit v1.2.3-59-g8ed1b From 26f4dbab7de240f697cbe4d46dfc37b8a7e58d70 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:02:59 +0200 Subject: net: mscc: ocelot: refactor adjust_link into a netdev-independent function This will be called from the Felix DSA frontend, which will work in PHYLIB compatibility mode initially. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 4cb78e14f2fd..7f0bd89fc363 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -410,15 +410,13 @@ static u16 ocelot_wm_enc(u16 value) return value; } -static void ocelot_port_adjust_link(struct net_device *dev) +static void ocelot_adjust_link(struct ocelot *ocelot, int port, + struct phy_device *phydev) { - struct ocelot_port_private *priv = netdev_priv(dev); - struct ocelot_port *ocelot_port = &priv->port; - struct ocelot *ocelot = ocelot_port->ocelot; + struct ocelot_port *ocelot_port = ocelot->ports[port]; int speed, atop_wm, mode = 0; - u8 port = priv->chip_port; - switch (dev->phydev->speed) { + switch (phydev->speed) { case SPEED_10: speed = OCELOT_SPEED_10; break; @@ -434,14 +432,14 @@ static void ocelot_port_adjust_link(struct net_device *dev) mode = DEV_MAC_MODE_CFG_GIGA_MODE_ENA; break; default: - netdev_err(dev, "Unsupported PHY speed: %d\n", - dev->phydev->speed); + dev_err(ocelot->dev, "Unsupported PHY speed on port %d: %d\n", + port, phydev->speed); return; } - phy_print_status(dev->phydev); + phy_print_status(phydev); - if (!dev->phydev->link) + if (!phydev->link) return; /* Only full duplex supported for now */ @@ -536,6 +534,15 @@ static void ocelot_port_adjust_link(struct net_device *dev) ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); } +static void ocelot_port_adjust_link(struct net_device *dev) +{ + struct ocelot_port_private *priv = netdev_priv(dev); + struct ocelot *ocelot = priv->port.ocelot; + int port = priv->chip_port; + + ocelot_adjust_link(ocelot, port, dev->phydev); +} + static void ocelot_port_enable(struct ocelot *ocelot, int port, struct phy_device *phy) { -- cgit v1.2.3-59-g8ed1b From 21468199016f4e4983c7c22368d1cfba3914facb Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:03:00 +0200 Subject: net: mscc: ocelot: split assignment of the cpu port into a separate function Now that the places that configure routing destinations for the CPU port have been marked as such, allow callers to specify their own CPU port that is different than ocelot->num_phys_ports. A user will be the Felix DSA driver, where the CPU port is one of the physical ports (NPI mode). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 65 +++++++++++++++++++++----------- drivers/net/ethernet/mscc/ocelot.h | 12 ++++++ drivers/net/ethernet/mscc/ocelot_board.c | 2 + 3 files changed, 57 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 7f0bd89fc363..bba6d60dc5a8 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -380,12 +380,6 @@ static void ocelot_vlan_init(struct ocelot *ocelot) ocelot->vlan_mask[0] = GENMASK(ocelot->num_phys_ports - 1, 0); ocelot_vlant_set_mask(ocelot, 0, ocelot->vlan_mask[0]); - /* Configure the CPU port to be VLAN aware */ - ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) | - ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | - ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1), - ANA_PORT_VLAN_CFG, ocelot->num_phys_ports); - /* Set vlan ingress filter mask to all ports but the CPU port by * default. */ @@ -2224,11 +2218,52 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, } EXPORT_SYMBOL(ocelot_probe_port); +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, + enum ocelot_tag_prefix extraction) +{ + /* Configure and enable the CPU port. */ + ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); + ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | + ANA_PORT_PORT_CFG_PORTID_VAL(cpu), + ANA_PORT_PORT_CFG, cpu); + + /* If the CPU port is a physical port, set up the port in Node + * Processor Interface (NPI) mode. This is the mode through which + * frames can be injected from and extracted to an external CPU. + * Only one port can be an NPI at the same time. + */ + if (cpu < ocelot->num_phys_ports) { + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | + QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), + QSYS_EXT_CPU_CFG); + } + + /* CPU port Injection/Extraction configuration */ + ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | + QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | + QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, cpu); + ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(extraction) | + SYS_PORT_MODE_INCL_INJ_HDR(injection), + SYS_PORT_MODE, cpu); + + /* Configure the CPU port to be VLAN aware */ + ocelot_write_gix(ocelot, ANA_PORT_VLAN_CFG_VLAN_VID(0) | + ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA | + ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1), + ANA_PORT_VLAN_CFG, cpu); + + ocelot->cpu = cpu; +} +EXPORT_SYMBOL(ocelot_set_cpu_port); + int ocelot_init(struct ocelot *ocelot) { - u32 port; - int i, ret, cpu = ocelot->num_phys_ports; char queue_name[32]; + int i, ret; + u32 port; ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, sizeof(u32), GFP_KERNEL); @@ -2308,13 +2343,6 @@ int ocelot_init(struct ocelot *ocelot) ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port); } - /* Configure and enable the CPU port. */ - ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, cpu); - ocelot_write_rix(ocelot, BIT(cpu), ANA_PGID_PGID, PGID_CPU); - ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_RECV_ENA | - ANA_PORT_PORT_CFG_PORTID_VAL(cpu), - ANA_PORT_PORT_CFG, cpu); - /* Allow broadcast MAC frames. */ for (i = ocelot->num_phys_ports + 1; i < PGID_CPU; i++) { u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0)); @@ -2327,13 +2355,6 @@ int ocelot_init(struct ocelot *ocelot) ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4); ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6); - /* CPU port Injection/Extraction configuration */ - ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | - QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | - QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, cpu); - ocelot_write_rix(ocelot, SYS_PORT_MODE_INCL_XTR_HDR(1) | - SYS_PORT_MODE_INCL_INJ_HDR(1), SYS_PORT_MODE, cpu); /* Allow manual injection via DEVCPU_QS registers, and byte swap these * registers endianness. */ diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 7f3526151fa9..4d8e769ccad9 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -427,6 +427,13 @@ struct ocelot_multicast { u16 ports; }; +enum ocelot_tag_prefix { + OCELOT_TAG_PREFIX_DISABLED = 0, + OCELOT_TAG_PREFIX_NONE, + OCELOT_TAG_PREFIX_SHORT, + OCELOT_TAG_PREFIX_LONG, +}; + struct ocelot_port; struct ocelot_stat_layout { @@ -455,6 +462,7 @@ struct ocelot { u8 num_phys_ports; u8 num_cpu_ports; + u8 cpu; struct ocelot_port **ports; u32 *lags; @@ -552,6 +560,10 @@ int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, struct phy_device *phy); +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, + enum ocelot_tag_prefix extraction); + extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_blocking_nb; diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 9985fb334aac..811599f32910 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -365,6 +365,8 @@ static int mscc_ocelot_probe(struct platform_device *pdev) sizeof(struct ocelot_port *), GFP_KERNEL); ocelot_init(ocelot); + ocelot_set_cpu_port(ocelot, ocelot->num_phys_ports, + OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_NONE); for_each_available_child_of_node(ports, portnp) { struct ocelot_port_private *priv; -- cgit v1.2.3-59-g8ed1b From c9d2203bcb813805cd74abe17e9a4c811fc0bf02 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sat, 9 Nov 2019 15:03:01 +0200 Subject: net: mscc: ocelot: don't hardcode the number of the CPU port VSC7514 is a 10-port switch with 2 extra "CPU ports" (targets in the queuing subsystem for terminating traffic locally). There are 2 issues with hardcoding the CPU port as #10: - It is not clear which snippets of the code are configuring something for one of the CPU ports, and which snippets are just doing something related to the number of physical ports. - Actually any physical port can act as a CPU port connected to an external CPU (in addition to the local CPU). This is called NPI mode (Node Processor Interface) and is the way that the 6-port VSC9959 (Felix) switch is integrated inside NXP LS1028A (the "local management CPU" functionality is not used there). This patch makes it clear that the ocelot_bridge_stp_state_set function operates on the CPU port (by making it an implicit member of the bridging domain), and at the same time adds logic for the NPI port (aka a physical port) to play the role of a CPU port (it shouldn't be part of bridge_fwd_mask, as it's not explicitly enslaved to a bridge). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index bba6d60dc5a8..3e7a2796c37d 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1383,7 +1383,7 @@ static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, * a source for the other ports. */ for (p = 0; p < ocelot->num_phys_ports; p++) { - if (ocelot->bridge_fwd_mask & BIT(p)) { + if (p == ocelot->cpu || (ocelot->bridge_fwd_mask & BIT(p))) { unsigned long mask = ocelot->bridge_fwd_mask & ~BIT(p); for (i = 0; i < ocelot->num_phys_ports; i++) { @@ -1398,15 +1398,18 @@ static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, } } - ocelot_write_rix(ocelot, - BIT(ocelot->num_phys_ports) | mask, + /* Avoid the NPI port from looping back to itself */ + if (p != ocelot->cpu) + mask |= BIT(ocelot->cpu); + + ocelot_write_rix(ocelot, mask, ANA_PGID_PGID, PGID_SRC + p); } else { /* Only the CPU port, this is compatible with link * aggregation. */ ocelot_write_rix(ocelot, - BIT(ocelot->num_phys_ports), + BIT(ocelot->cpu), ANA_PGID_PGID, PGID_SRC + p); } } -- cgit v1.2.3-59-g8ed1b From 7ec3f872bc85ada93db34448d73bb399d6b82c2c Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 10 Nov 2019 14:44:54 +0100 Subject: r8169: respect EEE user setting when restarting network Currently, if network is re-started, we advertise all supported EEE modes, thus potentially overriding a manual adjustment the user made e.g. via ethtool. Be friendly to the user and preserve a manual setting on network re-start. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index d4345493fdba..249b68d00d79 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -680,6 +680,7 @@ struct rtl8169_private { struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts; + int eee_adv; const char *fw_name; struct rtl_fw *rtl_fw; @@ -2101,6 +2102,10 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) } ret = phy_ethtool_set_eee(tp->phydev, data); + + if (!ret) + tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN, + MDIO_AN_EEE_ADV); out: pm_runtime_put_noidle(d); return ret; @@ -2131,10 +2136,16 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { static void rtl_enable_eee(struct rtl8169_private *tp) { struct phy_device *phydev = tp->phydev; - int supported = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); + int adv; + + /* respect EEE advertisement the user may have set */ + if (tp->eee_adv >= 0) + adv = tp->eee_adv; + else + adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - if (supported > 0) - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, supported); + if (adv >= 0) + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); } static void rtl8169_get_mac_version(struct rtl8169_private *tp) @@ -6719,6 +6730,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->pci_dev = pdev; tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; + tp->eee_adv = -1; /* Get the *optional* external "ether_clk" used on some boards */ rc = rtl_get_ether_clk(tp); -- cgit v1.2.3-59-g8ed1b From 2fca4ac914a16c85721a83fa30cc586faf46ca18 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:04:11 +0000 Subject: net: sfp: fix sfp_bus_put() kernel documentation The kbuild test robot found a problem with htmldocs with the recent change to the SFP interfaces. Fix the kernel documentation for sfp_bus_put() which was missing an '@' before the argument name description. Fixes: 727b3668b730 ("net: sfp: rework upstream interface") Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 715d45214e18..c5398a023440 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -331,7 +331,7 @@ static void sfp_bus_release(struct kref *kref) /** * sfp_bus_put() - put a reference on the &struct sfp_bus - * bus: the &struct sfp_bus found via sfp_bus_find_fwnode() + * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode() * * Put a reference on the &struct sfp_bus and free the underlying structure * if this was the last reference. -- cgit v1.2.3-59-g8ed1b From e85d81a1840a000adc00ed75be553b886660884f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:13 +0000 Subject: net: sfp: move sfp sub-state machines into separate functions Move the SFP sub-state machines out of the main state machine function, in preparation for it doing a bit more with the device state. By doing so, we ensure that our debug after the main state machine is always printed. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 74 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 272d5773573e..9d341ab4c96b 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1544,19 +1544,34 @@ static void sfp_sm_mod_remove(struct sfp *sfp) dev_info(sfp->dev, "module removed\n"); } -static void sfp_sm_event(struct sfp *sfp, unsigned int event) +/* This state machine tracks the netdev up/down state */ +static void sfp_sm_device(struct sfp *sfp, unsigned int event) { - mutex_lock(&sfp->sm_mutex); + switch (sfp->sm_dev_state) { + default: + if (event == SFP_E_DEV_UP) + sfp->sm_dev_state = SFP_DEV_UP; + break; - 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), - sm_state_to_str(sfp->sm_state), - event_to_str(event)); + case SFP_DEV_UP: + if (event == SFP_E_DEV_DOWN) { + /* If the module has a PHY, avoid raising TX disable + * as this resets the PHY. Otherwise, raise it to + * turn the laser off. + */ + if (!sfp->mod_phy) + sfp_module_tx_disable(sfp); + sfp->sm_dev_state = SFP_DEV_DOWN; + } + break; + } +} - /* This state machine tracks the insert/remove state of - * the module, and handles probing the on-board EEPROM. - */ +/* This state machine tracks the insert/remove state of + * the module, and handles probing the on-board EEPROM. + */ +static void sfp_sm_module(struct sfp *sfp, unsigned int event) +{ switch (sfp->sm_mod_state) { default: if (event == SFP_E_INSERT && sfp->attached) { @@ -1596,27 +1611,10 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) } break; } +} - /* This state machine tracks the netdev up/down state */ - switch (sfp->sm_dev_state) { - default: - if (event == SFP_E_DEV_UP) - sfp->sm_dev_state = SFP_DEV_UP; - break; - - case SFP_DEV_UP: - if (event == SFP_E_DEV_DOWN) { - /* If the module has a PHY, avoid raising TX disable - * as this resets the PHY. Otherwise, raise it to - * turn the laser off. - */ - if (!sfp->mod_phy) - sfp_module_tx_disable(sfp); - sfp->sm_dev_state = SFP_DEV_DOWN; - } - break; - } - +static void sfp_sm_main(struct sfp *sfp, unsigned int event) +{ /* Some events are global */ if (sfp->sm_state != SFP_S_DOWN && (sfp->sm_mod_state != SFP_MOD_PRESENT || @@ -1627,7 +1625,6 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) if (sfp->mod_phy) sfp_sm_phy_detach(sfp); sfp_sm_next(sfp, SFP_S_DOWN, 0); - mutex_unlock(&sfp->sm_mutex); return; } @@ -1682,6 +1679,21 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) case SFP_S_TX_DISABLE: break; } +} + +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), + sm_state_to_str(sfp->sm_state), + event_to_str(event)); + + sfp_sm_module(sfp, event); + sfp_sm_device(sfp, event); + sfp_sm_main(sfp, event); dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n", mod_state_to_str(sfp->sm_mod_state), -- cgit v1.2.3-59-g8ed1b From 1539e0d33bbc948351e340daaff1f9d98acb3dde Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:18 +0000 Subject: net: sfp: move tx disable on device down to main state machine Move the tx disable assertion on device down to the main state machine. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 9d341ab4c96b..04169681dd86 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1554,15 +1554,8 @@ static void sfp_sm_device(struct sfp *sfp, unsigned int event) break; case SFP_DEV_UP: - if (event == SFP_E_DEV_DOWN) { - /* If the module has a PHY, avoid raising TX disable - * as this resets the PHY. Otherwise, raise it to - * turn the laser off. - */ - if (!sfp->mod_phy) - sfp_module_tx_disable(sfp); + if (event == SFP_E_DEV_DOWN) sfp->sm_dev_state = SFP_DEV_DOWN; - } break; } } @@ -1624,6 +1617,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) sfp_sm_link_down(sfp); if (sfp->mod_phy) sfp_sm_phy_detach(sfp); + sfp_module_tx_disable(sfp); sfp_sm_next(sfp, SFP_S_DOWN, 0); return; } -- cgit v1.2.3-59-g8ed1b From 0936ebc42f5909da7cf4c58468d4107f7029fe29 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:23 +0000 Subject: net: sfp: rename sfp_sm_ins_next() as sfp_sm_mod_next() sfp_sm_ins_next() modifies the module state machine. Change it's name to reflect this. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 04169681dd86..7bcb9a8c0bcd 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1245,7 +1245,7 @@ static void sfp_sm_next(struct sfp *sfp, unsigned int state, sfp_sm_set_timer(sfp, timeout); } -static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state, +static void sfp_sm_mod_next(struct sfp *sfp, unsigned int state, unsigned int timeout) { sfp->sm_mod_state = state; @@ -1569,22 +1569,22 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) default: if (event == SFP_E_INSERT && sfp->attached) { sfp_module_tx_disable(sfp); - sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT); + sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT); } break; case SFP_MOD_PROBE: if (event == SFP_E_REMOVE) { - sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0); + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); } else if (event == SFP_E_TIMEOUT) { int val = sfp_sm_mod_probe(sfp); if (val == 0) - sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0); + sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); else if (val > 0) - sfp_sm_ins_next(sfp, SFP_MOD_HPOWER, val); + sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val); else if (val != -EAGAIN) - sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0); + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); else sfp_sm_set_timer(sfp, T_PROBE_RETRY); } @@ -1592,7 +1592,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) case SFP_MOD_HPOWER: if (event == SFP_E_TIMEOUT) { - sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0); + sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); break; } /* fallthrough */ @@ -1600,7 +1600,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) case SFP_MOD_ERROR: if (event == SFP_E_REMOVE) { sfp_sm_mod_remove(sfp); - sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0); + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); } break; } -- cgit v1.2.3-59-g8ed1b From d2e816c0293fc263b3f168c14992a5f1a50d7593 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:28 +0000 Subject: net: sfp: handle module remove outside state machine Removing a module resets the module state machine back to its initial state. Rather than explicitly handling this in every state, handle it early on outside of the state machine. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 7bcb9a8c0bcd..2f3073164333 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1565,6 +1565,14 @@ static void sfp_sm_device(struct sfp *sfp, unsigned int event) */ static void sfp_sm_module(struct sfp *sfp, unsigned int event) { + /* Handle remove event globally, it resets this state machine */ + if (event == SFP_E_REMOVE) { + if (sfp->sm_mod_state > SFP_MOD_PROBE) + sfp_sm_mod_remove(sfp); + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); + return; + } + switch (sfp->sm_mod_state) { default: if (event == SFP_E_INSERT && sfp->attached) { @@ -1574,9 +1582,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) break; case SFP_MOD_PROBE: - if (event == SFP_E_REMOVE) { - sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); - } else if (event == SFP_E_TIMEOUT) { + if (event == SFP_E_TIMEOUT) { int val = sfp_sm_mod_probe(sfp); if (val == 0) @@ -1598,10 +1604,6 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) /* fallthrough */ case SFP_MOD_PRESENT: case SFP_MOD_ERROR: - if (event == SFP_E_REMOVE) { - sfp_sm_mod_remove(sfp); - sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); - } break; } } -- cgit v1.2.3-59-g8ed1b From d900954f57c61b3fbca6df5c2af1f3207fcabf0e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:33 +0000 Subject: net: sfp: rename T_PROBE_WAIT to T_SERIAL SFF-8472 rev 12.2 defines the time for the serial bus to become ready using t_serial. Use this as our identifier for this timeout to make it clear what we are referring to. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 2f3073164333..b8254d10b2f0 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -149,11 +149,10 @@ static const enum gpiod_flags gpio_flags[] = { * the same length on the PCB, which means it's possible for MOD DEF 0 to * connect before the I2C bus on MOD DEF 1/2. * - * The SFP MSA specifies 300ms as t_init (the time taken for TX_FAULT to - * be deasserted) but makes no mention of the earliest time before we can - * access the I2C EEPROM. However, Avago modules require 300ms. + * The SFF-8472 specifies t_serial ("Time from power on until module is + * ready for data transmission over the two wire serial bus.") as 300ms. */ -#define T_PROBE_INIT msecs_to_jiffies(300) +#define T_SERIAL msecs_to_jiffies(300) #define T_HPOWER_LEVEL msecs_to_jiffies(300) #define T_PROBE_RETRY msecs_to_jiffies(100) @@ -1560,8 +1559,8 @@ static void sfp_sm_device(struct sfp *sfp, unsigned int event) } } -/* This state machine tracks the insert/remove state of - * the module, and handles probing the on-board EEPROM. +/* This state machine tracks the insert/remove state of the module, probes + * the on-board EEPROM, and sets up the power level. */ static void sfp_sm_module(struct sfp *sfp, unsigned int event) { @@ -1577,7 +1576,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) default: if (event == SFP_E_INSERT && sfp->attached) { sfp_module_tx_disable(sfp); - sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT); + sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); } break; -- cgit v1.2.3-59-g8ed1b From ed32abb1ee716da02e7d795e3057efc1551168f2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:39 +0000 Subject: net: sfp: parse SFP power requirement earlier Parse the SFP power requirement earlier, in preparation for moving the power level setup code. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index b8254d10b2f0..69f7683ba6ab 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -198,6 +198,8 @@ struct sfp { unsigned int sm_retries; struct sfp_eeprom_id id; + unsigned int module_power_mW; + #if IS_ENABLED(CONFIG_HWMON) struct sfp_diag diag; struct device *hwmon_dev; @@ -1374,17 +1376,14 @@ static void sfp_sm_mod_init(struct sfp *sfp) sfp_sm_probe_phy(sfp); } -static int sfp_sm_mod_hpower(struct sfp *sfp) +static int sfp_module_parse_power(struct sfp *sfp) { - u32 power; - u8 val; - int err; + u32 power_mW = 1000; - power = 1000; if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL)) - power = 1500; + power_mW = 1500; if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) - power = 2000; + power_mW = 2000; if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE && (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) != @@ -1393,23 +1392,33 @@ static int sfp_sm_mod_hpower(struct sfp *sfp) * or requires an address change sequence, so assume that * the module powers up in the indicated power mode. */ - if (power > sfp->max_power_mW) { + if (power_mW > sfp->max_power_mW) { dev_err(sfp->dev, "Host does not support %u.%uW modules\n", - power / 1000, (power / 100) % 10); + power_mW / 1000, (power_mW / 100) % 10); return -EINVAL; } return 0; } - if (power > sfp->max_power_mW) { + if (power_mW > sfp->max_power_mW) { dev_warn(sfp->dev, "Host does not support %u.%uW modules, module left in power mode 1\n", - power / 1000, (power / 100) % 10); + power_mW / 1000, (power_mW / 100) % 10); return 0; } - if (power <= 1000) + sfp->module_power_mW = power_mW; + + return 0; +} + +static int sfp_sm_mod_hpower(struct sfp *sfp) +{ + u8 val; + int err; + + if (sfp->module_power_mW <= 1000) return 0; err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); @@ -1429,7 +1438,8 @@ static int sfp_sm_mod_hpower(struct sfp *sfp) } dev_info(sfp->dev, "Module switched to %u.%uW power level\n", - power / 1000, (power / 100) % 10); + sfp->module_power_mW / 1000, + (sfp->module_power_mW / 100) % 10); return T_HPOWER_LEVEL; err: @@ -1516,6 +1526,11 @@ static int sfp_sm_mod_probe(struct sfp *sfp) dev_warn(sfp->dev, "module address swap to access page 0xA2 is not supported.\n"); + /* Parse the module power requirement */ + ret = sfp_module_parse_power(sfp); + if (ret < 0) + return ret; + ret = sfp_hwmon_insert(sfp); if (ret < 0) return ret; @@ -1539,6 +1554,7 @@ static void sfp_sm_mod_remove(struct sfp *sfp) sfp_module_tx_disable(sfp); memset(&sfp->id, 0, sizeof(sfp->id)); + sfp->module_power_mW = 0; dev_info(sfp->dev, "module removed\n"); } -- cgit v1.2.3-59-g8ed1b From 7cfa9c92d0a325f97ac13f894a7b47d37bd2040e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:44 +0000 Subject: net: sfp: avoid power switch on address-change modules If the module indicates that it requires an address change sequence to switch between address 0x50 and 0x51, which we don't support, we can't write to the register that controls the power mode to switch to high power mode. Warn the user that the module may not be functional in this case, and don't try to change the power mode. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 69f7683ba6ab..d8efa1d3a903 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1385,25 +1385,34 @@ static int sfp_module_parse_power(struct sfp *sfp) if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL)) power_mW = 2000; - if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE && - (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) != - SFP_DIAGMON_DDM) { - /* The module appears not to implement bus address 0xa2, - * or requires an address change sequence, so assume that - * the module powers up in the indicated power mode. - */ - if (power_mW > sfp->max_power_mW) { + if (power_mW > sfp->max_power_mW) { + /* Module power specification exceeds the allowed maximum. */ + if (sfp->id.ext.sff8472_compliance == + SFP_SFF8472_COMPLIANCE_NONE && + !(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) { + /* The module appears not to implement bus address + * 0xa2, so assume that the module powers up in the + * indicated mode. + */ dev_err(sfp->dev, "Host does not support %u.%uW modules\n", power_mW / 1000, (power_mW / 100) % 10); return -EINVAL; + } else { + dev_warn(sfp->dev, + "Host does not support %u.%uW modules, module left in power mode 1\n", + power_mW / 1000, (power_mW / 100) % 10); + return 0; } - return 0; } - if (power_mW > sfp->max_power_mW) { + /* If the module requires a higher power mode, but also requires + * an address change sequence, warn the user that the module may + * not be functional. + */ + if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE && power_mW > 1000) { dev_warn(sfp->dev, - "Host does not support %u.%uW modules, module left in power mode 1\n", + "Address Change Sequence not supported but module requies %u.%uW, module may not be functional\n", power_mW / 1000, (power_mW / 100) % 10); return 0; } -- cgit v1.2.3-59-g8ed1b From 8e210b6bdc2c91492735c9ff913e3cdf2161f8dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:49 +0000 Subject: net: sfp: control TX_DISABLE and phy only from main state machine We initialise TX_DISABLE when the sfp cage is probed, and then maintain its state in the main state machine. However, the module state machine: - negates it when detecting a newly inserted module when it's already guaranteed to be negated. - negates it when the module is removed, but the main state machine will do this anyway. Make TX_DISABLE entirely controlled by the main state machine. The main state machine also probes the module for a PHY, and removes the PHY when the the module is removed. Hence, removing the PHY in sfp_sm_module_remove() is also redundant, and is a left-over from when we tried to probe for the PHY from the module state machine. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index d8efa1d3a903..e0bc060bb693 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1557,11 +1557,6 @@ static void sfp_sm_mod_remove(struct sfp *sfp) sfp_hwmon_remove(sfp); - if (sfp->mod_phy) - sfp_sm_phy_detach(sfp); - - sfp_module_tx_disable(sfp); - memset(&sfp->id, 0, sizeof(sfp->id)); sfp->module_power_mW = 0; @@ -1599,10 +1594,8 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) switch (sfp->sm_mod_state) { default: - if (event == SFP_E_INSERT && sfp->attached) { - sfp_module_tx_disable(sfp); + if (event == SFP_E_INSERT && sfp->attached) sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); - } break; case SFP_MOD_PROBE: -- cgit v1.2.3-59-g8ed1b From 181f29da1582dec29f58ccd2a3dfbe917a1953cf Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:54 +0000 Subject: net: sfp: split the PHY probe from sfp_sm_mod_init() Move the PHY probe into a separate function, splitting it from sfp_sm_mod_init(). This will allow us to eliminate the 50ms mdelay() inside the state machine. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index e0bc060bb693..49919a75e338 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1353,14 +1353,10 @@ static void sfp_sm_fault(struct sfp *sfp, bool warn) static void sfp_sm_mod_init(struct sfp *sfp) { sfp_module_tx_enable(sfp); +} - /* Wait t_init before indicating that the link is up, provided the - * current state indicates no TX_FAULT. If TX_FAULT clears before - * this time, that's fine too. - */ - sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES); - sfp->sm_retries = 5; - +static void sfp_sm_probe_for_phy(struct sfp *sfp) +{ /* Setting the serdes link mode is guesswork: there's no * field in the EEPROM which indicates what mode should * be used. @@ -1645,8 +1641,17 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) switch (sfp->sm_state) { case SFP_S_DOWN: if (sfp->sm_mod_state == SFP_MOD_PRESENT && - sfp->sm_dev_state == SFP_DEV_UP) + sfp->sm_dev_state == SFP_DEV_UP) { sfp_sm_mod_init(sfp); + sfp_sm_probe_for_phy(sfp); + + /* Wait t_init before indicating that the link is up, + * provided the current state indicates no TX_FAULT. If + * TX_FAULT clears before this time, that's fine too. + */ + sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES); + sfp->sm_retries = 5; + } break; case SFP_S_INIT: -- cgit v1.2.3-59-g8ed1b From eefa6f1fa74f20420e536a79fa7e2c539b036be0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:06:59 +0000 Subject: net: sfp: eliminate mdelay() from PHY probe Rather than using mdelay() to wait before probing the PHY (which holds several locks, including the rtnl lock), add an extra wait state to the state machine to introduce the 50ms delay without holding any locks. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 52 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 49919a75e338..316ff719857b 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -54,6 +54,7 @@ enum { SFP_DEV_UP, SFP_S_DOWN = 0, + SFP_S_WAIT, SFP_S_INIT, SFP_S_WAIT_LOS, SFP_S_LINK_UP, @@ -110,6 +111,7 @@ static const char *event_to_str(unsigned short event) static const char * const sm_state_strings[] = { [SFP_S_DOWN] = "down", + [SFP_S_WAIT] = "wait", [SFP_S_INIT] = "init", [SFP_S_WAIT_LOS] = "wait_los", [SFP_S_LINK_UP] = "link_up", @@ -141,6 +143,7 @@ static const enum gpiod_flags gpio_flags[] = { GPIOD_ASIS, }; +#define T_WAIT msecs_to_jiffies(50) #define T_INIT_JIFFIES msecs_to_jiffies(300) #define T_RESET_US 10 #define T_FAULT_RECOVER msecs_to_jiffies(1000) @@ -161,9 +164,6 @@ static const enum gpiod_flags gpio_flags[] = { */ #define SFP_PHY_ADDR 22 -/* Give this long for the PHY to reset. */ -#define T_PHY_RESET_MS 50 - struct sff_data { unsigned int gpios; bool (*module_supported)(const struct sfp_eeprom_id *id); @@ -1267,8 +1267,6 @@ static void sfp_sm_probe_phy(struct sfp *sfp) struct phy_device *phy; int err; - msleep(T_PHY_RESET_MS); - phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR); if (phy == ERR_PTR(-ENODEV)) { dev_info(sfp->dev, "no PHY detected\n"); @@ -1623,6 +1621,8 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) static void sfp_sm_main(struct sfp *sfp, unsigned int event) { + unsigned long timeout; + /* Some events are global */ if (sfp->sm_state != SFP_S_DOWN && (sfp->sm_mod_state != SFP_MOD_PRESENT || @@ -1640,17 +1640,45 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) /* The main state machine */ switch (sfp->sm_state) { case SFP_S_DOWN: - if (sfp->sm_mod_state == SFP_MOD_PRESENT && - sfp->sm_dev_state == SFP_DEV_UP) { - sfp_sm_mod_init(sfp); - sfp_sm_probe_for_phy(sfp); + if (sfp->sm_mod_state != SFP_MOD_PRESENT || + sfp->sm_dev_state != SFP_DEV_UP) + break; + + sfp_sm_mod_init(sfp); + + /* Initialise the fault clearance retries */ + sfp->sm_retries = 5; + + /* We need to check the TX_FAULT state, which is not defined + * while TX_DISABLE is asserted. The earliest we want to do + * anything (such as probe for a PHY) is 50ms. + */ + sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); + break; + case SFP_S_WAIT: + if (event != SFP_E_TIMEOUT) + break; + + sfp_sm_probe_for_phy(sfp); + + if (sfp->state & SFP_F_TX_FAULT) { /* Wait t_init before indicating that the link is up, * provided the current state indicates no TX_FAULT. If * TX_FAULT clears before this time, that's fine too. */ - sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES); - sfp->sm_retries = 5; + timeout = T_INIT_JIFFIES; + if (timeout > T_WAIT) + timeout -= T_WAIT; + else + timeout = 1; + + sfp_sm_next(sfp, SFP_S_INIT, timeout); + } else { + /* TX_FAULT is not asserted, assume the module has + * finished initialising. + */ + goto init_done; } break; @@ -1658,7 +1686,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) sfp_sm_fault(sfp, true); else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) - sfp_sm_link_check_los(sfp); + init_done: sfp_sm_link_check_los(sfp); break; case SFP_S_WAIT_LOS: -- cgit v1.2.3-59-g8ed1b From 63ec1c7c3f3b55b7e126d5fb54744869f2b6608e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:04 +0000 Subject: net: sfp: allow fault processing to transition to other states Add the next state to sfp_sm_fault() so that it can branch to other states. This will be necessary to improve the initialisation path. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 316ff719857b..72c6776c1ce6 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1334,7 +1334,7 @@ static bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event) event == SFP_E_LOS_LOW); } -static void sfp_sm_fault(struct sfp *sfp, bool warn) +static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) { if (sfp->sm_retries && !--sfp->sm_retries) { dev_err(sfp->dev, @@ -1344,7 +1344,7 @@ static void sfp_sm_fault(struct sfp *sfp, bool warn) if (warn) dev_err(sfp->dev, "module transmit fault indicated\n"); - sfp_sm_next(sfp, SFP_S_TX_FAULT, T_FAULT_RECOVER); + sfp_sm_next(sfp, next_state, T_FAULT_RECOVER); } } @@ -1684,14 +1684,14 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) case SFP_S_INIT: if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) - sfp_sm_fault(sfp, true); + sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) init_done: sfp_sm_link_check_los(sfp); break; case SFP_S_WAIT_LOS: if (event == SFP_E_TX_FAULT) - sfp_sm_fault(sfp, true); + sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); else if (sfp_los_event_inactive(sfp, event)) sfp_sm_link_up(sfp); break; @@ -1699,7 +1699,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) case SFP_S_LINK_UP: if (event == SFP_E_TX_FAULT) { sfp_sm_link_down(sfp); - sfp_sm_fault(sfp, true); + sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); } else if (sfp_los_event_active(sfp, event)) { sfp_sm_link_down(sfp); sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0); @@ -1715,7 +1715,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) case SFP_S_REINIT: if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { - sfp_sm_fault(sfp, false); + sfp_sm_fault(sfp, SFP_S_TX_FAULT, false); } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { dev_info(sfp->dev, "module transmit fault recovered\n"); sfp_sm_link_check_los(sfp); -- cgit v1.2.3-59-g8ed1b From d23751a094012f7d0d7b6fb694f3c1ecb19e4a41 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:09 +0000 Subject: net: sfp: ensure TX_FAULT has deasserted before probing the PHY TX_FAULT should be deasserted to indicate that the module has completed its initialisation. This may include the on-board PHY, so wait until the module has deasserted TX_FAULT before probing the PHY. This means that we need an extra state to handle a TX_FAULT that remains set for longer than t_init, since using the existing handling state would bypass the PHY probe. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 72c6776c1ce6..cb0a35b1bb71 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -56,6 +56,7 @@ enum { SFP_S_DOWN = 0, SFP_S_WAIT, SFP_S_INIT, + SFP_S_INIT_TX_FAULT, SFP_S_WAIT_LOS, SFP_S_LINK_UP, SFP_S_TX_FAULT, @@ -113,6 +114,7 @@ static const char * const sm_state_strings[] = { [SFP_S_DOWN] = "down", [SFP_S_WAIT] = "wait", [SFP_S_INIT] = "init", + [SFP_S_INIT_TX_FAULT] = "init_tx_fault", [SFP_S_WAIT_LOS] = "wait_los", [SFP_S_LINK_UP] = "link_up", [SFP_S_TX_FAULT] = "tx_fault", @@ -1660,8 +1662,6 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) if (event != SFP_E_TIMEOUT) break; - sfp_sm_probe_for_phy(sfp); - if (sfp->state & SFP_F_TX_FAULT) { /* Wait t_init before indicating that the link is up, * provided the current state indicates no TX_FAULT. If @@ -1683,10 +1683,29 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) break; case SFP_S_INIT: - if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) - sfp_sm_fault(sfp, SFP_S_TX_FAULT, true); - else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) - init_done: sfp_sm_link_check_los(sfp); + if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) { + /* TX_FAULT is still asserted after t_init, so assume + * there is a fault. + */ + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, + sfp->sm_retries == 5); + } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { + init_done: /* TX_FAULT deasserted or we timed out with TX_FAULT + * clear. Probe for the PHY and check the LOS state. + */ + sfp_sm_probe_for_phy(sfp); + sfp_sm_link_check_los(sfp); + + /* Reset the fault retry count */ + sfp->sm_retries = 5; + } + break; + + case SFP_S_INIT_TX_FAULT: + if (event == SFP_E_TIMEOUT) { + sfp_module_tx_fault_reset(sfp); + sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES); + } break; case SFP_S_WAIT_LOS: -- cgit v1.2.3-59-g8ed1b From 6b0da5c9c1a39eeead9c75eef3a0f2f62c375b2f Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:14 +0000 Subject: net: sfp: track upstream's attachment state in state machine Track the upstream's attachment state in the state machine rather than maintaining a boolean, which ensures that we have a strict order of ATTACH followed by an UP event - we can never believe that a newly attached upstream will be anything but down. Rearrange the order of state machines so we run the module state machine after the upstream device's state machine, so the module state machine can check the current state of the device and take action to e.g. reset back to empty state when the upstream is detached. This is to allow the module detection to run independently of the network device becoming available. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index cb0a35b1bb71..bb4ede83bf53 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -36,6 +36,8 @@ enum { SFP_E_INSERT = 0, SFP_E_REMOVE, + SFP_E_DEV_ATTACH, + SFP_E_DEV_DETACH, SFP_E_DEV_DOWN, SFP_E_DEV_UP, SFP_E_TX_FAULT, @@ -50,7 +52,8 @@ enum { SFP_MOD_PRESENT, SFP_MOD_ERROR, - SFP_DEV_DOWN = 0, + SFP_DEV_DETACHED = 0, + SFP_DEV_DOWN, SFP_DEV_UP, SFP_S_DOWN = 0, @@ -80,6 +83,7 @@ static const char *mod_state_to_str(unsigned short mod_state) } static const char * const dev_state_strings[] = { + [SFP_DEV_DETACHED] = "detached", [SFP_DEV_DOWN] = "down", [SFP_DEV_UP] = "up", }; @@ -94,6 +98,8 @@ static const char *dev_state_to_str(unsigned short dev_state) static const char * const event_strings[] = { [SFP_E_INSERT] = "insert", [SFP_E_REMOVE] = "remove", + [SFP_E_DEV_ATTACH] = "dev_attach", + [SFP_E_DEV_DETACH] = "dev_detach", [SFP_E_DEV_DOWN] = "dev_down", [SFP_E_DEV_UP] = "dev_up", [SFP_E_TX_FAULT] = "tx_fault", @@ -188,7 +194,6 @@ struct sfp { struct gpio_desc *gpio[GPIO_MAX]; int gpio_irq[GPIO_MAX]; - bool attached; struct mutex st_mutex; /* Protects state */ unsigned int state; struct delayed_work poll; @@ -1559,17 +1564,26 @@ static void sfp_sm_mod_remove(struct sfp *sfp) dev_info(sfp->dev, "module removed\n"); } -/* This state machine tracks the netdev up/down state */ +/* This state machine tracks the upstream's state */ static void sfp_sm_device(struct sfp *sfp, unsigned int event) { switch (sfp->sm_dev_state) { default: - if (event == SFP_E_DEV_UP) + if (event == SFP_E_DEV_ATTACH) + sfp->sm_dev_state = SFP_DEV_DOWN; + break; + + case SFP_DEV_DOWN: + if (event == SFP_E_DEV_DETACH) + sfp->sm_dev_state = SFP_DEV_DETACHED; + else if (event == SFP_E_DEV_UP) sfp->sm_dev_state = SFP_DEV_UP; break; case SFP_DEV_UP: - if (event == SFP_E_DEV_DOWN) + if (event == SFP_E_DEV_DETACH) + sfp->sm_dev_state = SFP_DEV_DETACHED; + else if (event == SFP_E_DEV_DOWN) sfp->sm_dev_state = SFP_DEV_DOWN; break; } @@ -1580,17 +1594,20 @@ static void sfp_sm_device(struct sfp *sfp, unsigned int event) */ static void sfp_sm_module(struct sfp *sfp, unsigned int event) { - /* Handle remove event globally, it resets this state machine */ - if (event == SFP_E_REMOVE) { + /* Handle remove event globally, it resets this state machine. + * Also deal with upstream detachment. + */ + if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) { if (sfp->sm_mod_state > SFP_MOD_PROBE) sfp_sm_mod_remove(sfp); - sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); + if (sfp->sm_mod_state != SFP_MOD_EMPTY) + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); return; } switch (sfp->sm_mod_state) { default: - if (event == SFP_E_INSERT && sfp->attached) + if (event == SFP_E_INSERT) sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); break; @@ -1756,8 +1773,8 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) sm_state_to_str(sfp->sm_state), event_to_str(event)); - sfp_sm_module(sfp, event); sfp_sm_device(sfp, event); + sfp_sm_module(sfp, event); sfp_sm_main(sfp, event); dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n", @@ -1770,15 +1787,14 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) static void sfp_attach(struct sfp *sfp) { - sfp->attached = true; + sfp_sm_event(sfp, SFP_E_DEV_ATTACH); if (sfp->state & SFP_F_PRESENT) sfp_sm_event(sfp, SFP_E_INSERT); } static void sfp_detach(struct sfp *sfp) { - sfp->attached = false; - sfp_sm_event(sfp, SFP_E_REMOVE); + sfp_sm_event(sfp, SFP_E_DEV_DETACH); } static void sfp_start(struct sfp *sfp) -- cgit v1.2.3-59-g8ed1b From b036a554d0806a711cdd0abb4f5fdbbf0253cc46 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:20 +0000 Subject: net: sfp: split power mode switching from probe Switch the power mode switching from the probe, so that we don't repeatedly re-probe the SFP device if there is a problem accessing the registers at I2C address 0x51. In splitting this out, we can also fix a bug where we leave the module in high-power mode when the upstream device is detached but the module is still inserted. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 101 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index bb4ede83bf53..66946accb044 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -49,6 +49,7 @@ enum { SFP_MOD_EMPTY = 0, SFP_MOD_PROBE, SFP_MOD_HPOWER, + SFP_MOD_WAITPWR, SFP_MOD_PRESENT, SFP_MOD_ERROR, @@ -71,6 +72,7 @@ static const char * const mod_state_strings[] = { [SFP_MOD_EMPTY] = "empty", [SFP_MOD_PROBE] = "probe", [SFP_MOD_HPOWER] = "hpower", + [SFP_MOD_WAITPWR] = "waitpwr", [SFP_MOD_PRESENT] = "present", [SFP_MOD_ERROR] = "error", }; @@ -1423,37 +1425,34 @@ static int sfp_module_parse_power(struct sfp *sfp) return 0; } -static int sfp_sm_mod_hpower(struct sfp *sfp) +static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) { u8 val; int err; - if (sfp->module_power_mW <= 1000) - return 0; - err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); if (err != sizeof(val)) { dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err); - err = -EAGAIN; - goto err; + return -EAGAIN; } - val |= BIT(0); + if (enable) + val |= BIT(0); + else + val &= ~BIT(0); err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val)); if (err != sizeof(val)) { dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err); - err = -EAGAIN; - goto err; + return -EAGAIN; } - dev_info(sfp->dev, "Module switched to %u.%uW power level\n", - sfp->module_power_mW / 1000, - (sfp->module_power_mW / 100) % 10); - return T_HPOWER_LEVEL; + if (enable) + dev_info(sfp->dev, "Module switched to %u.%uW power level\n", + sfp->module_power_mW / 1000, + (sfp->module_power_mW / 100) % 10); -err: - return err; + return 0; } static int sfp_sm_mod_probe(struct sfp *sfp) @@ -1549,7 +1548,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp) if (ret < 0) return ret; - return sfp_sm_mod_hpower(sfp); + return 0; } static void sfp_sm_mod_remove(struct sfp *sfp) @@ -1594,13 +1593,22 @@ static void sfp_sm_device(struct sfp *sfp, unsigned int event) */ static void sfp_sm_module(struct sfp *sfp, unsigned int event) { - /* Handle remove event globally, it resets this state machine. - * Also deal with upstream detachment. - */ - if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) { + int err; + + /* Handle remove event globally, it resets this state machine */ + if (event == SFP_E_REMOVE) { if (sfp->sm_mod_state > SFP_MOD_PROBE) sfp_sm_mod_remove(sfp); - if (sfp->sm_mod_state != SFP_MOD_EMPTY) + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); + return; + } + + /* Handle device detach globally */ + if (sfp->sm_dev_state < SFP_DEV_DOWN) { + if (sfp->module_power_mW > 1000 && + sfp->sm_mod_state > SFP_MOD_HPOWER) + sfp_sm_mod_hpower(sfp, false); + if (sfp->sm_mod_state > SFP_MOD_EMPTY) sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); return; } @@ -1612,26 +1620,45 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) break; case SFP_MOD_PROBE: - if (event == SFP_E_TIMEOUT) { - int val = sfp_sm_mod_probe(sfp); - - if (val == 0) - sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); - else if (val > 0) - sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val); - else if (val != -EAGAIN) - sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); - else - sfp_sm_set_timer(sfp, T_PROBE_RETRY); + if (event != SFP_E_TIMEOUT) + break; + + err = sfp_sm_mod_probe(sfp); + if (err == -EAGAIN) { + sfp_sm_set_timer(sfp, T_PROBE_RETRY); + break; + } + if (err < 0) { + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + break; } - break; + /* If this is a power level 1 module, we are done */ + if (sfp->module_power_mW <= 1000) + goto insert; + + sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0); + /* fall through */ case SFP_MOD_HPOWER: - if (event == SFP_E_TIMEOUT) { - sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); + /* Enable high power mode */ + err = sfp_sm_mod_hpower(sfp, true); + if (err == 0) + sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); + else if (err != -EAGAIN) + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + else + sfp_sm_set_timer(sfp, T_PROBE_RETRY); + break; + + case SFP_MOD_WAITPWR: + /* Wait for T_HPOWER_LEVEL to time out */ + if (event != SFP_E_TIMEOUT) break; - } - /* fallthrough */ + + insert: + sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0); + break; + case SFP_MOD_PRESENT: case SFP_MOD_ERROR: break; -- cgit v1.2.3-59-g8ed1b From 73f5e847d83a2e1a06b47190291d2eebf6353499 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:25 +0000 Subject: net: sfp: move module insert reporting out of probe Move the module insertion reporting out of the probe handling, but after we have detected that the upstream has attached (since that is whom we are reporting insertion to.) Only report module removal if we had previously reported a module insertion. This gives cleaner semantics, and means we can probe the module before we have an upstream attached. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 58 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 66946accb044..8add54b52f4d 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -47,11 +47,12 @@ enum { SFP_E_TIMEOUT, SFP_MOD_EMPTY = 0, + SFP_MOD_ERROR, SFP_MOD_PROBE, + SFP_MOD_WAITDEV, SFP_MOD_HPOWER, SFP_MOD_WAITPWR, SFP_MOD_PRESENT, - SFP_MOD_ERROR, SFP_DEV_DETACHED = 0, SFP_DEV_DOWN, @@ -70,11 +71,12 @@ enum { static const char * const mod_state_strings[] = { [SFP_MOD_EMPTY] = "empty", + [SFP_MOD_ERROR] = "error", [SFP_MOD_PROBE] = "probe", + [SFP_MOD_WAITDEV] = "waitdev", [SFP_MOD_HPOWER] = "hpower", [SFP_MOD_WAITPWR] = "waitpwr", [SFP_MOD_PRESENT] = "present", - [SFP_MOD_ERROR] = "error", }; static const char *mod_state_to_str(unsigned short mod_state) @@ -1544,16 +1546,13 @@ static int sfp_sm_mod_probe(struct sfp *sfp) if (ret < 0) return ret; - ret = sfp_module_insert(sfp->sfp_bus, &sfp->id); - if (ret < 0) - return ret; - return 0; } static void sfp_sm_mod_remove(struct sfp *sfp) { - sfp_module_remove(sfp->sfp_bus); + if (sfp->sm_mod_state > SFP_MOD_WAITDEV) + sfp_module_remove(sfp->sfp_bus); sfp_hwmon_remove(sfp); @@ -1604,12 +1603,12 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) } /* Handle device detach globally */ - if (sfp->sm_dev_state < SFP_DEV_DOWN) { + if (sfp->sm_dev_state < SFP_DEV_DOWN && + sfp->sm_mod_state > SFP_MOD_WAITDEV) { if (sfp->module_power_mW > 1000 && sfp->sm_mod_state > SFP_MOD_HPOWER) sfp_sm_mod_hpower(sfp, false); - if (sfp->sm_mod_state > SFP_MOD_EMPTY) - sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); + sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); return; } @@ -1620,6 +1619,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) break; case SFP_MOD_PROBE: + /* Wait for T_PROBE_INIT to time out */ if (event != SFP_E_TIMEOUT) break; @@ -1633,6 +1633,20 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) break; } + sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0); + /* fall through */ + case SFP_MOD_WAITDEV: + /* Ensure that the device is attached before proceeding */ + if (sfp->sm_dev_state < SFP_DEV_DOWN) + break; + + /* Report the module insertion to the upstream device */ + err = sfp_module_insert(sfp->sfp_bus, &sfp->id); + if (err < 0) { + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + break; + } + /* If this is a power level 1 module, we are done */ if (sfp->module_power_mW <= 1000) goto insert; @@ -1642,12 +1656,17 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) case SFP_MOD_HPOWER: /* Enable high power mode */ err = sfp_sm_mod_hpower(sfp, true); - if (err == 0) - sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); - else if (err != -EAGAIN) - sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); - else - sfp_sm_set_timer(sfp, T_PROBE_RETRY); + if (err < 0) { + if (err != -EAGAIN) { + sfp_module_remove(sfp->sfp_bus); + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + } else { + sfp_sm_set_timer(sfp, T_PROBE_RETRY); + } + break; + } + + sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL); break; case SFP_MOD_WAITPWR: @@ -1815,8 +1834,6 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) static void sfp_attach(struct sfp *sfp) { sfp_sm_event(sfp, SFP_E_DEV_ATTACH); - if (sfp->state & SFP_F_PRESENT) - sfp_sm_event(sfp, SFP_E_INSERT); } static void sfp_detach(struct sfp *sfp) @@ -2084,6 +2101,11 @@ static int sfp_probe(struct platform_device *pdev) sfp->state |= SFP_F_RATE_SELECT; sfp_set_state(sfp, sfp->state); sfp_module_tx_disable(sfp); + if (sfp->state & SFP_F_PRESENT) { + rtnl_lock(); + sfp_sm_event(sfp, SFP_E_INSERT); + rtnl_unlock(); + } for (i = 0; i < GPIO_MAX; i++) { if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i]) -- cgit v1.2.3-59-g8ed1b From e117be74c5593d8aef9d62833d637839f3eae4e7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:30 +0000 Subject: net: sfp: allow sfp to probe slow to initialise GPON modules Some GPON modules (e.g. Huawei MA5671A) take a significant amount of time to start responding on the I2C bus, contary to the SFF specifications. Work around this by implementing a two-level timeout strategy, where we initially quickly retry for the module, and then use a slower retry after we exceed a maximum number of quick attempts. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 8add54b52f4d..3a79f54f7acd 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -167,9 +167,12 @@ static const enum gpiod_flags gpio_flags[] = { * The SFF-8472 specifies t_serial ("Time from power on until module is * ready for data transmission over the two wire serial bus.") as 300ms. */ -#define T_SERIAL msecs_to_jiffies(300) -#define T_HPOWER_LEVEL msecs_to_jiffies(300) -#define T_PROBE_RETRY msecs_to_jiffies(100) +#define T_SERIAL msecs_to_jiffies(300) +#define T_HPOWER_LEVEL msecs_to_jiffies(300) +#define T_PROBE_RETRY_INIT msecs_to_jiffies(100) +#define R_PROBE_RETRY_INIT 10 +#define T_PROBE_RETRY_SLOW msecs_to_jiffies(5000) +#define R_PROBE_RETRY_SLOW 12 /* SFP modules appear to always have their PHY configured for bus address * 0x56 (which with mdio-i2c, translates to a PHY address of 22). @@ -204,6 +207,8 @@ struct sfp { struct delayed_work timeout; struct mutex sm_mutex; /* Protects state machine */ unsigned char sm_mod_state; + unsigned char sm_mod_tries_init; + unsigned char sm_mod_tries; unsigned char sm_dev_state; unsigned short sm_state; unsigned int sm_retries; @@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable) return 0; } -static int sfp_sm_mod_probe(struct sfp *sfp) +static int sfp_sm_mod_probe(struct sfp *sfp, bool report) { /* SFP module inserted - read I2C data */ struct sfp_eeprom_id id; @@ -1467,7 +1472,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp) ret = sfp_read(sfp, false, 0, &id, sizeof(id)); if (ret < 0) { - dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); + if (report) + dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret); return -EAGAIN; } @@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) switch (sfp->sm_mod_state) { default: - if (event == SFP_E_INSERT) + if (event == SFP_E_INSERT) { sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); + sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT; + sfp->sm_mod_tries = R_PROBE_RETRY_SLOW; + } break; case SFP_MOD_PROBE: @@ -1623,10 +1632,19 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) if (event != SFP_E_TIMEOUT) break; - err = sfp_sm_mod_probe(sfp); + err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1); if (err == -EAGAIN) { - sfp_sm_set_timer(sfp, T_PROBE_RETRY); - break; + if (sfp->sm_mod_tries_init && + --sfp->sm_mod_tries_init) { + sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); + break; + } else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) { + if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1) + dev_warn(sfp->dev, + "please wait, module slow to respond\n"); + sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW); + break; + } } if (err < 0) { sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); @@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) sfp_module_remove(sfp->sfp_bus); sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); } else { - sfp_sm_set_timer(sfp, T_PROBE_RETRY); + sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT); } break; } -- cgit v1.2.3-59-g8ed1b From 139d3a212a1f009251ffaef174c0638f646dbae8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 10 Nov 2019 14:07:35 +0000 Subject: net: sfp: allow modules with slow diagnostics to probe When a module is inserted, we attempt to read read the ID from address 0x50. Once we are able to read the ID, we immediately attempt to initialise the hwmon support by reading from address 0x51. If this fails, then we fall into error state, and assume that the module is not usable. Modules such as the ALCATELLUCENT 3FE46541AA use a real EEPROM for I2C address 0x50, which responds immediately. However, address 0x51 is an emulated, which only becomes available once the on-board firmware has booted. This prompts us to fall into the error state. Since the module may be usable without diagnostics, arrange for the hwmon probe independent of the rest of the SFP itself, retrying every 5s for up to about 60s for the monitoring to become available, and print an error message if it doesn't become available. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 96 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 3a79f54f7acd..f9b8051c4247 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -218,6 +218,8 @@ struct sfp { #if IS_ENABLED(CONFIG_HWMON) struct sfp_diag diag; + struct delayed_work hwmon_probe; + unsigned int hwmon_tries; struct device *hwmon_dev; char *hwmon_name; #endif @@ -1159,29 +1161,27 @@ static const struct hwmon_chip_info sfp_hwmon_chip_info = { .info = sfp_hwmon_info, }; -static int sfp_hwmon_insert(struct sfp *sfp) +static void sfp_hwmon_probe(struct work_struct *work) { + struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work); int err, i; - if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) - return 0; - - if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) - return 0; - - if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) - /* This driver in general does not support address - * change. - */ - return 0; - err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag)); - if (err < 0) - return err; + if (err < 0) { + if (sfp->hwmon_tries--) { + mod_delayed_work(system_wq, &sfp->hwmon_probe, + T_PROBE_RETRY_SLOW); + } else { + dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); + } + return; + } sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL); - if (!sfp->hwmon_name) - return -ENODEV; + if (!sfp->hwmon_name) { + dev_err(sfp->dev, "out of memory for hwmon name\n"); + return; + } for (i = 0; sfp->hwmon_name[i]; i++) if (hwmon_is_bad_char(sfp->hwmon_name[i])) @@ -1191,18 +1191,52 @@ static int sfp_hwmon_insert(struct sfp *sfp) sfp->hwmon_name, sfp, &sfp_hwmon_chip_info, NULL); + if (IS_ERR(sfp->hwmon_dev)) + dev_err(sfp->dev, "failed to register hwmon device: %ld\n", + PTR_ERR(sfp->hwmon_dev)); +} + +static int sfp_hwmon_insert(struct sfp *sfp) +{ + if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE) + return 0; - return PTR_ERR_OR_ZERO(sfp->hwmon_dev); + if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) + return 0; + + if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE) + /* This driver in general does not support address + * change. + */ + return 0; + + mod_delayed_work(system_wq, &sfp->hwmon_probe, 1); + sfp->hwmon_tries = R_PROBE_RETRY_SLOW; + + return 0; } static void sfp_hwmon_remove(struct sfp *sfp) { + cancel_delayed_work_sync(&sfp->hwmon_probe); if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) { hwmon_device_unregister(sfp->hwmon_dev); sfp->hwmon_dev = NULL; kfree(sfp->hwmon_name); } } + +static int sfp_hwmon_init(struct sfp *sfp) +{ + INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe); + + return 0; +} + +static void sfp_hwmon_exit(struct sfp *sfp) +{ + cancel_delayed_work_sync(&sfp->hwmon_probe); +} #else static int sfp_hwmon_insert(struct sfp *sfp) { @@ -1212,6 +1246,15 @@ static int sfp_hwmon_insert(struct sfp *sfp) static void sfp_hwmon_remove(struct sfp *sfp) { } + +static int sfp_hwmon_init(struct sfp *sfp) +{ + return 0; +} + +static void sfp_hwmon_exit(struct sfp *sfp) +{ +} #endif /* Helpers */ @@ -1548,10 +1591,6 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) if (ret < 0) return ret; - ret = sfp_hwmon_insert(sfp); - if (ret < 0) - return ret; - return 0; } @@ -1700,6 +1739,15 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event) case SFP_MOD_ERROR: break; } + +#if IS_ENABLED(CONFIG_HWMON) + if (sfp->sm_mod_state >= SFP_MOD_WAITDEV && + IS_ERR_OR_NULL(sfp->hwmon_dev)) { + err = sfp_hwmon_insert(sfp); + if (err) + dev_warn(sfp->dev, "hwmon probe failed: %d\n", err); + } +#endif } static void sfp_sm_main(struct sfp *sfp, unsigned int event) @@ -2001,6 +2049,8 @@ static struct sfp *sfp_alloc(struct device *dev) INIT_DELAYED_WORK(&sfp->poll, sfp_poll); INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout); + sfp_hwmon_init(sfp); + return sfp; } @@ -2008,6 +2058,8 @@ static void sfp_cleanup(void *data) { struct sfp *sfp = data; + sfp_hwmon_exit(sfp); + cancel_delayed_work_sync(&sfp->poll); cancel_delayed_work_sync(&sfp->timeout); if (sfp->i2c_mii) { -- cgit v1.2.3-59-g8ed1b From 1287723aa139b46dc0b9b53c7212af71f1acfc39 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sun, 10 Nov 2019 16:13:35 +0100 Subject: r8169: add support for RTL8117 Add support for chip version RTL8117. Settings have been copied from Realtek's r8168 driver, there however chip ID 54a belongs to a chip version called RTL8168FP. It was confirmed that RTL8117 works with Realtek's driver, so both chip versions seem to be the same or at least compatible. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 135 ++++++++++++++++++++++++++---- 1 file changed, 120 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 249b68d00d79..9a21ac962c27 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -135,6 +135,7 @@ enum mac_version { RTL_GIGA_MAC_VER_49, RTL_GIGA_MAC_VER_50, RTL_GIGA_MAC_VER_51, + RTL_GIGA_MAC_VER_52, RTL_GIGA_MAC_VER_60, RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_NONE @@ -202,6 +203,7 @@ static const struct { [RTL_GIGA_MAC_VER_49] = {"RTL8168ep/8111ep" }, [RTL_GIGA_MAC_VER_50] = {"RTL8168ep/8111ep" }, [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" }, + [RTL_GIGA_MAC_VER_52] = {"RTL8117" }, [RTL_GIGA_MAC_VER_60] = {"RTL8125" }, [RTL_GIGA_MAC_VER_61] = {"RTL8125", FIRMWARE_8125A_3}, }; @@ -751,7 +753,7 @@ static bool rtl_is_8168evl_up(struct rtl8169_private *tp) { return tp->mac_version >= RTL_GIGA_MAC_VER_34 && tp->mac_version != RTL_GIGA_MAC_VER_39 && - tp->mac_version <= RTL_GIGA_MAC_VER_51; + tp->mac_version <= RTL_GIGA_MAC_VER_52; } static bool rtl_supports_eee(struct rtl8169_private *tp) @@ -1290,9 +1292,7 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_31: rtl8168dp_driver_start(tp); break; - case RTL_GIGA_MAC_VER_49: - case RTL_GIGA_MAC_VER_50: - case RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: rtl8168ep_driver_start(tp); break; default: @@ -1324,9 +1324,7 @@ static void rtl8168_driver_stop(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_31: rtl8168dp_driver_stop(tp); break; - case RTL_GIGA_MAC_VER_49: - case RTL_GIGA_MAC_VER_50: - case RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: rtl8168ep_driver_stop(tp); break; default: @@ -1354,9 +1352,7 @@ static bool r8168_check_dash(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return r8168dp_check_dash(tp); - case RTL_GIGA_MAC_VER_49: - case RTL_GIGA_MAC_VER_50: - case RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: return r8168ep_check_dash(tp); default: return false; @@ -1531,7 +1527,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_52: options = RTL_R8(tp, Config2) & ~PME_SIGNAL; if (wolopts) options |= PME_SIGNAL; @@ -2170,6 +2166,9 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp) { 0x7cf, 0x608, RTL_GIGA_MAC_VER_60 }, { 0x7c8, 0x608, RTL_GIGA_MAC_VER_61 }, + /* RTL8117 */ + { 0x7cf, 0x54a, RTL_GIGA_MAC_VER_52 }, + /* 8168EP family. */ { 0x7cf, 0x502, RTL_GIGA_MAC_VER_51 }, { 0x7cf, 0x501, RTL_GIGA_MAC_VER_50 }, @@ -3336,6 +3335,46 @@ static void rtl8168ep_2_hw_phy_config(struct rtl8169_private *tp) rtl_enable_eee(tp); } +static void rtl8117_hw_phy_config(struct rtl8169_private *tp) +{ + struct phy_device *phydev = tp->phydev; + + /* CHN EST parameters adjust - fnet */ + r8168g_phy_param(phydev, 0x808e, 0xff00, 0x4800); + r8168g_phy_param(phydev, 0x8090, 0xff00, 0xcc00); + r8168g_phy_param(phydev, 0x8092, 0xff00, 0xb000); + + r8168g_phy_param(phydev, 0x8088, 0xff00, 0x6000); + r8168g_phy_param(phydev, 0x808b, 0x3f00, 0x0b00); + r8168g_phy_param(phydev, 0x808d, 0x1f00, 0x0600); + r8168g_phy_param(phydev, 0x808c, 0xff00, 0xb000); + r8168g_phy_param(phydev, 0x80a0, 0xff00, 0x2800); + r8168g_phy_param(phydev, 0x80a2, 0xff00, 0x5000); + r8168g_phy_param(phydev, 0x809b, 0xf800, 0xb000); + r8168g_phy_param(phydev, 0x809a, 0xff00, 0x4b00); + r8168g_phy_param(phydev, 0x809d, 0x3f00, 0x0800); + r8168g_phy_param(phydev, 0x80a1, 0xff00, 0x7000); + r8168g_phy_param(phydev, 0x809f, 0x1f00, 0x0300); + r8168g_phy_param(phydev, 0x809e, 0xff00, 0x8800); + r8168g_phy_param(phydev, 0x80b2, 0xff00, 0x2200); + r8168g_phy_param(phydev, 0x80ad, 0xf800, 0x9800); + r8168g_phy_param(phydev, 0x80af, 0x3f00, 0x0800); + r8168g_phy_param(phydev, 0x80b3, 0xff00, 0x6f00); + r8168g_phy_param(phydev, 0x80b1, 0x1f00, 0x0300); + r8168g_phy_param(phydev, 0x80b0, 0xff00, 0x9300); + + r8168g_phy_param(phydev, 0x8011, 0x0000, 0x0800); + + /* enable GPHY 10M */ + phy_modify_paged(tp->phydev, 0x0a44, 0x11, 0, BIT(11)); + + r8168g_phy_param(phydev, 0x8016, 0x0000, 0x0400); + + rtl8168g_disable_aldps(tp); + rtl8168h_config_eee_phy(tp); + rtl_enable_eee(tp); +} + static void rtl8102e_hw_phy_config(struct rtl8169_private *tp) { static const struct phy_reg phy_reg_init[] = { @@ -3564,6 +3603,7 @@ static void rtl_hw_phy_config(struct net_device *dev) [RTL_GIGA_MAC_VER_49] = rtl8168ep_1_hw_phy_config, [RTL_GIGA_MAC_VER_50] = rtl8168ep_2_hw_phy_config, [RTL_GIGA_MAC_VER_51] = rtl8168ep_2_hw_phy_config, + [RTL_GIGA_MAC_VER_52] = rtl8117_hw_phy_config, [RTL_GIGA_MAC_VER_60] = rtl8125_1_hw_phy_config, [RTL_GIGA_MAC_VER_61] = rtl8125_2_hw_phy_config, }; @@ -3657,7 +3697,7 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_32: case RTL_GIGA_MAC_VER_33: case RTL_GIGA_MAC_VER_34: - case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_52: RTL_W32(tp, RxConfig, RTL_R32(tp, RxConfig) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys); break; @@ -3693,6 +3733,7 @@ static void rtl_pll_power_down(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_48: case RTL_GIGA_MAC_VER_50: case RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_52: case RTL_GIGA_MAC_VER_60: case RTL_GIGA_MAC_VER_61: RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~0x80); @@ -3724,6 +3765,7 @@ static void rtl_pll_power_up(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_48: case RTL_GIGA_MAC_VER_50: case RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_52: case RTL_GIGA_MAC_VER_60: case RTL_GIGA_MAC_VER_61: RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | 0xc0); @@ -3755,7 +3797,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_38: RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF); break; case RTL_GIGA_MAC_VER_60 ... RTL_GIGA_MAC_VER_61: @@ -3941,7 +3983,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42); break; case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_52: RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); break; @@ -4787,6 +4829,68 @@ static void rtl_hw_start_8168ep_3(struct rtl8169_private *tp) rtl_hw_aspm_clkreq_enable(tp, true); } +static void rtl_hw_start_8117(struct rtl8169_private *tp) +{ + static const struct ephy_info e_info_8117[] = { + { 0x19, 0x0040, 0x1100 }, + { 0x59, 0x0040, 0x1100 }, + }; + int rg_saw_cnt; + + rtl8168ep_stop_cmac(tp); + + /* disable aspm and clock request before access ephy */ + rtl_hw_aspm_clkreq_enable(tp, false); + rtl_ephy_init(tp, e_info_8117); + + rtl_set_fifo_size(tp, 0x08, 0x10, 0x02, 0x06); + rtl8168g_set_pause_thresholds(tp, 0x2f, 0x5f); + + rtl_set_def_aspm_entry_latency(tp); + + rtl_reset_packet_filter(tp); + + rtl_eri_set_bits(tp, 0xd4, ERIAR_MASK_1111, 0x1f90); + + rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87); + + RTL_W32(tp, MISC, RTL_R32(tp, MISC) & ~RXDV_GATED_EN); + + rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000); + rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000); + + rtl8168_config_eee_mac(tp); + + RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~PFM_EN); + RTL_W8(tp, MISC_1, RTL_R8(tp, MISC_1) & ~PFM_D3COLD_EN); + + RTL_W8(tp, DLLPR, RTL_R8(tp, DLLPR) & ~TX_10M_PS_EN); + + rtl_eri_clear_bits(tp, 0x1b0, ERIAR_MASK_0011, BIT(12)); + + rtl_pcie_state_l2l3_disable(tp); + + rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff; + if (rg_saw_cnt > 0) { + u16 sw_cnt_1ms_ini; + + sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff; + r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini); + } + + r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0070); + r8168_mac_ocp_write(tp, 0xea80, 0x0003); + r8168_mac_ocp_modify(tp, 0xe052, 0x0000, 0x0009); + r8168_mac_ocp_modify(tp, 0xd420, 0x0fff, 0x047f); + + r8168_mac_ocp_write(tp, 0xe63e, 0x0001); + r8168_mac_ocp_write(tp, 0xe63e, 0x0000); + r8168_mac_ocp_write(tp, 0xc094, 0x0000); + r8168_mac_ocp_write(tp, 0xc09e, 0x0000); + + rtl_hw_aspm_clkreq_enable(tp, true); +} + static void rtl_hw_start_8102e_1(struct rtl8169_private *tp) { static const struct ephy_info e_info_8102e_1[] = { @@ -5074,6 +5178,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_49] = rtl_hw_start_8168ep_1, [RTL_GIGA_MAC_VER_50] = rtl_hw_start_8168ep_2, [RTL_GIGA_MAC_VER_51] = rtl_hw_start_8168ep_3, + [RTL_GIGA_MAC_VER_52] = rtl_hw_start_8117, [RTL_GIGA_MAC_VER_60] = rtl_hw_start_8125_1, [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125_2, }; @@ -6620,7 +6725,7 @@ static void rtl_hw_init_8125(struct rtl8169_private *tp) static void rtl_hw_initialize(struct rtl8169_private *tp) { switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_51: + case RTL_GIGA_MAC_VER_49 ... RTL_GIGA_MAC_VER_52: rtl8168ep_stop_cmac(tp); /* fall through */ case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: -- cgit v1.2.3-59-g8ed1b From 5b67a3ed4fe3f859045cfcc5b1dbd80d058075b5 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 10 Nov 2019 16:31:44 +0100 Subject: mlxsw: core: Enable devlink reload only on probe Call devlink enable only during probe time and avoid deadlock during reload. Reported-by: Shalom Toledo Fixes: a0c76345e3d3 ("devlink: disallow reload operation during device cleanup") Signed-off-by: Jiri Pirko Tested-by: Shalom Toledo Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index da436a6aad2f..42e1ce3e39e1 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1198,10 +1198,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, if (err) goto err_thermal_init; - if (mlxsw_driver->params_register) { + if (mlxsw_driver->params_register) devlink_params_publish(devlink); + + if (!reload) devlink_reload_enable(devlink); - } return 0; -- cgit v1.2.3-59-g8ed1b From 29711306ce971d55903a4a2de7ac5d051d4a8306 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 11 Nov 2019 12:44:13 +0000 Subject: cxgb4: remove redundant assignment to hdr_len Variable hdr_len is being assigned a value that is never read. The assignment is redundant and hence can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index e346830ebca9..09059adc3067 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -3810,7 +3810,6 @@ int cxgb4_ethofld_rx_handler(struct sge_rspq *q, const __be64 *rsp, eosw_txq->state == CXGB4_EO_STATE_FLOWC_CLOSE_REPLY) && eosw_txq->cidx == eosw_txq->flowc_idx)) { - hdr_len = skb->len; flits = DIV_ROUND_UP(skb->len, 8); if (eosw_txq->state == CXGB4_EO_STATE_FLOWC_OPEN_REPLY) -- cgit v1.2.3-59-g8ed1b From a24cae7012b59bfe1aed01fe3fc13d81b7b97b08 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:34 +0100 Subject: net: stmmac: Fix sparse warning The VID is converted to le16 so the variable must be __le16 type. Reported-by: kbuild test robot Fixes: c7ab0b8088d7 ("net: stmmac: Fallback to VLAN Perfect filtering if HASH is not available") Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 2 +- drivers/net/ethernet/stmicro/stmmac/hwif.h | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index a2ecab5dc8c8..40ca00e596dd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -733,7 +733,7 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable) } static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double) + __le16 perfect_match, bool is_double) { void __iomem *ioaddr = hw->pcsr; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 9553d2bec1a7..082f5ee9e525 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -556,7 +556,7 @@ static int dwxgmac2_rss_configure(struct mac_device_info *hw, } static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double) + __le16 perfect_match, bool is_double) { void __iomem *ioaddr = hw->pcsr; diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 1303d1e9a18f..509daeefdb79 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -357,7 +357,7 @@ struct stmmac_ops { struct stmmac_rss *cfg, u32 num_rxq); /* VLAN */ void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double); + __le16 perfect_match, bool is_double); void (*enable_vlan)(struct mac_device_info *hw, u32 type); /* TX Timestamp */ int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 199c4f938bb2..5f40fbb67bac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4214,6 +4214,7 @@ static u32 stmmac_vid_crc32_le(__le16 vid_le) static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double) { u32 crc, hash = 0; + __le16 pmatch = 0; int count = 0; u16 vid = 0; @@ -4228,11 +4229,11 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double) if (count > 2) /* VID = 0 always passes filter */ return -EOPNOTSUPP; - vid = cpu_to_le16(vid); + pmatch = cpu_to_le16(vid); hash = 0; } - return stmmac_update_vlan_hash(priv, priv->hw, hash, vid, is_double); + return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double); } static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) -- cgit v1.2.3-59-g8ed1b From 8c6fc097a2f4acf2e9c217e04e2620bf98cfddd3 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:35 +0100 Subject: net: stmmac: gmac4+: Add Split Header support GMAC4+ cores also support the Split Header feature. Add the support for Split Header feature in the RX path following the same implementation logic that XGMAC followed. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 7 +++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 21 ++++++++++++++++++--- drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 19 +++++++++++++++++++ drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h | 1 + 5 files changed, 46 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 07e97f45755d..2dc70d104161 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -14,6 +14,7 @@ /* MAC registers */ #define GMAC_CONFIG 0x00000000 +#define GMAC_EXT_CONFIG 0x00000004 #define GMAC_PACKET_FILTER 0x00000008 #define GMAC_HASH_TAB(x) (0x10 + (x) * 4) #define GMAC_VLAN_TAG 0x00000050 @@ -188,6 +189,11 @@ enum power_event { #define GMAC_CONFIG_TE BIT(1) #define GMAC_CONFIG_RE BIT(0) +/* MAC extended config */ +#define GMAC_CONFIG_HDSMS GENMASK(22, 20) +#define GMAC_CONFIG_HDSMS_SHIFT 20 +#define GMAC_CONFIG_HDSMS_256 (0x2 << GMAC_CONFIG_HDSMS_SHIFT) + /* MAC HW features0 bitmap */ #define GMAC_HW_FEAT_SAVLANINS BIT(27) #define GMAC_HW_FEAT_ADDMAC BIT(18) @@ -211,6 +217,7 @@ enum power_event { #define GMAC_HW_HASH_TB_SZ GENMASK(25, 24) #define GMAC_HW_FEAT_AVSEL BIT(20) #define GMAC_HW_TSOEN BIT(18) +#define GMAC_HW_FEAT_SPHEN BIT(17) #define GMAC_HW_ADDR64 GENMASK(15, 14) #define GMAC_HW_TXFIFOSIZE GENMASK(10, 6) #define GMAC_HW_RXFIFOSIZE GENMASK(4, 0) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index 707ab5eba8da..3e14da69f378 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -83,9 +83,10 @@ static int dwmac4_wrback_get_rx_status(void *data, struct stmmac_extra_stats *x, if (unlikely(rdes3 & RDES3_OWN)) return dma_own; - /* Verify rx error by looking at the last segment. */ - if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR))) + if (unlikely(rdes3 & RDES3_CONTEXT_DESCRIPTOR)) return discard_frame; + if (likely(!(rdes3 & RDES3_LAST_DESCRIPTOR))) + return rx_not_ls; if (unlikely(rdes3 & RDES3_ERROR_SUMMARY)) { if (unlikely(rdes3 & RDES3_GIANT_PACKET)) @@ -188,7 +189,7 @@ static void dwmac4_set_tx_owner(struct dma_desc *p) static void dwmac4_set_rx_owner(struct dma_desc *p, int disable_rx_ic) { - p->des3 = cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR); + p->des3 |= cpu_to_le32(RDES3_OWN | RDES3_BUFFER1_VALID_ADDR); if (!disable_rx_ic) p->des3 |= cpu_to_le32(RDES3_INT_ON_COMPLETION_EN); @@ -492,6 +493,18 @@ static void dwmac4_set_vlan(struct dma_desc *p, u32 type) p->des2 |= cpu_to_le32(type & TDES2_VLAN_TAG_MASK); } +static int dwmac4_get_rx_header_len(struct dma_desc *p, unsigned int *len) +{ + *len = le32_to_cpu(p->des2) & RDES2_HL; + return 0; +} + +static void dwmac4_set_sec_addr(struct dma_desc *p, dma_addr_t addr) +{ + p->des2 = cpu_to_le32(lower_32_bits(addr)); + p->des3 = cpu_to_le32(upper_32_bits(addr) | RDES3_BUFFER2_VALID_ADDR); +} + const struct stmmac_desc_ops dwmac4_desc_ops = { .tx_status = dwmac4_wrback_get_tx_status, .rx_status = dwmac4_wrback_get_rx_status, @@ -519,6 +532,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = { .set_sarc = dwmac4_set_sarc, .set_vlan_tag = dwmac4_set_vlan_tag, .set_vlan = dwmac4_set_vlan, + .get_rx_header_len = dwmac4_get_rx_header_len, + .set_sec_addr = dwmac4_set_sec_addr, }; const struct stmmac_mode_ops dwmac4_ring_mode_ops = { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h index 0d7b3bbcd5a7..6d92109dc9aa 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.h @@ -109,6 +109,7 @@ #define RDES2_L4_FILTER_MATCH BIT(28) #define RDES2_L3_L4_FILT_NB_MATCH_MASK GENMASK(27, 26) #define RDES2_L3_L4_FILT_NB_MATCH_SHIFT 26 +#define RDES2_HL GENMASK(9, 0) /* RDES3 (write back format) */ #define RDES3_PACKET_SIZE_MASK GENMASK(14, 0) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index b24c89572745..36a0af8bf89f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -368,6 +368,7 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr, dma_cap->hash_tb_sz = (hw_cap & GMAC_HW_HASH_TB_SZ) >> 24; dma_cap->av = (hw_cap & GMAC_HW_FEAT_AVSEL) >> 20; dma_cap->tsoen = (hw_cap & GMAC_HW_TSOEN) >> 18; + dma_cap->sphen = (hw_cap & GMAC_HW_FEAT_SPHEN) >> 17; dma_cap->addr64 = (hw_cap & GMAC_HW_ADDR64) >> 14; switch (dma_cap->addr64) { @@ -460,6 +461,22 @@ static void dwmac4_set_bfsize(void __iomem *ioaddr, int bfsize, u32 chan) writel(value, ioaddr + DMA_CHAN_RX_CONTROL(chan)); } +static void dwmac4_enable_sph(void __iomem *ioaddr, bool en, u32 chan) +{ + u32 value = readl(ioaddr + GMAC_EXT_CONFIG); + + value &= ~GMAC_CONFIG_HDSMS; + value |= GMAC_CONFIG_HDSMS_256; /* Segment max 256 bytes */ + writel(value, ioaddr + GMAC_EXT_CONFIG); + + value = readl(ioaddr + DMA_CHAN_CONTROL(chan)); + if (en) + value |= DMA_CONTROL_SPH; + else + value &= ~DMA_CONTROL_SPH; + writel(value, ioaddr + DMA_CHAN_CONTROL(chan)); +} + const struct stmmac_dma_ops dwmac4_dma_ops = { .reset = dwmac4_dma_reset, .init = dwmac4_dma_init, @@ -486,6 +503,7 @@ const struct stmmac_dma_ops dwmac4_dma_ops = { .enable_tso = dwmac4_enable_tso, .qmode = dwmac4_qmode, .set_bfsize = dwmac4_set_bfsize, + .enable_sph = dwmac4_enable_sph, }; const struct stmmac_dma_ops dwmac410_dma_ops = { @@ -514,4 +532,5 @@ const struct stmmac_dma_ops dwmac410_dma_ops = { .enable_tso = dwmac4_enable_tso, .qmode = dwmac4_qmode, .set_bfsize = dwmac4_set_bfsize, + .enable_sph = dwmac4_enable_sph, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index 5299fa1001a3..589931795847 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -110,6 +110,7 @@ #define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x60) /* DMA Control X */ +#define DMA_CONTROL_SPH BIT(24) #define DMA_CONTROL_MSS_MASK GENMASK(13, 0) /* DMA Tx Channel X Control register defines */ -- cgit v1.2.3-59-g8ed1b From 04d1190aca774792e0304bef5624ee8a47331ca2 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:36 +0100 Subject: net: stmmac: xgmac: Add C45 PHY support in the MDIO callbacks Add the support for C45 PHYs in the MDIO callbacks for XGMAC. This was tested using Synopsys DesignWare XPCS. v2: - Pull out the readl_poll_timeout() calls into common code (Andrew) Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 58 +++++++++++++++++++---- 1 file changed, 48 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 40c42637ad75..cfe5d8b73142 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -41,20 +41,32 @@ #define MII_XGMAC_BUSY BIT(22) #define MII_XGMAC_MAX_C22ADDR 3 #define MII_XGMAC_C22P_MASK GENMASK(MII_XGMAC_MAX_C22ADDR, 0) +#define MII_XGMAC_PA_SHIFT 16 +#define MII_XGMAC_DA_SHIFT 21 + +static int stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, + int phyreg, u32 *hw_addr) +{ + u32 tmp; + + /* Set port as Clause 45 */ + tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); + tmp &= ~BIT(phyaddr); + writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); + + *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0xffff); + *hw_addr |= (phyreg >> MII_DEVADDR_C45_SHIFT) << MII_XGMAC_DA_SHIFT; + return 0; +} static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, int phyreg, u32 *hw_addr) { - unsigned int mii_data = priv->hw->mii.data; u32 tmp; /* HW does not support C22 addr >= 4 */ if (phyaddr > MII_XGMAC_MAX_C22ADDR) return -ENODEV; - /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) - return -EBUSY; /* Set port as Clause 22 */ tmp = readl(priv->ioaddr + XGMAC_MDIO_C22P); @@ -62,7 +74,7 @@ static int stmmac_xgmac2_c22_format(struct stmmac_priv *priv, int phyaddr, tmp |= BIT(phyaddr); writel(tmp, priv->ioaddr + XGMAC_MDIO_C22P); - *hw_addr = (phyaddr << 16) | (phyreg & 0x1f); + *hw_addr = (phyaddr << MII_XGMAC_PA_SHIFT) | (phyreg & 0x1f); return 0; } @@ -75,17 +87,28 @@ static int stmmac_xgmac2_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) u32 tmp, addr, value = MII_XGMAC_BUSY; int ret; + /* Wait until any existing MII operation is complete */ + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, + !(tmp & MII_XGMAC_BUSY), 100, 10000)) + return -EBUSY; + if (phyreg & MII_ADDR_C45) { - return -EOPNOTSUPP; + phyreg &= ~MII_ADDR_C45; + + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); + if (ret) + return ret; } else { ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); if (ret) return ret; + + value |= MII_XGMAC_SADDR; } value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) & priv->hw->mii.clk_csr_mask; - value |= MII_XGMAC_SADDR | MII_XGMAC_READ; + value |= MII_XGMAC_READ; /* Wait until any existing MII operation is complete */ if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, @@ -115,17 +138,28 @@ static int stmmac_xgmac2_mdio_write(struct mii_bus *bus, int phyaddr, u32 addr, tmp, value = MII_XGMAC_BUSY; int ret; + /* Wait until any existing MII operation is complete */ + if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, + !(tmp & MII_XGMAC_BUSY), 100, 10000)) + return -EBUSY; + if (phyreg & MII_ADDR_C45) { - return -EOPNOTSUPP; + phyreg &= ~MII_ADDR_C45; + + ret = stmmac_xgmac2_c45_format(priv, phyaddr, phyreg, &addr); + if (ret) + return ret; } else { ret = stmmac_xgmac2_c22_format(priv, phyaddr, phyreg, &addr); if (ret) return ret; + + value |= MII_XGMAC_SADDR; } value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) & priv->hw->mii.clk_csr_mask; - value |= phydata | MII_XGMAC_SADDR; + value |= phydata; value |= MII_XGMAC_WRITE; /* Wait until any existing MII operation is complete */ @@ -363,6 +397,10 @@ int stmmac_mdio_register(struct net_device *ndev) goto bus_register_fail; } + /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ + if (priv->plat->has_xgmac) + stmmac_xgmac2_mdio_read(new_bus, 0, MII_ADDR_C45); + if (priv->plat->phy_node || mdio_node) goto bus_register_done; -- cgit v1.2.3-59-g8ed1b From bc41a6689b30abaf213c66ac574beefb6d02717c Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:37 +0100 Subject: net: stmmac: tc: Remove the speed dependency XGMAC3 supports full CBS features with speeds that can go up to 10G so we can now remove the maximum speed check of CBS. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index f9a9a9d82233..7d972e0fd2b0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -321,8 +321,6 @@ static int tc_setup_cbs(struct stmmac_priv *priv, return -EINVAL; if (!priv->dma_cap.av) return -EOPNOTSUPP; - if (priv->speed != SPEED_100 && priv->speed != SPEED_1000) - return -EOPNOTSUPP; mode_to_use = priv->plat->tx_queues_cfg[queue].mode_to_use; if (mode_to_use == MTL_QUEUE_DCB && qopt->enable) { -- cgit v1.2.3-59-g8ed1b From 88ebe2cf7f3fc9da95e0f06483fd58da3e67e675 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:38 +0100 Subject: net: stmmac: Rework stmmac_rx() This looks over-engineered. Let's use some helpers to get the buffer length and hereby simplify the stmmac_rx() function. No performance drop was seen with the new implementation. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 146 ++++++++++++++-------- 1 file changed, 94 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5f40fbb67bac..a2fac7772666 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3443,6 +3443,55 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue); } +static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv, + struct dma_desc *p, + int status, unsigned int len) +{ + int ret, coe = priv->hw->rx_csum; + unsigned int plen = 0, hlen = 0; + + /* Not first descriptor, buffer is always zero */ + if (priv->sph && len) + return 0; + + /* First descriptor, get split header length */ + ret = stmmac_get_rx_header_len(priv, p, &hlen); + if (priv->sph && hlen) { + priv->xstats.rx_split_hdr_pkt_n++; + return hlen; + } + + /* First descriptor, not last descriptor and not split header */ + if (status & rx_not_ls) + return priv->dma_buf_sz; + + plen = stmmac_get_rx_frame_len(priv, p, coe); + + /* First descriptor and last descriptor and not split header */ + return min_t(unsigned int, priv->dma_buf_sz, plen); +} + +static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, + struct dma_desc *p, + int status, unsigned int len) +{ + int coe = priv->hw->rx_csum; + unsigned int plen = 0; + + /* Not split header, buffer is not available */ + if (!priv->sph) + return 0; + + /* Not last descriptor */ + if (status & rx_not_ls) + return priv->dma_buf_sz; + + plen = stmmac_get_rx_frame_len(priv, p, coe); + + /* Last descriptor */ + return plen - len; +} + /** * stmmac_rx - manage the receive process * @priv: driver private structure @@ -3472,11 +3521,10 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true); } while (count < limit) { - unsigned int hlen = 0, prev_len = 0; + unsigned int buf1_len = 0, buf2_len = 0; enum pkt_hash_types hash_type; struct stmmac_rx_buffer *buf; struct dma_desc *np, *p; - unsigned int sec_len; int entry; u32 hash; @@ -3495,7 +3543,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) break; read_again: - sec_len = 0; + buf1_len = 0; + buf2_len = 0; entry = next_entry; buf = &rx_q->buf_pool[entry]; @@ -3520,7 +3569,6 @@ read_again: np = rx_q->dma_rx + next_entry; prefetch(np); - prefetch(page_address(buf->page)); if (priv->extend_desc) stmmac_rx_extended_status(priv, &priv->dev->stats, @@ -3537,69 +3585,61 @@ read_again: goto read_again; if (unlikely(error)) { dev_kfree_skb(skb); + skb = NULL; count++; continue; } /* Buffer is good. Go on. */ - if (likely(status & rx_not_ls)) { - len += priv->dma_buf_sz; - } else { - prev_len = len; - len = stmmac_get_rx_frame_len(priv, p, coe); - - /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 - * Type frames (LLC/LLC-SNAP) - * - * llc_snap is never checked in GMAC >= 4, so this ACS - * feature is always disabled and packets need to be - * stripped manually. - */ - if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) || - unlikely(status != llc_snap)) - len -= ETH_FCS_LEN; + prefetch(page_address(buf->page)); + if (buf->sec_page) + prefetch(page_address(buf->sec_page)); + + buf1_len = stmmac_rx_buf1_len(priv, p, status, len); + len += buf1_len; + buf2_len = stmmac_rx_buf2_len(priv, p, status, len); + len += buf2_len; + + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 + * Type frames (LLC/LLC-SNAP) + * + * llc_snap is never checked in GMAC >= 4, so this ACS + * feature is always disabled and packets need to be + * stripped manually. + */ + if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00) || + unlikely(status != llc_snap)) { + if (buf2_len) + buf2_len -= ETH_FCS_LEN; + else + buf1_len -= ETH_FCS_LEN; + + len -= ETH_FCS_LEN; } if (!skb) { - int ret = stmmac_get_rx_header_len(priv, p, &hlen); - - if (priv->sph && !ret && (hlen > 0)) { - sec_len = len; - if (!(status & rx_not_ls)) - sec_len = sec_len - hlen; - len = hlen; - - prefetch(page_address(buf->sec_page)); - priv->xstats.rx_split_hdr_pkt_n++; - } - - skb = napi_alloc_skb(&ch->rx_napi, len); + skb = napi_alloc_skb(&ch->rx_napi, buf1_len); if (!skb) { priv->dev->stats.rx_dropped++; count++; - continue; + goto drain_data; } - dma_sync_single_for_cpu(priv->device, buf->addr, len, - DMA_FROM_DEVICE); + dma_sync_single_for_cpu(priv->device, buf->addr, + buf1_len, DMA_FROM_DEVICE); skb_copy_to_linear_data(skb, page_address(buf->page), - len); - skb_put(skb, len); + buf1_len); + skb_put(skb, buf1_len); /* Data payload copied into SKB, page ready for recycle */ page_pool_recycle_direct(rx_q->page_pool, buf->page); buf->page = NULL; - } else { - unsigned int buf_len = len - prev_len; - - if (likely(status & rx_not_ls)) - buf_len = priv->dma_buf_sz; - + } else if (buf1_len) { dma_sync_single_for_cpu(priv->device, buf->addr, - buf_len, DMA_FROM_DEVICE); + buf1_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - buf->page, 0, buf_len, + buf->page, 0, buf1_len, priv->dma_buf_sz); /* Data payload appended into SKB */ @@ -3607,22 +3647,23 @@ read_again: buf->page = NULL; } - if (sec_len > 0) { + if (buf2_len) { dma_sync_single_for_cpu(priv->device, buf->sec_addr, - sec_len, DMA_FROM_DEVICE); + buf2_len, DMA_FROM_DEVICE); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - buf->sec_page, 0, sec_len, + buf->sec_page, 0, buf2_len, priv->dma_buf_sz); - len += sec_len; - /* Data payload appended into SKB */ page_pool_release_page(rx_q->page_pool, buf->sec_page); buf->sec_page = NULL; } +drain_data: if (likely(status & rx_not_ls)) goto read_again; + if (!skb) + continue; /* Got entire packet into SKB. Finish it. */ @@ -3640,13 +3681,14 @@ read_again: skb_record_rx_queue(skb, queue); napi_gro_receive(&ch->rx_napi, skb); + skb = NULL; priv->dev->stats.rx_packets++; priv->dev->stats.rx_bytes += len; count++; } - if (status & rx_not_ls) { + if (status & rx_not_ls || skb) { rx_q->state_saved = true; rx_q->state.skb = skb; rx_q->state.error = error; -- cgit v1.2.3-59-g8ed1b From b776620651a1182976b51643bb2c5b08d535fb2e Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Mon, 11 Nov 2019 15:42:39 +0100 Subject: net: stmmac: Implement UDP Segmentation Offload Implement the UDP Segmentation Offload feature in stmmac. This is only available in GMAC4+ cores. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 32 ++++++++++++++++------- 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a2fac7772666..39b4efd521f9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -36,6 +36,7 @@ #endif /* CONFIG_DEBUG_FS */ #include #include +#include #include #include "stmmac_ptp.h" #include "stmmac.h" @@ -2916,9 +2917,9 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) u32 queue = skb_get_queue_mapping(skb); struct stmmac_tx_queue *tx_q; unsigned int first_entry; + u8 proto_hdr_len, hdr; int tmp_pay_len = 0; u32 pay_len, mss; - u8 proto_hdr_len; dma_addr_t des; bool has_vlan; int i; @@ -2926,7 +2927,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) tx_q = &priv->tx_queue[queue]; /* Compute header lengths */ - proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { + proto_hdr_len = skb_transport_offset(skb) + sizeof(struct udphdr); + hdr = sizeof(struct udphdr); + } else { + proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + hdr = tcp_hdrlen(skb); + } /* Desc availability based on threshold should be enough safe */ if (unlikely(stmmac_tx_avail(priv, queue) < @@ -2956,8 +2963,8 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) } if (netif_msg_tx_queued(priv)) { - pr_info("%s: tcphdrlen %d, hdr_len %d, pay_len %d, mss %d\n", - __func__, tcp_hdrlen(skb), proto_hdr_len, pay_len, mss); + pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n", + __func__, hdr, proto_hdr_len, pay_len, mss); pr_info("\tskb->len %d, skb->data_len %d\n", skb->len, skb->data_len); } @@ -3071,7 +3078,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) proto_hdr_len, pay_len, 1, tx_q->tx_skbuff_dma[first_entry].last_segment, - tcp_hdrlen(skb) / 4, (skb->len - proto_hdr_len)); + hdr / 4, (skb->len - proto_hdr_len)); /* If context desc is used to change MSS */ if (mss_desc) { @@ -3130,6 +3137,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) int i, csum_insertion = 0, is_jumbo = 0; u32 queue = skb_get_queue_mapping(skb); int nfrags = skb_shinfo(skb)->nr_frags; + int gso = skb_shinfo(skb)->gso_type; struct dma_desc *desc, *first; struct stmmac_tx_queue *tx_q; unsigned int first_entry; @@ -3145,7 +3153,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* Manage oversized TCP frames for GMAC4 device */ if (skb_is_gso(skb) && priv->tso) { - if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) + if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) + return stmmac_tso_xmit(skb, dev); + if (priv->plat->has_gmac4 && (gso & SKB_GSO_UDP_L4)) return stmmac_tso_xmit(skb, dev); } @@ -4036,11 +4046,13 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type, static u16 stmmac_select_queue(struct net_device *dev, struct sk_buff *skb, struct net_device *sb_dev) { - if (skb_shinfo(skb)->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { + int gso = skb_shinfo(skb)->gso_type; + + if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6 | SKB_GSO_UDP_L4)) { /* - * There is no way to determine the number of TSO + * There is no way to determine the number of TSO/USO * capable Queues. Let's use always the Queue 0 - * because if TSO is supported then at least this + * because if TSO/USO is supported then at least this * one will be capable. */ return 0; @@ -4555,6 +4567,8 @@ int stmmac_dvr_probe(struct device *device, if ((priv->plat->tso_en) && (priv->dma_cap.tsoen)) { ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + if (priv->plat->has_gmac4) + ndev->hw_features |= NETIF_F_GSO_UDP_L4; priv->tso = true; dev_info(priv->device, "TSO feature enabled\n"); } -- cgit v1.2.3-59-g8ed1b From b2ef81dcdf3835bd55e5f97ff30131bb327be7fa Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Tue, 12 Nov 2019 14:33:58 +0800 Subject: net: ethernet: ti: Add dependency for TI_DAVINCI_EMAC If TI_DAVINCI_EMAC=y and GENERIC_ALLOCATOR is not set, below erros can be seen: drivers/net/ethernet/ti/davinci_cpdma.o: In function `cpdma_desc_pool_destroy.isra.14': davinci_cpdma.c:(.text+0x359): undefined reference to `gen_pool_size' davinci_cpdma.c:(.text+0x365): undefined reference to `gen_pool_avail' davinci_cpdma.c:(.text+0x373): undefined reference to `gen_pool_avail' davinci_cpdma.c:(.text+0x37f): undefined reference to `gen_pool_size' drivers/net/ethernet/ti/davinci_cpdma.o: In function `__cpdma_chan_free': davinci_cpdma.c:(.text+0x4a2): undefined reference to `gen_pool_free_owner' drivers/net/ethernet/ti/davinci_cpdma.o: In function `cpdma_chan_submit_si': davinci_cpdma.c:(.text+0x66c): undefined reference to `gen_pool_alloc_algo_owner' davinci_cpdma.c:(.text+0x805): undefined reference to `gen_pool_free_owner' drivers/net/ethernet/ti/davinci_cpdma.o: In function `cpdma_ctlr_create': davinci_cpdma.c:(.text+0xabd): undefined reference to `devm_gen_pool_create' davinci_cpdma.c:(.text+0xb79): undefined reference to `gen_pool_add_owner' drivers/net/ethernet/ti/davinci_cpdma.o: In function `cpdma_check_free_tx_desc': davinci_cpdma.c:(.text+0x16c6): undefined reference to `gen_pool_avail' This patch mades TI_DAVINCI_EMAC select GENERIC_ALLOCATOR. Fixes: 99f629718272 ("net: ethernet: ti: cpsw: drop TI_DAVINCI_CPDMA config option") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 834afca3a019..137632b09c72 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -22,6 +22,7 @@ config TI_DAVINCI_EMAC depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 ) || COMPILE_TEST select TI_DAVINCI_MDIO select PHYLIB + select GENERIC_ALLOCATOR ---help--- This driver supports TI's DaVinci Ethernet . -- cgit v1.2.3-59-g8ed1b From 5aa4165c60aaade3aebe0c5278111781142a5636 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:24 +0200 Subject: mlxsw: core: Parse TLVs' offsets of incoming EMADs Until now the code assumes a fixed structure which makes it difficult to support EMADs with and without new TLVs. Make it more generic by parsing the TLVs when the EMADs are received and store the offset to the different TLVs in the control block. Using these offsets to extract information from the EMADs without relying on a specific structure. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 53 +++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 42e1ce3e39e1..698c7bcb1aad 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -361,20 +361,45 @@ static void mlxsw_emad_construct(struct sk_buff *skb, mlxsw_emad_construct_eth_hdr(skb); } +struct mlxsw_emad_tlv_offsets { + u16 op_tlv; + u16 reg_tlv; +}; + +static void mlxsw_emad_tlv_parse(struct sk_buff *skb) +{ + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN; + offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN + + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); +} + static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) { - return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN)); + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + return ((char *) (skb->data + offsets->op_tlv)); } static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb) { - return ((char *) (skb->data + MLXSW_EMAD_ETH_HDR_LEN + - MLXSW_EMAD_OP_TLV_LEN * sizeof(u32))); + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + return ((char *) (skb->data + offsets->reg_tlv)); } -static char *mlxsw_emad_reg_payload(const char *op_tlv) +static char *mlxsw_emad_reg_payload(const char *reg_tlv) { - return ((char *) (op_tlv + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); + return ((char *) (reg_tlv + sizeof(u32))); +} + +static char *mlxsw_emad_reg_payload_cmd(const char *mbox) +{ + return ((char *) (mbox + (MLXSW_EMAD_OP_TLV_LEN + 1) * sizeof(u32))); } static u64 mlxsw_emad_get_tid(const struct sk_buff *skb) @@ -535,11 +560,11 @@ static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core, mlxsw_emad_transmit_retry(mlxsw_core, trans); } else { if (err == 0) { - char *op_tlv = mlxsw_emad_op_tlv(skb); + char *reg_tlv = mlxsw_emad_reg_tlv(skb); if (trans->cb) trans->cb(mlxsw_core, - mlxsw_emad_reg_payload(op_tlv), + mlxsw_emad_reg_payload(reg_tlv), trans->reg->len, trans->cb_priv); } mlxsw_emad_trans_finish(trans, err); @@ -556,6 +581,8 @@ static void mlxsw_emad_rx_listener_func(struct sk_buff *skb, u8 local_port, trace_devlink_hwmsg(priv_to_devlink(mlxsw_core), true, 0, skb->data, skb->len); + mlxsw_emad_tlv_parse(skb); + if (!mlxsw_emad_is_resp(skb)) goto free_skb; @@ -1395,12 +1422,16 @@ static void mlxsw_core_event_listener_func(struct sk_buff *skb, u8 local_port, struct mlxsw_event_listener_item *event_listener_item = priv; struct mlxsw_reg_info reg; char *payload; - char *op_tlv = mlxsw_emad_op_tlv(skb); - char *reg_tlv = mlxsw_emad_reg_tlv(skb); + char *reg_tlv; + char *op_tlv; + + mlxsw_emad_tlv_parse(skb); + op_tlv = mlxsw_emad_op_tlv(skb); + reg_tlv = mlxsw_emad_reg_tlv(skb); reg.id = mlxsw_emad_op_tlv_register_id_get(op_tlv); reg.len = (mlxsw_emad_reg_tlv_len_get(reg_tlv) - 1) * sizeof(u32); - payload = mlxsw_emad_reg_payload(op_tlv); + payload = mlxsw_emad_reg_payload(reg_tlv); event_listener_item->el.func(®, payload, event_listener_item->priv); dev_kfree_skb(skb); } @@ -1713,7 +1744,7 @@ retry: } if (!err) - memcpy(payload, mlxsw_emad_reg_payload(out_mbox), + memcpy(payload, mlxsw_emad_reg_payload_cmd(out_mbox), reg->len); mlxsw_cmd_mbox_free(out_mbox); -- cgit v1.2.3-59-g8ed1b From d17eb4030cc3061d3d2f313b9b898103701c44a4 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:25 +0200 Subject: mlxsw: emad: Remove deprecated EMAD TLVs Remove deprecated EMAD TLVs. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/emad.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/emad.h b/drivers/net/ethernet/mellanox/mlxsw/emad.h index a33b896f4bb8..5d7c78419fa7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/emad.h +++ b/drivers/net/ethernet/mellanox/mlxsw/emad.h @@ -19,10 +19,7 @@ enum { MLXSW_EMAD_TLV_TYPE_END, MLXSW_EMAD_TLV_TYPE_OP, - MLXSW_EMAD_TLV_TYPE_DR, - MLXSW_EMAD_TLV_TYPE_REG, - MLXSW_EMAD_TLV_TYPE_USERDATA, - MLXSW_EMAD_TLV_TYPE_OOBETH, + MLXSW_EMAD_TLV_TYPE_REG = 0x3, }; /* OP TLV */ -- cgit v1.2.3-59-g8ed1b From 664b3dd9ba58462d1f74f2c9536e500898450edc Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:26 +0200 Subject: mlxsw: core: Add EMAD string TLV Add EMAD string TLV, an ASCII string the driver can receive from the firmware in case of an error. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 19 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlxsw/emad.h | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 698c7bcb1aad..a50a36f9584b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -249,6 +249,25 @@ MLXSW_ITEM32(emad, op_tlv, class, 0x04, 0, 8); */ MLXSW_ITEM64(emad, op_tlv, tid, 0x08, 0, 64); +/* emad_string_tlv_type + * Type of the TLV. + * Must be set to 0x2 (string TLV). + */ +MLXSW_ITEM32(emad, string_tlv, type, 0x00, 27, 5); + +/* emad_string_tlv_len + * Length of the string TLV in u32. + */ +MLXSW_ITEM32(emad, string_tlv, len, 0x00, 16, 11); + +#define MLXSW_EMAD_STRING_TLV_STRING_LEN 128 + +/* emad_string_tlv_string + * String provided by the device's firmware in case of erroneous register access + */ +MLXSW_ITEM_BUF(emad, string_tlv, string, 0x04, + MLXSW_EMAD_STRING_TLV_STRING_LEN); + /* emad_reg_tlv_type * Type of the TLV. * Must be set to 0x3 (register TLV). diff --git a/drivers/net/ethernet/mellanox/mlxsw/emad.h b/drivers/net/ethernet/mellanox/mlxsw/emad.h index 5d7c78419fa7..acfbbec52424 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/emad.h +++ b/drivers/net/ethernet/mellanox/mlxsw/emad.h @@ -19,7 +19,8 @@ enum { MLXSW_EMAD_TLV_TYPE_END, MLXSW_EMAD_TLV_TYPE_OP, - MLXSW_EMAD_TLV_TYPE_REG = 0x3, + MLXSW_EMAD_TLV_TYPE_STRING, + MLXSW_EMAD_TLV_TYPE_REG, }; /* OP TLV */ @@ -86,6 +87,9 @@ enum { MLXSW_EMAD_OP_TLV_METHOD_EVENT = 5, }; +/* STRING TLV */ +#define MLXSW_EMAD_STRING_TLV_LEN 33 /* Length in u32 */ + /* END TLV */ #define MLXSW_EMAD_END_TLV_LEN 1 /* Length in u32 */ -- cgit v1.2.3-59-g8ed1b From 2aa4aa2051f86d032ef86a268b38569cb3d450d0 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:27 +0200 Subject: mlxsw: core: Add support for EMAD string TLV parsing During parsing of incoming EMADs, fill the string TLV's offset when it is used. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index a50a36f9584b..d834bdc632ef 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -382,17 +382,32 @@ static void mlxsw_emad_construct(struct sk_buff *skb, struct mlxsw_emad_tlv_offsets { u16 op_tlv; + u16 string_tlv; u16 reg_tlv; }; +static bool mlxsw_emad_tlv_is_string_tlv(const char *tlv) +{ + u8 tlv_type = mlxsw_emad_string_tlv_type_get(tlv); + + return tlv_type == MLXSW_EMAD_TLV_TYPE_STRING; +} + static void mlxsw_emad_tlv_parse(struct sk_buff *skb) { struct mlxsw_emad_tlv_offsets *offsets = (struct mlxsw_emad_tlv_offsets *) skb->cb; offsets->op_tlv = MLXSW_EMAD_ETH_HDR_LEN; + offsets->string_tlv = 0; offsets->reg_tlv = MLXSW_EMAD_ETH_HDR_LEN + MLXSW_EMAD_OP_TLV_LEN * sizeof(u32); + + /* If string TLV is present, it must come after the operation TLV. */ + if (mlxsw_emad_tlv_is_string_tlv(skb->data + offsets->reg_tlv)) { + offsets->string_tlv = offsets->reg_tlv; + offsets->reg_tlv += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); + } } static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) -- cgit v1.2.3-59-g8ed1b From 72c8f428b5dc786d901d00370fa88923b40d7539 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:28 +0200 Subject: mlxsw: core: Extend EMAD information reported to devlink hwerr Extend EMAD information reported to devlink hwerr tracepoint with transaction id and reg id (both, hex and string). Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index d834bdc632ef..d6a10727d4e6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1683,8 +1683,11 @@ int mlxsw_reg_trans_write(struct mlxsw_core *mlxsw_core, } EXPORT_SYMBOL(mlxsw_reg_trans_write); +#define MLXSW_REG_TRANS_ERR_STRING_SIZE 256 + static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) { + char err_string[MLXSW_REG_TRANS_ERR_STRING_SIZE]; struct mlxsw_core *mlxsw_core = trans->core; int err; @@ -1702,9 +1705,14 @@ static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) mlxsw_core_reg_access_type_str(trans->type), trans->emad_status, mlxsw_emad_op_tlv_status_str(trans->emad_status)); + + snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE, + "(tid=%llx,reg_id=%x(%s)) %s\n", trans->tid, + trans->reg->id, mlxsw_reg_id_str(trans->reg->id), + mlxsw_emad_op_tlv_status_str(trans->emad_status)); + trace_devlink_hwerr(priv_to_devlink(mlxsw_core), - trans->emad_status, - mlxsw_emad_op_tlv_status_str(trans->emad_status)); + trans->emad_status, err_string); } list_del(&trans->bulk_list); -- cgit v1.2.3-59-g8ed1b From 5d716ab45ad5e02461cb3b33062573d7cf43596a Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:29 +0200 Subject: mlxsw: core: Add support for using EMAD string TLV In case the firmware had an error while processing EMADs, it can send back an ASCII string with the reason using EMAD string TLV. This patch adds the support for using EMAD string TLV. In case of an error, reports the reason using devlink hwerr tracepoint. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 76 +++++++++++++++++++++++++++--- drivers/net/ethernet/mellanox/mlxsw/core.h | 2 + 2 files changed, 72 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index d6a10727d4e6..e9f791c43f20 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -71,6 +71,7 @@ struct mlxsw_core { struct list_head trans_list; spinlock_t trans_list_lock; /* protects trans_list writes */ bool use_emad; + bool enable_string_tlv; } emad; struct { u8 *mapping; /* lag_id+port_index to local_port mapping */ @@ -323,6 +324,12 @@ static void mlxsw_emad_pack_reg_tlv(char *reg_tlv, memcpy(reg_tlv + sizeof(u32), payload, reg->len); } +static void mlxsw_emad_pack_string_tlv(char *string_tlv) +{ + mlxsw_emad_string_tlv_type_set(string_tlv, MLXSW_EMAD_TLV_TYPE_STRING); + mlxsw_emad_string_tlv_len_set(string_tlv, MLXSW_EMAD_STRING_TLV_LEN); +} + static void mlxsw_emad_pack_op_tlv(char *op_tlv, const struct mlxsw_reg_info *reg, enum mlxsw_core_reg_access_type type, @@ -364,7 +371,7 @@ static void mlxsw_emad_construct(struct sk_buff *skb, const struct mlxsw_reg_info *reg, char *payload, enum mlxsw_core_reg_access_type type, - u64 tid) + u64 tid, bool enable_string_tlv) { char *buf; @@ -374,6 +381,11 @@ static void mlxsw_emad_construct(struct sk_buff *skb, buf = skb_push(skb, reg->len + sizeof(u32)); mlxsw_emad_pack_reg_tlv(buf, reg, payload); + if (enable_string_tlv) { + buf = skb_push(skb, MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32)); + mlxsw_emad_pack_string_tlv(buf); + } + buf = skb_push(skb, MLXSW_EMAD_OP_TLV_LEN * sizeof(u32)); mlxsw_emad_pack_op_tlv(buf, reg, type, tid); @@ -418,6 +430,17 @@ static char *mlxsw_emad_op_tlv(const struct sk_buff *skb) return ((char *) (skb->data + offsets->op_tlv)); } +static char *mlxsw_emad_string_tlv(const struct sk_buff *skb) +{ + struct mlxsw_emad_tlv_offsets *offsets = + (struct mlxsw_emad_tlv_offsets *) skb->cb; + + if (!offsets->string_tlv) + return NULL; + + return ((char *) (skb->data + offsets->string_tlv)); +} + static char *mlxsw_emad_reg_tlv(const struct sk_buff *skb) { struct mlxsw_emad_tlv_offsets *offsets = @@ -499,10 +522,31 @@ struct mlxsw_reg_trans { const struct mlxsw_reg_info *reg; enum mlxsw_core_reg_access_type type; int err; + char *emad_err_string; enum mlxsw_emad_op_tlv_status emad_status; struct rcu_head rcu; }; +static void mlxsw_emad_process_string_tlv(const struct sk_buff *skb, + struct mlxsw_reg_trans *trans) +{ + char *string_tlv; + char *string; + + string_tlv = mlxsw_emad_string_tlv(skb); + if (!string_tlv) + return; + + trans->emad_err_string = kzalloc(MLXSW_EMAD_STRING_TLV_STRING_LEN, + GFP_ATOMIC); + if (!trans->emad_err_string) + return; + + string = mlxsw_emad_string_tlv_string_data(string_tlv); + strlcpy(trans->emad_err_string, string, + MLXSW_EMAD_STRING_TLV_STRING_LEN); +} + #define MLXSW_EMAD_TIMEOUT_DURING_FW_FLASH_MS 3000 #define MLXSW_EMAD_TIMEOUT_MS 200 @@ -600,6 +644,8 @@ static void mlxsw_emad_process_response(struct mlxsw_core *mlxsw_core, trans->cb(mlxsw_core, mlxsw_emad_reg_payload(reg_tlv), trans->reg->len, trans->cb_priv); + } else { + mlxsw_emad_process_string_tlv(skb, trans); } mlxsw_emad_trans_finish(trans, err); } @@ -692,7 +738,7 @@ static void mlxsw_emad_fini(struct mlxsw_core *mlxsw_core) } static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, - u16 reg_len) + u16 reg_len, bool enable_string_tlv) { struct sk_buff *skb; u16 emad_len; @@ -700,6 +746,8 @@ static struct sk_buff *mlxsw_emad_alloc(const struct mlxsw_core *mlxsw_core, emad_len = (reg_len + sizeof(u32) + MLXSW_EMAD_ETH_HDR_LEN + (MLXSW_EMAD_OP_TLV_LEN + MLXSW_EMAD_END_TLV_LEN) * sizeof(u32) + mlxsw_core->driver->txhdr_len); + if (enable_string_tlv) + emad_len += MLXSW_EMAD_STRING_TLV_LEN * sizeof(u32); if (emad_len > MLXSW_EMAD_MAX_FRAME_LEN) return NULL; @@ -721,6 +769,7 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, mlxsw_reg_trans_cb_t *cb, unsigned long cb_priv, u64 tid) { + bool enable_string_tlv; struct sk_buff *skb; int err; @@ -728,7 +777,12 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, tid, reg->id, mlxsw_reg_id_str(reg->id), mlxsw_core_reg_access_type_str(type)); - skb = mlxsw_emad_alloc(mlxsw_core, reg->len); + /* Since this can be changed during emad_reg_access, read it once and + * use the value all the way. + */ + enable_string_tlv = mlxsw_core->emad.enable_string_tlv; + + skb = mlxsw_emad_alloc(mlxsw_core, reg->len, enable_string_tlv); if (!skb) return -ENOMEM; @@ -745,7 +799,8 @@ static int mlxsw_emad_reg_access(struct mlxsw_core *mlxsw_core, trans->reg = reg; trans->type = type; - mlxsw_emad_construct(skb, reg, payload, type, trans->tid); + mlxsw_emad_construct(skb, reg, payload, type, trans->tid, + enable_string_tlv); mlxsw_core->driver->txhdr_construct(skb, &trans->tx_info); spin_lock_bh(&mlxsw_core->emad.trans_list_lock); @@ -1707,12 +1762,15 @@ static int mlxsw_reg_trans_wait(struct mlxsw_reg_trans *trans) mlxsw_emad_op_tlv_status_str(trans->emad_status)); snprintf(err_string, MLXSW_REG_TRANS_ERR_STRING_SIZE, - "(tid=%llx,reg_id=%x(%s)) %s\n", trans->tid, + "(tid=%llx,reg_id=%x(%s)) %s (%s)\n", trans->tid, trans->reg->id, mlxsw_reg_id_str(trans->reg->id), - mlxsw_emad_op_tlv_status_str(trans->emad_status)); + mlxsw_emad_op_tlv_status_str(trans->emad_status), + trans->emad_err_string ? trans->emad_err_string : ""); trace_devlink_hwerr(priv_to_devlink(mlxsw_core), trans->emad_status, err_string); + + kfree(trans->emad_err_string); } list_del(&trans->bulk_list); @@ -2283,6 +2341,12 @@ u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core) } EXPORT_SYMBOL(mlxsw_core_read_frc_l); +void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core) +{ + mlxsw_core->emad.enable_string_tlv = true; +} +EXPORT_SYMBOL(mlxsw_core_emad_string_tlv_enable); + static int __init mlxsw_core_module_init(void) { int err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index 0d18bee6d140..543476a2e503 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -347,6 +347,8 @@ void mlxsw_core_fw_flash_end(struct mlxsw_core *mlxsw_core); u32 mlxsw_core_read_frc_h(struct mlxsw_core *mlxsw_core); u32 mlxsw_core_read_frc_l(struct mlxsw_core *mlxsw_core); +void mlxsw_core_emad_string_tlv_enable(struct mlxsw_core *mlxsw_core); + bool mlxsw_core_res_valid(struct mlxsw_core *mlxsw_core, enum mlxsw_res_id res_id); -- cgit v1.2.3-59-g8ed1b From 9032b9e8f2107c6d30327492e4e4b32f92956a8f Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Tue, 12 Nov 2019 08:48:30 +0200 Subject: mlxsw: spectrum: Enable EMAD string TLV Make sure to enable EMAD string TLV only after using the required firmware version. Signed-off-by: Shalom Toledo Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 471478eb1d86..556dca328bb5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4894,6 +4894,8 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, if (err) return err; + mlxsw_core_emad_string_tlv_enable(mlxsw_core); + err = mlxsw_sp_base_mac_get(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to get base mac\n"); -- cgit v1.2.3-59-g8ed1b From 0ee0bbb018938addf87b54d447cc5633d2e53490 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 12 Nov 2019 14:59:41 +0800 Subject: net: atlantic: make symbol 'aq_pm_ops' static Fix sparse warnings: drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c:426:25: warning: symbol 'aq_pm_ops' was not declared. Should it be static? Reported-by: Hulk Robot Fixes: 8aaa112a57c1 ("net: atlantic: refactoring pm logic") Signed-off-by: zhengbin Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index a161026cfbfd..2bb329606794 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c @@ -423,7 +423,7 @@ static int aq_pm_resume_restore(struct device *dev) return atl_resume_common(dev, true); } -const struct dev_pm_ops aq_pm_ops = { +static const struct dev_pm_ops aq_pm_ops = { .suspend = aq_pm_suspend_poweroff, .poweroff = aq_pm_suspend_poweroff, .freeze = aq_pm_freeze, -- cgit v1.2.3-59-g8ed1b From 7b094968ccbb55da9e9fa749bdfd9b90b57d64e5 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 12 Nov 2019 14:59:42 +0800 Subject: net: atlantic: make function 'aq_ethtool_get_priv_flags', 'aq_ethtool_set_priv_flags' static Fix sparse warnings: drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c:706:5: warning: symbol 'aq_ethtool_get_priv_flags' was not declared. Should it be static? drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c:713:5: warning: symbol 'aq_ethtool_set_priv_flags' was not declared. Should it be static? Reported-by: Hulk Robot Fixes: ea4b4d7fc106 ("net: atlantic: loopback tests via private flags") Signed-off-by: zhengbin Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 6353a5c5ed27..a1f99bef4a68 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -703,14 +703,14 @@ static void aq_set_msg_level(struct net_device *ndev, u32 data) aq_nic->msg_enable = data; } -u32 aq_ethtool_get_priv_flags(struct net_device *ndev) +static u32 aq_ethtool_get_priv_flags(struct net_device *ndev) { struct aq_nic_s *aq_nic = netdev_priv(ndev); return aq_nic->aq_nic_cfg.priv_flags; } -int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags) +static int aq_ethtool_set_priv_flags(struct net_device *ndev, u32 flags) { struct aq_nic_s *aq_nic = netdev_priv(ndev); struct aq_nic_cfg_s *cfg; -- cgit v1.2.3-59-g8ed1b From 8b8371b5bad3aea1e1e4b9682066f07afe2efdea Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 12 Nov 2019 15:08:40 +0800 Subject: cxgb4: make function 'cxgb4_mqprio_free_hw_resources' static Fix sparse warnings: drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c:242:6: warning: symbol 'cxgb4_mqprio_free_hw_resources' was not declared. Should it be static? Reported-by: Hulk Robot Fixes: 2d0cb84dd973 ("cxgb4: add ETHOFLD hardware queue support") Signed-off-by: zhengbin Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index 143cb1f31bc0..388078488fb5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -239,7 +239,7 @@ out_free_queues: return ret; } -void cxgb4_mqprio_free_hw_resources(struct net_device *dev) +static void cxgb4_mqprio_free_hw_resources(struct net_device *dev) { struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); -- cgit v1.2.3-59-g8ed1b From d4e82cf4df300368e8d271a2caf14611a5e176a6 Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Tue, 12 Nov 2019 14:07:50 +0200 Subject: net/mlx5: Dump of fw_fatal use updated devlink binary interface Remove redundant code from fw_fatal reporter's dump callback. Use updated devlink interface of binary fmsg pair which breaks the output into chunks internally. Signed-off-by: Aya Levin Acked-by: Jiri Pirko Acked-by: Saeed Mahameed Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/health.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index e718170a80c3..d9f4e8c59c1f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -555,7 +555,6 @@ mlx5_fw_fatal_reporter_recover(struct devlink_health_reporter *reporter, return mlx5_health_try_recover(dev); } -#define MLX5_CR_DUMP_CHUNK_SIZE 256 static int mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, void *priv_ctx, @@ -564,8 +563,6 @@ mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, struct mlx5_core_dev *dev = devlink_health_reporter_priv(reporter); u32 crdump_size = dev->priv.health.crdump_size; u32 *cr_data; - u32 data_size; - u32 offset; int err; if (!mlx5_core_is_pf(dev)) @@ -586,20 +583,7 @@ mlx5_fw_fatal_reporter_dump(struct devlink_health_reporter *reporter, goto free_data; } - err = devlink_fmsg_arr_pair_nest_start(fmsg, "crdump_data"); - if (err) - goto free_data; - for (offset = 0; offset < crdump_size; offset += data_size) { - if (crdump_size - offset < MLX5_CR_DUMP_CHUNK_SIZE) - data_size = crdump_size - offset; - else - data_size = MLX5_CR_DUMP_CHUNK_SIZE; - err = devlink_fmsg_binary_put(fmsg, (char *)cr_data + offset, - data_size); - if (err) - goto free_data; - } - err = devlink_fmsg_arr_pair_nest_end(fmsg); + err = devlink_fmsg_binary_pair_put(fmsg, "crdump_data", cr_data, crdump_size); free_data: kvfree(cr_data); -- cgit v1.2.3-59-g8ed1b From 8fdcd8fb21c054217b5ca5cb627a9a726dba630f Mon Sep 17 00:00:00 2001 From: Aya Levin Date: Tue, 12 Nov 2019 14:07:51 +0200 Subject: netdevsim: Update dummy reporter's devlink binary interface Update dummy reporter's output to use updated devlink interface of binary fmsg pair. Signed-off-by: Aya Levin Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/netdevsim/health.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c index 2716235a0336..9aa637d162eb 100644 --- a/drivers/net/netdevsim/health.c +++ b/drivers/net/netdevsim/health.c @@ -82,18 +82,12 @@ static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len) if (err) return err; - err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_binary"); - if (err) - return err; binary = kmalloc(binary_len, GFP_KERNEL); if (!binary) return -ENOMEM; get_random_bytes(binary, binary_len); - err = devlink_fmsg_binary_put(fmsg, binary, binary_len); + err = devlink_fmsg_binary_pair_put(fmsg, "test_binary", binary, binary_len); kfree(binary); - if (err) - return err; - err = devlink_fmsg_arr_pair_nest_end(fmsg); if (err) return err; -- cgit v1.2.3-59-g8ed1b From 4e4637b10374ede3cd33d7e1b389e6cea6343ea3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 12 Nov 2019 13:05:23 +0000 Subject: net: dsa: mv88e6xxx: fix broken if statement because of a stray semicolon There is a stray semicolon in an if statement that will cause a dev_err message to be printed unconditionally. Fix this by removing the stray semicolon. Addresses-Coverity: ("Stay semicolon") Fixes: f0942e00a1ab ("net: dsa: mv88e6xxx: Add support for port mirroring") Signed-off-by: Colin Ian King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index e8bf6ac1e0f4..3bd988529178 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -5317,7 +5317,7 @@ static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, if (chip->info->ops->set_egress_port(chip, direction, dsa_upstream_port(ds, - port))); + port))) dev_err(ds->dev, "failed to set egress port\n"); } -- cgit v1.2.3-59-g8ed1b From 9440a875b8359090fa9ae65b4fb640893c04a80d Mon Sep 17 00:00:00 2001 From: Arthur Fabre Date: Tue, 12 Nov 2019 15:36:01 +0000 Subject: sfc: trace_xdp_exception on XDP failure The sfc driver can drop packets processed with XDP, notably when running out of buffer space on XDP_TX, or returning an unknown XDP action. This increments the rx_xdp_bad_drops ethtool counter. Call trace_xdp_exception everywhere rx_xdp_bad_drops is incremented, except for fragmented RX packets as the XDP program hasn't run yet. This allows it to easily be monitored from userspace. This mirrors the behavior of other drivers. Signed-off-by: Arthur Fabre Acked-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/rx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index a7d9841105d8..bec261905530 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -724,6 +724,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, netif_err(efx, rx_err, efx->net_dev, "XDP TX failed (%d)\n", err); channel->n_rx_xdp_bad_drops++; + trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act); } else { channel->n_rx_xdp_tx++; } @@ -737,6 +738,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, netif_err(efx, rx_err, efx->net_dev, "XDP redirect failed (%d)\n", err); channel->n_rx_xdp_bad_drops++; + trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act); } else { channel->n_rx_xdp_redirect++; } @@ -746,6 +748,7 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel, bpf_warn_invalid_xdp_action(xdp_act); efx_free_rx_buffers(rx_queue, rx_buf, 1); channel->n_rx_xdp_bad_drops++; + trace_xdp_exception(efx->net_dev, xdp_prog, xdp_act); break; case XDP_ABORTED: -- cgit v1.2.3-59-g8ed1b From 36fe3a61aaca2be4ef7484187e7484d19d54553e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 12 Nov 2019 22:12:24 +0100 Subject: vxlan: implement get_link_ksettings ethtool method Similar to VLAN and similar drivers, we can forward get_link_ksettings to the lower dev if we have one to get meaningful speed/duplex data. Signed-off-by: Matthias Schiffer Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 11f5776affb1..bf04bc2e68c2 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -3175,9 +3175,29 @@ static void vxlan_get_drvinfo(struct net_device *netdev, strlcpy(drvinfo->driver, "vxlan", sizeof(drvinfo->driver)); } +static int vxlan_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + struct vxlan_dev *vxlan = netdev_priv(dev); + struct vxlan_rdst *dst = &vxlan->default_dst; + struct net_device *lowerdev = __dev_get_by_index(vxlan->net, + dst->remote_ifindex); + + if (!lowerdev) { + cmd->base.duplex = DUPLEX_UNKNOWN; + cmd->base.port = PORT_OTHER; + cmd->base.speed = SPEED_UNKNOWN; + + return 0; + } + + return __ethtool_get_link_ksettings(lowerdev, cmd); +} + static const struct ethtool_ops vxlan_ethtool_ops = { - .get_drvinfo = vxlan_get_drvinfo, - .get_link = ethtool_op_get_link, + .get_drvinfo = vxlan_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_link_ksettings = vxlan_get_link_ksettings, }; static struct socket *vxlan_create_sock(struct net *net, bool ipv6, -- cgit v1.2.3-59-g8ed1b From 2eea1fa82f681b484acb8e5a0d213b64a5c5574c Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 12 Nov 2019 23:22:00 +0200 Subject: net: dsa: sja1105: Print the reset reason Sometimes it can be quite opaque even for me why the driver decided to reset the switch. So instead of adding dump_stack() calls each time for debugging, just add a reset reason to sja1105_static_config_reload calls which gets printed to the console. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 10 +++++++++- drivers/net/dsa/sja1105/sja1105_main.c | 18 +++++++++++++++--- drivers/net/dsa/sja1105/sja1105_ptp.c | 2 +- drivers/net/dsa/sja1105/sja1105_tas.c | 4 ++-- 4 files changed, 27 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 64b3ee7b9771..1a3722971b61 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -115,7 +115,15 @@ typedef enum { } sja1105_spi_rw_mode_t; /* From sja1105_main.c */ -int sja1105_static_config_reload(struct sja1105_private *priv); +enum sja1105_reset_reason { + SJA1105_VLAN_FILTERING = 0, + SJA1105_RX_HWTSTAMPING, + SJA1105_AGEING_TIME, + SJA1105_SCHEDULING, +}; + +int sja1105_static_config_reload(struct sja1105_private *priv, + enum sja1105_reset_reason reason); /* From sja1105_spi.c */ int sja1105_xfer_buf(const struct sja1105_private *priv, diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 475cc2d8b0e8..b60224c55244 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1341,13 +1341,21 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, sja1105_bridge_member(ds, port, br, false); } +static const char * const sja1105_reset_reasons[] = { + [SJA1105_VLAN_FILTERING] = "VLAN filtering", + [SJA1105_RX_HWTSTAMPING] = "RX timestamping", + [SJA1105_AGEING_TIME] = "Ageing time", + [SJA1105_SCHEDULING] = "Time-aware scheduling", +}; + /* For situations where we need to change a setting at runtime that is only * available through the static configuration, resetting the switch in order * to upload the new static config is unavoidable. Back up the settings we * modify at runtime (currently only MAC) and restore them after uploading, * such that this operation is relatively seamless. */ -int sja1105_static_config_reload(struct sja1105_private *priv) +int sja1105_static_config_reload(struct sja1105_private *priv, + enum sja1105_reset_reason reason) { struct ptp_system_timestamp ptp_sts_before; struct ptp_system_timestamp ptp_sts_after; @@ -1405,6 +1413,10 @@ int sja1105_static_config_reload(struct sja1105_private *priv) out_unlock_ptp: mutex_unlock(&priv->ptp_data.lock); + dev_info(priv->ds->dev, + "Reset switch and programmed static config. Reason: %s\n", + sja1105_reset_reasons[reason]); + /* Configure the CGU (PLLs) for MII and RMII PHYs. * For these interfaces there is no dynamic configuration * needed, since PLLs have same settings at all speeds. @@ -1599,7 +1611,7 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) l2_lookup_params = table->entries; l2_lookup_params->shared_learn = !enabled; - rc = sja1105_static_config_reload(priv); + rc = sja1105_static_config_reload(priv, SJA1105_VLAN_FILTERING); if (rc) dev_err(ds->dev, "Failed to change VLAN Ethertype\n"); @@ -1871,7 +1883,7 @@ static int sja1105_set_ageing_time(struct dsa_switch *ds, l2_lookup_params->maxage = maxage; - return sja1105_static_config_reload(priv); + return sja1105_static_config_reload(priv, SJA1105_AGEING_TIME); } static int sja1105_port_setup_tc(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 0a35813f9328..6b9b2bef8a7b 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -102,7 +102,7 @@ static int sja1105_change_rxtstamping(struct sja1105_private *priv, priv->tagger_data.stampable_skb = NULL; } - return sja1105_static_config_reload(priv); + return sja1105_static_config_reload(priv, SJA1105_RX_HWTSTAMPING); } int sja1105_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr) diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c index 33eca6a82ec5..d846fb5c4e4d 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.c +++ b/drivers/net/dsa/sja1105/sja1105_tas.c @@ -352,7 +352,7 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, if (rc < 0) return rc; - return sja1105_static_config_reload(priv); + return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); } /* The cycle time extension is the amount of time the last cycle from @@ -400,7 +400,7 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, if (rc < 0) return rc; - return sja1105_static_config_reload(priv); + return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); } void sja1105_tas_setup(struct dsa_switch *ds) -- cgit v1.2.3-59-g8ed1b From 5b1f0e62941b8b307c589c586928a28718e934ef Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 11 Nov 2019 20:49:20 +0100 Subject: net: bcmgenet: Avoid touching non-existent interrupt As platform_get_irq() now prints an error when the interrupt does not exist, we are getting a confusing error message in case the optional WOL IRQ is not defined: bcmgenet fd58000.ethernet: IRQ index 2 not found Fix this by using the platform_get_irq_optional(). Signed-off-by: Stefan Wahren Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 3504f77b1a2f..575f162537af 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3459,7 +3459,7 @@ static int bcmgenet_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->irq0 = platform_get_irq(pdev, 0); priv->irq1 = platform_get_irq(pdev, 1); - priv->wol_irq = platform_get_irq(pdev, 2); + priv->wol_irq = platform_get_irq_optional(pdev, 2); if (!priv->irq0 || !priv->irq1) { dev_err(&pdev->dev, "can't find IRQs\n"); err = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 2b65f93687fb2481c4fe5a27aa30a09a46c6389a Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 11 Nov 2019 20:49:21 +0100 Subject: net: bcmgenet: Fix error handling on IRQ retrieval This fixes the error handling for the mandatory IRQs. There is no need for the error message anymore, this is now handled by platform_get_irq. Signed-off-by: Stefan Wahren Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 575f162537af..ee4d8ef66f38 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3458,13 +3458,16 @@ static int bcmgenet_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->irq0 = platform_get_irq(pdev, 0); + if (priv->irq0 < 0) { + err = priv->irq0; + goto err; + } priv->irq1 = platform_get_irq(pdev, 1); - priv->wol_irq = platform_get_irq_optional(pdev, 2); - if (!priv->irq0 || !priv->irq1) { - dev_err(&pdev->dev, "can't find IRQs\n"); - err = -EINVAL; + if (priv->irq1 < 0) { + err = priv->irq1; goto err; } + priv->wol_irq = platform_get_irq_optional(pdev, 2); if (dn) macaddr = of_get_mac_address(dn); -- cgit v1.2.3-59-g8ed1b From a50e3a9931c198313b404b897f3cd47d8fc0999b Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 11 Nov 2019 20:49:23 +0100 Subject: net: bcmgenet: Add BCM2711 support The BCM2711 needs a different maximum DMA burst length. If not set accordingly a timeout in the transmit queue happens and no package can be sent. So use the new compatible to derive this value. Until now the GENET HW version was used as the platform identifier. This doesn't work with SoC-specific modifications, so introduce a proper platform data structure. Signed-off-by: Stefan Wahren Acked-by: Florian Fainelli Reviewed-by: Matthias Brugger Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 63 ++++++++++++++++++++++---- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 + 2 files changed, 54 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index ee4d8ef66f38..120fa05a39ff 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2576,7 +2576,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) } /* Init rDma */ - bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + bcmgenet_rdma_writel(priv, priv->dma_max_burst_length, + DMA_SCB_BURST_SIZE); /* Initialize Rx queues */ ret = bcmgenet_init_rx_queues(priv->dev); @@ -2589,7 +2590,8 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv) } /* Init tDma */ - bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + bcmgenet_tdma_writel(priv, priv->dma_max_burst_length, + DMA_SCB_BURST_SIZE); /* Initialize Tx queues */ bcmgenet_init_tx_queues(priv->dev); @@ -3420,12 +3422,48 @@ static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) params->words_per_bd); } +struct bcmgenet_plat_data { + enum bcmgenet_version version; + u32 dma_max_burst_length; +}; + +static const struct bcmgenet_plat_data v1_plat_data = { + .version = GENET_V1, + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, +}; + +static const struct bcmgenet_plat_data v2_plat_data = { + .version = GENET_V2, + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, +}; + +static const struct bcmgenet_plat_data v3_plat_data = { + .version = GENET_V3, + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, +}; + +static const struct bcmgenet_plat_data v4_plat_data = { + .version = GENET_V4, + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, +}; + +static const struct bcmgenet_plat_data v5_plat_data = { + .version = GENET_V5, + .dma_max_burst_length = DMA_MAX_BURST_LENGTH, +}; + +static const struct bcmgenet_plat_data bcm2711_plat_data = { + .version = GENET_V5, + .dma_max_burst_length = 0x08, +}; + static const struct of_device_id bcmgenet_match[] = { - { .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 }, - { .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 }, - { .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 }, - { .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 }, - { .compatible = "brcm,genet-v5", .data = (void *)GENET_V5 }, + { .compatible = "brcm,genet-v1", .data = &v1_plat_data }, + { .compatible = "brcm,genet-v2", .data = &v2_plat_data }, + { .compatible = "brcm,genet-v3", .data = &v3_plat_data }, + { .compatible = "brcm,genet-v4", .data = &v4_plat_data }, + { .compatible = "brcm,genet-v5", .data = &v5_plat_data }, + { .compatible = "brcm,bcm2711-genet-v5", .data = &bcm2711_plat_data }, { }, }; MODULE_DEVICE_TABLE(of, bcmgenet_match); @@ -3435,6 +3473,7 @@ static int bcmgenet_probe(struct platform_device *pdev) struct bcmgenet_platform_data *pd = pdev->dev.platform_data; struct device_node *dn = pdev->dev.of_node; const struct of_device_id *of_id = NULL; + const struct bcmgenet_plat_data *pdata; struct bcmgenet_priv *priv; struct net_device *dev; const void *macaddr; @@ -3516,10 +3555,14 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->dev = dev; priv->pdev = pdev; - if (of_id) - priv->version = (enum bcmgenet_version)of_id->data; - else + if (of_id) { + pdata = of_id->data; + priv->version = pdata->version; + priv->dma_max_burst_length = pdata->dma_max_burst_length; + } else { priv->version = pd->genet_version; + priv->dma_max_burst_length = DMA_MAX_BURST_LENGTH; + } priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); if (IS_ERR(priv->clk)) { diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index dbc69d8fa05f..a5659197598f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -664,6 +664,7 @@ struct bcmgenet_priv { bool crc_fwd_en; unsigned int dma_rx_chk_bit; + u32 dma_max_burst_length; u32 msg_enable; -- cgit v1.2.3-59-g8ed1b From 4f8d81b77e6624e222aefb7583da16ef8a656588 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 11 Nov 2019 20:49:24 +0100 Subject: net: bcmgenet: Refactor register access in bcmgenet_mii_config The register access in bcmgenet_mii_config() is a little bit opaque and not easy to extend. In preparation for the missing RGMII PHY modes move all the phy name assignments into the switch statement and the register access to the end of the function. This make the code easier to read and extend. Signed-off-by: Stefan Wahren Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 42 +++++++++++++--------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 6f291ee193a8..021ce9e40c79 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -213,11 +213,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) udelay(2); } - priv->ext_phy = !priv->internal_phy && - (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); - switch (priv->phy_interface) { case PHY_INTERFACE_MODE_INTERNAL: + phy_name = "internal PHY"; + /* fall through */ case PHY_INTERFACE_MODE_MOCA: /* Irrespective of the actually configured PHY speed (100 or * 1000) GENETv4 only has an internal GPHY so we will just end @@ -229,11 +228,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) else port_ctrl = PORT_MODE_INT_EPHY; - bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); - - if (priv->internal_phy) { - phy_name = "internal PHY"; - } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { + if (!phy_name) { phy_name = "MoCA"; bcmgenet_moca_phy_setup(priv); } @@ -242,11 +237,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) case PHY_INTERFACE_MODE_MII: phy_name = "external MII"; phy_set_max_speed(phydev, SPEED_100); - bcmgenet_sys_writel(priv, - PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); - /* Restore the MII PHY after isolation */ - if (bmcr >= 0) - phy_write(phydev, MII_BMCR, bmcr); + port_ctrl = PORT_MODE_EXT_EPHY; break; case PHY_INTERFACE_MODE_REVMII: @@ -261,31 +252,38 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) port_ctrl = PORT_MODE_EXT_RVMII_50; else port_ctrl = PORT_MODE_EXT_RVMII_25; - bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); break; case PHY_INTERFACE_MODE_RGMII: /* RGMII_NO_ID: TXC transitions at the same time as TXD * (requires PCB or receiver-side delay) - * RGMII: Add 2ns delay on TXC (90 degree shift) * * ID is implicitly disabled for 100Mbps (RG)MII operation. */ + phy_name = "external RGMII (no delay)"; id_mode_dis = BIT(16); - /* fall through */ + port_ctrl = PORT_MODE_EXT_GPHY; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: - if (id_mode_dis) - phy_name = "external RGMII (no delay)"; - else - phy_name = "external RGMII (TX delay)"; - bcmgenet_sys_writel(priv, - PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); + /* RGMII_TXID: Add 2ns delay on TXC (90 degree shift) */ + phy_name = "external RGMII (TX delay)"; + port_ctrl = PORT_MODE_EXT_GPHY; break; default: dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface); return -EINVAL; } + bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); + + /* Restore the MII PHY after isolation */ + if (bmcr >= 0) + phy_write(phydev, MII_BMCR, bmcr); + + priv->ext_phy = !priv->internal_phy && + (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); + /* This is an external PHY (xMII), so we need to enable the RGMII * block for the interface to work */ -- cgit v1.2.3-59-g8ed1b From da38802211cc3fd294211a642932edb09e3af632 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 11 Nov 2019 20:49:25 +0100 Subject: net: bcmgenet: Add RGMII_RXID support This adds the missing support for the PHY mode RGMII_RXID. It's necessary for the Raspberry Pi 4. Signed-off-by: Stefan Wahren Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 021ce9e40c79..6392a2530183 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -270,6 +270,11 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) phy_name = "external RGMII (TX delay)"; port_ctrl = PORT_MODE_EXT_GPHY; break; + + case PHY_INTERFACE_MODE_RGMII_RXID: + phy_name = "external RGMII (RX delay)"; + port_ctrl = PORT_MODE_EXT_GPHY; + break; default: dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From d7eaf962a90bf922c1ea2697933edfeca285a7d7 Mon Sep 17 00:00:00 2001 From: Radhey Shyam Pandey Date: Wed, 13 Nov 2019 10:51:23 +0530 Subject: net: axienet: In kconfig remove arch dependency for axi_emac To enable xilinx axi_emac driver support on zynqmp ultrascale platform (ARCH64) there are two choices, mention ARCH64 as a dependency list and other is to check if this ARCH dependency list is really needed. Later approach seems more reasonable, so remove the obsolete ARCH dependency list for the axi_emac driver. Sanity test done for microblaze, zynq and zynqmp ultrascale platform. Signed-off-by: Radhey Shyam Pandey Signed-off-by: David S. Miller --- drivers/net/ethernet/xilinx/Kconfig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 8d994cebb6b0..6304ebd8b5c6 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -6,7 +6,6 @@ config NET_VENDOR_XILINX bool "Xilinx devices" default y - depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS || X86 || ARM || COMPILE_TEST ---help--- If you have a network (Ethernet) card belonging to this class, say Y. @@ -26,11 +25,10 @@ config XILINX_EMACLITE config XILINX_AXI_EMAC tristate "Xilinx 10/100/1000 AXI Ethernet support" - depends on MICROBLAZE || X86 || ARM || COMPILE_TEST select PHYLINK ---help--- This driver supports the 10/100/1000 Ethernet from Xilinx for the - AXI bus interface used in Xilinx Virtex FPGAs. + AXI bus interface used in Xilinx Virtex FPGAs and Soc's. config XILINX_LL_TEMAC tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" -- cgit v1.2.3-59-g8ed1b From 6e952d95cab1f6671c4da90ead4680572bb12ea7 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 13 Nov 2019 10:00:05 +0100 Subject: net: macb: move the Tx and Rx buffer initialization into a function This patch moves the Tx and Rx buffer initialization into its own function. This does not modify the behaviour of the driver and will be helpful to convert the driver to phylink. Signed-off-by: Antoine Tenart Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb_main.c | 39 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index b884cf7f339b..1b3c8d678116 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -388,6 +388,27 @@ mdio_pm_exit: return status; } +static void macb_init_buffers(struct macb *bp) +{ + struct macb_queue *queue; + unsigned int q; + + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { + queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue_writel(queue, RBQPH, + upper_32_bits(queue->rx_ring_dma)); +#endif + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap & HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, + upper_32_bits(queue->tx_ring_dma)); +#endif + } +} + /** * macb_set_tx_clk() - Set a clock to a new frequency * @clk Pointer to the clock to change @@ -1314,26 +1335,14 @@ static void macb_hresp_error_task(unsigned long data) bp->macbgem_ops.mog_init_rings(bp); /* Initialize TX and RX buffers */ - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, RBQPH, - upper_32_bits(queue->rx_ring_dma)); -#endif - queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, TBQPH, - upper_32_bits(queue->tx_ring_dma)); -#endif + macb_init_buffers(bp); - /* Enable interrupts */ + /* Enable interrupts */ + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) queue_writel(queue, IER, bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); - } ctrl |= MACB_BIT(RE) | MACB_BIT(TE); macb_writel(bp, NCR, ctrl); -- cgit v1.2.3-59-g8ed1b From 7897b071ac3b45a5788d084fc7f8a8ee9e5f07f0 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Wed, 13 Nov 2019 10:00:06 +0100 Subject: net: macb: convert to phylink This patch converts the MACB Ethernet driver to the Phylink framework. The MAC configuration is moved to the Phylink ops and Phylink helpers are now used in the ethtools functions. This helps to access the flow control and pauseparam logic and this will be helpful in the future for boards using this controller with SFP cages. Tested-by: Alexandre Belloni Signed-off-by: Antoine Tenart Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Kconfig | 2 +- drivers/net/ethernet/cadence/macb.h | 9 +- drivers/net/ethernet/cadence/macb_main.c | 445 ++++++++++++++++--------------- 3 files changed, 237 insertions(+), 219 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index f4b3bd85dfe3..53b50c24d9c9 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -22,7 +22,7 @@ if NET_VENDOR_CADENCE config MACB tristate "Cadence MACB/GEM support" depends on HAS_DMA && COMMON_CLK - select PHYLIB + select PHYLINK ---help--- The Cadence MACB ethernet interface is found on many Atmel AT32 and AT91 parts. This driver also supports the Cadence GEM (Gigabit diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 03983bd46eef..19fe4f4867c7 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -7,7 +7,7 @@ #ifndef _MACB_H #define _MACB_H -#include +#include #include #include #include @@ -1185,15 +1185,14 @@ struct macb { struct macb_or_gem_ops macbgem_ops; struct mii_bus *mii_bus; - struct device_node *phy_node; - int link; - int speed; - int duplex; + struct phylink *phylink; + struct phylink_config phylink_config; u32 caps; unsigned int dma_burst_length; phy_interface_t phy_interface; + int speed; /* AT91RM9200 transmit */ struct sk_buff *skb; /* holds skb until xmit interrupt completes */ diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 1b3c8d678116..8fc2e21f0bb1 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -453,114 +453,178 @@ static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) netdev_err(dev, "adjusting tx_clk failed.\n"); } -static void macb_handle_link_change(struct net_device *dev) +static void macb_validate(struct phylink_config *config, + unsigned long *supported, + struct phylink_link_state *state) { - struct macb *bp = netdev_priv(dev); - struct phy_device *phydev = dev->phydev; + struct net_device *ndev = to_net_dev(config->dev); + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + struct macb *bp = netdev_priv(ndev); + + /* We only support MII, RMII, GMII, RGMII & SGMII. */ + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != PHY_INTERFACE_MODE_MII && + state->interface != PHY_INTERFACE_MODE_RMII && + state->interface != PHY_INTERFACE_MODE_GMII && + state->interface != PHY_INTERFACE_MODE_SGMII && + !phy_interface_mode_is_rgmii(state->interface)) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + return; + } + + if (!macb_is_gem(bp) && + (state->interface == PHY_INTERFACE_MODE_GMII || + phy_interface_mode_is_rgmii(state->interface))) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + return; + } + + phylink_set_port_modes(mask); + phylink_set(mask, Autoneg); + phylink_set(mask, Asym_Pause); + + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + + if (bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE && + (state->interface == PHY_INTERFACE_MODE_NA || + state->interface == PHY_INTERFACE_MODE_GMII || + state->interface == PHY_INTERFACE_MODE_SGMII || + phy_interface_mode_is_rgmii(state->interface))) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + + if (!(bp->caps & MACB_CAPS_NO_GIGABIT_HALF)) + phylink_set(mask, 1000baseT_Half); + } + + bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static int macb_mac_link_state(struct phylink_config *config, + struct phylink_link_state *state) +{ + return -EOPNOTSUPP; +} + +static void macb_mac_an_restart(struct phylink_config *config) +{ + /* Not supported */ +} + +static void macb_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ + struct net_device *ndev = to_net_dev(config->dev); + struct macb *bp = netdev_priv(ndev); unsigned long flags; - int status_change = 0; + u32 old_ctrl, ctrl; spin_lock_irqsave(&bp->lock, flags); - if (phydev->link) { - if ((bp->speed != phydev->speed) || - (bp->duplex != phydev->duplex)) { - u32 reg; + old_ctrl = ctrl = macb_or_gem_readl(bp, NCFGR); - reg = macb_readl(bp, NCFGR); - reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); - if (macb_is_gem(bp)) - reg &= ~GEM_BIT(GBE); + /* Clear all the bits we might set later */ + ctrl &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD) | MACB_BIT(PAE) | + GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL)); - if (phydev->duplex) - reg |= MACB_BIT(FD); - if (phydev->speed == SPEED_100) - reg |= MACB_BIT(SPD); - if (phydev->speed == SPEED_1000 && - bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - reg |= GEM_BIT(GBE); + if (state->speed == SPEED_1000) + ctrl |= GEM_BIT(GBE); + else if (state->speed == SPEED_100) + ctrl |= MACB_BIT(SPD); - macb_or_gem_writel(bp, NCFGR, reg); + if (state->duplex) + ctrl |= MACB_BIT(FD); - bp->speed = phydev->speed; - bp->duplex = phydev->duplex; - status_change = 1; - } - } + /* We do not support MLO_PAUSE_RX yet */ + if (state->pause & MLO_PAUSE_TX) + ctrl |= MACB_BIT(PAE); - if (phydev->link != bp->link) { - if (!phydev->link) { - bp->speed = 0; - bp->duplex = -1; - } - bp->link = phydev->link; + if (state->interface == PHY_INTERFACE_MODE_SGMII) + ctrl |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); - status_change = 1; - } + /* Apply the new configuration, if any */ + if (old_ctrl ^ ctrl) + macb_or_gem_writel(bp, NCFGR, ctrl); + + bp->speed = state->speed; spin_unlock_irqrestore(&bp->lock, flags); +} - if (status_change) { - if (phydev->link) { - /* Update the TX clock rate if and only if the link is - * up and there has been a link change. - */ - macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); +static void macb_mac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct net_device *ndev = to_net_dev(config->dev); + struct macb *bp = netdev_priv(ndev); + struct macb_queue *queue; + unsigned int q; + u32 ctrl; - netif_carrier_on(dev); - netdev_info(dev, "link up (%d/%s)\n", - phydev->speed, - phydev->duplex == DUPLEX_FULL ? - "Full" : "Half"); - } else { - netif_carrier_off(dev); - netdev_info(dev, "link down\n"); - } - } + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) + queue_writel(queue, IDR, + bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); + + /* Disable Rx and Tx */ + ctrl = macb_readl(bp, NCR) & ~(MACB_BIT(RE) | MACB_BIT(TE)); + macb_writel(bp, NCR, ctrl); + + netif_tx_stop_all_queues(ndev); } -/* based on au1000_eth. c*/ -static int macb_mii_probe(struct net_device *dev) +static void macb_mac_link_up(struct phylink_config *config, unsigned int mode, + phy_interface_t interface, struct phy_device *phy) { - struct macb *bp = netdev_priv(dev); - struct phy_device *phydev; - struct device_node *np; - int ret, i; + struct net_device *ndev = to_net_dev(config->dev); + struct macb *bp = netdev_priv(ndev); + struct macb_queue *queue; + unsigned int q; - np = bp->pdev->dev.of_node; - ret = 0; + macb_set_tx_clk(bp->tx_clk, bp->speed, ndev); - if (np) { - if (of_phy_is_fixed_link(np)) { - bp->phy_node = of_node_get(np); - } else { - bp->phy_node = of_parse_phandle(np, "phy-handle", 0); - /* fallback to standard phy registration if no - * phy-handle was found nor any phy found during - * dt phy registration - */ - if (!bp->phy_node && !phy_find_first(bp->mii_bus)) { - for (i = 0; i < PHY_MAX_ADDR; i++) { - phydev = mdiobus_scan(bp->mii_bus, i); - if (IS_ERR(phydev) && - PTR_ERR(phydev) != -ENODEV) { - ret = PTR_ERR(phydev); - break; - } - } + /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down + * cleared the pipeline and control registers. + */ + bp->macbgem_ops.mog_init_rings(bp); + macb_init_buffers(bp); - if (ret) - return -ENODEV; - } - } - } + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) + queue_writel(queue, IER, + bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP)); - if (bp->phy_node) { - phydev = of_phy_connect(dev, bp->phy_node, - &macb_handle_link_change, 0, - bp->phy_interface); - if (!phydev) - return -ENODEV; + /* Enable Rx and Tx */ + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); + + netif_tx_wake_all_queues(ndev); +} + +static const struct phylink_mac_ops macb_phylink_ops = { + .validate = macb_validate, + .mac_link_state = macb_mac_link_state, + .mac_an_restart = macb_mac_an_restart, + .mac_config = macb_mac_config, + .mac_link_down = macb_mac_link_down, + .mac_link_up = macb_mac_link_up, +}; + +static int macb_phylink_connect(struct macb *bp) +{ + struct net_device *dev = bp->dev; + struct phy_device *phydev; + int ret; + + if (bp->pdev->dev.of_node && + of_parse_phandle(bp->pdev->dev.of_node, "phy-handle", 0)) { + ret = phylink_of_phy_connect(bp->phylink, bp->pdev->dev.of_node, + 0); + if (ret) { + netdev_err(dev, "Could not attach PHY (%d)\n", ret); + return ret; + } } else { phydev = phy_find_first(bp->mii_bus); if (!phydev) { @@ -569,27 +633,33 @@ static int macb_mii_probe(struct net_device *dev) } /* attach the mac to the phy */ - ret = phy_connect_direct(dev, phydev, &macb_handle_link_change, - bp->phy_interface); + ret = phylink_connect_phy(bp->phylink, phydev); if (ret) { - netdev_err(dev, "Could not attach to PHY\n"); + netdev_err(dev, "Could not attach to PHY (%d)\n", ret); return ret; } } - /* mask with MAC supported features */ - if (macb_is_gem(bp) && bp->caps & MACB_CAPS_GIGABIT_MODE_AVAILABLE) - phy_set_max_speed(phydev, SPEED_1000); - else - phy_set_max_speed(phydev, SPEED_100); + phylink_start(bp->phylink); - if (bp->caps & MACB_CAPS_NO_GIGABIT_HALF) - phy_remove_link_mode(phydev, - ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + return 0; +} - bp->link = 0; - bp->speed = 0; - bp->duplex = -1; +/* based on au1000_eth. c*/ +static int macb_mii_probe(struct net_device *dev) +{ + struct macb *bp = netdev_priv(dev); + + bp->phylink_config.dev = &dev->dev; + bp->phylink_config.type = PHYLINK_NETDEV; + + bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode, + bp->phy_interface, &macb_phylink_ops); + if (IS_ERR(bp->phylink)) { + netdev_err(dev, "Could not create a phylink instance (%ld)\n", + PTR_ERR(bp->phylink)); + return PTR_ERR(bp->phylink); + } return 0; } @@ -619,20 +689,10 @@ static int macb_mii_init(struct macb *bp) dev_set_drvdata(&bp->dev->dev, bp->mii_bus); np = bp->pdev->dev.of_node; - if (np && of_phy_is_fixed_link(np)) { - if (of_phy_register_fixed_link(np) < 0) { - dev_err(&bp->pdev->dev, - "broken fixed-link specification %pOF\n", np); - goto err_out_free_mdiobus; - } - - err = mdiobus_register(bp->mii_bus); - } else { - err = of_mdiobus_register(bp->mii_bus, np); - } + err = of_mdiobus_register(bp->mii_bus, np); if (err) - goto err_out_free_fixed_link; + goto err_out_free_mdiobus; err = macb_mii_probe(bp->dev); if (err) @@ -642,11 +702,7 @@ static int macb_mii_init(struct macb *bp) err_out_unregister_bus: mdiobus_unregister(bp->mii_bus); -err_out_free_fixed_link: - if (np && of_phy_is_fixed_link(np)) - of_phy_deregister_fixed_link(np); err_out_free_mdiobus: - of_node_put(bp->phy_node); mdiobus_free(bp->mii_bus); err_out: return err; @@ -2230,19 +2286,13 @@ static void macb_configure_dma(struct macb *bp) static void macb_init_hw(struct macb *bp) { - struct macb_queue *queue; - unsigned int q; - u32 config; macb_reset_hw(bp); macb_set_hwaddr(bp); config = macb_mdc_clk_div(bp); - if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) - config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL); config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ - config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ if (bp->caps & MACB_CAPS_JUMBO) config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ @@ -2258,36 +2308,11 @@ static void macb_init_hw(struct macb *bp) macb_writel(bp, NCFGR, config); if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) gem_writel(bp, JML, bp->jumbo_max_len); - bp->speed = SPEED_10; - bp->duplex = DUPLEX_HALF; bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; if (bp->caps & MACB_CAPS_JUMBO) bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; macb_configure_dma(bp); - - /* Initialize TX and RX buffers */ - for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, RBQP, lower_32_bits(queue->rx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, RBQPH, upper_32_bits(queue->rx_ring_dma)); -#endif - queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (bp->hw_dma_cap & HW_DMA_CAP_64B) - queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); -#endif - - /* Enable interrupts */ - queue_writel(queue, IER, - bp->rx_intr_mask | - MACB_TX_INT_FLAGS | - MACB_BIT(HRESP)); - } - - /* Enable TX and RX */ - macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(RE) | MACB_BIT(TE)); } /* The hash address register is 64 bits long and takes up two @@ -2411,8 +2436,8 @@ static void macb_set_rx_mode(struct net_device *dev) static int macb_open(struct net_device *dev) { - struct macb *bp = netdev_priv(dev); size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN; + struct macb *bp = netdev_priv(dev); struct macb_queue *queue; unsigned int q; int err; @@ -2423,15 +2448,6 @@ static int macb_open(struct net_device *dev) if (err < 0) goto pm_exit; - /* carrier starts down */ - netif_carrier_off(dev); - - /* if the phy is not yet register, retry later*/ - if (!dev->phydev) { - err = -EAGAIN; - goto pm_exit; - } - /* RX buffers initialization */ macb_init_rx_buffer_size(bp, bufsz); @@ -2445,11 +2461,11 @@ static int macb_open(struct net_device *dev) for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) napi_enable(&queue->napi); - bp->macbgem_ops.mog_init_rings(bp); macb_init_hw(bp); - /* schedule a link state check */ - phy_start(dev->phydev); + err = macb_phylink_connect(bp); + if (err) + goto pm_exit; netif_tx_start_all_queues(dev); @@ -2476,8 +2492,8 @@ static int macb_close(struct net_device *dev) for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) napi_disable(&queue->napi); - if (dev->phydev) - phy_stop(dev->phydev); + phylink_stop(bp->phylink); + phylink_disconnect_phy(bp->phylink); spin_lock_irqsave(&bp->lock, flags); macb_reset_hw(bp); @@ -2711,17 +2727,18 @@ static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) wol->supported = 0; wol->wolopts = 0; - if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) { - wol->supported = WAKE_MAGIC; - - if (bp->wol & MACB_WOL_ENABLED) - wol->wolopts |= WAKE_MAGIC; - } + if (bp->wol & MACB_WOL_HAS_MAGIC_PACKET) + phylink_ethtool_get_wol(bp->phylink, wol); } static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct macb *bp = netdev_priv(netdev); + int ret; + + ret = phylink_ethtool_set_wol(bp->phylink, wol); + if (!ret) + return 0; if (!(bp->wol & MACB_WOL_HAS_MAGIC_PACKET) || (wol->wolopts & ~WAKE_MAGIC)) @@ -2737,6 +2754,22 @@ static int macb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) return 0; } +static int macb_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *kset) +{ + struct macb *bp = netdev_priv(netdev); + + return phylink_ethtool_ksettings_get(bp->phylink, kset); +} + +static int macb_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *kset) +{ + struct macb *bp = netdev_priv(netdev); + + return phylink_ethtool_ksettings_set(bp->phylink, kset); +} + static void macb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { @@ -3173,8 +3206,8 @@ static const struct ethtool_ops macb_ethtool_ops = { .get_ts_info = ethtool_op_get_ts_info, .get_wol = macb_get_wol, .set_wol = macb_set_wol, - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_link_ksettings = macb_get_link_ksettings, + .set_link_ksettings = macb_set_link_ksettings, .get_ringparam = macb_get_ringparam, .set_ringparam = macb_set_ringparam, }; @@ -3187,8 +3220,8 @@ static const struct ethtool_ops gem_ethtool_ops = { .get_ethtool_stats = gem_get_ethtool_stats, .get_strings = gem_get_ethtool_strings, .get_sset_count = gem_get_sset_count, - .get_link_ksettings = phy_ethtool_get_link_ksettings, - .set_link_ksettings = phy_ethtool_set_link_ksettings, + .get_link_ksettings = macb_get_link_ksettings, + .set_link_ksettings = macb_set_link_ksettings, .get_ringparam = macb_get_ringparam, .set_ringparam = macb_set_ringparam, .get_rxnfc = gem_get_rxnfc, @@ -3197,26 +3230,21 @@ static const struct ethtool_ops gem_ethtool_ops = { static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct phy_device *phydev = dev->phydev; struct macb *bp = netdev_priv(dev); if (!netif_running(dev)) return -EINVAL; - if (!phydev) - return -ENODEV; - - if (!bp->ptp_info) - return phy_mii_ioctl(phydev, rq, cmd); - - switch (cmd) { - case SIOCSHWTSTAMP: - return bp->ptp_info->set_hwtst(dev, rq, cmd); - case SIOCGHWTSTAMP: - return bp->ptp_info->get_hwtst(dev, rq); - default: - return phy_mii_ioctl(phydev, rq, cmd); + if (bp->ptp_info) { + switch (cmd) { + case SIOCSHWTSTAMP: + return bp->ptp_info->set_hwtst(dev, rq, cmd); + case SIOCGHWTSTAMP: + return bp->ptp_info->get_hwtst(dev, rq); + } } + + return phylink_mii_ioctl(bp->phylink, rq, cmd); } static inline void macb_set_txcsum_feature(struct macb *bp, @@ -3339,7 +3367,8 @@ static void macb_configure_caps(struct macb *bp, #ifdef CONFIG_MACB_USE_HWSTAMP if (gem_has_ptp(bp)) { if (!GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) - pr_err("GEM doesn't support hardware ptp.\n"); + dev_err(&bp->pdev->dev, + "GEM doesn't support hardware ptp.\n"); else { bp->hw_dma_cap |= HW_DMA_CAP_PTP; bp->ptp_info = &gem_ptp_info; @@ -3716,8 +3745,9 @@ static int at91ether_open(struct net_device *dev) MACB_BIT(ISR_ROVR) | MACB_BIT(HRESP)); - /* schedule a link state check */ - phy_start(dev->phydev); + ret = macb_phylink_connect(lp); + if (ret) + return ret; netif_start_queue(dev); @@ -3746,6 +3776,9 @@ static int at91ether_close(struct net_device *dev) netif_stop_queue(dev); + phylink_stop(lp->phylink); + phylink_disconnect_phy(lp->phylink); + dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * macb_dma_desc_get_size(lp), @@ -4190,7 +4223,6 @@ static int macb_probe(struct platform_device *pdev) struct clk *tsu_clk = NULL; unsigned int queue_mask, num_queues; bool native_io; - struct phy_device *phydev; phy_interface_t interface; struct net_device *dev; struct resource *regs; @@ -4325,6 +4357,8 @@ static int macb_probe(struct platform_device *pdev) else bp->phy_interface = interface; + bp->speed = SPEED_UNKNOWN; + /* IP specific init */ err = init(pdev); if (err) @@ -4334,8 +4368,6 @@ static int macb_probe(struct platform_device *pdev) if (err) goto err_out_free_netdev; - phydev = dev->phydev; - netif_carrier_off(dev); err = register_netdev(dev); @@ -4347,8 +4379,6 @@ static int macb_probe(struct platform_device *pdev) tasklet_init(&bp->hresp_err_tasklet, macb_hresp_error_task, (unsigned long)bp); - phy_attached_info(phydev); - netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n", macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID), dev->base_addr, dev->irq, dev->dev_addr); @@ -4359,11 +4389,7 @@ static int macb_probe(struct platform_device *pdev) return 0; err_out_unregister_mdio: - phy_disconnect(dev->phydev); mdiobus_unregister(bp->mii_bus); - of_node_put(bp->phy_node); - if (np && of_phy_is_fixed_link(np)) - of_phy_deregister_fixed_link(np); mdiobus_free(bp->mii_bus); err_out_free_netdev: @@ -4387,18 +4413,12 @@ static int macb_remove(struct platform_device *pdev) { struct net_device *dev; struct macb *bp; - struct device_node *np = pdev->dev.of_node; dev = platform_get_drvdata(pdev); if (dev) { bp = netdev_priv(dev); - if (dev->phydev) - phy_disconnect(dev->phydev); mdiobus_unregister(bp->mii_bus); - if (np && of_phy_is_fixed_link(np)) - of_phy_deregister_fixed_link(np); - dev->phydev = NULL; mdiobus_free(bp->mii_bus); unregister_netdev(dev); @@ -4413,7 +4433,7 @@ static int macb_remove(struct platform_device *pdev) clk_disable_unprepare(bp->tsu_clk); pm_runtime_set_suspended(&pdev->dev); } - of_node_put(bp->phy_node); + phylink_destroy(bp->phylink); free_netdev(dev); } @@ -4431,7 +4451,6 @@ static int __maybe_unused macb_suspend(struct device *dev) if (!netif_running(netdev)) return 0; - if (bp->wol & MACB_WOL_ENABLED) { macb_writel(bp, IER, MACB_BIT(WOL)); macb_writel(bp, WOL, MACB_BIT(MAG)); @@ -4442,8 +4461,9 @@ static int __maybe_unused macb_suspend(struct device *dev) for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) napi_disable(&queue->napi); - phy_stop(netdev->phydev); - phy_suspend(netdev->phydev); + rtnl_lock(); + phylink_stop(bp->phylink); + rtnl_unlock(); spin_lock_irqsave(&bp->lock, flags); macb_reset_hw(bp); spin_unlock_irqrestore(&bp->lock, flags); @@ -4491,12 +4511,11 @@ static int __maybe_unused macb_resume(struct device *dev) for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) napi_enable(&queue->napi); - phy_resume(netdev->phydev); - phy_init_hw(netdev->phydev); - phy_start(netdev->phydev); + rtnl_lock(); + phylink_start(bp->phylink); + rtnl_unlock(); } - bp->macbgem_ops.mog_init_rings(bp); macb_init_hw(bp); macb_set_rx_mode(netdev); macb_restore_features(bp); -- cgit v1.2.3-59-g8ed1b From 07f23d90478ce33671eb6d070a81021ea0334c14 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 13 Nov 2019 09:55:48 +0000 Subject: net: sfp: fix spelling mistake "requies" -> "requires" There is a spelling mistake in a dev_warn message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index f9b8051c4247..b0f88c2c0153 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -1465,7 +1465,7 @@ static int sfp_module_parse_power(struct sfp *sfp) */ if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE && power_mW > 1000) { dev_warn(sfp->dev, - "Address Change Sequence not supported but module requies %u.%uW, module may not be functional\n", + "Address Change Sequence not supported but module requires %u.%uW, module may not be functional\n", power_mW / 1000, (power_mW / 100) % 10); return 0; } -- cgit v1.2.3-59-g8ed1b From 945fe45759bc001c1f81e25fbe9a40b43e59f7b5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 13 Nov 2019 16:22:38 +0000 Subject: net: ethernet: stmmac: fix indentation issue There is a return statement that is indented too deeply, remove the extraneous tab. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index 95ffaec4ab42..9b7be996d07b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -158,7 +158,7 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) ret = clk_prepare_enable(dwmac->clk_eth_ck); if (ret) { clk_disable_unprepare(dwmac->syscfg_clk); - return ret; + return ret; } } else { clk_disable_unprepare(dwmac->syscfg_clk); -- cgit v1.2.3-59-g8ed1b From 75a1ccfe6c726ba33a2f9859d39deb2eba620583 Mon Sep 17 00:00:00 2001 From: Bryan Whitehead Date: Wed, 13 Nov 2019 11:33:15 -0500 Subject: mscc.c: Add support for additional VSC PHYs Add support for the following VSC PHYs VSC8504, VSC8552, VSC8572 VSC8562, VSC8564, VSC8575, VSC8582 Updates for v2: Checked for NULL on input to container_of Changed a large if else series to a switch statement. Added a WARN_ON to make sure lowest nibble of mask is 0 Signed-off-by: Bryan Whitehead Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 188 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 805cda3465d7..aadee8db0ff8 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -252,13 +252,21 @@ enum rgmii_rx_clock_delay { #define MSCC_PHY_TR_LSB 17 #define MSCC_PHY_TR_MSB 18 -/* Microsemi PHY ID's */ +/* Microsemi PHY ID's + * Code assumes lowest nibble is 0 + */ +#define PHY_ID_VSC8504 0x000704c0 #define PHY_ID_VSC8514 0x00070670 #define PHY_ID_VSC8530 0x00070560 #define PHY_ID_VSC8531 0x00070570 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 +#define PHY_ID_VSC8552 0x000704e0 +#define PHY_ID_VSC856X 0x000707e0 +#define PHY_ID_VSC8572 0x000704d0 #define PHY_ID_VSC8574 0x000704a0 +#define PHY_ID_VSC8575 0x000707d0 +#define PHY_ID_VSC8582 0x000707b0 #define PHY_ID_VSC8584 0x000707c0 #define MSCC_VDDMAC_1500 1500 @@ -1595,6 +1603,9 @@ static bool vsc8584_is_pkg_init(struct phy_device *phydev, bool reversed) else addr = vsc8531->base_addr + i; + if (!map[addr]) + continue; + phy = container_of(map[addr], struct phy_device, mdio); if ((phy->phy_id & phydev->drv->phy_id_mask) != @@ -1647,14 +1658,29 @@ static int vsc8584_config_init(struct phy_device *phydev) * in this pre-init function. */ if (!vsc8584_is_pkg_init(phydev, val & PHY_ADDR_REVERSED ? 1 : 0)) { - if ((phydev->phy_id & phydev->drv->phy_id_mask) == - (PHY_ID_VSC8574 & phydev->drv->phy_id_mask)) + /* The following switch statement assumes that the lowest + * nibble of the phy_id_mask is always 0. This works because + * the lowest nibble of the PHY_ID's below are also 0. + */ + WARN_ON(phydev->drv->phy_id_mask & 0xf); + + switch (phydev->phy_id & phydev->drv->phy_id_mask) { + case PHY_ID_VSC8504: + case PHY_ID_VSC8552: + case PHY_ID_VSC8572: + case PHY_ID_VSC8574: ret = vsc8574_config_pre_init(phydev); - else if ((phydev->phy_id & phydev->drv->phy_id_mask) == - (PHY_ID_VSC8584 & phydev->drv->phy_id_mask)) + break; + case PHY_ID_VSC856X: + case PHY_ID_VSC8575: + case PHY_ID_VSC8582: + case PHY_ID_VSC8584: ret = vsc8584_config_pre_init(phydev); - else + break; + default: ret = -EINVAL; + break; + }; if (ret) goto err; @@ -2321,6 +2347,32 @@ static int vsc85xx_probe(struct phy_device *phydev) /* Microsemi VSC85xx PHYs */ static struct phy_driver vsc85xx_driver[] = { +{ + .phy_id = PHY_ID_VSC8504, + .name = "Microsemi GE VSC8504 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8574_probe, + .set_wol = &vsc85xx_wol_set, + .get_wol = &vsc85xx_wol_get, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, { .phy_id = PHY_ID_VSC8514, .name = "Microsemi GE VSC8514 SyncE", @@ -2444,6 +2496,82 @@ static struct phy_driver vsc85xx_driver[] = { .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, }, +{ + .phy_id = PHY_ID_VSC8552, + .name = "Microsemi GE VSC8552 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8574_probe, + .set_wol = &vsc85xx_wol_set, + .get_wol = &vsc85xx_wol_get, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, +{ + .phy_id = PHY_ID_VSC856X, + .name = "Microsemi GE VSC856X SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8584_probe, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, +{ + .phy_id = PHY_ID_VSC8572, + .name = "Microsemi GE VSC8572 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8574_probe, + .set_wol = &vsc85xx_wol_set, + .get_wol = &vsc85xx_wol_get, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, { .phy_id = PHY_ID_VSC8574, .name = "Microsemi GE VSC8574 SyncE", @@ -2470,6 +2598,54 @@ static struct phy_driver vsc85xx_driver[] = { .get_strings = &vsc85xx_get_strings, .get_stats = &vsc85xx_get_stats, }, +{ + .phy_id = PHY_ID_VSC8575, + .name = "Microsemi GE VSC8575 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8584_probe, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, +{ + .phy_id = PHY_ID_VSC8582, + .name = "Microsemi GE VSC8582 SyncE", + .phy_id_mask = 0xfffffff0, + /* PHY_GBIT_FEATURES */ + .soft_reset = &genphy_soft_reset, + .config_init = &vsc8584_config_init, + .config_aneg = &vsc85xx_config_aneg, + .aneg_done = &genphy_aneg_done, + .read_status = &vsc85xx_read_status, + .ack_interrupt = &vsc85xx_ack_interrupt, + .config_intr = &vsc85xx_config_intr, + .did_interrupt = &vsc8584_did_interrupt, + .suspend = &genphy_suspend, + .resume = &genphy_resume, + .probe = &vsc8584_probe, + .get_tunable = &vsc85xx_get_tunable, + .set_tunable = &vsc85xx_set_tunable, + .read_page = &vsc85xx_phy_read_page, + .write_page = &vsc85xx_phy_write_page, + .get_sset_count = &vsc85xx_get_sset_count, + .get_strings = &vsc85xx_get_strings, + .get_stats = &vsc85xx_get_stats, +}, { .phy_id = PHY_ID_VSC8584, .name = "Microsemi GE VSC8584 SyncE", @@ -2500,12 +2676,18 @@ static struct phy_driver vsc85xx_driver[] = { module_phy_driver(vsc85xx_driver); static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { + { 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, }, { } }; -- cgit v1.2.3-59-g8ed1b From 12063c2e4c0e38f36c0e6f0942cd138feed022b3 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:24 +0100 Subject: net/mlx5: Simplify fdb chain and prio eswitch defines FDB_MAX_CHAIN and FDB_MAX_PRIO were defined differently depending on if CONFIG_MLX5_ESWITCH is enabled to save space on allocations. This is a minor space saving, and there is no real need for it. Simplify things instead, and define them the same in both cases. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index a05b948a6287..ab8cdd3dd8d0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -43,6 +43,10 @@ #include #include "lib/mpfs.h" +#define FDB_MAX_CHAIN 3 +#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) +#define FDB_MAX_PRIO 16 + #ifdef CONFIG_MLX5_ESWITCH #define MLX5_MAX_UC_PER_VPORT(dev) \ @@ -59,10 +63,6 @@ #define mlx5_esw_has_fwd_fdb(dev) \ MLX5_CAP_ESW_FLOWTABLE(dev, fdb_multi_path_to_table) -#define FDB_MAX_CHAIN 3 -#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) -#define FDB_MAX_PRIO 16 - struct vport_ingress { struct mlx5_flow_table *acl; struct mlx5_flow_handle *allow_rule; @@ -637,10 +637,6 @@ static inline const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev) static inline void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs) {} -#define FDB_MAX_CHAIN 1 -#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) -#define FDB_MAX_PRIO 1 - #endif /* CONFIG_MLX5_ESWITCH */ #endif /* __MLX5_ESWITCH_H__ */ -- cgit v1.2.3-59-g8ed1b From 2cf2954bd7ffd8250ae257b45b96915003c26d7d Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:25 +0100 Subject: net/mlx5: Rename FDB_* tc related defines to FDB_TC_* defines Rename it to prepare for next patch that will add a different type of offload to the FDB. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 8 ++++---- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 10 +++++----- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 3e78a727f3e6..15b771b6c09d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -1074,7 +1074,7 @@ mlx5e_tc_offload_to_slow_path(struct mlx5_eswitch *esw, memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; slow_attr->split_count = 0; - slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN; + slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; rule = mlx5e_tc_offload_fdb_rules(esw, flow, spec, slow_attr); if (!IS_ERR(rule)) @@ -1091,7 +1091,7 @@ mlx5e_tc_unoffload_from_slow_path(struct mlx5_eswitch *esw, memcpy(slow_attr, flow->esw_attr, sizeof(*slow_attr)); slow_attr->action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; slow_attr->split_count = 0; - slow_attr->dest_chain = FDB_SLOW_PATH_CHAIN; + slow_attr->dest_chain = FDB_TC_SLOW_PATH_CHAIN; mlx5e_tc_unoffload_fdb_rules(esw, flow, slow_attr); flow_flag_clear(flow, SLOW); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index ab8cdd3dd8d0..d73187bdbc06 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -43,9 +43,9 @@ #include #include "lib/mpfs.h" -#define FDB_MAX_CHAIN 3 -#define FDB_SLOW_PATH_CHAIN (FDB_MAX_CHAIN + 1) -#define FDB_MAX_PRIO 16 +#define FDB_TC_MAX_CHAIN 3 +#define FDB_TC_SLOW_PATH_CHAIN (FDB_TC_MAX_CHAIN + 1) +#define FDB_TC_MAX_PRIO 16 #ifdef CONFIG_MLX5_ESWITCH @@ -173,7 +173,7 @@ struct mlx5_eswitch_fdb { struct { struct mlx5_flow_table *fdb; u32 num_rules; - } fdb_prio[FDB_MAX_CHAIN + 1][FDB_MAX_PRIO + 1][PRIO_LEVELS]; + } fdb_prio[FDB_TC_MAX_CHAIN + 1][FDB_TC_MAX_PRIO + 1][PRIO_LEVELS]; /* Protects fdb_prio table */ struct mutex fdb_prio_lock; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index d8e25416a15d..9c51fedd890f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -75,7 +75,7 @@ bool mlx5_eswitch_prios_supported(struct mlx5_eswitch *esw) u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) { if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) - return FDB_MAX_CHAIN; + return FDB_TC_MAX_CHAIN; return 0; } @@ -83,7 +83,7 @@ u32 mlx5_eswitch_get_chain_range(struct mlx5_eswitch *esw) u16 mlx5_eswitch_get_prio_range(struct mlx5_eswitch *esw) { if (esw->fdb_table.flags & ESW_FDB_CHAINS_AND_PRIOS_SUPPORTED) - return FDB_MAX_PRIO; + return FDB_TC_MAX_PRIO; return 1; } @@ -928,7 +928,7 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) int table_prio, l = 0; u32 flags = 0; - if (chain == FDB_SLOW_PATH_CHAIN) + if (chain == FDB_TC_SLOW_PATH_CHAIN) return esw->fdb_table.offloads.slow_fdb; mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); @@ -953,7 +953,7 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - table_prio = (chain * FDB_MAX_PRIO) + prio - 1; + table_prio = (chain * FDB_TC_MAX_PRIO) + prio - 1; /* create earlier levels for correct fs_core lookup when * connecting tables @@ -990,7 +990,7 @@ esw_put_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) { int l; - if (chain == FDB_SLOW_PATH_CHAIN) + if (chain == FDB_TC_SLOW_PATH_CHAIN) return; mutex_lock(&esw->fdb_table.offloads.fdb_prio_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 3bbb49354829..b33f77892d10 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2565,7 +2565,7 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) return -ENOMEM; steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) * - (FDB_MAX_CHAIN + 1), GFP_KERNEL); + (FDB_TC_MAX_CHAIN + 1), GFP_KERNEL); if (!steering->fdb_sub_ns) return -ENOMEM; @@ -2576,7 +2576,7 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) goto out_err; } - levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1); + levels = 2 * FDB_TC_MAX_PRIO * (FDB_TC_MAX_CHAIN + 1); maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, FDB_FAST_PATH, levels); @@ -2585,14 +2585,14 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) goto out_err; } - for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) { + for (chain = 0; chain <= FDB_TC_MAX_CHAIN; chain++) { ns = fs_create_namespace(maj_prio, MLX5_FLOW_TABLE_MISS_ACTION_DEF); if (IS_ERR(ns)) { err = PTR_ERR(ns); goto out_err; } - for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) { + for (prio = 0; prio < FDB_TC_MAX_PRIO * (chain + 1); prio++) { min_prio = fs_create_prio(ns, prio, 2); if (IS_ERR(min_prio)) { err = PTR_ERR(min_prio); -- cgit v1.2.3-59-g8ed1b From 4db7b98e943225dc2a7435811767e44f63640462 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:26 +0100 Subject: net/mlx5: Define fdb tc levels per prio Define FDB_TC_LEVELS_PER_PRIO instead of magic number 2. This is the number of levels used by each tc prio table in the fdb. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index d73187bdbc06..8c9d8dc85861 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -46,6 +46,7 @@ #define FDB_TC_MAX_CHAIN 3 #define FDB_TC_SLOW_PATH_CHAIN (FDB_TC_MAX_CHAIN + 1) #define FDB_TC_MAX_PRIO 16 +#define FDB_TC_LEVELS_PER_PRIO 2 #ifdef CONFIG_MLX5_ESWITCH @@ -146,7 +147,6 @@ enum offloads_fdb_flags { extern const unsigned int ESW_POOLS[4]; -#define PRIO_LEVELS 2 struct mlx5_eswitch_fdb { union { struct legacy_fdb { @@ -173,7 +173,7 @@ struct mlx5_eswitch_fdb { struct { struct mlx5_flow_table *fdb; u32 num_rules; - } fdb_prio[FDB_TC_MAX_CHAIN + 1][FDB_TC_MAX_PRIO + 1][PRIO_LEVELS]; + } fdb_prio[FDB_TC_MAX_CHAIN + 1][FDB_TC_MAX_PRIO + 1][FDB_TC_LEVELS_PER_PRIO]; /* Protects fdb_prio table */ struct mutex fdb_prio_lock; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index b33f77892d10..190c5c71b534 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2576,7 +2576,8 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) goto out_err; } - levels = 2 * FDB_TC_MAX_PRIO * (FDB_TC_MAX_CHAIN + 1); + levels = FDB_TC_LEVELS_PER_PRIO * + FDB_TC_MAX_PRIO * (FDB_TC_MAX_CHAIN + 1); maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, FDB_FAST_PATH, levels); @@ -2593,7 +2594,8 @@ static int init_fdb_root_ns(struct mlx5_flow_steering *steering) } for (prio = 0; prio < FDB_TC_MAX_PRIO * (chain + 1); prio++) { - min_prio = fs_create_prio(ns, prio, 2); + min_prio = fs_create_prio(ns, prio, + FDB_TC_LEVELS_PER_PRIO); if (IS_ERR(min_prio)) { err = PTR_ERR(min_prio); goto out_err; -- cgit v1.2.3-59-g8ed1b From 34b13cb3eaa5ad205f4497da6420262da4940b9e Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:27 +0100 Subject: net/mlx5: Accumulate levels for chains prio namespaces Tc chains are implemented by creating a chained prio steering type, and inside it there is a namespace for each chain (FDB_TC_MAX_CHAINS). Each of those has a list of priorities. Currently, all namespaces in a prio start at the parent prio level. But since we can jump from chain (namespace) to another chain in the same prio, we need the levels for higher chains to be higher as well. So we created unused prios to account for levels in previous namespaces. Fix that by accumulating the namespaces levels if we are inside a chained type prio, and removing the unused prios. Fixes: 328edb499f99 ('net/mlx5: Split FDB fast path prio to multiple namespaces') Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c | 2 +- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 9c51fedd890f..60d3d88e406c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -953,7 +953,7 @@ esw_get_prio_table(struct mlx5_eswitch *esw, u32 chain, u16 prio, int level) flags |= (MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT | MLX5_FLOW_TABLE_TUNNEL_EN_DECAP); - table_prio = (chain * FDB_TC_MAX_PRIO) + prio - 1; + table_prio = prio - 1; /* create earlier levels for correct fs_core lookup when * connecting tables diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 190c5c71b534..3cdad1d1021f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2359,9 +2359,17 @@ static void set_prio_attrs_in_prio(struct fs_prio *prio, int acc_level) int acc_level_ns = acc_level; prio->start_level = acc_level; - fs_for_each_ns(ns, prio) + fs_for_each_ns(ns, prio) { /* This updates start_level and num_levels of ns's priority descendants */ acc_level_ns = set_prio_attrs_in_ns(ns, acc_level); + + /* If this a prio with chains, and we can jump from one chain + * (namepsace) to another, so we accumulate the levels + */ + if (prio->node.type == FS_TYPE_PRIO_CHAINS) + acc_level = acc_level_ns; + } + if (!prio->num_levels) prio->num_levels = acc_level_ns - prio->start_level; WARN_ON(prio->num_levels < acc_level_ns - prio->start_level); -- cgit v1.2.3-59-g8ed1b From 439e843f1f43640fd52530433d803db8585cd028 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:28 +0100 Subject: net/mlx5: Refactor creating fast path prio chains Next patch will re-use this to add a new chain but in a different prio. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 118 +++++++++++++++------- 1 file changed, 82 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 3cdad1d1021f..4aa6990a38b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2558,60 +2558,106 @@ out_err: steering->rdma_rx_root_ns = NULL; return err; } -static int init_fdb_root_ns(struct mlx5_flow_steering *steering) + +/* FT and tc chains are stored in the same array so we can re-use the + * mlx5_get_fdb_sub_ns() and tc api for FT chains. + * When creating a new ns for each chain store it in the first available slot. + * Assume tc chains are created and stored first and only then the FT chain. + */ +static void store_fdb_sub_ns_prio_chain(struct mlx5_flow_steering *steering, + struct mlx5_flow_namespace *ns) +{ + int chain = 0; + + while (steering->fdb_sub_ns[chain]) + ++chain; + + steering->fdb_sub_ns[chain] = ns; +} + +static int create_fdb_sub_ns_prio_chain(struct mlx5_flow_steering *steering, + struct fs_prio *maj_prio) { struct mlx5_flow_namespace *ns; - struct fs_prio *maj_prio; struct fs_prio *min_prio; + int prio; + + ns = fs_create_namespace(maj_prio, MLX5_FLOW_TABLE_MISS_ACTION_DEF); + if (IS_ERR(ns)) + return PTR_ERR(ns); + + for (prio = 0; prio < FDB_TC_MAX_PRIO; prio++) { + min_prio = fs_create_prio(ns, prio, FDB_TC_LEVELS_PER_PRIO); + if (IS_ERR(min_prio)) + return PTR_ERR(min_prio); + } + + store_fdb_sub_ns_prio_chain(steering, ns); + + return 0; +} + +static int create_fdb_chains(struct mlx5_flow_steering *steering, + int fs_prio, + int chains) +{ + struct fs_prio *maj_prio; int levels; int chain; - int prio; int err; - steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); - if (!steering->fdb_root_ns) - return -ENOMEM; + levels = FDB_TC_LEVELS_PER_PRIO * FDB_TC_MAX_PRIO * chains; + maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, + fs_prio, + levels); + if (IS_ERR(maj_prio)) + return PTR_ERR(maj_prio); + + for (chain = 0; chain < chains; chain++) { + err = create_fdb_sub_ns_prio_chain(steering, maj_prio); + if (err) + return err; + } + + return 0; +} - steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) * - (FDB_TC_MAX_CHAIN + 1), GFP_KERNEL); +static int create_fdb_fast_path(struct mlx5_flow_steering *steering) +{ + const int total_chains = FDB_TC_MAX_CHAIN + 1; + int err; + + steering->fdb_sub_ns = kcalloc(total_chains, + sizeof(*steering->fdb_sub_ns), + GFP_KERNEL); if (!steering->fdb_sub_ns) return -ENOMEM; + err = create_fdb_chains(steering, FDB_FAST_PATH, FDB_TC_MAX_CHAIN + 1); + if (err) + return err; + + return 0; +} + +static int init_fdb_root_ns(struct mlx5_flow_steering *steering) +{ + struct fs_prio *maj_prio; + int err; + + steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB); + if (!steering->fdb_root_ns) + return -ENOMEM; + maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_BYPASS_PATH, 1); if (IS_ERR(maj_prio)) { err = PTR_ERR(maj_prio); goto out_err; } - - levels = FDB_TC_LEVELS_PER_PRIO * - FDB_TC_MAX_PRIO * (FDB_TC_MAX_CHAIN + 1); - maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, - FDB_FAST_PATH, - levels); - if (IS_ERR(maj_prio)) { - err = PTR_ERR(maj_prio); + err = create_fdb_fast_path(steering); + if (err) goto out_err; - } - - for (chain = 0; chain <= FDB_TC_MAX_CHAIN; chain++) { - ns = fs_create_namespace(maj_prio, MLX5_FLOW_TABLE_MISS_ACTION_DEF); - if (IS_ERR(ns)) { - err = PTR_ERR(ns); - goto out_err; - } - - for (prio = 0; prio < FDB_TC_MAX_PRIO * (chain + 1); prio++) { - min_prio = fs_create_prio(ns, prio, - FDB_TC_LEVELS_PER_PRIO); - if (IS_ERR(min_prio)) { - err = PTR_ERR(min_prio); - goto out_err; - } - } - - steering->fdb_sub_ns[chain] = ns; - } maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, FDB_SLOW_PATH, 1); if (IS_ERR(maj_prio)) { -- cgit v1.2.3-59-g8ed1b From 975b992fdd4b38028d7c1dcf38286d6e7991c1b2 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:29 +0100 Subject: net/mlx5: Add new chain for netfilter flow table offload Netfilter tables (nftables) implements a software datapath that comes after tc ingress datapath. The datapath supports offloading such rules via the flow table offload API. This API is currently only used by NFT and it doesn't provide the global priority in regards to tc offload, so we assume offloading such rules must come after tc. It does provide a flow table priority parameter, so we need to provide some supported priority range. For that, split fastpath prio to two, flow table offload and tc offload, with one dedicated priority chain for flow table offload. Next patch will re-use the multi chain API to access this chain by allowing access to this chain by the fdb_sub_namespace. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/eswitch.h | 9 +++++++-- drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 9 ++++++--- include/linux/mlx5/fs.h | 3 ++- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 8c9d8dc85861..2b563700c664 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -44,7 +44,12 @@ #include "lib/mpfs.h" #define FDB_TC_MAX_CHAIN 3 -#define FDB_TC_SLOW_PATH_CHAIN (FDB_TC_MAX_CHAIN + 1) +#define FDB_FT_CHAIN (FDB_TC_MAX_CHAIN + 1) +#define FDB_TC_SLOW_PATH_CHAIN (FDB_FT_CHAIN + 1) + +/* The index of the last real chain (FT) + 1 as chain zero is valid as well */ +#define FDB_NUM_CHAINS (FDB_FT_CHAIN + 1) + #define FDB_TC_MAX_PRIO 16 #define FDB_TC_LEVELS_PER_PRIO 2 @@ -173,7 +178,7 @@ struct mlx5_eswitch_fdb { struct { struct mlx5_flow_table *fdb; u32 num_rules; - } fdb_prio[FDB_TC_MAX_CHAIN + 1][FDB_TC_MAX_PRIO + 1][FDB_TC_LEVELS_PER_PRIO]; + } fdb_prio[FDB_NUM_CHAINS][FDB_TC_MAX_PRIO + 1][FDB_TC_LEVELS_PER_PRIO]; /* Protects fdb_prio table */ struct mutex fdb_prio_lock; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 4aa6990a38b3..84e90b21e148 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -2624,16 +2624,19 @@ static int create_fdb_chains(struct mlx5_flow_steering *steering, static int create_fdb_fast_path(struct mlx5_flow_steering *steering) { - const int total_chains = FDB_TC_MAX_CHAIN + 1; int err; - steering->fdb_sub_ns = kcalloc(total_chains, + steering->fdb_sub_ns = kcalloc(FDB_NUM_CHAINS, sizeof(*steering->fdb_sub_ns), GFP_KERNEL); if (!steering->fdb_sub_ns) return -ENOMEM; - err = create_fdb_chains(steering, FDB_FAST_PATH, FDB_TC_MAX_CHAIN + 1); + err = create_fdb_chains(steering, FDB_TC_OFFLOAD, FDB_TC_MAX_CHAIN + 1); + if (err) + return err; + + err = create_fdb_chains(steering, FDB_FT_OFFLOAD, 1); if (err) return err; diff --git a/include/linux/mlx5/fs.h b/include/linux/mlx5/fs.h index 724d276ea133..4e5b84e66822 100644 --- a/include/linux/mlx5/fs.h +++ b/include/linux/mlx5/fs.h @@ -80,7 +80,8 @@ enum mlx5_flow_namespace_type { enum { FDB_BYPASS_PATH, - FDB_FAST_PATH, + FDB_TC_OFFLOAD, + FDB_FT_OFFLOAD, FDB_SLOW_PATH, }; -- cgit v1.2.3-59-g8ed1b From 86bb811b08086f98744ecc600907673af7f2aec5 Mon Sep 17 00:00:00 2001 From: Alex Vesker Date: Sun, 10 Nov 2019 18:10:13 +0200 Subject: net/mlx5: DR, Fix matcher builders select check When selecting a matcher ste_builder_arr will always be evaluated as true, instead check if num_of_builders is set for validity. Fixes: 667f264676c7 ("net/mlx5: DR, Support IPv4 and IPv6 mixed matcher") Signed-off-by: Alex Vesker Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c index 5db947df8763..c6548980daf0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c @@ -154,7 +154,7 @@ int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, nic_matcher->num_of_builders = nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv]; - if (!nic_matcher->ste_builder) { + if (!nic_matcher->num_of_builders) { mlx5dr_dbg(matcher->tbl->dmn, "Rule not supported on this matcher due to IP related fields\n"); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From a7cba0a4d508d2d78f2932ee944feadd38c97c2c Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Mon, 28 Oct 2019 13:29:17 -0500 Subject: net/mlx5: Read num_vfs before disabling SR-IOV mlx5_device_disable_sriov() currently reads num_vfs from the PCI core. However when mlx5_device_disable_sriov() is executed, SR-IOV is already disabled at the PCI level. Due to this disable_hca() cleanup is not done during SR-IOV disable flow. mlx5_sriov_disable() pci_enable_sriov() mlx5_device_disable_sriov() <- num_vfs is zero here. When SR-IOV enablement fails during mlx5_sriov_enable(), HCA's are left in enabled stage because mlx5_device_disable_sriov() relies on num_vfs from PCI core. mlx5_sriov_enable() mlx5_device_enable_sriov() pci_enable_sriov() <- Fails Hence, to overcome above issues, (a) Read num_vfs before disabling SR-IOV and use it. (b) Use num_vfs given when enabling sriov in error unwinding path. Fixes: d886aba677a0 ("net/mlx5: Reduce dependency on enabled_vfs counter and num_vfs") Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/sriov.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c index f641f1336402..03f037811f1d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/sriov.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/sriov.c @@ -108,10 +108,10 @@ enable_vfs_hca: return 0; } -static void mlx5_device_disable_sriov(struct mlx5_core_dev *dev, bool clear_vf) +static void +mlx5_device_disable_sriov(struct mlx5_core_dev *dev, int num_vfs, bool clear_vf) { struct mlx5_core_sriov *sriov = &dev->priv.sriov; - int num_vfs = pci_num_vf(dev->pdev); int err; int vf; @@ -147,7 +147,7 @@ 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, true); + mlx5_device_disable_sriov(dev, num_vfs, true); } return err; } @@ -155,9 +155,10 @@ static int mlx5_sriov_enable(struct pci_dev *pdev, int num_vfs) static void mlx5_sriov_disable(struct pci_dev *pdev) { struct mlx5_core_dev *dev = pci_get_drvdata(pdev); + int num_vfs = pci_num_vf(dev->pdev); pci_disable_sriov(pdev); - mlx5_device_disable_sriov(dev, true); + mlx5_device_disable_sriov(dev, num_vfs, true); } int mlx5_core_sriov_configure(struct pci_dev *pdev, int num_vfs) @@ -192,7 +193,7 @@ void mlx5_sriov_detach(struct mlx5_core_dev *dev) if (!mlx5_core_is_pf(dev)) return; - mlx5_device_disable_sriov(dev, false); + mlx5_device_disable_sriov(dev, pci_num_vf(dev->pdev), false); } static u16 mlx5_get_max_vfs(struct mlx5_core_dev *dev) -- cgit v1.2.3-59-g8ed1b From e6014afd1c5717d556778ec1307cf7ab27ba5a2d Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 30 Oct 2019 16:48:15 +0200 Subject: net/mlx5: Remove redundant NULL initializations Neighbour initializations to NULL are not necessary as the pointers are not used if an error is returned, and if success returned, pointers are initialized. Signed-off-by: Eli Cohen Reviewed-by: Vlad Buslov Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index 13af72556987..4f78efeb6ee8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -77,8 +77,8 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, struct neighbour **out_n, u8 *out_ttl) { + struct neighbour *n; struct rtable *rt; - struct neighbour *n = NULL; #if IS_ENABLED(CONFIG_INET) struct mlx5_core_dev *mdev = priv->mdev; @@ -138,8 +138,8 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, struct neighbour **out_n, u8 *out_ttl) { - struct neighbour *n = NULL; struct dst_entry *dst; + struct neighbour *n; #if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) int ret; @@ -212,8 +212,8 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi4 fl4 = {}; + struct neighbour *n; int ipv4_encap_size; char *encap_header; u8 nud_state, ttl; @@ -328,9 +328,9 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); const struct ip_tunnel_key *tun_key = &e->tun_info->key; struct net_device *out_dev, *route_dev; - struct neighbour *n = NULL; struct flowi6 fl6 = {}; struct ipv6hdr *ip6h; + struct neighbour *n; int ipv6_encap_size; char *encap_header; u8 nud_state, ttl; -- cgit v1.2.3-59-g8ed1b From 85bf490af1e2e4b6263898f0d47af13ee1bb4d28 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 31 Oct 2019 09:00:43 +0200 Subject: net/mlx5e: Fix error flow cleanup in mlx5e_tc_tun_create_header_ipv4/6 Be sure to release the neighbour in case of failures after successful route lookup. Signed-off-by: Eli Cohen Reviewed-by: Roi Dayan Reviewed-by: Vlad Buslov Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index 4f78efeb6ee8..5316cedd78bf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -239,12 +239,15 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, if (max_encap_size < ipv4_encap_size) { mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv4_encap_size, max_encap_size); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto out; } encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); - if (!encap_header) - return -ENOMEM; + if (!encap_header) { + err = -ENOMEM; + goto out; + } /* used by mlx5e_detach_encap to lookup a neigh hash table * entry in the neigh hash table when a user deletes a rule @@ -355,12 +358,15 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, if (max_encap_size < ipv6_encap_size) { mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv6_encap_size, max_encap_size); - return -EOPNOTSUPP; + err = -EOPNOTSUPP; + goto out; } encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); - if (!encap_header) - return -ENOMEM; + if (!encap_header) { + err = -ENOMEM; + goto out; + } /* used by mlx5e_detach_encap to lookup a neigh hash table * entry in the neigh hash table when a user deletes a rule -- cgit v1.2.3-59-g8ed1b From 71c6eaebf06aa8353b0dcd57786b801b96fe2c08 Mon Sep 17 00:00:00 2001 From: Michael Guralnik Date: Tue, 29 Oct 2019 17:04:30 +0200 Subject: net/mlx5e: Set netdev name space on creation Use devlink instance name space to set the netdev net namespace. Preparation patch for devlink reload implementation. Signed-off-by: Michael Guralnik Acked-by: Jiri Pirko Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 ++ drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h | 5 +++++ 3 files changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 772bfdbdeb9c..06a592fb62bf 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -63,6 +63,7 @@ #include "en/xsk/rx.h" #include "en/xsk/tx.h" #include "en/hv_vhca_stats.h" +#include "lib/mlx5.h" bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev) @@ -5427,6 +5428,7 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev) return NULL; } + dev_net_set(netdev, mlx5_core_net(mdev)); priv = netdev_priv(netdev); err = mlx5e_attach(mdev, priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index cd9bb7c7b341..c7f98f1fd9b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -47,6 +47,7 @@ #include "en/tc_tun.h" #include "fs_core.h" #include "lib/port_tun.h" +#include "lib/mlx5.h" #define CREATE_TRACE_POINTS #include "diag/en_rep_tracepoint.h" @@ -1877,6 +1878,7 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep) return -EINVAL; } + dev_net_set(netdev, mlx5_core_net(dev)); rpriv->netdev = netdev; rep->rep_data[REP_ETH].priv = rpriv; INIT_LIST_HEAD(&rpriv->vport_sqs_list); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h index b99d469e4e64..249539247e2e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lib/mlx5.h @@ -84,4 +84,9 @@ int mlx5_create_encryption_key(struct mlx5_core_dev *mdev, void *key, u32 sz_bytes, u32 *p_key_id); void mlx5_destroy_encryption_key(struct mlx5_core_dev *mdev, u32 key_id); +static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev) +{ + return devlink_net(priv_to_devlink(dev)); +} + #endif -- cgit v1.2.3-59-g8ed1b From 4383cfcc65e7879e1858da56954dae9fc20dfae9 Mon Sep 17 00:00:00 2001 From: Michael Guralnik Date: Sun, 27 Oct 2019 14:34:11 +0200 Subject: net/mlx5: Add devlink reload Implement devlink reload for mlx5. Usage example: devlink dev reload pci/0000:06:00.0 Signed-off-by: Michael Guralnik Acked-by: Jiri Pirko Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 20 ++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 +++ 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index b2c26388edb1..ac108f1e5bd6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -85,6 +85,22 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, return 0; } +static int mlx5_devlink_reload_down(struct devlink *devlink, bool netns_change, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + return mlx5_unload_one(dev, false); +} + +static int mlx5_devlink_reload_up(struct devlink *devlink, + struct netlink_ext_ack *extack) +{ + struct mlx5_core_dev *dev = devlink_priv(devlink); + + return mlx5_load_one(dev, false); +} + static const struct devlink_ops mlx5_devlink_ops = { #ifdef CONFIG_MLX5_ESWITCH .eswitch_mode_set = mlx5_devlink_eswitch_mode_set, @@ -96,6 +112,8 @@ static const struct devlink_ops mlx5_devlink_ops = { #endif .flash_update = mlx5_devlink_flash_update, .info_get = mlx5_devlink_info_get, + .reload_down = mlx5_devlink_reload_down, + .reload_up = mlx5_devlink_reload_up, }; struct devlink *mlx5_devlink_alloc(void) @@ -235,6 +253,7 @@ int mlx5_devlink_register(struct devlink *devlink, struct device *dev) goto params_reg_err; mlx5_devlink_set_params_init_values(devlink); devlink_params_publish(devlink); + devlink_reload_enable(devlink); return 0; params_reg_err: @@ -244,6 +263,7 @@ params_reg_err: void mlx5_devlink_unregister(struct devlink *devlink) { + devlink_reload_disable(devlink); devlink_params_unregister(devlink, mlx5_devlink_params, ARRAY_SIZE(mlx5_devlink_params)); devlink_unregister(devlink); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c9a091d3226c..31fbfd6e8bb9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1168,7 +1168,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev) mlx5_put_uars_page(dev, dev->priv.uar); } -static int mlx5_load_one(struct mlx5_core_dev *dev, bool boot) +int mlx5_load_one(struct mlx5_core_dev *dev, bool boot) { int err = 0; @@ -1226,7 +1226,7 @@ function_teardown: return err; } -static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) +int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup) { if (cleanup) { mlx5_unregister_device(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b100489dc85c..da67b28d6e23 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -243,4 +243,7 @@ enum { u8 mlx5_get_nic_state(struct mlx5_core_dev *dev); void mlx5_set_nic_state(struct mlx5_core_dev *dev, u8 state); + +int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup); +int mlx5_load_one(struct mlx5_core_dev *dev, bool boot); #endif /* __MLX5_CORE_H__ */ -- cgit v1.2.3-59-g8ed1b From 84179981317fb4fb3e9df5acd42ea33cf6037793 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Tue, 12 Nov 2019 00:34:30 +0100 Subject: net/mlx5: TC: Offload flow table rules Since both tc rules and flow table rules are of the same format, we can re-use tc parsing for that, and move the flow table rules to their steering domain - In this case, the next chain after max tc chain. Signed-off-by: Paul Blakey Reviewed-by: Mark Bloch Acked-by: Pablo Neira Ayuso Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 45 ++++++++++++++++++++++-- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 28 ++++++++++++++- drivers/net/ethernet/mellanox/mlx5/core/en_tc.h | 3 +- 3 files changed, 71 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c index c7f98f1fd9b1..f175cb24bb67 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c @@ -1244,21 +1244,60 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data, } } -static LIST_HEAD(mlx5e_rep_block_cb_list); +static int mlx5e_rep_setup_ft_cb(enum tc_setup_type type, void *type_data, + void *cb_priv) +{ + struct flow_cls_offload *f = type_data; + struct flow_cls_offload cls_flower; + struct mlx5e_priv *priv = cb_priv; + struct mlx5_eswitch *esw; + unsigned long flags; + int err; + + flags = MLX5_TC_FLAG(INGRESS) | + MLX5_TC_FLAG(ESW_OFFLOAD) | + MLX5_TC_FLAG(FT_OFFLOAD); + esw = priv->mdev->priv.eswitch; + switch (type) { + case TC_SETUP_CLSFLOWER: + if (!mlx5_eswitch_prios_supported(esw) || f->common.chain_index) + return -EOPNOTSUPP; + + /* Re-use tc offload path by moving the ft flow to the + * reserved ft chain. + */ + memcpy(&cls_flower, f, sizeof(*f)); + cls_flower.common.chain_index = FDB_FT_CHAIN; + err = mlx5e_rep_setup_tc_cls_flower(priv, &cls_flower, flags); + memcpy(&f->stats, &cls_flower.stats, sizeof(f->stats)); + return err; + default: + return -EOPNOTSUPP; + } +} + +static LIST_HEAD(mlx5e_rep_block_tc_cb_list); +static LIST_HEAD(mlx5e_rep_block_ft_cb_list); static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { struct mlx5e_priv *priv = netdev_priv(dev); struct flow_block_offload *f = type_data; + f->unlocked_driver_cb = true; + switch (type) { case TC_SETUP_BLOCK: - f->unlocked_driver_cb = true; return flow_block_cb_setup_simple(type_data, - &mlx5e_rep_block_cb_list, + &mlx5e_rep_block_tc_cb_list, mlx5e_rep_setup_tc_cb, priv, priv, true); + case TC_SETUP_FT: + return flow_block_cb_setup_simple(type_data, + &mlx5e_rep_block_ft_cb_list, + mlx5e_rep_setup_ft_cb, + priv, priv, true); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 0c1022cda128..3a707d788022 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -74,6 +74,7 @@ enum { MLX5E_TC_FLOW_FLAG_INGRESS = MLX5E_TC_FLAG_INGRESS_BIT, MLX5E_TC_FLOW_FLAG_EGRESS = MLX5E_TC_FLAG_EGRESS_BIT, MLX5E_TC_FLOW_FLAG_ESWITCH = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, + MLX5E_TC_FLOW_FLAG_FT = MLX5E_TC_FLAG_FT_OFFLOAD_BIT, MLX5E_TC_FLOW_FLAG_NIC = MLX5E_TC_FLAG_NIC_OFFLOAD_BIT, MLX5E_TC_FLOW_FLAG_OFFLOADED = MLX5E_TC_FLOW_BASE, MLX5E_TC_FLOW_FLAG_HAIRPIN = MLX5E_TC_FLOW_BASE + 1, @@ -276,6 +277,11 @@ static bool mlx5e_is_eswitch_flow(struct mlx5e_tc_flow *flow) return flow_flag_test(flow, ESWITCH); } +static bool mlx5e_is_ft_flow(struct mlx5e_tc_flow *flow) +{ + return flow_flag_test(flow, FT); +} + static bool mlx5e_is_offloaded_flow(struct mlx5e_tc_flow *flow) { return flow_flag_test(flow, OFFLOADED); @@ -1168,7 +1174,12 @@ mlx5e_tc_add_fdb_flow(struct mlx5e_priv *priv, return -EOPNOTSUPP; } - if (attr->chain > max_chain) { + /* We check chain range only for tc flows. + * For ft flows, we checked attr->chain was originally 0 and set it to + * FDB_FT_CHAIN which is outside tc range. + * See mlx5e_rep_setup_ft_cb(). + */ + if (!mlx5e_is_ft_flow(flow) && attr->chain > max_chain) { NL_SET_ERR_MSG(extack, "Requested chain is out of supported range"); return -EOPNOTSUPP; } @@ -3217,6 +3228,7 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct mlx5e_tc_flow_parse_attr *parse_attr = attr->parse_attr; struct mlx5e_rep_priv *rpriv = priv->ppriv; const struct ip_tunnel_info *info = NULL; + bool ft_flow = mlx5e_is_ft_flow(flow); const struct flow_action_entry *act; bool encap = false; u32 action = 0; @@ -3261,6 +3273,14 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, return -EINVAL; } + if (ft_flow && out_dev == priv->netdev) { + /* Ignore forward to self rules generated + * by adding both mlx5 devs to the flow table + * block on a normal nft offload setup. + */ + return -EOPNOTSUPP; + } + if (attr->out_count >= MLX5_MAX_FLOW_FWD_VPORTS) { NL_SET_ERR_MSG_MOD(extack, "can't support more output ports, can't offload forwarding"); @@ -3385,6 +3405,10 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, u32 dest_chain = act->chain_index; u32 max_chain = mlx5_eswitch_get_chain_range(esw); + if (ft_flow) { + NL_SET_ERR_MSG_MOD(extack, "Goto action is not supported"); + return -EOPNOTSUPP; + } if (dest_chain <= attr->chain) { NL_SET_ERR_MSG(extack, "Goto earlier chain isn't supported"); return -EOPNOTSUPP; @@ -3475,6 +3499,8 @@ static void get_flags(int flags, unsigned long *flow_flags) __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_ESWITCH); if (flags & MLX5_TC_FLAG(NIC_OFFLOAD)) __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_NIC); + if (flags & MLX5_TC_FLAG(FT_OFFLOAD)) + __flow_flags |= BIT(MLX5E_TC_FLOW_FLAG_FT); *flow_flags = __flow_flags; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h index 924c6ef86a14..262cdb7b69b1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.h @@ -44,7 +44,8 @@ enum { MLX5E_TC_FLAG_EGRESS_BIT, MLX5E_TC_FLAG_NIC_OFFLOAD_BIT, MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, - MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_ESW_OFFLOAD_BIT, + MLX5E_TC_FLAG_FT_OFFLOAD_BIT, + MLX5E_TC_FLAG_LAST_EXPORTED_BIT = MLX5E_TC_FLAG_FT_OFFLOAD_BIT, }; #define MLX5_TC_FLAG(flag) BIT(MLX5E_TC_FLAG_##flag##_BIT) -- cgit v1.2.3-59-g8ed1b From 3128aad163d36d99247fc76b4efbbba2d5465cc4 Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Wed, 13 Nov 2019 13:51:19 -0500 Subject: bnxt_en: Fix array overrun in bnxt_fill_l2_rewrite_fields(). Fix the array overrun while keeping the eth_addr and eth_addr_mask pointers as u16 to avoid unaligned u16 access. These were overlooked when modifying the code to use u16 pointer for proper alignment. Fixes: 90f906243bf6 ("bnxt_en: Add support for L2 rewrite") Reported-by: Olof Johansson Signed-off-by: Venkat Duvvuru Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c index 174412a55e53..0cc6ec51f45f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c @@ -166,8 +166,8 @@ bnxt_fill_l2_rewrite_fields(struct bnxt_tc_actions *actions, actions->l2_rewrite_dmac[j] = cpu_to_be16(*(p + j)); } - if (!is_wildcard(ð_addr_mask[ETH_ALEN], ETH_ALEN)) { - if (!is_exactmatch(ð_addr_mask[ETH_ALEN], ETH_ALEN)) + if (!is_wildcard(ð_addr_mask[ETH_ALEN / 2], ETH_ALEN)) { + if (!is_exactmatch(ð_addr_mask[ETH_ALEN / 2], ETH_ALEN)) return -EINVAL; /* FW expects smac to be in u16 array format */ p = ð_addr[ETH_ALEN / 2]; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h index 286754903543..10c62b094914 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_tc.h @@ -64,9 +64,9 @@ struct bnxt_tc_tunnel_key { #define bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask) \ ((is_wildcard(&(eth_addr)[0], ETH_ALEN) && \ - is_wildcard(&(eth_addr)[ETH_ALEN], ETH_ALEN)) || \ + is_wildcard(&(eth_addr)[ETH_ALEN / 2], ETH_ALEN)) || \ (is_wildcard(&(eth_addr_mask)[0], ETH_ALEN) && \ - is_wildcard(&(eth_addr_mask)[ETH_ALEN], ETH_ALEN))) + is_wildcard(&(eth_addr_mask)[ETH_ALEN / 2], ETH_ALEN))) struct bnxt_tc_actions { u32 flags; -- cgit v1.2.3-59-g8ed1b From d41378713eef6a7d9d9c30cb9a6181ad72f69596 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Nov 2019 21:31:58 +0300 Subject: net: atlantic: Signedness bug in aq_vec_isr_legacy() irqreturn_t type is an enum and in this context it's unsigned, so "err" can't be irqreturn_t or it breaks the error handling. In fact the "err" variable is only used to store integers (never irqreturn_t) so it should be declared as int. I removed the initialization because it's not required. Using a bogus initializer turns off GCC's uninitialized variable warnings. Secondly, there is a GCC warning about unused assignments and we would like to enable that feature eventually so we have been trying to remove these unnecessary initializers. Fixes: 7b0c342f1f67 ("net: atlantic: code style cleanup") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/aquantia/atlantic/aq_vec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index 6e19e27b6200..f40a427970dc 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c @@ -307,8 +307,8 @@ err_exit: irqreturn_t aq_vec_isr_legacy(int irq, void *private) { struct aq_vec_s *self = private; - irqreturn_t err = 0; u64 irq_mask = 0U; + int err; if (!self) return IRQ_NONE; -- cgit v1.2.3-59-g8ed1b From 72c996099dc6fd83947a79cdac05625c6a52ffa6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 13 Nov 2019 21:25:48 +0300 Subject: cxgb4: Fix an error code in cxgb4_mqprio_alloc_hw_resources() "ret" is zero or possibly uninitialized on this error path. It should be a negative error code instead. Fixes: 2d0cb84dd973 ("cxgb4: add ETHOFLD hardware queue support") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index 388078488fb5..ce442c63f496 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -158,8 +158,10 @@ static int cxgb4_mqprio_alloc_hw_resources(struct net_device *dev) /* Allocate Rxqs for receiving ETHOFLD Tx completions */ if (msix >= 0) { msix = cxgb4_get_msix_idx_from_bmap(adap); - if (msix < 0) + if (msix < 0) { + ret = msix; goto out_free_queues; + } eorxq->msix = &adap->msix_info[msix]; snprintf(eorxq->msix->desc, -- cgit v1.2.3-59-g8ed1b From 0e531cc575c4e9e3dd52ad287b49d3c2dc74c810 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 11 Nov 2019 13:40:44 -0600 Subject: rtlwifi: rtl8192de: Fix missing code to retrieve RX buffer address In commit 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers"), a callback to get the RX buffer address was added to the PCI driver. Unfortunately, driver rtl8192de was not modified appropriately and the code runs into a WARN_ONCE() call. The use of an incorrect array is also fixed. Fixes: 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers") Cc: Stable # 3.18+ Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index 2494e1f118f8..b4561923a70a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -804,13 +804,15 @@ u64 rtl92de_get_desc(struct ieee80211_hw *hw, break; } } else { - struct rx_desc_92c *pdesc = (struct rx_desc_92c *)p_desc; switch (desc_name) { case HW_DESC_OWN: - ret = GET_RX_DESC_OWN(pdesc); + ret = GET_RX_DESC_OWN(p_desc); break; case HW_DESC_RXPKT_LEN: - ret = GET_RX_DESC_PKT_LEN(pdesc); + ret = GET_RX_DESC_PKT_LEN(p_desc); + break; + case HW_DESC_RXBUFF_ADDR: + ret = GET_RX_DESC_BUFF_ADDR(p_desc); break; default: WARN_ONCE(true, "rtl8192de: ERR rxdesc :%d not processed\n", -- cgit v1.2.3-59-g8ed1b From 3155db7613edea8fb943624062baf1e4f9cfbfd6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 11 Nov 2019 13:40:45 -0600 Subject: rtlwifi: rtl8192de: Fix missing callback that tests for hw release of buffer In commit 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers"), a callback needed to check if the hardware has released a buffer indicating that a DMA operation is completed was not added. Fixes: 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers") Cc: Stable # v3.18+ Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c | 1 + drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c | 17 +++++++++++++++++ drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h | 2 ++ 3 files changed, 20 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index 99e5cd9a5c86..1dbdddce0823 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -216,6 +216,7 @@ static struct rtl_hal_ops rtl8192de_hal_ops = { .led_control = rtl92de_led_control, .set_desc = rtl92de_set_desc, .get_desc = rtl92de_get_desc, + .is_tx_desc_closed = rtl92de_is_tx_desc_closed, .tx_polling = rtl92de_tx_polling, .enable_hw_sec = rtl92de_enable_hw_security_config, .set_key = rtl92de_set_key, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index b4561923a70a..92c9fb45f800 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -823,6 +823,23 @@ u64 rtl92de_get_desc(struct ieee80211_hw *hw, return ret; } +bool rtl92de_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + u8 *entry = (u8 *)(&ring->desc[ring->idx]); + u8 own = (u8)rtl92de_get_desc(hw, entry, true, HW_DESC_OWN); + + /* a beacon packet will only use the first + * descriptor by defaut, and the own bit may not + * be cleared by the hardware + */ + if (own) + return false; + return true; +} + void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h index 36820070fd76..635989e15282 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.h @@ -715,6 +715,8 @@ void rtl92de_set_desc(struct ieee80211_hw *hw, u8 *pdesc, bool istx, u8 desc_name, u8 *val); u64 rtl92de_get_desc(struct ieee80211_hw *hw, u8 *p_desc, bool istx, u8 desc_name); +bool rtl92de_is_tx_desc_closed(struct ieee80211_hw *hw, + u8 hw_queue, u16 index); void rtl92de_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool b_firstseg, bool b_lastseg, -- cgit v1.2.3-59-g8ed1b From 330bb7117101099c687e9c7f13d48068670b9c62 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 11 Nov 2019 13:40:46 -0600 Subject: rtlwifi: rtl8192de: Fix missing enable interrupt flag In commit 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers"), the flag that indicates that interrupts are enabled was never set. In addition, there are several places when enable/disable interrupts were commented out are restored. A sychronize_interrupts() call is removed. Fixes: 38506ecefab9 ("rtlwifi: rtl_pci: Start modification for new drivers") Cc: Stable # v3.18+ Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c index c7f29a9be50d..146fe144f5f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c @@ -1176,6 +1176,7 @@ void rtl92de_enable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); + rtlpci->irq_enabled = true; } void rtl92de_disable_interrupt(struct ieee80211_hw *hw) @@ -1185,7 +1186,7 @@ void rtl92de_disable_interrupt(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED); rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED); - synchronize_irq(rtlpci->pdev->irq); + rtlpci->irq_enabled = false; } static void _rtl92de_poweroff_adapter(struct ieee80211_hw *hw) @@ -1351,7 +1352,7 @@ void rtl92de_set_beacon_related_registers(struct ieee80211_hw *hw) bcn_interval = mac->beacon_interval; atim_window = 2; - /*rtl92de_disable_interrupt(hw); */ + rtl92de_disable_interrupt(hw); rtl_write_word(rtlpriv, REG_ATIMWND, atim_window); rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f); @@ -1371,9 +1372,9 @@ void rtl92de_set_beacon_interval(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG, "beacon_interval:%d\n", bcn_interval); - /* rtl92de_disable_interrupt(hw); */ + rtl92de_disable_interrupt(hw); rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval); - /* rtl92de_enable_interrupt(hw); */ + rtl92de_enable_interrupt(hw); } void rtl92de_update_interrupt_mask(struct ieee80211_hw *hw, -- cgit v1.2.3-59-g8ed1b From 408f122a1f923011099468e9f317e6dbe200fd31 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Tue, 12 Nov 2019 15:28:50 -0500 Subject: rtl8xxxu: Add support for Edimax EW-7611ULB A number of people have reported the Edimax EW-7611ULB works fine. Signed-off-by: Jes Sorensen Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index bcb92831d376..32a40b82c5f5 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -6481,7 +6481,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, } break; case 0x7392: - if (id->idProduct == 0x7811) + if (id->idProduct == 0x7811 || id->idProduct == 0xa611) untested = 0; break; case 0x050d: @@ -6689,6 +6689,8 @@ static const struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8192eu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0xb720, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8723bu_fops}, +{USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xa611, 0xff, 0xff, 0xff), + .driver_info = (unsigned long)&rtl8723bu_fops}, #ifdef CONFIG_RTL8XXXU_UNTESTED /* Still supported by rtlwifi */ {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8176, 0xff, 0xff, 0xff), -- cgit v1.2.3-59-g8ed1b From 4a33f21cef84b1b933958c99ed5dac1726214b35 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:47 +0000 Subject: qtnfmac: fix using skb after free KASAN reported use-after-free error: [ 995.220767] BUG: KASAN: use-after-free in qtnf_cmd_send_with_reply+0x169/0x3e0 [qtnfmac] [ 995.221098] Read of size 2 at addr ffff888213d1ded0 by task kworker/1:1/71 The issue in qtnf_cmd_send_with_reply impacts all the commands that do not need response other then return code. For such commands, consume_skb is used for response skb and right after that return code in response skb is accessed. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index dc0c7244b60e..c0c32805fb8d 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -83,6 +83,7 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, struct qlink_cmd *cmd; struct qlink_resp *resp = NULL; struct sk_buff *resp_skb = NULL; + int resp_res = 0; u16 cmd_id; u8 mac_id; u8 vif_id; @@ -113,6 +114,7 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus, } resp = (struct qlink_resp *)resp_skb->data; + resp_res = le16_to_cpu(resp->result); ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id, const_resp_size); if (ret) @@ -128,8 +130,8 @@ out: else consume_skb(resp_skb); - if (!ret && resp) - return qtnf_cmd_resp_result_decode(le16_to_cpu(resp->result)); + if (!ret) + return qtnf_cmd_resp_result_decode(resp_res); pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n", mac_id, vif_id, cmd_id, ret); -- cgit v1.2.3-59-g8ed1b From dd4c2260dab04f5ae7bdb79b9470e7da56f48145 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:49 +0000 Subject: qtnfmac: fix debugfs support for multiple cards Fix merge artifact for commit 0b68fe10b8e8 ("qtnfmac: modify debugfs to support multiple cards") and finally add debugfs support for multiple qtnfmac wireless cards. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index 8ae318b5fe54..4824be0c6231 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -130,6 +130,8 @@ static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus) { + struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + char card_id[64]; int ret; bus->fw_state = QTNF_FW_STATE_BOOT_DONE; @@ -137,7 +139,9 @@ int qtnf_pcie_fw_boot_done(struct qtnf_bus *bus) if (ret) { pr_err("failed to attach core\n"); } else { - qtnf_debugfs_init(bus, DRV_NAME); + snprintf(card_id, sizeof(card_id), "%s:%s", + DRV_NAME, pci_name(priv->pdev)); + qtnf_debugfs_init(bus, card_id); qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); -- cgit v1.2.3-59-g8ed1b From 24227a9e956a7c9913a7e6e7199a9ae3f540fe88 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:51 +0000 Subject: qtnfmac: fix invalid channel information output Do not attempt to print frequency for an invalid channel provided by firmware. That channel may simply not exist. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/event.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index b57c8c18a8d0..7846383c8828 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -171,8 +171,9 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, return -EPROTO; } - pr_debug("VIF%u.%u: BSSID:%pM status:%u\n", - vif->mac->macid, vif->vifid, join_info->bssid, status); + pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n", + vif->mac->macid, vif->vifid, join_info->bssid, + le16_to_cpu(join_info->chan.chan.center_freq), status); if (status != WLAN_STATUS_SUCCESS) goto done; @@ -181,7 +182,7 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif, if (!cfg80211_chandef_valid(&chandef)) { pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", vif->mac->macid, vif->vifid, - chandef.chan->center_freq, + chandef.chan ? chandef.chan->center_freq : 0, chandef.center_freq1, chandef.center_freq2, chandef.width); -- cgit v1.2.3-59-g8ed1b From 97aef03cb71b49e651ea286beea2ec75cae86d8b Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:53 +0000 Subject: qtnfmac: modify Rx descriptors queue setup Rx descriptors queue length is hardware specific. Current common default value is no more than an accident. So move Rx descriptor queue setup to platform PCIe backend in the same way as it is already done for Tx. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 5 ++- .../wireless/quantenna/qtnfmac/pcie/pcie_priv.h | 3 +- .../wireless/quantenna/qtnfmac/pcie/pearl_pcie.c | 36 ++++++++++++---------- .../wireless/quantenna/qtnfmac/pcie/topaz_pcie.c | 20 ++++++++++-- 4 files changed, 41 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index 4824be0c6231..3360b836fc44 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -33,7 +33,7 @@ static unsigned int tx_bd_size_param; module_param(tx_bd_size_param, uint, 0644); MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size"); -static unsigned int rx_bd_size_param = 256; +static unsigned int rx_bd_size_param; module_param(rx_bd_size_param, uint, 0644); MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size"); @@ -341,7 +341,6 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus->fw_state = QTNF_FW_STATE_DETACHED; pcie_priv->pdev = pdev; pcie_priv->tx_stopped = 0; - pcie_priv->rx_bd_num = rx_bd_size_param; pcie_priv->flashboot = flashboot; if (fw_blksize_param > QTN_PCIE_MAX_FW_BUFSZ) @@ -381,7 +380,7 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcie_priv->epmem_bar = epmem_bar; pci_save_state(pdev); - ret = pcie_priv->probe_cb(bus, tx_bd_size_param); + ret = pcie_priv->probe_cb(bus, tx_bd_size_param, rx_bd_size_param); if (ret) goto error; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h index 5e8b9cb68419..8bc4300518d0 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -23,7 +23,8 @@ struct qtnf_pcie_bus_priv { struct pci_dev *pdev; - int (*probe_cb)(struct qtnf_bus *bus, unsigned int tx_bd_size); + int (*probe_cb)(struct qtnf_bus *bus, unsigned int tx_bd_size, + unsigned int rx_bd_size); void (*remove_cb)(struct qtnf_bus *bus); int (*suspend_cb)(struct qtnf_bus *bus); int (*resume_cb)(struct qtnf_bus *bus); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index 5ec1c9bc1612..a501a1fd5332 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -24,6 +24,7 @@ #include "debug.h" #define PEARL_TX_BD_SIZE_DEFAULT 32 +#define PEARL_RX_BD_SIZE_DEFAULT 256 struct qtnf_pearl_bda { __le16 bda_len; @@ -397,7 +398,8 @@ static int pearl_hhbm_init(struct qtnf_pcie_pearl_state *ps) } static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps, - unsigned int tx_bd_size) + unsigned int tx_bd_size, + unsigned int rx_bd_size) { struct qtnf_pcie_bus_priv *priv = &ps->base; int ret; @@ -409,28 +411,29 @@ static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps, val = tx_bd_size * sizeof(struct qtnf_pearl_tx_bd); if (!is_power_of_2(tx_bd_size) || val > PCIE_HHBM_MAX_SIZE) { - pr_warn("bad tx_bd_size value %u\n", tx_bd_size); + pr_warn("invalid tx_bd_size value %u, use default %u\n", + tx_bd_size, PEARL_TX_BD_SIZE_DEFAULT); priv->tx_bd_num = PEARL_TX_BD_SIZE_DEFAULT; } else { priv->tx_bd_num = tx_bd_size; } - priv->rx_bd_w_index = 0; - priv->rx_bd_r_index = 0; + if (rx_bd_size == 0) + rx_bd_size = PEARL_RX_BD_SIZE_DEFAULT; - if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) { - pr_err("rx_bd_size_param %u is not power of two\n", - priv->rx_bd_num); - return -EINVAL; - } + val = rx_bd_size * sizeof(dma_addr_t); - val = priv->rx_bd_num * sizeof(dma_addr_t); - if (val > PCIE_HHBM_MAX_SIZE) { - pr_err("rx_bd_size_param %u is too large\n", - priv->rx_bd_num); - return -EINVAL; + if (!is_power_of_2(rx_bd_size) || val > PCIE_HHBM_MAX_SIZE) { + pr_warn("invalid rx_bd_size value %u, use default %u\n", + rx_bd_size, PEARL_RX_BD_SIZE_DEFAULT); + priv->rx_bd_num = PEARL_RX_BD_SIZE_DEFAULT; + } else { + priv->rx_bd_num = rx_bd_size; } + priv->rx_bd_w_index = 0; + priv->rx_bd_r_index = 0; + ret = pearl_hhbm_init(ps); if (ret) { pr_err("failed to init h/w queues\n"); @@ -1064,7 +1067,8 @@ static u64 qtnf_pearl_dma_mask_get(void) #endif } -static int qtnf_pcie_pearl_probe(struct qtnf_bus *bus, unsigned int tx_bd_size) +static int qtnf_pcie_pearl_probe(struct qtnf_bus *bus, unsigned int tx_bd_size, + unsigned int rx_bd_size) { struct qtnf_shm_ipc_int ipc_int; struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); @@ -1079,7 +1083,7 @@ static int qtnf_pcie_pearl_probe(struct qtnf_bus *bus, unsigned int tx_bd_size) ps->bda = ps->base.epmem_bar; writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled); - ret = qtnf_pcie_pearl_init_xfer(ps, tx_bd_size); + ret = qtnf_pcie_pearl_init_xfer(ps, tx_bd_size, rx_bd_size); if (ret) { pr_err("PCIE xfer init failed\n"); return ret; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index 1f91088e3dff..ef255fb57405 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -23,6 +23,7 @@ #include "debug.h" #define TOPAZ_TX_BD_SIZE_DEFAULT 128 +#define TOPAZ_RX_BD_SIZE_DEFAULT 256 struct qtnf_topaz_tx_bd { __le32 addr; @@ -331,7 +332,8 @@ static void qtnf_topaz_free_xfer_buffers(struct qtnf_pcie_topaz_state *ts) } static int qtnf_pcie_topaz_init_xfer(struct qtnf_pcie_topaz_state *ts, - unsigned int tx_bd_size) + unsigned int tx_bd_size, + unsigned int rx_bd_size) { struct qtnf_topaz_bda __iomem *bda = ts->bda; struct qtnf_pcie_bus_priv *priv = &ts->base; @@ -349,6 +351,17 @@ static int qtnf_pcie_topaz_init_xfer(struct qtnf_pcie_topaz_state *ts, priv->tx_bd_num = tx_bd_size; qtnf_non_posted_write(priv->tx_bd_num, &bda->bda_rc_tx_bd_num); + + if (rx_bd_size == 0) + rx_bd_size = TOPAZ_RX_BD_SIZE_DEFAULT; + + if (rx_bd_size > TOPAZ_RX_BD_SIZE_DEFAULT) { + pr_warn("RX BD queue cannot exceed %d\n", + TOPAZ_RX_BD_SIZE_DEFAULT); + rx_bd_size = TOPAZ_RX_BD_SIZE_DEFAULT; + } + + priv->rx_bd_num = rx_bd_size; qtnf_non_posted_write(priv->rx_bd_num, &bda->bda_rc_rx_bd_num); priv->rx_bd_w_index = 0; @@ -1111,7 +1124,8 @@ static u64 qtnf_topaz_dma_mask_get(void) return DMA_BIT_MASK(32); } -static int qtnf_pcie_topaz_probe(struct qtnf_bus *bus, unsigned int tx_bd_num) +static int qtnf_pcie_topaz_probe(struct qtnf_bus *bus, + unsigned int tx_bd_num, unsigned int rx_bd_num) { struct qtnf_pcie_topaz_state *ts = get_bus_priv(bus); struct pci_dev *pdev = ts->base.pdev; @@ -1145,7 +1159,7 @@ static int qtnf_pcie_topaz_probe(struct qtnf_bus *bus, unsigned int tx_bd_num) return ret; } - ret = qtnf_pcie_topaz_init_xfer(ts, tx_bd_num); + ret = qtnf_pcie_topaz_init_xfer(ts, tx_bd_num, rx_bd_num); if (ret) { pr_err("PCIE xfer init failed\n"); return ret; -- cgit v1.2.3-59-g8ed1b From 46d55fcec1637c58b39b6e1b4907906808bb7c32 Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:55 +0000 Subject: qtnfmac: send EAPOL frames via control path Send EAPOL frames via control path so they can be treated in a different way rather than normal data frames. In this case EAPOLs are sent with higher priority and with disabled aggregation and encryption. Besides, all devices benefit from sending EAPOL frames via high priority path, so move the functionality from chip specific to common code. Signed-off-by: Igor Mitsyanko Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/core.c | 23 +++++++++++++--------- drivers/net/wireless/quantenna/qtnfmac/core.h | 1 - drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c | 1 - .../wireless/quantenna/qtnfmac/pcie/pcie_priv.h | 1 - .../wireless/quantenna/qtnfmac/pcie/topaz_pcie.c | 8 -------- 5 files changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 8d699cc03d26..8116b224c946 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -67,6 +67,14 @@ static int qtnf_netdev_close(struct net_device *ndev) return 0; } +static void qtnf_packet_send_hi_pri(struct sk_buff *skb) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(skb->dev); + + skb_queue_tail(&vif->high_pri_tx_queue, skb); + queue_work(vif->mac->bus->hprio_workqueue, &vif->high_pri_tx_work); +} + /* Netdev handler for data transmission. */ static netdev_tx_t @@ -107,6 +115,12 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* tx path is enabled: reset vif timeout */ vif->cons_tx_timeout_cnt = 0; + if (unlikely(skb->protocol == htons(ETH_P_PAE))) { + qtnf_packet_send_hi_pri(skb); + qtnf_update_tx_stats(ndev, skb); + return NETDEV_TX_OK; + } + return qtnf_bus_data_tx(mac->bus, skb); } @@ -841,15 +855,6 @@ void qtnf_update_tx_stats(struct net_device *ndev, const struct sk_buff *skb) } EXPORT_SYMBOL_GPL(qtnf_update_tx_stats); -void qtnf_packet_send_hi_pri(struct sk_buff *skb) -{ - struct qtnf_vif *vif = qtnf_netdev_get_priv(skb->dev); - - skb_queue_tail(&vif->high_pri_tx_queue, skb); - queue_work(vif->mac->bus->hprio_workqueue, &vif->high_pri_tx_work); -} -EXPORT_SYMBOL_GPL(qtnf_packet_send_hi_pri); - struct dentry *qtnf_get_debugfs_dir(void) { return qtnf_debugfs_dir; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index 322858df600c..e3feea31191e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -152,7 +152,6 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev); void qtnf_netdev_updown(struct net_device *ndev, bool up); void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted); -void qtnf_packet_send_hi_pri(struct sk_buff *skb); struct dentry *qtnf_get_debugfs_dir(void); static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c index 3360b836fc44..5337e67092ca 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -357,7 +357,6 @@ static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) pcie_priv->pcie_irq_count = 0; pcie_priv->tx_reclaim_done = 0; pcie_priv->tx_reclaim_req = 0; - pcie_priv->tx_eapol = 0; pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE"); if (!pcie_priv->workqueue) { diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h index 8bc4300518d0..2a6a928e13bd 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -63,7 +63,6 @@ struct qtnf_pcie_bus_priv { u32 tx_done_count; u32 tx_reclaim_done; u32 tx_reclaim_req; - u32 tx_eapol; u8 msi_enabled; u8 tx_stopped; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index ef255fb57405..a0587472736f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -509,13 +509,6 @@ static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) int len; int i; - if (unlikely(skb->protocol == htons(ETH_P_PAE))) { - qtnf_packet_send_hi_pri(skb); - qtnf_update_tx_stats(skb->dev, skb); - priv->tx_eapol++; - return NETDEV_TX_OK; - } - spin_lock_irqsave(&priv->tx_lock, flags); if (!qtnf_tx_queue_ready(ts)) { @@ -779,7 +772,6 @@ static int qtnf_dbg_pkt_stats(struct seq_file *s, void *data) seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); - seq_printf(s, "tx_eapol(%u)\n", priv->tx_eapol); seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); seq_printf(s, "tx_done_index(%u)\n", tx_done_index); -- cgit v1.2.3-59-g8ed1b From 239ce8a79778b62eb50a2084ac43cb0b410ee15b Mon Sep 17 00:00:00 2001 From: Sergey Matyukevich Date: Wed, 13 Nov 2019 11:06:57 +0000 Subject: qtnfmac: handle MIC failure event from firmware Report MIC failure from firmware to cfg80211 subsystem using dedicated callback cfg80211_michael_mic_failure. Signed-off-by: Sergey Matyukevich Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/event.c | 40 ++++++++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 15 ++++++++++ 2 files changed, 55 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 7846383c8828..51af93bdf06e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -618,6 +618,42 @@ qtnf_event_handle_external_auth(struct qtnf_vif *vif, return ret; } +static int +qtnf_event_handle_mic_failure(struct qtnf_vif *vif, + const struct qlink_event_mic_failure *mic_ev, + u16 len) +{ + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + u8 pairwise; + + if (len < sizeof(*mic_ev)) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_mic_failure)); + return -EINVAL; + } + + if (!wiphy->registered || !vif->netdev) + return 0; + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: MIC_FAILURE event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pairwise = mic_ev->pairwise ? + NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP; + + pr_info("%s: MIC error: src=%pM key_index=%u pairwise=%u\n", + vif->netdev->name, mic_ev->src, mic_ev->key_index, pairwise); + + cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise, + mic_ev->key_index, NULL, GFP_KERNEL); + + return 0; +} + static int qtnf_event_parse(struct qtnf_wmac *mac, const struct sk_buff *event_skb) { @@ -680,6 +716,10 @@ static int qtnf_event_parse(struct qtnf_wmac *mac, ret = qtnf_event_handle_external_auth(vif, (const void *)event, event_len); break; + case QLINK_EVENT_MIC_FAILURE: + ret = qtnf_event_handle_mic_failure(vif, (const void *)event, + event_len); + break; default: pr_warn("unknown event type: %x\n", event_id); break; diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 8a3c6344fa8e..ac1ebe4bb580 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -958,6 +958,7 @@ enum qlink_event_type { QLINK_EVENT_FREQ_CHANGE = 0x0028, QLINK_EVENT_RADAR = 0x0029, QLINK_EVENT_EXTERNAL_AUTH = 0x0030, + QLINK_EVENT_MIC_FAILURE = 0x0031, }; /** @@ -1151,6 +1152,20 @@ struct qlink_event_external_auth { u8 action; } __packed; +/** + * struct qlink_event_mic_failure - data for QLINK_EVENT_MIC_FAILURE event + * + * @src: source MAC address of the frame + * @key_index: index of the key being reported + * @pairwise: whether the key is pairwise or group + */ +struct qlink_event_mic_failure { + struct qlink_event ehdr; + u8 src[ETH_ALEN]; + u8 key_index; + u8 pairwise; +} __packed; + /* QLINK TLVs (Type-Length Values) definitions */ -- cgit v1.2.3-59-g8ed1b From 0756e913fc020ab3640bcfe7de55b8024ecb88ad Mon Sep 17 00:00:00 2001 From: Mikhail Karpenko Date: Wed, 13 Nov 2019 11:06:59 +0000 Subject: qtnfmac: add support for getting/setting transmit power Add new command for getting/setting current transmit power and propagate requests from user space to firmware. Signed-off-by: Mikhail Karpenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 41 ++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.c | 65 +++++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.h | 3 ++ drivers/net/wireless/quantenna/qtnfmac/qlink.h | 42 +++++++++++++++ 4 files changed, 151 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index d90016125dfc..aa0ed0f2b973 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -897,6 +897,45 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, return ret; } +static int qtnf_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int *dbm) +{ + struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); + int ret; + + ret = qtnf_cmd_get_tx_power(vif, dbm); + if (ret) + pr_err("MAC%u: failed to get Tx power\n", vif->mac->macid); + + return ret; +} + +static int qtnf_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + struct qtnf_vif *vif; + int ret; + + if (wdev) { + vif = qtnf_netdev_get_priv(wdev->netdev); + } else { + struct qtnf_wmac *mac = wiphy_priv(wiphy); + + vif = qtnf_mac_get_base_vif(mac); + if (!vif) { + pr_err("MAC%u: primary VIF is not configured\n", + mac->macid); + return -EFAULT; + } + } + + ret = qtnf_cmd_set_tx_power(vif, type, mbm); + if (ret) + pr_err("MAC%u: failed to set Tx power\n", vif->mac->macid); + + return ret; +} + #ifdef CONFIG_PM static int qtnf_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { @@ -991,6 +1030,8 @@ static struct cfg80211_ops qtn_cfg80211_ops = { .start_radar_detection = qtnf_start_radar_detection, .set_mac_acl = qtnf_set_mac_acl, .set_power_mgmt = qtnf_set_power_mgmt, + .get_tx_power = qtnf_get_tx_power, + .set_tx_power = qtnf_set_tx_power, #ifdef CONFIG_PM .suspend = qtnf_suspend, .resume = qtnf_resume, diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index c0c32805fb8d..61bda34e2ac2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2643,6 +2643,71 @@ out: return ret; } +int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm) +{ + struct qtnf_bus *bus = vif->mac->bus; + const struct qlink_resp_txpwr *resp; + struct sk_buff *resp_skb = NULL; + struct qlink_cmd_txpwr *cmd; + struct sk_buff *cmd_skb; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_TXPWR, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; + cmd->op_type = QLINK_TXPWR_GET; + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, + sizeof(*resp), NULL); + if (ret) + goto out; + + resp = (const struct qlink_resp_txpwr *)resp_skb->data; + *dbm = MBM_TO_DBM(le32_to_cpu(resp->txpwr)); + +out: + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + +int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, + enum nl80211_tx_power_setting type, int mbm) +{ + struct qtnf_bus *bus = vif->mac->bus; + const struct qlink_resp_txpwr *resp; + struct sk_buff *resp_skb = NULL; + struct qlink_cmd_txpwr *cmd; + struct sk_buff *cmd_skb; + int ret = 0; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_TXPWR, sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + cmd = (struct qlink_cmd_txpwr *)cmd_skb->data; + cmd->op_type = QLINK_TXPWR_SET; + cmd->txpwr_setting = type; + cmd->txpwr = cpu_to_le32(mbm); + + qtnf_bus_lock(bus); + + ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, + sizeof(*resp), NULL); + + qtnf_bus_unlock(bus); + consume_skb(resp_skb); + + return ret; +} + int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, const struct cfg80211_wowlan *wowl) { diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index 88d7a3cd90d2..e0de65261213 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -70,6 +70,9 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif, int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif, const struct cfg80211_acl_data *params); int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout); +int qtnf_cmd_get_tx_power(const struct qtnf_vif *vif, int *dbm); +int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, + enum nl80211_tx_power_setting type, int mbm); int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, const struct cfg80211_wowlan *wowl); diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index ac1ebe4bb580..59c69c0a6e06 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -217,6 +217,8 @@ struct qlink_sta_info_state { * command is supported only if device reports QLINK_HW_SUPPORTS_REG_UPDATE * capability. * @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel. + * @QLINK_CMD_TXPWR: get or set current channel transmit power for + * the specified MAC. */ enum qlink_cmd_type { QLINK_CMD_FW_INIT = 0x0001, @@ -254,6 +256,7 @@ enum qlink_cmd_type { QLINK_CMD_PM_SET = 0x0062, QLINK_CMD_WOWLAN_SET = 0x0063, QLINK_CMD_EXTERNAL_AUTH = 0x0066, + QLINK_CMD_TXPWR = 0x0067, }; /** @@ -718,6 +721,32 @@ struct qlink_cmd_pm_set { u8 pm_mode; } __packed; +/** + * enum qlink_txpwr_op - transmit power operation type + * @QLINK_TXPWR_SET: set tx power + * @QLINK_TXPWR_GET: get current tx power setting + */ +enum qlink_txpwr_op { + QLINK_TXPWR_SET, + QLINK_TXPWR_GET +}; + +/** + * struct qlink_cmd_txpwr - get or set current transmit power + * + * @txpwr: new transmit power setting, in mBm + * @txpwr_setting: transmit power setting type, one of + * &enum nl80211_tx_power_setting + * @op_type: type of operation, one of &enum qlink_txpwr_op + */ +struct qlink_cmd_txpwr { + struct qlink_cmd chdr; + __le32 txpwr; + u8 txpwr_setting; + u8 op_type; + u8 rsvd[2]; +} __packed; + /** * enum qlink_wowlan_trigger * @@ -944,6 +973,19 @@ struct qlink_resp_channel_get { struct qlink_chandef chan; } __packed; +/** + * struct qlink_resp_txpwr - response for QLINK_CMD_TXPWR command + * + * This response is intended for QLINK_TXPWR_GET operation and does not + * contain any meaningful information in case of QLINK_TXPWR_SET operation. + * + * @txpwr: current transmit power setting, in mBm + */ +struct qlink_resp_txpwr { + struct qlink_resp rhdr; + __le32 txpwr; +} __packed; + /* QLINK Events messages related definitions */ -- cgit v1.2.3-59-g8ed1b From 41603d78b3626cf0da8aa562ecc2a276033db76c Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 12 Nov 2019 02:11:53 +0200 Subject: net: dsa: sja1105: Make the PTP command read-write The PTPSTRTSCH and PTPSTOPSCH bits are actually readable and indicate whether the time-aware scheduler is running or not. We will be using that for monitoring the scheduler in the next patch, so refactor the PTP command API in order to allow that. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 14 ++++----- drivers/net/dsa/sja1105/sja1105_ptp.c | 59 ++++++++++++++++++++--------------- drivers/net/dsa/sja1105/sja1105_ptp.h | 12 +++---- drivers/net/dsa/sja1105/sja1105_spi.c | 12 +++---- 4 files changed, 53 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 1a3722971b61..38340b74249e 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -20,6 +20,11 @@ */ #define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10) +typedef enum { + SPI_READ = 0, + SPI_WRITE = 1, +} sja1105_spi_rw_mode_t; + #include "sja1105_tas.h" #include "sja1105_ptp.h" @@ -71,8 +76,6 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - int (*ptp_cmd)(const struct dsa_switch *ds, - const struct sja1105_ptp_cmd *cmd); int (*reset_cmd)(const void *ctx, const void *data); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ @@ -80,6 +83,8 @@ struct sja1105_info { const unsigned char *addr, u16 vid); int (*fdb_del_cmd)(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid); + void (*ptp_cmd_packing)(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); const char *name; }; @@ -109,11 +114,6 @@ struct sja1105_spi_message { u64 address; }; -typedef enum { - SPI_READ = 0, - SPI_WRITE = 1, -} sja1105_spi_rw_mode_t; - /* From sja1105_main.c */ enum sja1105_reset_reason { SJA1105_VLAN_FILTERING = 0, diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 6b9b2bef8a7b..00014e836d3f 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -193,42 +193,50 @@ int sja1105_get_ts_info(struct dsa_switch *ds, int port, return 0; } -int sja1105et_ptp_cmd(const struct dsa_switch *ds, - const struct sja1105_ptp_cmd *cmd) +void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op) { - const struct sja1105_private *priv = ds->priv; - const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; /* No need to keep this as part of the structure */ u64 valid = 1; - sja1105_pack(buf, &valid, 31, 31, size); - sja1105_pack(buf, &cmd->resptp, 2, 2, size); - sja1105_pack(buf, &cmd->corrclk4ts, 1, 1, size); - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); - - return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, - SJA1105_SIZE_PTP_CMD); + sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->resptp, 2, 2, size, op); + sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op); + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); } -int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, - const struct sja1105_ptp_cmd *cmd) +void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op) { - const struct sja1105_private *priv = ds->priv; - const struct sja1105_regs *regs = priv->info->regs; const int size = SJA1105_SIZE_PTP_CMD; - u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; /* No need to keep this as part of the structure */ u64 valid = 1; - sja1105_pack(buf, &valid, 31, 31, size); - sja1105_pack(buf, &cmd->resptp, 3, 3, size); - sja1105_pack(buf, &cmd->corrclk4ts, 2, 2, size); - sja1105_pack(buf, &cmd->ptpclkadd, 0, 0, size); + sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->resptp, 3, 3, size, op); + sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op); + sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); +} + +static int sja1105_ptp_commit(struct sja1105_private *priv, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) +{ + const struct sja1105_regs *regs = priv->info->regs; + u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; + int rc; + + if (rw == SPI_WRITE) + priv->info->ptp_cmd_packing(buf, cmd, PACK); - return sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, - SJA1105_SIZE_PTP_CMD); + rc = sja1105_xfer_buf(priv, SPI_WRITE, regs->ptp_control, buf, + SJA1105_SIZE_PTP_CMD); + + if (rw == SPI_READ) + priv->info->ptp_cmd_packing(buf, cmd, UNPACK); + + return rc; } /* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap @@ -438,8 +446,9 @@ static int sja1105_ptp_reset(struct dsa_switch *ds) mutex_lock(&ptp_data->lock); cmd.resptp = 1; + dev_dbg(ds->dev, "Resetting PTP clock\n"); - rc = priv->info->ptp_cmd(ds, &cmd); + rc = sja1105_ptp_commit(priv, &cmd, SPI_WRITE); mutex_unlock(&ptp_data->lock); @@ -495,7 +504,7 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, ptp_data->cmd.ptpclkadd = mode; - return priv->info->ptp_cmd(priv->ds, &ptp_data->cmd); + return sja1105_ptp_commit(priv, &ptp_data->cmd, SPI_WRITE); } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 19e707db7e8c..83d9d4ae6d3a 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -39,11 +39,11 @@ int sja1105_ptp_clock_register(struct dsa_switch *ds); void sja1105_ptp_clock_unregister(struct dsa_switch *ds); -int sja1105et_ptp_cmd(const struct dsa_switch *ds, - const struct sja1105_ptp_cmd *cmd); +void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); -int sja1105pqrs_ptp_cmd(const struct dsa_switch *ds, - const struct sja1105_ptp_cmd *cmd); +void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, + enum packing_op op); int sja1105_get_ts_info(struct dsa_switch *ds, int port, struct ethtool_ts_info *ts); @@ -110,9 +110,9 @@ static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) return 0; } -#define sja1105et_ptp_cmd NULL +#define sja1105et_ptp_cmd_packing NULL -#define sja1105pqrs_ptp_cmd NULL +#define sja1105pqrs_ptp_cmd_packing NULL #define sja1105_get_ts_info NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index cb48e77f63fd..ba245bd98124 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -584,7 +584,7 @@ struct sja1105_info sja1105e_info = { .reset_cmd = sja1105et_reset_cmd, .fdb_add_cmd = sja1105et_fdb_add, .fdb_del_cmd = sja1105et_fdb_del, - .ptp_cmd = sja1105et_ptp_cmd, + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, .regs = &sja1105et_regs, .name = "SJA1105E", }; @@ -598,7 +598,7 @@ struct sja1105_info sja1105t_info = { .reset_cmd = sja1105et_reset_cmd, .fdb_add_cmd = sja1105et_fdb_add, .fdb_del_cmd = sja1105et_fdb_del, - .ptp_cmd = sja1105et_ptp_cmd, + .ptp_cmd_packing = sja1105et_ptp_cmd_packing, .regs = &sja1105et_regs, .name = "SJA1105T", }; @@ -613,7 +613,7 @@ struct sja1105_info sja1105p_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105P", }; @@ -628,7 +628,7 @@ struct sja1105_info sja1105q_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105Q", }; @@ -643,7 +643,7 @@ struct sja1105_info sja1105r_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .regs = &sja1105pqrs_regs, .name = "SJA1105R", }; @@ -659,6 +659,6 @@ struct sja1105_info sja1105s_info = { .reset_cmd = sja1105pqrs_reset_cmd, .fdb_add_cmd = sja1105pqrs_fdb_add, .fdb_del_cmd = sja1105pqrs_fdb_del, - .ptp_cmd = sja1105pqrs_ptp_cmd, + .ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing, .name = "SJA1105S", }; -- cgit v1.2.3-59-g8ed1b From 86db36a347b4ea030ee3e6c73ce04e35e4732999 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Tue, 12 Nov 2019 02:11:54 +0200 Subject: net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/Kconfig | 1 + drivers/net/dsa/sja1105/sja1105.h | 2 + drivers/net/dsa/sja1105/sja1105_ptp.c | 30 ++- drivers/net/dsa/sja1105/sja1105_ptp.h | 12 + drivers/net/dsa/sja1105/sja1105_spi.c | 4 + drivers/net/dsa/sja1105/sja1105_tas.c | 428 +++++++++++++++++++++++++++++++++- drivers/net/dsa/sja1105/sja1105_tas.h | 27 +++ 7 files changed, 487 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig index ffac0ea4e8d5..0fe1ae173aa1 100644 --- a/drivers/net/dsa/sja1105/Kconfig +++ b/drivers/net/dsa/sja1105/Kconfig @@ -28,6 +28,7 @@ config NET_DSA_SJA1105_TAS bool "Support for the Time-Aware Scheduler on NXP SJA1105" depends on NET_DSA_SJA1105 && NET_SCH_TAPRIO depends on NET_SCH_TAPRIO=y || NET_DSA_SJA1105=m + depends on NET_DSA_SJA1105_PTP help This enables support for the TTEthernet-based egress scheduling engine in the SJA1105 DSA driver, which is controlled using a diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 38340b74249e..29c7ed60cfdc 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -40,6 +40,8 @@ struct sja1105_regs { u64 ptp_control; u64 ptpclkval; u64 ptpclkrate; + u64 ptpclkcorp; + u64 ptpschtm; u64 ptpegr_ts[SJA1105_NUM_PORTS]; u64 pad_mii_tx[SJA1105_NUM_PORTS]; u64 pad_mii_id[SJA1105_NUM_PORTS]; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 00014e836d3f..54258a25031d 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -201,6 +201,8 @@ void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, u64 valid = 1; sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); sja1105_packing(buf, &cmd->resptp, 2, 2, size, op); sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op); sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); @@ -214,15 +216,17 @@ void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd, u64 valid = 1; sja1105_packing(buf, &valid, 31, 31, size, op); + sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op); + sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op); sja1105_packing(buf, &cmd->resptp, 3, 3, size, op); sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op); sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op); } -static int sja1105_ptp_commit(struct sja1105_private *priv, - struct sja1105_ptp_cmd *cmd, - sja1105_spi_rw_mode_t rw) +int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) { + const struct sja1105_private *priv = ds->priv; const struct sja1105_regs *regs = priv->info->regs; u8 buf[SJA1105_SIZE_PTP_CMD] = {0}; int rc; @@ -448,7 +452,9 @@ static int sja1105_ptp_reset(struct dsa_switch *ds) cmd.resptp = 1; dev_dbg(ds->dev, "Resetting PTP clock\n"); - rc = sja1105_ptp_commit(priv, &cmd, SPI_WRITE); + rc = sja1105_ptp_commit(ds, &cmd, SPI_WRITE); + + sja1105_tas_clockstep(priv->ds); mutex_unlock(&ptp_data->lock); @@ -504,7 +510,7 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, ptp_data->cmd.ptpclkadd = mode; - return sja1105_ptp_commit(priv, &ptp_data->cmd, SPI_WRITE); + return sja1105_ptp_commit(priv->ds, &ptp_data->cmd, SPI_WRITE); } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ @@ -521,7 +527,11 @@ int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, return rc; } - return sja1105_ptpclkval_write(priv, ticks, ptp_sts); + rc = sja1105_ptpclkval_write(priv, ticks, ptp_sts); + + sja1105_tas_clockstep(priv->ds); + + return rc; } static int sja1105_ptp_settime(struct ptp_clock_info *ptp, @@ -563,6 +573,8 @@ static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32, NULL); + sja1105_tas_adjfreq(priv->ds); + mutex_unlock(&ptp_data->lock); return rc; @@ -581,7 +593,11 @@ int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) return rc; } - return sja1105_ptpclkval_write(priv, ticks, NULL); + rc = sja1105_ptpclkval_write(priv, ticks, NULL); + + sja1105_tas_clockstep(priv->ds); + + return rc; } static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 83d9d4ae6d3a..470f44b76318 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -22,6 +22,8 @@ static inline s64 sja1105_ticks_to_ns(s64 ticks) } struct sja1105_ptp_cmd { + u64 ptpstrtsch; /* start schedule */ + u64 ptpstopsch; /* stop schedule */ u64 resptp; /* reset */ u64 corrclk4ts; /* use the corrected clock for timestamps */ u64 ptpclkadd; /* enum sja1105_ptp_clk_mode */ @@ -69,6 +71,9 @@ int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns, int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta); +int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw); + #else struct sja1105_ptp_cmd; @@ -110,6 +115,13 @@ static inline int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta) return 0; } +static inline int sja1105_ptp_commit(struct dsa_switch *ds, + struct sja1105_ptp_cmd *cmd, + sja1105_spi_rw_mode_t rw) +{ + return 0; +} + #define sja1105et_ptp_cmd_packing NULL #define sja1105pqrs_ptp_cmd_packing NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index ba245bd98124..fca3a973764b 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -539,9 +539,11 @@ static struct sja1105_regs sja1105et_regs = { .rmii_ref_clk = {0x100015, 0x10001C, 0x100023, 0x10002A, 0x100031}, .rmii_ext_tx_clk = {0x100018, 0x10001F, 0x100026, 0x10002D, 0x100034}, .ptpegr_ts = {0xC0, 0xC2, 0xC4, 0xC6, 0xC8}, + .ptpschtm = 0x12, /* Spans 0x12 to 0x13 */ .ptp_control = 0x17, .ptpclkval = 0x18, /* Spans 0x18 to 0x19 */ .ptpclkrate = 0x1A, + .ptpclkcorp = 0x1D, }; static struct sja1105_regs sja1105pqrs_regs = { @@ -569,9 +571,11 @@ static struct sja1105_regs sja1105pqrs_regs = { .rmii_ext_tx_clk = {0x100017, 0x10001D, 0x100023, 0x100029, 0x10002F}, .qlevel = {0x604, 0x614, 0x624, 0x634, 0x644}, .ptpegr_ts = {0xC0, 0xC4, 0xC8, 0xCC, 0xD0}, + .ptpschtm = 0x13, /* Spans 0x13 to 0x14 */ .ptp_control = 0x18, .ptpclkval = 0x19, .ptpclkrate = 0x1B, + .ptpclkcorp = 0x1E, }; struct sja1105_info sja1105e_info = { diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c index d846fb5c4e4d..26b925b5dace 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.c +++ b/drivers/net/dsa/sja1105/sja1105_tas.c @@ -10,6 +10,11 @@ #define SJA1105_TAS_MAX_DELTA BIT(19) #define SJA1105_GATE_MASK GENMASK_ULL(SJA1105_NUM_TC - 1, 0) +#define work_to_sja1105_tas(d) \ + container_of((d), struct sja1105_tas_data, tas_work) +#define tas_to_sja1105(d) \ + container_of((d), struct sja1105_private, tas_data) + /* This is not a preprocessor macro because the "ns" argument may or may not be * s64 at caller side. This ensures it is properly type-cast before div_s64. */ @@ -18,6 +23,100 @@ static s64 ns_to_sja1105_delta(s64 ns) return div_s64(ns, 200); } +static s64 sja1105_delta_to_ns(s64 delta) +{ + return delta * 200; +} + +/* Calculate the first base_time in the future that satisfies this + * relationship: + * + * future_base_time = base_time + N x cycle_time >= now, or + * + * now - base_time + * N >= --------------- + * cycle_time + * + * Because N is an integer, the ceiling value of the above "a / b" ratio + * is in fact precisely the floor value of "(a + b - 1) / b", which is + * easier to calculate only having integer division tools. + */ +static s64 future_base_time(s64 base_time, s64 cycle_time, s64 now) +{ + s64 a, b, n; + + if (base_time >= now) + return base_time; + + a = now - base_time; + b = cycle_time; + n = div_s64(a + b - 1, b); + + return base_time + n * cycle_time; +} + +static int sja1105_tas_set_runtime_params(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct dsa_switch *ds = priv->ds; + s64 earliest_base_time = S64_MAX; + s64 latest_base_time = 0; + s64 its_cycle_time = 0; + s64 max_cycle_time = 0; + int port; + + tas_data->enabled = false; + + for (port = 0; port < SJA1105_NUM_PORTS; port++) { + const struct tc_taprio_qopt_offload *offload; + + offload = tas_data->offload[port]; + if (!offload) + continue; + + tas_data->enabled = true; + + if (max_cycle_time < offload->cycle_time) + max_cycle_time = offload->cycle_time; + if (latest_base_time < offload->base_time) + latest_base_time = offload->base_time; + if (earliest_base_time > offload->base_time) { + earliest_base_time = offload->base_time; + its_cycle_time = offload->cycle_time; + } + } + + if (!tas_data->enabled) + return 0; + + /* Roll the earliest base time over until it is in a comparable + * time base with the latest, then compare their deltas. + * We want to enforce that all ports' base times are within + * SJA1105_TAS_MAX_DELTA 200ns cycles of one another. + */ + earliest_base_time = future_base_time(earliest_base_time, + its_cycle_time, + latest_base_time); + while (earliest_base_time > latest_base_time) + earliest_base_time -= its_cycle_time; + if (latest_base_time - earliest_base_time > + sja1105_delta_to_ns(SJA1105_TAS_MAX_DELTA)) { + dev_err(ds->dev, + "Base times too far apart: min %llu max %llu\n", + earliest_base_time, latest_base_time); + return -ERANGE; + } + + tas_data->earliest_base_time = earliest_base_time; + tas_data->max_cycle_time = max_cycle_time; + + dev_dbg(ds->dev, "earliest base time %lld ns\n", earliest_base_time); + dev_dbg(ds->dev, "latest base time %lld ns\n", latest_base_time); + dev_dbg(ds->dev, "longest cycle time %lld ns\n", max_cycle_time); + + return 0; +} + /* Lo and behold: the egress scheduler from hell. * * At the hardware level, the Time-Aware Shaper holds a global linear arrray of @@ -99,7 +198,11 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) int num_cycles = 0; int cycle = 0; int i, k = 0; - int port; + int port, rc; + + rc = sja1105_tas_set_runtime_params(priv); + if (rc < 0) + return rc; /* Discard previous Schedule Table */ table = &priv->static_config.tables[BLK_IDX_SCHEDULE]; @@ -184,11 +287,13 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) schedule_entry_points = table->entries; /* Finally start populating the static config tables */ - schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_STANDALONE; + schedule_entry_points_params->clksrc = SJA1105_TAS_CLKSRC_PTP; schedule_entry_points_params->actsubsch = num_cycles - 1; for (port = 0; port < SJA1105_NUM_PORTS; port++) { const struct tc_taprio_qopt_offload *offload; + /* Relative base time */ + s64 rbt; offload = tas_data->offload[port]; if (!offload) @@ -196,15 +301,21 @@ static int sja1105_init_scheduling(struct sja1105_private *priv) schedule_start_idx = k; schedule_end_idx = k + offload->num_entries - 1; - /* TODO this is the base time for the port's subschedule, - * relative to PTPSCHTM. But as we're using the standalone - * clock source and not PTP clock as time reference, there's - * little point in even trying to put more logic into this, - * like preserving the phases between the subschedules of - * different ports. We'll get all of that when switching to the - * PTP clock source. + /* This is the base time expressed as a number of TAS ticks + * relative to PTPSCHTM, which we'll (perhaps improperly) call + * the operational base time. + */ + rbt = future_base_time(offload->base_time, + offload->cycle_time, + tas_data->earliest_base_time); + rbt -= tas_data->earliest_base_time; + /* UM10944.pdf 4.2.2. Schedule Entry Points table says that + * delta cannot be zero, which is shitty. Advance all relative + * base times by 1 TAS delta, so that even the earliest base + * time becomes 1 in relative terms. Then start the operational + * base time (PTPSCHTM) one TAS delta earlier than planned. */ - entry_point_delta = 1; + entry_point_delta = ns_to_sja1105_delta(rbt) + 1; schedule_entry_points[cycle].subschindx = cycle; schedule_entry_points[cycle].delta = entry_point_delta; @@ -403,8 +514,303 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, return sja1105_static_config_reload(priv, SJA1105_SCHEDULING); } +static int sja1105_tas_check_running(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct dsa_switch *ds = priv->ds; + struct sja1105_ptp_cmd cmd = {0}; + int rc; + + rc = sja1105_ptp_commit(ds, &cmd, SPI_READ); + if (rc < 0) + return rc; + + if (cmd.ptpstrtsch == 1) + /* Schedule successfully started */ + tas_data->state = SJA1105_TAS_STATE_RUNNING; + else if (cmd.ptpstopsch == 1) + /* Schedule is stopped */ + tas_data->state = SJA1105_TAS_STATE_DISABLED; + else + /* Schedule is probably not configured with PTP clock source */ + rc = -EINVAL; + + return rc; +} + +/* Write to PTPCLKCORP */ +static int sja1105_tas_adjust_drift(struct sja1105_private *priv, + u64 correction) +{ + const struct sja1105_regs *regs = priv->info->regs; + u32 ptpclkcorp = ns_to_sja1105_ticks(correction); + + return sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkcorp, + &ptpclkcorp, NULL); +} + +/* Write to PTPSCHTM */ +static int sja1105_tas_set_base_time(struct sja1105_private *priv, + u64 base_time) +{ + const struct sja1105_regs *regs = priv->info->regs; + u64 ptpschtm = ns_to_sja1105_ticks(base_time); + + return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpschtm, + &ptpschtm, NULL); +} + +static int sja1105_tas_start(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; + struct dsa_switch *ds = priv->ds; + int rc; + + dev_dbg(ds->dev, "Starting the TAS\n"); + + if (tas_data->state == SJA1105_TAS_STATE_ENABLED_NOT_RUNNING || + tas_data->state == SJA1105_TAS_STATE_RUNNING) { + dev_err(ds->dev, "TAS already started\n"); + return -EINVAL; + } + + cmd->ptpstrtsch = 1; + cmd->ptpstopsch = 0; + + rc = sja1105_ptp_commit(ds, cmd, SPI_WRITE); + if (rc < 0) + return rc; + + tas_data->state = SJA1105_TAS_STATE_ENABLED_NOT_RUNNING; + + return 0; +} + +static int sja1105_tas_stop(struct sja1105_private *priv) +{ + struct sja1105_tas_data *tas_data = &priv->tas_data; + struct sja1105_ptp_cmd *cmd = &priv->ptp_data.cmd; + struct dsa_switch *ds = priv->ds; + int rc; + + dev_dbg(ds->dev, "Stopping the TAS\n"); + + if (tas_data->state == SJA1105_TAS_STATE_DISABLED) { + dev_err(ds->dev, "TAS already disabled\n"); + return -EINVAL; + } + + cmd->ptpstopsch = 1; + cmd->ptpstrtsch = 0; + + rc = sja1105_ptp_commit(ds, cmd, SPI_WRITE); + if (rc < 0) + return rc; + + tas_data->state = SJA1105_TAS_STATE_DISABLED; + + return 0; +} + +/* The schedule engine and the PTP clock are driven by the same oscillator, and + * they run in parallel. But whilst the PTP clock can keep an absolute + * time-of-day, the schedule engine is only running in 'ticks' (25 ticks make + * up a delta, which is 200ns), and wrapping around at the end of each cycle. + * The schedule engine is started when the PTP clock reaches the PTPSCHTM time + * (in PTP domain). + * Because the PTP clock can be rate-corrected (accelerated or slowed down) by + * a software servo, and the schedule engine clock runs in parallel to the PTP + * clock, there is logic internal to the switch that periodically keeps the + * schedule engine from drifting away. The frequency with which this internal + * syntonization happens is the PTP clock correction period (PTPCLKCORP). It is + * a value also in the PTP clock domain, and is also rate-corrected. + * To be precise, during a correction period, there is logic to determine by + * how many scheduler clock ticks has the PTP clock drifted. At the end of each + * correction period/beginning of new one, the length of a delta is shrunk or + * expanded with an integer number of ticks, compared with the typical 25. + * So a delta lasts for 200ns (or 25 ticks) only on average. + * Sometimes it is longer, sometimes it is shorter. The internal syntonization + * logic can adjust for at most 5 ticks each 20 ticks. + * + * The first implication is that you should choose your schedule correction + * period to be an integer multiple of the schedule length. Preferably one. + * In case there are schedules of multiple ports active, then the correction + * period needs to be a multiple of them all. Given the restriction that the + * cycle times have to be multiples of one another anyway, this means the + * correction period can simply be the largest cycle time, hence the current + * choice. This way, the updates are always synchronous to the transmission + * cycle, and therefore predictable. + * + * The second implication is that at the beginning of a correction period, the + * first few deltas will be modulated in time, until the schedule engine is + * properly phase-aligned with the PTP clock. For this reason, you should place + * your best-effort traffic at the beginning of a cycle, and your + * time-triggered traffic afterwards. + * + * The third implication is that once the schedule engine is started, it can + * only adjust for so much drift within a correction period. In the servo you + * can only change the PTPCLKRATE, but not step the clock (PTPCLKADD). If you + * want to do the latter, you need to stop and restart the schedule engine, + * which is what the state machine handles. + */ +static void sja1105_tas_state_machine(struct work_struct *work) +{ + struct sja1105_tas_data *tas_data = work_to_sja1105_tas(work); + struct sja1105_private *priv = tas_to_sja1105(tas_data); + struct sja1105_ptp_data *ptp_data = &priv->ptp_data; + struct timespec64 base_time_ts, now_ts; + struct dsa_switch *ds = priv->ds; + struct timespec64 diff; + s64 base_time, now; + int rc = 0; + + mutex_lock(&ptp_data->lock); + + switch (tas_data->state) { + case SJA1105_TAS_STATE_DISABLED: + /* Can't do anything at all if clock is still being stepped */ + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) + break; + + rc = sja1105_tas_adjust_drift(priv, tas_data->max_cycle_time); + if (rc < 0) + break; + + rc = __sja1105_ptp_gettimex(ds, &now, NULL); + if (rc < 0) + break; + + /* Plan to start the earliest schedule first. The others + * will be started in hardware, by way of their respective + * entry points delta. + * Try our best to avoid fringe cases (race condition between + * ptpschtm and ptpstrtsch) by pushing the oper_base_time at + * least one second in the future from now. This is not ideal, + * but this only needs to buy us time until the + * sja1105_tas_start command below gets executed. + */ + base_time = future_base_time(tas_data->earliest_base_time, + tas_data->max_cycle_time, + now + 1ull * NSEC_PER_SEC); + base_time -= sja1105_delta_to_ns(1); + + rc = sja1105_tas_set_base_time(priv, base_time); + if (rc < 0) + break; + + tas_data->oper_base_time = base_time; + + rc = sja1105_tas_start(priv); + if (rc < 0) + break; + + base_time_ts = ns_to_timespec64(base_time); + now_ts = ns_to_timespec64(now); + + dev_dbg(ds->dev, "OPER base time %lld.%09ld (now %lld.%09ld)\n", + base_time_ts.tv_sec, base_time_ts.tv_nsec, + now_ts.tv_sec, now_ts.tv_nsec); + + break; + + case SJA1105_TAS_STATE_ENABLED_NOT_RUNNING: + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { + /* Clock was stepped.. bad news for TAS */ + sja1105_tas_stop(priv); + break; + } + + /* Check if TAS has actually started, by comparing the + * scheduled start time with the SJA1105 PTP clock + */ + rc = __sja1105_ptp_gettimex(ds, &now, NULL); + if (rc < 0) + break; + + if (now < tas_data->oper_base_time) { + /* TAS has not started yet */ + diff = ns_to_timespec64(tas_data->oper_base_time - now); + dev_dbg(ds->dev, "time to start: [%lld.%09ld]", + diff.tv_sec, diff.tv_nsec); + break; + } + + /* Time elapsed, what happened? */ + rc = sja1105_tas_check_running(priv); + if (rc < 0) + break; + + if (tas_data->state != SJA1105_TAS_STATE_RUNNING) + /* TAS has started */ + dev_err(ds->dev, + "TAS not started despite time elapsed\n"); + + break; + + case SJA1105_TAS_STATE_RUNNING: + /* Clock was stepped.. bad news for TAS */ + if (tas_data->last_op != SJA1105_PTP_ADJUSTFREQ) { + sja1105_tas_stop(priv); + break; + } + + rc = sja1105_tas_check_running(priv); + if (rc < 0) + break; + + if (tas_data->state != SJA1105_TAS_STATE_RUNNING) + dev_err(ds->dev, "TAS surprisingly stopped\n"); + + break; + + default: + if (net_ratelimit()) + dev_err(ds->dev, "TAS in an invalid state (incorrect use of API)!\n"); + } + + if (rc && net_ratelimit()) + dev_err(ds->dev, "An operation returned %d\n", rc); + + mutex_unlock(&ptp_data->lock); +} + +void sja1105_tas_clockstep(struct dsa_switch *ds) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_tas_data *tas_data = &priv->tas_data; + + if (!tas_data->enabled) + return; + + tas_data->last_op = SJA1105_PTP_CLOCKSTEP; + schedule_work(&tas_data->tas_work); +} + +void sja1105_tas_adjfreq(struct dsa_switch *ds) +{ + struct sja1105_private *priv = ds->priv; + struct sja1105_tas_data *tas_data = &priv->tas_data; + + if (!tas_data->enabled) + return; + + /* No reason to schedule the workqueue, nothing changed */ + if (tas_data->state == SJA1105_TAS_STATE_RUNNING) + return; + + tas_data->last_op = SJA1105_PTP_ADJUSTFREQ; + schedule_work(&tas_data->tas_work); +} + void sja1105_tas_setup(struct dsa_switch *ds) { + struct sja1105_private *priv = ds->priv; + struct sja1105_tas_data *tas_data = &priv->tas_data; + + INIT_WORK(&tas_data->tas_work, sja1105_tas_state_machine); + tas_data->state = SJA1105_TAS_STATE_DISABLED; + tas_data->last_op = SJA1105_PTP_NONE; } void sja1105_tas_teardown(struct dsa_switch *ds) @@ -413,6 +819,8 @@ void sja1105_tas_teardown(struct dsa_switch *ds) struct tc_taprio_qopt_offload *offload; int port; + cancel_work_sync(&priv->tas_data.tas_work); + for (port = 0; port < SJA1105_NUM_PORTS; port++) { offload = priv->tas_data.offload[port]; if (!offload) diff --git a/drivers/net/dsa/sja1105/sja1105_tas.h b/drivers/net/dsa/sja1105/sja1105_tas.h index 0aad212d88b2..b226c3dfd5b1 100644 --- a/drivers/net/dsa/sja1105/sja1105_tas.h +++ b/drivers/net/dsa/sja1105/sja1105_tas.h @@ -8,8 +8,27 @@ #if IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) +enum sja1105_tas_state { + SJA1105_TAS_STATE_DISABLED, + SJA1105_TAS_STATE_ENABLED_NOT_RUNNING, + SJA1105_TAS_STATE_RUNNING, +}; + +enum sja1105_ptp_op { + SJA1105_PTP_NONE, + SJA1105_PTP_CLOCKSTEP, + SJA1105_PTP_ADJUSTFREQ, +}; + struct sja1105_tas_data { struct tc_taprio_qopt_offload *offload[SJA1105_NUM_PORTS]; + enum sja1105_tas_state state; + enum sja1105_ptp_op last_op; + struct work_struct tas_work; + s64 earliest_base_time; + s64 oper_base_time; + u64 max_cycle_time; + bool enabled; }; int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port, @@ -19,6 +38,10 @@ void sja1105_tas_setup(struct dsa_switch *ds); void sja1105_tas_teardown(struct dsa_switch *ds); +void sja1105_tas_clockstep(struct dsa_switch *ds); + +void sja1105_tas_adjfreq(struct dsa_switch *ds); + #else /* C doesn't allow empty structures, bah! */ @@ -36,6 +59,10 @@ static inline void sja1105_tas_setup(struct dsa_switch *ds) { } static inline void sja1105_tas_teardown(struct dsa_switch *ds) { } +static inline void sja1105_tas_clockstep(struct dsa_switch *ds) { } + +static inline void sja1105_tas_adjfreq(struct dsa_switch *ds) { } + #endif /* IS_ENABLED(CONFIG_NET_DSA_SJA1105_TAS) */ #endif /* _SJA1105_TAS_H */ -- cgit v1.2.3-59-g8ed1b From abfb228ae64268991653a6e73eb203c759764075 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Wed, 13 Nov 2019 00:16:41 +0200 Subject: net: dsa: sja1105: Simplify reset handling We don't really need 10k species of reset. Remove everything except cold reset which is what is actually used. Too bad the hardware designers couldn't agree to use the same bit field for rev 1 and rev 2, so the (*reset_cmd) function pointer is there to stay. However let's simplify the prototype and give it a struct dsa_switch (we want to avoid forward-declarations of structures, in this case struct sja1105_private, wherever we can). Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105.h | 2 +- drivers/net/dsa/sja1105/sja1105_spi.c | 110 +++++----------------------------- 2 files changed, 15 insertions(+), 97 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 29c7ed60cfdc..d801fc204d19 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -78,7 +78,7 @@ struct sja1105_info { const struct sja1105_dynamic_table_ops *dyn_ops; const struct sja1105_table_ops *static_ops; const struct sja1105_regs *regs; - int (*reset_cmd)(const void *ctx, const void *data); + int (*reset_cmd)(struct dsa_switch *ds); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ int (*fdb_add_cmd)(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index fca3a973764b..29b127f3bf9c 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -205,116 +205,34 @@ int sja1105_xfer_u32(const struct sja1105_private *priv, return rc; } -/* Back-ported structure from UM11040 Table 112. - * Reset control register (addr. 100440h) - * In the SJA1105 E/T, only warm_rst and cold_rst are - * supported (exposed in UM10944 as rst_ctrl), but the bit - * offsets of warm_rst and cold_rst are actually reversed. - */ -struct sja1105_reset_cmd { - u64 switch_rst; - u64 cfg_rst; - u64 car_rst; - u64 otp_rst; - u64 warm_rst; - u64 cold_rst; - u64 por_rst; -}; - -static void -sja1105et_reset_cmd_pack(void *buf, const struct sja1105_reset_cmd *reset) +static int sja1105et_reset_cmd(struct dsa_switch *ds) { - const int size = SJA1105_SIZE_RESET_CMD; - - memset(buf, 0, size); - - sja1105_pack(buf, &reset->cold_rst, 3, 3, size); - sja1105_pack(buf, &reset->warm_rst, 2, 2, size); -} - -static void -sja1105pqrs_reset_cmd_pack(void *buf, const struct sja1105_reset_cmd *reset) -{ - const int size = SJA1105_SIZE_RESET_CMD; - - memset(buf, 0, size); - - sja1105_pack(buf, &reset->switch_rst, 8, 8, size); - sja1105_pack(buf, &reset->cfg_rst, 7, 7, size); - sja1105_pack(buf, &reset->car_rst, 5, 5, size); - sja1105_pack(buf, &reset->otp_rst, 4, 4, size); - sja1105_pack(buf, &reset->warm_rst, 3, 3, size); - sja1105_pack(buf, &reset->cold_rst, 2, 2, size); - sja1105_pack(buf, &reset->por_rst, 1, 1, size); -} - -static int sja1105et_reset_cmd(const void *ctx, const void *data) -{ - const struct sja1105_private *priv = ctx; - const struct sja1105_reset_cmd *reset = data; + struct sja1105_private *priv = ds->priv; const struct sja1105_regs *regs = priv->info->regs; - struct device *dev = priv->ds->dev; - u8 packed_buf[SJA1105_SIZE_RESET_CMD]; - - if (reset->switch_rst || - reset->cfg_rst || - reset->car_rst || - reset->otp_rst || - reset->por_rst) { - dev_err(dev, "Only warm and cold reset is supported " - "for SJA1105 E/T!\n"); - return -EINVAL; - } - - if (reset->warm_rst) - dev_dbg(dev, "Warm reset requested\n"); - if (reset->cold_rst) - dev_dbg(dev, "Cold reset requested\n"); + u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0}; + const int size = SJA1105_SIZE_RESET_CMD; + u64 cold_rst = 1; - sja1105et_reset_cmd_pack(packed_buf, reset); + sja1105_pack(packed_buf, &cold_rst, 3, 3, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, SJA1105_SIZE_RESET_CMD); } -static int sja1105pqrs_reset_cmd(const void *ctx, const void *data) +static int sja1105pqrs_reset_cmd(struct dsa_switch *ds) { - const struct sja1105_private *priv = ctx; - const struct sja1105_reset_cmd *reset = data; + struct sja1105_private *priv = ds->priv; const struct sja1105_regs *regs = priv->info->regs; - struct device *dev = priv->ds->dev; - u8 packed_buf[SJA1105_SIZE_RESET_CMD]; - - if (reset->switch_rst) - dev_dbg(dev, "Main reset for all functional modules requested\n"); - if (reset->cfg_rst) - dev_dbg(dev, "Chip configuration reset requested\n"); - if (reset->car_rst) - dev_dbg(dev, "Clock and reset control logic reset requested\n"); - if (reset->otp_rst) - dev_dbg(dev, "OTP read cycle for reading product " - "config settings requested\n"); - if (reset->warm_rst) - dev_dbg(dev, "Warm reset requested\n"); - if (reset->cold_rst) - dev_dbg(dev, "Cold reset requested\n"); - if (reset->por_rst) - dev_dbg(dev, "Power-on reset requested\n"); - - sja1105pqrs_reset_cmd_pack(packed_buf, reset); + u8 packed_buf[SJA1105_SIZE_RESET_CMD] = {0}; + const int size = SJA1105_SIZE_RESET_CMD; + u64 cold_rst = 1; + + sja1105_pack(packed_buf, &cold_rst, 2, 2, size); return sja1105_xfer_buf(priv, SPI_WRITE, regs->rgu, packed_buf, SJA1105_SIZE_RESET_CMD); } -static int sja1105_cold_reset(const struct sja1105_private *priv) -{ - struct sja1105_reset_cmd reset = {0}; - - reset.cold_rst = 1; - return priv->info->reset_cmd(priv, &reset); -} - int sja1105_inhibit_tx(const struct sja1105_private *priv, unsigned long port_bitmap, bool tx_inhibited) { @@ -459,7 +377,7 @@ int sja1105_static_config_upload(struct sja1105_private *priv) usleep_range(500, 1000); do { /* Put the SJA1105 in programming mode */ - rc = sja1105_cold_reset(priv); + rc = priv->info->reset_cmd(priv->ds); if (rc < 0) { dev_err(dev, "Failed to reset switch, retrying...\n"); continue; -- cgit v1.2.3-59-g8ed1b From 8d3f4a95a626a2e111d5bf9813e71557f5567da3 Mon Sep 17 00:00:00 2001 From: MarkLee Date: Wed, 13 Nov 2019 10:38:42 +0800 Subject: net: ethernet: mediatek: Integrate GDM/PSE setup operations Integrate GDM/PSE setup operations into single function "mtk_gdm_config" Signed-off-by: MarkLee Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 ++++++++++++++++++----------- drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 385a4ab9ec99..df07d237eef0 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2180,6 +2180,28 @@ static int mtk_start_dma(struct mtk_eth *eth) return 0; } +static void mtk_gdm_config(struct mtk_eth *eth, u32 config) +{ + int i; + + for (i = 0; i < MTK_MAC_COUNT; i++) { + u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); + + /* default setup the forward port to send frame to PDMA */ + val &= ~0xffff; + + /* Enable RX checksum */ + val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; + + val |= config; + + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); + } + /* Reset and enable PSE */ + mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); + mtk_w32(eth, 0, MTK_RST_GL); +} + static int mtk_open(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); @@ -2375,8 +2397,6 @@ static int mtk_hw_init(struct mtk_eth *eth) mtk_w32(eth, 0, MTK_QDMA_DELAY_INT); mtk_tx_irq_disable(eth, ~0); mtk_rx_irq_disable(eth, ~0); - mtk_w32(eth, RST_GL_PSE, MTK_RST_GL); - mtk_w32(eth, 0, MTK_RST_GL); /* FE int grouping */ mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); @@ -2385,18 +2405,7 @@ static int mtk_hw_init(struct mtk_eth *eth) mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); - for (i = 0; i < MTK_MAC_COUNT; i++) { - u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); - - /* setup the forward port to send frame to PDMA */ - val &= ~0xffff; - - /* Enable RX checksum */ - val |= MTK_GDMA_ICS_EN | MTK_GDMA_TCS_EN | MTK_GDMA_UCS_EN; - - /* setup the mac dma */ - mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); - } + mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); return 0; diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index 76bd12cb8150..b16d8d9b196a 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -84,6 +84,7 @@ #define MTK_GDMA_ICS_EN BIT(22) #define MTK_GDMA_TCS_EN BIT(21) #define MTK_GDMA_UCS_EN BIT(20) +#define MTK_GDMA_TO_PDMA 0x0 /* Unicast Filter MAC Address Register - Low */ #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) -- cgit v1.2.3-59-g8ed1b From 5ac9eda060c74aaa399d0c3ddd6bc244c8e2de96 Mon Sep 17 00:00:00 2001 From: MarkLee Date: Wed, 13 Nov 2019 10:38:43 +0800 Subject: net: ethernet: mediatek: Refine the timing of GDM/PSE setup Refine the timing of GDM/PSE setup, move it from mtk_hw_init to mtk_open. This is recommended by the mt762x HW design to do GDM/PSE setup only after PDMA has been started. We exclude mt7628 in mtk_gdm_config function since it is a old IP and there is no GDM/PSE block on it. Signed-off-by: MarkLee Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index df07d237eef0..bb9e260d34e4 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2184,6 +2184,9 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config) { int i; + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + return; + for (i = 0; i < MTK_MAC_COUNT; i++) { u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); @@ -2222,6 +2225,8 @@ static int mtk_open(struct net_device *dev) if (err) return err; + mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); + napi_enable(ð->tx_napi); napi_enable(ð->rx_napi); mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); @@ -2405,8 +2410,6 @@ static int mtk_hw_init(struct mtk_eth *eth) mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); - mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); - return 0; err_disable_pm: -- cgit v1.2.3-59-g8ed1b From 8d66a8183d0cc3a3667f9e179999736fad4519f3 Mon Sep 17 00:00:00 2001 From: MarkLee Date: Wed, 13 Nov 2019 10:38:44 +0800 Subject: net: ethernet: mediatek: Enable GDM GDMA_DROP_ALL mode Enable GDM GDMA_DROP_ALL mode to drop all packet during the stop operation. This is recommended by the mt762x HW design to drop all packet from GMAC before stopping PDMA. Signed-off-by: MarkLee Signed-off-by: David S. Miller --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 ++ drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index bb9e260d34e4..1923ba76a1ec 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2279,6 +2279,8 @@ static int mtk_stop(struct net_device *dev) if (!refcount_dec_and_test(ð->dma_refcnt)) return 0; + mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); napi_disable(ð->tx_napi); diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h index b16d8d9b196a..85830fe14a1b 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h @@ -85,6 +85,7 @@ #define MTK_GDMA_TCS_EN BIT(21) #define MTK_GDMA_UCS_EN BIT(20) #define MTK_GDMA_TO_PDMA 0x0 +#define MTK_GDMA_DROP_ALL 0x7777 /* Unicast Filter MAC Address Register - Low */ #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) -- cgit v1.2.3-59-g8ed1b From 01db923e83779bf39b15e258a58eb1d0c5167f56 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 13 Nov 2019 10:42:26 -0600 Subject: net: phy: dp83869: Add TI dp83869 phy Add support for the TI DP83869 Gigabit ethernet phy device. The DP83869 is a robust, low power, fully featured Physical Layer transceiver with integrated PMD sublayers to support 10BASE-T, 100BASE-TX and 1000BASE-T Ethernet protocols. Signed-off-by: Dan Murphy Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/dp83869.c | 431 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 438 insertions(+) create mode 100644 drivers/net/phy/dp83869.c (limited to 'drivers/net') diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index fd6a82ce49a4..5848219005d7 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -359,6 +359,12 @@ config DP83867_PHY ---help--- Currently supports the DP83867 PHY. +config DP83869_PHY + tristate "Texas Instruments DP83869 Gigabit PHY" + ---help--- + Currently supports the DP83869 PHY. This PHY supports copper and + fiber connections. + config FIXED_PHY tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index a03437e091f3..b433ec3bf9a6 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_DP83822_PHY) += dp83822.o obj-$(CONFIG_DP83TC811_PHY) += dp83tc811.o obj-$(CONFIG_DP83848_PHY) += dp83848.o obj-$(CONFIG_DP83867_PHY) += dp83867.o +obj-$(CONFIG_DP83869_PHY) += dp83869.o obj-$(CONFIG_FIXED_PHY) += fixed_phy.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c new file mode 100644 index 000000000000..fcd418716c10 --- /dev/null +++ b/drivers/net/phy/dp83869.c @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for the Texas Instruments DP83869 PHY + * Copyright (C) 2019 Texas Instruments Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DP83869_PHY_ID 0x2000a0f1 +#define DP83869_DEVADDR 0x1f + +#define MII_DP83869_PHYCTRL 0x10 +#define MII_DP83869_MICR 0x12 +#define MII_DP83869_ISR 0x13 +#define DP83869_CTRL 0x1f +#define DP83869_CFG4 0x1e + +/* Extended Registers */ +#define DP83869_GEN_CFG3 0x0031 +#define DP83869_RGMIICTL 0x0032 +#define DP83869_STRAP_STS1 0x006e +#define DP83869_RGMIIDCTL 0x0086 +#define DP83869_IO_MUX_CFG 0x0170 +#define DP83869_OP_MODE 0x01df +#define DP83869_FX_CTRL 0x0c00 + +#define DP83869_SW_RESET BIT(15) +#define DP83869_SW_RESTART BIT(14) + +/* MICR Interrupt bits */ +#define MII_DP83869_MICR_AN_ERR_INT_EN BIT(15) +#define MII_DP83869_MICR_SPEED_CHNG_INT_EN BIT(14) +#define MII_DP83869_MICR_DUP_MODE_CHNG_INT_EN BIT(13) +#define MII_DP83869_MICR_PAGE_RXD_INT_EN BIT(12) +#define MII_DP83869_MICR_AUTONEG_COMP_INT_EN BIT(11) +#define MII_DP83869_MICR_LINK_STS_CHNG_INT_EN BIT(10) +#define MII_DP83869_MICR_FALSE_CARRIER_INT_EN BIT(8) +#define MII_DP83869_MICR_SLEEP_MODE_CHNG_INT_EN BIT(4) +#define MII_DP83869_MICR_WOL_INT_EN BIT(3) +#define MII_DP83869_MICR_XGMII_ERR_INT_EN BIT(2) +#define MII_DP83869_MICR_POL_CHNG_INT_EN BIT(1) +#define MII_DP83869_MICR_JABBER_INT_EN BIT(0) + +#define MII_DP83869_BMCR_DEFAULT (BMCR_ANENABLE | \ + BMCR_FULLDPLX | \ + BMCR_SPEED1000) + +/* This is the same bit mask as the BMCR so re-use the BMCR default */ +#define DP83869_FX_CTRL_DEFAULT MII_DP83869_BMCR_DEFAULT + +/* CFG1 bits */ +#define DP83869_CFG1_DEFAULT (ADVERTISE_1000HALF | \ + ADVERTISE_1000FULL | \ + CTL1000_AS_MASTER) + +/* RGMIICTL bits */ +#define DP83869_RGMII_TX_CLK_DELAY_EN BIT(1) +#define DP83869_RGMII_RX_CLK_DELAY_EN BIT(0) + +/* STRAP_STS1 bits */ +#define DP83869_STRAP_STS1_RESERVED BIT(11) + +/* PHYCTRL bits */ +#define DP83869_RX_FIFO_SHIFT 12 +#define DP83869_TX_FIFO_SHIFT 14 + +/* PHY_CTRL lower bytes 0x48 are declared as reserved */ +#define DP83869_PHY_CTRL_DEFAULT 0x48 +#define DP83869_PHYCR_FIFO_DEPTH_MASK GENMASK(15, 12) +#define DP83869_PHYCR_RESERVED_MASK BIT(11) + +/* RGMIIDCTL bits */ +#define DP83869_RGMII_TX_CLK_DELAY_SHIFT 4 + +/* IO_MUX_CFG bits */ +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL 0x1f + +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX 0x0 +#define DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN 0x1f +#define DP83869_IO_MUX_CFG_CLK_O_SEL_MASK (0x1f << 8) +#define DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT 8 + +/* CFG3 bits */ +#define DP83869_CFG3_PORT_MIRROR_EN BIT(0) + +/* CFG4 bits */ +#define DP83869_INT_OE BIT(7) + +/* OP MODE */ +#define DP83869_OP_MODE_MII BIT(5) +#define DP83869_SGMII_RGMII_BRIDGE BIT(6) + +enum { + DP83869_PORT_MIRRORING_KEEP, + DP83869_PORT_MIRRORING_EN, + DP83869_PORT_MIRRORING_DIS, +}; + +struct dp83869_private { + int tx_fifo_depth; + int rx_fifo_depth; + int io_impedance; + int port_mirroring; + bool rxctrl_strap_quirk; + int clk_output_sel; + int mode; +}; + +static int dp83869_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_DP83869_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int dp83869_config_intr(struct phy_device *phydev) +{ + int micr_status = 0; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + micr_status = phy_read(phydev, MII_DP83869_MICR); + if (micr_status < 0) + return micr_status; + + micr_status |= + (MII_DP83869_MICR_AN_ERR_INT_EN | + MII_DP83869_MICR_SPEED_CHNG_INT_EN | + MII_DP83869_MICR_AUTONEG_COMP_INT_EN | + MII_DP83869_MICR_LINK_STS_CHNG_INT_EN | + MII_DP83869_MICR_DUP_MODE_CHNG_INT_EN | + MII_DP83869_MICR_SLEEP_MODE_CHNG_INT_EN); + + return phy_write(phydev, MII_DP83869_MICR, micr_status); + } + + return phy_write(phydev, MII_DP83869_MICR, micr_status); +} + +static int dp83869_config_port_mirroring(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + + if (dp83869->port_mirroring == DP83869_PORT_MIRRORING_EN) + phy_set_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); + else + phy_clear_bits_mmd(phydev, DP83869_DEVADDR, DP83869_GEN_CFG3, + DP83869_CFG3_PORT_MIRROR_EN); + + return 0; +} + +#ifdef CONFIG_OF_MDIO +static int dp83869_of_init(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct device_node *of_node = dev->of_node; + int ret; + + if (!of_node) + return -ENODEV; + + dp83869->io_impedance = -EINVAL; + + /* Optional configuration */ + ret = of_property_read_u32(of_node, "ti,clk-output-sel", + &dp83869->clk_output_sel); + if (ret || dp83869->clk_output_sel > DP83869_CLK_O_SEL_REF_CLK) + dp83869->clk_output_sel = DP83869_CLK_O_SEL_REF_CLK; + + ret = of_property_read_u32(of_node, "ti,op-mode", &dp83869->mode); + if (ret == 0) { + if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET || + dp83869->mode > DP83869_SGMII_COPPER_ETHERNET) + return -EINVAL; + } + + if (of_property_read_bool(of_node, "ti,max-output-impedance")) + dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MAX; + else if (of_property_read_bool(of_node, "ti,min-output-impedance")) + dp83869->io_impedance = DP83869_IO_MUX_CFG_IO_IMPEDANCE_MIN; + + if (of_property_read_bool(of_node, "enet-phy-lane-swap")) + dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN; + else + dp83869->port_mirroring = DP83869_PORT_MIRRORING_DIS; + + if (of_property_read_u32(of_node, "rx-fifo-depth", + &dp83869->rx_fifo_depth)) + dp83869->rx_fifo_depth = DP83869_PHYCR_FIFO_DEPTH_4_B_NIB; + + if (of_property_read_u32(of_node, "tx-fifo-depth", + &dp83869->tx_fifo_depth)) + dp83869->tx_fifo_depth = DP83869_PHYCR_FIFO_DEPTH_4_B_NIB; + + return 0; +} +#else +static int dp83869_of_init(struct phy_device *phydev) +{ + return 0; +} +#endif /* CONFIG_OF_MDIO */ + +static int dp83869_configure_rgmii(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int ret, val; + + if (phy_interface_is_rgmii(phydev)) { + val = phy_read(phydev, MII_DP83869_PHYCTRL); + if (val < 0) + return val; + + val &= ~DP83869_PHYCR_FIFO_DEPTH_MASK; + val |= (dp83869->tx_fifo_depth << DP83869_TX_FIFO_SHIFT); + val |= (dp83869->rx_fifo_depth << DP83869_RX_FIFO_SHIFT); + + ret = phy_write(phydev, MII_DP83869_PHYCTRL, val); + if (ret) + return ret; + } + + if (dp83869->io_impedance >= 0) + phy_modify_mmd(phydev, DP83869_DEVADDR, + DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL, + dp83869->io_impedance & + DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); + + return ret; +} + +static int dp83869_configure_mode(struct phy_device *phydev, + struct dp83869_private *dp83869) +{ + int phy_ctrl_val; + int ret; + + if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET || + dp83869->mode > DP83869_SGMII_COPPER_ETHERNET) + return -EINVAL; + + /* Below init sequence for each operational mode is defined in + * section 9.4.8 of the datasheet. + */ + ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, + dp83869->mode); + if (ret) + return ret; + + ret = phy_write(phydev, MII_BMCR, MII_DP83869_BMCR_DEFAULT); + if (ret) + return ret; + + phy_ctrl_val = (dp83869->rx_fifo_depth << DP83869_RX_FIFO_SHIFT | + dp83869->tx_fifo_depth << DP83869_TX_FIFO_SHIFT | + DP83869_PHY_CTRL_DEFAULT); + + switch (dp83869->mode) { + case DP83869_RGMII_COPPER_ETHERNET: + ret = phy_write(phydev, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write(phydev, MII_CTRL1000, DP83869_CFG1_DEFAULT); + if (ret) + return ret; + + ret = dp83869_configure_rgmii(phydev, dp83869); + if (ret) + return ret; + break; + case DP83869_RGMII_SGMII_BRIDGE: + phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE, + DP83869_SGMII_RGMII_BRIDGE, + DP83869_SGMII_RGMII_BRIDGE); + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + + break; + case DP83869_1000M_MEDIA_CONVERT: + ret = phy_write(phydev, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + break; + case DP83869_100M_MEDIA_CONVERT: + ret = phy_write(phydev, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + break; + case DP83869_SGMII_COPPER_ETHERNET: + ret = phy_write(phydev, MII_DP83869_PHYCTRL, + phy_ctrl_val); + if (ret) + return ret; + + ret = phy_write(phydev, MII_CTRL1000, DP83869_CFG1_DEFAULT); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, DP83869_DEVADDR, + DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); + if (ret) + return ret; + + break; + case DP83869_RGMII_1000_BASE: + case DP83869_RGMII_100_BASE: + break; + default: + return -EINVAL; + }; + + return 0; +} + +static int dp83869_config_init(struct phy_device *phydev) +{ + struct dp83869_private *dp83869 = phydev->priv; + int ret, val; + + ret = dp83869_configure_mode(phydev, dp83869); + if (ret) + return ret; + + /* Enable Interrupt output INT_OE in CFG4 register */ + if (phy_interrupt_is_valid(phydev)) { + val = phy_read(phydev, DP83869_CFG4); + val |= DP83869_INT_OE; + phy_write(phydev, DP83869_CFG4, val); + } + + if (dp83869->port_mirroring != DP83869_PORT_MIRRORING_KEEP) + dp83869_config_port_mirroring(phydev); + + /* Clock output selection if muxing property is set */ + if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK) + phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_IO_MUX_CFG, + DP83869_IO_MUX_CFG_CLK_O_SEL_MASK, + dp83869->clk_output_sel << + DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT); + + return 0; +} + +static int dp83869_probe(struct phy_device *phydev) +{ + struct dp83869_private *dp83869; + int ret; + + dp83869 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83869), + GFP_KERNEL); + if (!dp83869) + return -ENOMEM; + + phydev->priv = dp83869; + + ret = dp83869_of_init(phydev); + if (ret) + return ret; + + return dp83869_config_init(phydev); +} + +static int dp83869_phy_reset(struct phy_device *phydev) +{ + int ret; + + ret = phy_write(phydev, DP83869_CTRL, DP83869_SW_RESET); + if (ret < 0) + return ret; + + usleep_range(10, 20); + + /* Global sw reset sets all registers to default. + * Need to set the registers in the PHY to the right config. + */ + return dp83869_config_init(phydev); +} + +static struct phy_driver dp83869_driver[] = { + { + PHY_ID_MATCH_MODEL(DP83869_PHY_ID), + .name = "TI DP83869", + + .probe = dp83869_probe, + .config_init = dp83869_config_init, + .soft_reset = dp83869_phy_reset, + + /* IRQ related */ + .ack_interrupt = dp83869_ack_interrupt, + .config_intr = dp83869_config_intr, + + .suspend = genphy_suspend, + .resume = genphy_resume, + }, +}; +module_phy_driver(dp83869_driver); + +static struct mdio_device_id __maybe_unused dp83869_tbl[] = { + { PHY_ID_MATCH_MODEL(DP83869_PHY_ID) }, + { } +}; +MODULE_DEVICE_TABLE(mdio, dp83869_tbl); + +MODULE_DESCRIPTION("Texas Instruments DP83869 PHY driver"); +MODULE_AUTHOR("Dan Murphy Date: Wed, 13 Nov 2019 15:06:16 -0600 Subject: ibmveth: Detect unsupported packets before sending to the hypervisor Currently, when ibmveth receive a loopback packet, it reports an ambiguous error message "tx: h_send_logical_lan failed with rc=-4" because the hypervisor rejects those types of packets. This fix detects loopback packet and assures the source packet's MAC address matches the driver's MAC address before transmitting to the hypervisor. Signed-off-by: Cris Forno Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index c5be4ebd8437..84121aab7ff1 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1011,6 +1011,29 @@ static int ibmveth_send(struct ibmveth_adapter *adapter, return 0; } +static int ibmveth_is_packet_unsupported(struct sk_buff *skb, + struct net_device *netdev) +{ + struct ethhdr *ether_header; + int ret = 0; + + ether_header = eth_hdr(skb); + + if (ether_addr_equal(ether_header->h_dest, netdev->dev_addr)) { + netdev_dbg(netdev, "veth doesn't support loopback packets, dropping packet.\n"); + netdev->stats.tx_dropped++; + ret = -EOPNOTSUPP; + } + + if (!ether_addr_equal(ether_header->h_source, netdev->dev_addr)) { + netdev_dbg(netdev, "source packet MAC address does not match veth device's, dropping packet.\n"); + netdev->stats.tx_dropped++; + ret = -EOPNOTSUPP; + } + + return ret; +} + static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) { @@ -1022,6 +1045,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, dma_addr_t dma_addr; unsigned long mss = 0; + if (ibmveth_is_packet_unsupported(skb, netdev)) + goto out; + /* veth doesn't handle frag_list, so linearize the skb. * When GRO is enabled SKB's can have frag_list. */ -- cgit v1.2.3-59-g8ed1b From d0db136ffb59bfb8d66b45dba277191db6914f49 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 13 Nov 2019 23:03:26 +0100 Subject: r8169: use r8168d_modify_extpage in rtl8168f_config_eee_phy Use r8168d_modify_extpage() also in rtl8168f_config_eee_phy() to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 9a21ac962c27..81a0c426a9a1 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2324,11 +2324,7 @@ static void rtl8168f_config_eee_phy(struct rtl8169_private *tp) { struct phy_device *phydev = tp->phydev; - phy_write(phydev, 0x1f, 0x0007); - phy_write(phydev, 0x1e, 0x0020); - phy_set_bits(phydev, 0x15, BIT(8)); - phy_write(phydev, 0x1f, 0x0000); - + r8168d_modify_extpage(phydev, 0x0020, 0x15, 0, BIT(8)); r8168d_phy_param(phydev, 0x8b85, 0, BIT(13)); } -- cgit v1.2.3-59-g8ed1b From b37fa92e20ef28aada852cbf03b368d29a20478c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Nov 2019 01:25:55 +0200 Subject: net: mvneta: fix build skb for bm capable devices Fix build_skb for bm capable devices when they fall-back using swbm path (e.g. when bm properties are configured in device tree but CONFIG_MVNETA_BM_ENABLE is not set). In this case rx_offset_correction is overwritten so we need to use it building skb instead of MVNETA_SKB_HEADROOM directly Fixes: 8dc9a0888f4c ("net: mvneta: rely on build_skb in mvneta_rx_swbm poll routine") Fixes: 0db51da7a8e9 ("net: mvneta: add basic XDP support") Signed-off-by: Lorenzo Bianconi Reported-by: Andrew Lunn Tested-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 274ac39c0f0f..12e03b15f0ab 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2154,7 +2154,7 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, prefetch(data); xdp->data_hard_start = data; - xdp->data = data + MVNETA_SKB_HEADROOM + MVNETA_MH_SIZE; + xdp->data = data + pp->rx_offset_correction + MVNETA_MH_SIZE; xdp->data_end = xdp->data + data_len; xdp_set_data_meta_invalid(xdp); @@ -2219,7 +2219,7 @@ mvneta_swbm_add_rx_fragment(struct mvneta_port *pp, /* refill descriptor with new buffer later */ skb_add_rx_frag(rxq->skb, skb_shinfo(rxq->skb)->nr_frags, - page, MVNETA_SKB_HEADROOM, data_len, + page, pp->rx_offset_correction, data_len, PAGE_SIZE); } page_pool_release_page(rxq->page_pool, page); -- cgit v1.2.3-59-g8ed1b From 23205e6d06d42a8e1c73e4a865b4d0a791814f22 Mon Sep 17 00:00:00 2001 From: Christina Jacob Date: Thu, 14 Nov 2019 10:56:16 +0530 Subject: octeontx2-af: Dump current resource provisioning status Added support to dump current resource provisioning status of all resource virtualization unit (RVU) block's (i.e NPA, NIX, SSO, SSOW, CPT, TIM) local functions attached to a PF_FUNC into a debugfs file. 'cat /sys/kernel/debug/octeontx2/rsrc_alloc' will show the current block LF's allocation status. Signed-off-by: Christina Jacob Signed-off-by: Prakash Brahmajyosyula Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/Makefile | 2 +- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 4 + drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 18 +++ .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 146 +++++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/Makefile b/drivers/net/ethernet/marvell/octeontx2/af/Makefile index 06329acf9c2c..1b25948c662b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/Makefile +++ b/drivers/net/ethernet/marvell/octeontx2/af/Makefile @@ -8,4 +8,4 @@ obj-$(CONFIG_OCTEONTX2_AF) += octeontx2_af.o octeontx2_mbox-y := mbox.o octeontx2_af-y := cgx.o rvu.o rvu_cgx.o rvu_npa.o rvu_nix.o \ - rvu_reg.o rvu_npc.o + rvu_reg.o rvu_npc.o rvu_debugfs.o diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index e581091c09c4..8ed54989dd68 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -2456,6 +2456,9 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_irq; + /* Initialize debugfs */ + rvu_dbg_init(rvu); + return 0; err_irq: rvu_unregister_interrupts(rvu); @@ -2482,6 +2485,7 @@ static void rvu_remove(struct pci_dev *pdev) { struct rvu *rvu = pci_get_drvdata(pdev); + rvu_dbg_exit(rvu); rvu_unregister_interrupts(rvu); rvu_flr_wq_destroy(rvu); rvu_cgx_exit(rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index c9d60b0554c0..9e8ef1f36700 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -35,6 +35,12 @@ #define RVU_PFVF_FUNC_SHIFT 0 #define RVU_PFVF_FUNC_MASK 0x3FF +#ifdef CONFIG_DEBUG_FS +struct rvu_debugfs { + struct dentry *root; +}; +#endif + struct rvu_work { struct work_struct work; struct rvu *rvu; @@ -263,6 +269,10 @@ struct rvu { struct list_head cgx_evq_head; /* cgx event queue head */ char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */ + +#ifdef CONFIG_DEBUG_FS + struct rvu_debugfs rvu_dbg; +#endif }; static inline void rvu_write64(struct rvu *rvu, u64 block, u64 offset, u64 val) @@ -501,4 +511,12 @@ int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu, struct npc_mcam_alloc_and_write_entry_rsp *rsp); int rvu_mbox_handler_npc_get_kex_cfg(struct rvu *rvu, struct msg_req *req, struct npc_get_kex_cfg_rsp *rsp); + +#ifdef CONFIG_DEBUG_FS +void rvu_dbg_init(struct rvu *rvu); +void rvu_dbg_exit(struct rvu *rvu); +#else +static inline void rvu_dbg_init(struct rvu *rvu) {} +static inline void rvu_dbg_exit(struct rvu *rvu) {} +#endif #endif /* RVU_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c new file mode 100644 index 000000000000..ede6cdb7cf23 --- /dev/null +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Marvell OcteonTx2 RVU Admin Function driver + * + * Copyright (C) 2019 Marvell International Ltd. + * + * 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. + */ + +#ifdef CONFIG_DEBUG_FS + +#include +#include +#include +#include + +#include "rvu_struct.h" +#include "rvu_reg.h" +#include "rvu.h" + +#define DEBUGFS_DIR_NAME "octeontx2" + +#define rvu_dbg_NULL NULL + +#define RVU_DEBUG_FOPS(name, read_op, write_op) \ +static const struct file_operations rvu_dbg_##name##_fops = { \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = rvu_dbg_##read_op, \ + .write = rvu_dbg_##write_op \ +} + +/* Dumps current provisioning status of all RVU block LFs */ +static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + int index, off = 0, flag = 0, go_back = 0, off_prev; + struct rvu *rvu = filp->private_data; + int lf, pf, vf, pcifunc; + struct rvu_block block; + int bytes_not_copied; + int buf_size = 2048; + char *buf; + + /* don't allow partial reads */ + if (*ppos != 0) + return 0; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOSPC; + off += scnprintf(&buf[off], buf_size - 1 - off, "\npcifunc\t\t"); + for (index = 0; index < BLK_COUNT; index++) + if (strlen(rvu->hw->block[index].name)) + off += scnprintf(&buf[off], buf_size - 1 - off, + "%*s\t", (index - 1) * 2, + rvu->hw->block[index].name); + off += scnprintf(&buf[off], buf_size - 1 - off, "\n"); + for (pf = 0; pf < rvu->hw->total_pfs; pf++) { + for (vf = 0; vf <= rvu->hw->total_vfs; vf++) { + pcifunc = pf << 10 | vf; + if (!pcifunc) + continue; + + if (vf) { + go_back = scnprintf(&buf[off], + buf_size - 1 - off, + "PF%d:VF%d\t\t", pf, + vf - 1); + } else { + go_back = scnprintf(&buf[off], + buf_size - 1 - off, + "PF%d\t\t", pf); + } + + off += go_back; + for (index = 0; index < BLKTYPE_MAX; index++) { + block = rvu->hw->block[index]; + if (!strlen(block.name)) + continue; + off_prev = off; + for (lf = 0; lf < block.lf.max; lf++) { + if (block.fn_map[lf] != pcifunc) + continue; + flag = 1; + off += scnprintf(&buf[off], buf_size - 1 + - off, "%3d,", lf); + } + if (flag && off_prev != off) + off--; + else + go_back++; + off += scnprintf(&buf[off], buf_size - 1 - off, + "\t"); + } + if (!flag) + off -= go_back; + else + flag = 0; + off--; + off += scnprintf(&buf[off], buf_size - 1 - off, "\n"); + } + } + + bytes_not_copied = copy_to_user(buffer, buf, off); + kfree(buf); + + if (bytes_not_copied) + return -EFAULT; + + *ppos = off; + return off; +} + +RVU_DEBUG_FOPS(rsrc_status, rsrc_attach_status, NULL); + +void rvu_dbg_init(struct rvu *rvu) +{ + struct device *dev = &rvu->pdev->dev; + struct dentry *pfile; + + rvu->rvu_dbg.root = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL); + if (!rvu->rvu_dbg.root) { + dev_err(rvu->dev, "%s failed\n", __func__); + return; + } + pfile = debugfs_create_file("rsrc_alloc", 0444, rvu->rvu_dbg.root, rvu, + &rvu_dbg_rsrc_status_fops); + if (!pfile) + goto create_failed; + + return; + +create_failed: + dev_err(dev, "Failed to create debugfs dir\n"); + debugfs_remove_recursive(rvu->rvu_dbg.root); +} + +void rvu_dbg_exit(struct rvu *rvu) +{ + debugfs_remove_recursive(rvu->rvu_dbg.root); +} + +#endif /* CONFIG_DEBUG_FS */ -- cgit v1.2.3-59-g8ed1b From 8756828a81485f7b28b588adbf0bac9bf6fc6651 Mon Sep 17 00:00:00 2001 From: Christina Jacob Date: Thu, 14 Nov 2019 10:56:17 +0530 Subject: octeontx2-af: Add NPA aura and pool contexts to debugfs To aid in debugging NPA related issues, added support to dump NPA (pool allocator) block LF's aura and pool hardware contexts in debugfs. User can check which contexts are enabled currently and dump it's current HW context. Three new files 'qsize', 'aura_ctx', 'pool_ctx' are added to the debugfs at 'sys/kernel/debug/octeontx2/npa/' 'echo > qsize' will display current enabled Aura/Pools. 'echo [aura number/all] > aura_ctx' & 'echo [aura number/all] > pool_ctx' will dump Aura/Pool context info. Signed-off-by: Christina Jacob Signed-off-by: Prakash Brahmajyosyula Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 12 + .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 516 +++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu_npa.c | 4 +- 3 files changed, 530 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 9e8ef1f36700..3ca2bfeca3a1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -36,8 +36,18 @@ #define RVU_PFVF_FUNC_MASK 0x3FF #ifdef CONFIG_DEBUG_FS +struct dump_ctx { + int lf; + int id; + bool all; +}; + struct rvu_debugfs { struct dentry *root; + struct dentry *npa; + struct dump_ctx npa_aura_ctx; + struct dump_ctx npa_pool_ctx; + int npa_qsize_id; }; #endif @@ -387,6 +397,8 @@ int rvu_mbox_handler_cgx_intlbk_disable(struct rvu *rvu, struct msg_req *req, int rvu_npa_init(struct rvu *rvu); void rvu_npa_freemem(struct rvu *rvu); void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf); +int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp); int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu, struct npa_aq_enq_req *req, struct npa_aq_enq_rsp *rsp); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index ede6cdb7cf23..c84a501c4f1c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -22,6 +22,21 @@ #define DEBUGFS_DIR_NAME "octeontx2" #define rvu_dbg_NULL NULL +#define rvu_dbg_open_NULL NULL + +#define RVU_DEBUG_SEQ_FOPS(name, read_op, write_op) \ +static int rvu_dbg_open_##name(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, rvu_dbg_##read_op, inode->i_private); \ +} \ +static const struct file_operations rvu_dbg_##name##_fops = { \ + .owner = THIS_MODULE, \ + .open = rvu_dbg_open_##name, \ + .read = seq_read, \ + .write = rvu_dbg_##write_op, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} #define RVU_DEBUG_FOPS(name, read_op, write_op) \ static const struct file_operations rvu_dbg_##name##_fops = { \ @@ -116,6 +131,505 @@ static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp, RVU_DEBUG_FOPS(rsrc_status, rsrc_attach_status, NULL); +static bool rvu_dbg_is_valid_lf(struct rvu *rvu, int blktype, int lf, + u16 *pcifunc) +{ + struct rvu_block *block; + struct rvu_hwinfo *hw; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, blktype, 0); + if (blkaddr < 0) { + dev_warn(rvu->dev, "Invalid blktype\n"); + return false; + } + + hw = rvu->hw; + block = &hw->block[blkaddr]; + + if (lf < 0 || lf >= block->lf.max) { + dev_warn(rvu->dev, "Invalid LF: valid range: 0-%d\n", + block->lf.max - 1); + return false; + } + + *pcifunc = block->fn_map[lf]; + if (!*pcifunc) { + dev_warn(rvu->dev, + "This LF is not attached to any RVU PFFUNC\n"); + return false; + } + return true; +} + +static void print_npa_qsize(struct seq_file *m, struct rvu_pfvf *pfvf) +{ + char *buf; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + + if (!pfvf->aura_ctx) { + seq_puts(m, "Aura context is not initialized\n"); + } else { + bitmap_print_to_pagebuf(false, buf, pfvf->aura_bmap, + pfvf->aura_ctx->qsize); + seq_printf(m, "Aura count : %d\n", pfvf->aura_ctx->qsize); + seq_printf(m, "Aura context ena/dis bitmap : %s\n", buf); + } + + if (!pfvf->pool_ctx) { + seq_puts(m, "Pool context is not initialized\n"); + } else { + bitmap_print_to_pagebuf(false, buf, pfvf->pool_bmap, + pfvf->pool_ctx->qsize); + seq_printf(m, "Pool count : %d\n", pfvf->pool_ctx->qsize); + seq_printf(m, "Pool context ena/dis bitmap : %s\n", buf); + } + kfree(buf); +} + +/* The 'qsize' entry dumps current Aura/Pool context Qsize + * and each context's current enable/disable status in a bitmap. + */ +static int rvu_dbg_qsize_display(struct seq_file *filp, void *unsused, + int blktype) +{ + void (*print_qsize)(struct seq_file *filp, + struct rvu_pfvf *pfvf) = NULL; + struct rvu_pfvf *pfvf; + struct rvu *rvu; + int qsize_id; + u16 pcifunc; + + rvu = filp->private; + switch (blktype) { + case BLKTYPE_NPA: + qsize_id = rvu->rvu_dbg.npa_qsize_id; + print_qsize = print_npa_qsize; + break; + default: + return -EINVAL; + } + + if (!rvu_dbg_is_valid_lf(rvu, blktype, qsize_id, &pcifunc)) + return -EINVAL; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + print_qsize(filp, pfvf); + + return 0; +} + +static ssize_t rvu_dbg_qsize_write(struct file *filp, + const char __user *buffer, size_t count, + loff_t *ppos, int blktype) +{ + char *blk_string = (blktype == BLKTYPE_NPA) ? "npa" : "nix"; + struct seq_file *seqfile = filp->private_data; + char *cmd_buf, *cmd_buf_tmp, *subtoken; + struct rvu *rvu = seqfile->private; + u16 pcifunc; + int ret, lf; + + cmd_buf = memdup_user(buffer, count); + if (IS_ERR(cmd_buf)) + return -ENOMEM; + + cmd_buf[count] = '\0'; + + cmd_buf_tmp = strchr(cmd_buf, '\n'); + if (cmd_buf_tmp) { + *cmd_buf_tmp = '\0'; + count = cmd_buf_tmp - cmd_buf + 1; + } + + cmd_buf_tmp = cmd_buf; + subtoken = strsep(&cmd_buf, " "); + ret = subtoken ? kstrtoint(subtoken, 10, &lf) : -EINVAL; + if (cmd_buf) + ret = -EINVAL; + + if (!strncmp(subtoken, "help", 4) || ret < 0) { + dev_info(rvu->dev, "Use echo <%s-lf > qsize\n", blk_string); + goto qsize_write_done; + } + + if (!rvu_dbg_is_valid_lf(rvu, blktype, lf, &pcifunc)) { + ret = -EINVAL; + goto qsize_write_done; + } + if (blktype == BLKTYPE_NPA) + rvu->rvu_dbg.npa_qsize_id = lf; + +qsize_write_done: + kfree(cmd_buf_tmp); + return ret ? ret : count; +} + +static ssize_t rvu_dbg_npa_qsize_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_qsize_write(filp, buffer, count, ppos, + BLKTYPE_NPA); +} + +static int rvu_dbg_npa_qsize_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_qsize_display(filp, unused, BLKTYPE_NPA); +} + +RVU_DEBUG_SEQ_FOPS(npa_qsize, npa_qsize_display, npa_qsize_write); + +/* Dumps given NPA Aura's context */ +static void print_npa_aura_ctx(struct seq_file *m, struct npa_aq_enq_rsp *rsp) +{ + struct npa_aura_s *aura = &rsp->aura; + + seq_printf(m, "W0: Pool addr\t\t%llx\n", aura->pool_addr); + + seq_printf(m, "W1: ena\t\t\t%d\nW1: pool caching\t%d\n", + aura->ena, aura->pool_caching); + seq_printf(m, "W1: pool way mask\t%d\nW1: avg con\t\t%d\n", + aura->pool_way_mask, aura->avg_con); + seq_printf(m, "W1: pool drop ena\t%d\nW1: aura drop ena\t%d\n", + aura->pool_drop_ena, aura->aura_drop_ena); + seq_printf(m, "W1: bp_ena\t\t%d\nW1: aura drop\t\t%d\n", + aura->bp_ena, aura->aura_drop); + seq_printf(m, "W1: aura shift\t\t%d\nW1: avg_level\t\t%d\n", + aura->shift, aura->avg_level); + + seq_printf(m, "W2: count\t\t%llu\nW2: nix0_bpid\t\t%d\nW2: nix1_bpid\t\t%d\n", + (u64)aura->count, aura->nix0_bpid, aura->nix1_bpid); + + seq_printf(m, "W3: limit\t\t%llu\nW3: bp\t\t\t%d\nW3: fc_ena\t\t%d\n", + (u64)aura->limit, aura->bp, aura->fc_ena); + seq_printf(m, "W3: fc_up_crossing\t%d\nW3: fc_stype\t\t%d\n", + aura->fc_up_crossing, aura->fc_stype); + seq_printf(m, "W3: fc_hyst_bits\t%d\n", aura->fc_hyst_bits); + + seq_printf(m, "W4: fc_addr\t\t%llx\n", aura->fc_addr); + + seq_printf(m, "W5: pool_drop\t\t%d\nW5: update_time\t\t%d\n", + aura->pool_drop, aura->update_time); + seq_printf(m, "W5: err_int \t\t%d\nW5: err_int_ena\t\t%d\n", + aura->err_int, aura->err_int_ena); + seq_printf(m, "W5: thresh_int\t\t%d\nW5: thresh_int_ena \t%d\n", + aura->thresh_int, aura->thresh_int_ena); + seq_printf(m, "W5: thresh_up\t\t%d\nW5: thresh_qint_idx\t%d\n", + aura->thresh_up, aura->thresh_qint_idx); + seq_printf(m, "W5: err_qint_idx \t%d\n", aura->err_qint_idx); + + seq_printf(m, "W6: thresh\t\t%llu\n", (u64)aura->thresh); +} + +/* Dumps given NPA Pool's context */ +static void print_npa_pool_ctx(struct seq_file *m, struct npa_aq_enq_rsp *rsp) +{ + struct npa_pool_s *pool = &rsp->pool; + + seq_printf(m, "W0: Stack base\t\t%llx\n", pool->stack_base); + + seq_printf(m, "W1: ena \t\t%d\nW1: nat_align \t\t%d\n", + pool->ena, pool->nat_align); + seq_printf(m, "W1: stack_caching\t%d\nW1: stack_way_mask\t%d\n", + pool->stack_caching, pool->stack_way_mask); + seq_printf(m, "W1: buf_offset\t\t%d\nW1: buf_size\t\t%d\n", + pool->buf_offset, pool->buf_size); + + seq_printf(m, "W2: stack_max_pages \t%d\nW2: stack_pages\t\t%d\n", + pool->stack_max_pages, pool->stack_pages); + + seq_printf(m, "W3: op_pc \t\t%llu\n", (u64)pool->op_pc); + + seq_printf(m, "W4: stack_offset\t%d\nW4: shift\t\t%d\nW4: avg_level\t\t%d\n", + pool->stack_offset, pool->shift, pool->avg_level); + seq_printf(m, "W4: avg_con \t\t%d\nW4: fc_ena\t\t%d\nW4: fc_stype\t\t%d\n", + pool->avg_con, pool->fc_ena, pool->fc_stype); + seq_printf(m, "W4: fc_hyst_bits\t%d\nW4: fc_up_crossing\t%d\n", + pool->fc_hyst_bits, pool->fc_up_crossing); + seq_printf(m, "W4: update_time\t\t%d\n", pool->update_time); + + seq_printf(m, "W5: fc_addr\t\t%llx\n", pool->fc_addr); + + seq_printf(m, "W6: ptr_start\t\t%llx\n", pool->ptr_start); + + seq_printf(m, "W7: ptr_end\t\t%llx\n", pool->ptr_end); + + seq_printf(m, "W8: err_int\t\t%d\nW8: err_int_ena\t\t%d\n", + pool->err_int, pool->err_int_ena); + seq_printf(m, "W8: thresh_int\t\t%d\n", pool->thresh_int); + seq_printf(m, "W8: thresh_int_ena\t%d\nW8: thresh_up\t\t%d\n", + pool->thresh_int_ena, pool->thresh_up); + seq_printf(m, "W8: thresh_qint_idx\t%d\nW8: err_qint_idx\t\t%d\n", + pool->thresh_qint_idx, pool->err_qint_idx); +} + +/* Reads aura/pool's ctx from admin queue */ +static int rvu_dbg_npa_ctx_display(struct seq_file *m, void *unused, int ctype) +{ + void (*print_npa_ctx)(struct seq_file *m, struct npa_aq_enq_rsp *rsp); + struct npa_aq_enq_req aq_req; + struct npa_aq_enq_rsp rsp; + struct rvu_pfvf *pfvf; + int aura, rc, max_id; + int npalf, id, all; + struct rvu *rvu; + u16 pcifunc; + + rvu = m->private; + + switch (ctype) { + case NPA_AQ_CTYPE_AURA: + npalf = rvu->rvu_dbg.npa_aura_ctx.lf; + id = rvu->rvu_dbg.npa_aura_ctx.id; + all = rvu->rvu_dbg.npa_aura_ctx.all; + break; + + case NPA_AQ_CTYPE_POOL: + npalf = rvu->rvu_dbg.npa_pool_ctx.lf; + id = rvu->rvu_dbg.npa_pool_ctx.id; + all = rvu->rvu_dbg.npa_pool_ctx.all; + break; + default: + return -EINVAL; + } + + if (!rvu_dbg_is_valid_lf(rvu, BLKTYPE_NPA, npalf, &pcifunc)) + return -EINVAL; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + if (ctype == NPA_AQ_CTYPE_AURA && !pfvf->aura_ctx) { + seq_puts(m, "Aura context is not initialized\n"); + return -EINVAL; + } else if (ctype == NPA_AQ_CTYPE_POOL && !pfvf->pool_ctx) { + seq_puts(m, "Pool context is not initialized\n"); + return -EINVAL; + } + + memset(&aq_req, 0, sizeof(struct npa_aq_enq_req)); + aq_req.hdr.pcifunc = pcifunc; + aq_req.ctype = ctype; + aq_req.op = NPA_AQ_INSTOP_READ; + if (ctype == NPA_AQ_CTYPE_AURA) { + max_id = pfvf->aura_ctx->qsize; + print_npa_ctx = print_npa_aura_ctx; + } else { + max_id = pfvf->pool_ctx->qsize; + print_npa_ctx = print_npa_pool_ctx; + } + + if (id < 0 || id >= max_id) { + seq_printf(m, "Invalid %s, valid range is 0-%d\n", + (ctype == NPA_AQ_CTYPE_AURA) ? "aura" : "pool", + max_id - 1); + return -EINVAL; + } + + if (all) + id = 0; + else + max_id = id + 1; + + for (aura = id; aura < max_id; aura++) { + aq_req.aura_id = aura; + seq_printf(m, "======%s : %d=======\n", + (ctype == NPA_AQ_CTYPE_AURA) ? "AURA" : "POOL", + aq_req.aura_id); + rc = rvu_npa_aq_enq_inst(rvu, &aq_req, &rsp); + if (rc) { + seq_puts(m, "Failed to read context\n"); + return -EINVAL; + } + print_npa_ctx(m, &rsp); + } + return 0; +} + +static int write_npa_ctx(struct rvu *rvu, bool all, + int npalf, int id, int ctype) +{ + struct rvu_pfvf *pfvf; + int max_id = 0; + u16 pcifunc; + + if (!rvu_dbg_is_valid_lf(rvu, BLKTYPE_NPA, npalf, &pcifunc)) + return -EINVAL; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + + if (ctype == NPA_AQ_CTYPE_AURA) { + if (!pfvf->aura_ctx) { + dev_warn(rvu->dev, "Aura context is not initialized\n"); + return -EINVAL; + } + max_id = pfvf->aura_ctx->qsize; + } else if (ctype == NPA_AQ_CTYPE_POOL) { + if (!pfvf->pool_ctx) { + dev_warn(rvu->dev, "Pool context is not initialized\n"); + return -EINVAL; + } + max_id = pfvf->pool_ctx->qsize; + } + + if (id < 0 || id >= max_id) { + dev_warn(rvu->dev, "Invalid %s, valid range is 0-%d\n", + (ctype == NPA_AQ_CTYPE_AURA) ? "aura" : "pool", + max_id - 1); + return -EINVAL; + } + + switch (ctype) { + case NPA_AQ_CTYPE_AURA: + rvu->rvu_dbg.npa_aura_ctx.lf = npalf; + rvu->rvu_dbg.npa_aura_ctx.id = id; + rvu->rvu_dbg.npa_aura_ctx.all = all; + break; + + case NPA_AQ_CTYPE_POOL: + rvu->rvu_dbg.npa_pool_ctx.lf = npalf; + rvu->rvu_dbg.npa_pool_ctx.id = id; + rvu->rvu_dbg.npa_pool_ctx.all = all; + break; + default: + return -EINVAL; + } + return 0; +} + +static int parse_cmd_buffer_ctx(char *cmd_buf, size_t *count, + const char __user *buffer, int *npalf, + int *id, bool *all) +{ + int bytes_not_copied; + char *cmd_buf_tmp; + char *subtoken; + int ret; + + bytes_not_copied = copy_from_user(cmd_buf, buffer, *count); + if (bytes_not_copied) + return -EFAULT; + + cmd_buf[*count] = '\0'; + cmd_buf_tmp = strchr(cmd_buf, '\n'); + + if (cmd_buf_tmp) { + *cmd_buf_tmp = '\0'; + *count = cmd_buf_tmp - cmd_buf + 1; + } + + subtoken = strsep(&cmd_buf, " "); + ret = subtoken ? kstrtoint(subtoken, 10, npalf) : -EINVAL; + if (ret < 0) + return ret; + subtoken = strsep(&cmd_buf, " "); + if (subtoken && strcmp(subtoken, "all") == 0) { + *all = true; + } else { + ret = subtoken ? kstrtoint(subtoken, 10, id) : -EINVAL; + if (ret < 0) + return ret; + } + if (cmd_buf) + return -EINVAL; + return ret; +} + +static ssize_t rvu_dbg_npa_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos, int ctype) +{ + char *cmd_buf, *ctype_string = (ctype == NPA_AQ_CTYPE_AURA) ? + "aura" : "pool"; + struct seq_file *seqfp = filp->private_data; + struct rvu *rvu = seqfp->private; + int npalf, id = 0, ret; + bool all = false; + + if ((*ppos != 0) || !count) + return -EINVAL; + + cmd_buf = kzalloc(count + 1, GFP_KERNEL); + if (!cmd_buf) + return count; + ret = parse_cmd_buffer_ctx(cmd_buf, &count, buffer, + &npalf, &id, &all); + if (ret < 0) { + dev_info(rvu->dev, + "Usage: echo [%s number/all] > %s_ctx\n", + ctype_string, ctype_string); + goto done; + } else { + ret = write_npa_ctx(rvu, all, npalf, id, ctype); + } +done: + kfree(cmd_buf); + return ret ? ret : count; +} + +static ssize_t rvu_dbg_npa_aura_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_npa_ctx_write(filp, buffer, count, ppos, + NPA_AQ_CTYPE_AURA); +} + +static int rvu_dbg_npa_aura_ctx_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_npa_ctx_display(filp, unused, NPA_AQ_CTYPE_AURA); +} + +RVU_DEBUG_SEQ_FOPS(npa_aura_ctx, npa_aura_ctx_display, npa_aura_ctx_write); + +static ssize_t rvu_dbg_npa_pool_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_npa_ctx_write(filp, buffer, count, ppos, + NPA_AQ_CTYPE_POOL); +} + +static int rvu_dbg_npa_pool_ctx_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_npa_ctx_display(filp, unused, NPA_AQ_CTYPE_POOL); +} + +RVU_DEBUG_SEQ_FOPS(npa_pool_ctx, npa_pool_ctx_display, npa_pool_ctx_write); + +static void rvu_dbg_npa_init(struct rvu *rvu) +{ + const struct device *dev = &rvu->pdev->dev; + struct dentry *pfile; + + rvu->rvu_dbg.npa = debugfs_create_dir("npa", rvu->rvu_dbg.root); + if (!rvu->rvu_dbg.npa) + return; + + pfile = debugfs_create_file("qsize", 0600, rvu->rvu_dbg.npa, rvu, + &rvu_dbg_npa_qsize_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("aura_ctx", 0600, rvu->rvu_dbg.npa, rvu, + &rvu_dbg_npa_aura_ctx_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("pool_ctx", 0600, rvu->rvu_dbg.npa, rvu, + &rvu_dbg_npa_pool_ctx_fops); + if (!pfile) + goto create_failed; + + return; + +create_failed: + dev_err(dev, "Failed to create debugfs dir/file for NPA\n"); + debugfs_remove_recursive(rvu->rvu_dbg.npa); +} + void rvu_dbg_init(struct rvu *rvu) { struct device *dev = &rvu->pdev->dev; @@ -131,6 +645,8 @@ void rvu_dbg_init(struct rvu *rvu) if (!pfile) goto create_failed; + rvu_dbg_npa_init(rvu); + return; create_failed: diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index c0e165dfc403..e702a1159de9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -52,8 +52,8 @@ static int npa_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block, return 0; } -static int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, - struct npa_aq_enq_rsp *rsp) +int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp) { struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; -- cgit v1.2.3-59-g8ed1b From 02e202c3d15e1f6363ab3df5685ed7b2630e77a4 Mon Sep 17 00:00:00 2001 From: Prakash Brahmajyosyula Date: Thu, 14 Nov 2019 10:56:18 +0530 Subject: octeontx2-af: Add NIX RQ, SQ and CQ contexts to debugfs To aid in debugging NIX block related issues, added support to dump NIX block LF's RQ, SQ and CQ hardware contexts in debugfs. User can check which contexts are enabled currently and dump it's current HW context. Four new files 'qsize', 'rq_ctx', 'sq_ctx' and 'cq_ctx' are added to the debugfs at 'sys/kernel/debug/octeontx2/nix/' 'echo > qsize' will display current enabled CQ/SQ/RQs. 'echo [rq number/all] > rq_ctx', 'echo [sq number/all] > sq_ctx' & 'echo [cq number/all] > cq_ctx' will dump RQ/SQ/CQ's current hardware context. Signed-off-by: Prakash Brahmajyosyula Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 5 + .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 500 +++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu_struct.h | 4 +- 3 files changed, 507 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 3ca2bfeca3a1..269c43fd1f78 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -45,9 +45,14 @@ struct dump_ctx { struct rvu_debugfs { struct dentry *root; struct dentry *npa; + struct dentry *nix; struct dump_ctx npa_aura_ctx; struct dump_ctx npa_pool_ctx; + struct dump_ctx nix_cq_ctx; + struct dump_ctx nix_rq_ctx; + struct dump_ctx nix_sq_ctx; int npa_qsize_id; + int nix_qsize_id; }; #endif diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index c84a501c4f1c..125b94fc9f92 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -46,6 +46,8 @@ static const struct file_operations rvu_dbg_##name##_fops = { \ .write = rvu_dbg_##write_op \ } +static void print_nix_qsize(struct seq_file *filp, struct rvu_pfvf *pfvf); + /* Dumps current provisioning status of all RVU block LFs */ static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp, char __user *buffer, @@ -209,6 +211,12 @@ static int rvu_dbg_qsize_display(struct seq_file *filp, void *unsused, qsize_id = rvu->rvu_dbg.npa_qsize_id; print_qsize = print_npa_qsize; break; + + case BLKTYPE_NIX: + qsize_id = rvu->rvu_dbg.nix_qsize_id; + print_qsize = print_nix_qsize; + break; + default: return -EINVAL; } @@ -262,6 +270,8 @@ static ssize_t rvu_dbg_qsize_write(struct file *filp, } if (blktype == BLKTYPE_NPA) rvu->rvu_dbg.npa_qsize_id = lf; + else + rvu->rvu_dbg.nix_qsize_id = lf; qsize_write_done: kfree(cmd_buf_tmp); @@ -599,6 +609,495 @@ static int rvu_dbg_npa_pool_ctx_display(struct seq_file *filp, void *unused) RVU_DEBUG_SEQ_FOPS(npa_pool_ctx, npa_pool_ctx_display, npa_pool_ctx_write); +/* Dumps given nix_sq's context */ +static void print_nix_sq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) +{ + struct nix_sq_ctx_s *sq_ctx = &rsp->sq; + + seq_printf(m, "W0: sqe_way_mask \t\t%d\nW0: cq \t\t\t\t%d\n", + sq_ctx->sqe_way_mask, sq_ctx->cq); + seq_printf(m, "W0: sdp_mcast \t\t\t%d\nW0: substream \t\t\t0x%03x\n", + sq_ctx->sdp_mcast, sq_ctx->substream); + seq_printf(m, "W0: qint_idx \t\t\t%d\nW0: ena \t\t\t%d\n\n", + sq_ctx->qint_idx, sq_ctx->ena); + + seq_printf(m, "W1: sqb_count \t\t\t%d\nW1: default_chan \t\t%d\n", + sq_ctx->sqb_count, sq_ctx->default_chan); + seq_printf(m, "W1: smq_rr_quantum \t\t%d\nW1: sso_ena \t\t\t%d\n", + sq_ctx->smq_rr_quantum, sq_ctx->sso_ena); + seq_printf(m, "W1: xoff \t\t\t%d\nW1: cq_ena \t\t\t%d\nW1: smq\t\t\t\t%d\n\n", + sq_ctx->xoff, sq_ctx->cq_ena, sq_ctx->smq); + + seq_printf(m, "W2: sqe_stype \t\t\t%d\nW2: sq_int_ena \t\t\t%d\n", + sq_ctx->sqe_stype, sq_ctx->sq_int_ena); + seq_printf(m, "W2: sq_int \t\t\t%d\nW2: sqb_aura \t\t\t%d\n", + sq_ctx->sq_int, sq_ctx->sqb_aura); + seq_printf(m, "W2: smq_rr_count \t\t%d\n\n", sq_ctx->smq_rr_count); + + seq_printf(m, "W3: smq_next_sq_vld\t\t%d\nW3: smq_pend\t\t\t%d\n", + sq_ctx->smq_next_sq_vld, sq_ctx->smq_pend); + seq_printf(m, "W3: smenq_next_sqb_vld \t\t%d\nW3: head_offset\t\t\t%d\n", + sq_ctx->smenq_next_sqb_vld, sq_ctx->head_offset); + seq_printf(m, "W3: smenq_offset\t\t%d\nW3: tail_offset\t\t\t%d\n", + sq_ctx->smenq_offset, sq_ctx->tail_offset); + seq_printf(m, "W3: smq_lso_segnum \t\t%d\nW3: smq_next_sq\t\t\t%d\n", + sq_ctx->smq_lso_segnum, sq_ctx->smq_next_sq); + seq_printf(m, "W3: mnq_dis \t\t\t%d\nW3: lmt_dis \t\t\t%d\n", + sq_ctx->mnq_dis, sq_ctx->lmt_dis); + seq_printf(m, "W3: cq_limit\t\t\t%d\nW3: max_sqe_size\t\t%d\n\n", + sq_ctx->cq_limit, sq_ctx->max_sqe_size); + + seq_printf(m, "W4: next_sqb \t\t\t%llx\n\n", sq_ctx->next_sqb); + seq_printf(m, "W5: tail_sqb \t\t\t%llx\n\n", sq_ctx->tail_sqb); + seq_printf(m, "W6: smenq_sqb \t\t\t%llx\n\n", sq_ctx->smenq_sqb); + seq_printf(m, "W7: smenq_next_sqb \t\t%llx\n\n", + sq_ctx->smenq_next_sqb); + + seq_printf(m, "W8: head_sqb\t\t\t%llx\n\n", sq_ctx->head_sqb); + + seq_printf(m, "W9: vfi_lso_vld\t\t\t%d\nW9: vfi_lso_vlan1_ins_ena\t%d\n", + sq_ctx->vfi_lso_vld, sq_ctx->vfi_lso_vlan1_ins_ena); + seq_printf(m, "W9: vfi_lso_vlan0_ins_ena\t%d\nW9: vfi_lso_mps\t\t\t%d\n", + sq_ctx->vfi_lso_vlan0_ins_ena, sq_ctx->vfi_lso_mps); + seq_printf(m, "W9: vfi_lso_sb\t\t\t%d\nW9: vfi_lso_sizem1\t\t%d\n", + sq_ctx->vfi_lso_sb, sq_ctx->vfi_lso_sizem1); + seq_printf(m, "W9: vfi_lso_total\t\t%d\n\n", sq_ctx->vfi_lso_total); + + seq_printf(m, "W10: scm_lso_rem \t\t%llu\n\n", + (u64)sq_ctx->scm_lso_rem); + seq_printf(m, "W11: octs \t\t\t%llu\n\n", (u64)sq_ctx->octs); + seq_printf(m, "W12: pkts \t\t\t%llu\n\n", (u64)sq_ctx->pkts); + seq_printf(m, "W14: dropped_octs \t\t%llu\n\n", + (u64)sq_ctx->dropped_octs); + seq_printf(m, "W15: dropped_pkts \t\t%llu\n\n", + (u64)sq_ctx->dropped_pkts); +} + +/* Dumps given nix_rq's context */ +static void print_nix_rq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) +{ + struct nix_rq_ctx_s *rq_ctx = &rsp->rq; + + seq_printf(m, "W0: wqe_aura \t\t\t%d\nW0: substream \t\t\t0x%03x\n", + rq_ctx->wqe_aura, rq_ctx->substream); + seq_printf(m, "W0: cq \t\t\t\t%d\nW0: ena_wqwd \t\t\t%d\n", + rq_ctx->cq, rq_ctx->ena_wqwd); + seq_printf(m, "W0: ipsech_ena \t\t\t%d\nW0: sso_ena \t\t\t%d\n", + rq_ctx->ipsech_ena, rq_ctx->sso_ena); + seq_printf(m, "W0: ena \t\t\t%d\n\n", rq_ctx->ena); + + seq_printf(m, "W1: lpb_drop_ena \t\t%d\nW1: spb_drop_ena \t\t%d\n", + rq_ctx->lpb_drop_ena, rq_ctx->spb_drop_ena); + seq_printf(m, "W1: xqe_drop_ena \t\t%d\nW1: wqe_caching \t\t%d\n", + rq_ctx->xqe_drop_ena, rq_ctx->wqe_caching); + seq_printf(m, "W1: pb_caching \t\t\t%d\nW1: sso_tt \t\t\t%d\n", + rq_ctx->pb_caching, rq_ctx->sso_tt); + seq_printf(m, "W1: sso_grp \t\t\t%d\nW1: lpb_aura \t\t\t%d\n", + rq_ctx->sso_grp, rq_ctx->lpb_aura); + seq_printf(m, "W1: spb_aura \t\t\t%d\n\n", rq_ctx->spb_aura); + + seq_printf(m, "W2: xqe_hdr_split \t\t%d\nW2: xqe_imm_copy \t\t%d\n", + rq_ctx->xqe_hdr_split, rq_ctx->xqe_imm_copy); + seq_printf(m, "W2: xqe_imm_size \t\t%d\nW2: later_skip \t\t\t%d\n", + rq_ctx->xqe_imm_size, rq_ctx->later_skip); + seq_printf(m, "W2: first_skip \t\t\t%d\nW2: lpb_sizem1 \t\t\t%d\n", + rq_ctx->first_skip, rq_ctx->lpb_sizem1); + seq_printf(m, "W2: spb_ena \t\t\t%d\nW2: wqe_skip \t\t\t%d\n", + rq_ctx->spb_ena, rq_ctx->wqe_skip); + seq_printf(m, "W2: spb_sizem1 \t\t\t%d\n\n", rq_ctx->spb_sizem1); + + seq_printf(m, "W3: spb_pool_pass \t\t%d\nW3: spb_pool_drop \t\t%d\n", + rq_ctx->spb_pool_pass, rq_ctx->spb_pool_drop); + seq_printf(m, "W3: spb_aura_pass \t\t%d\nW3: spb_aura_drop \t\t%d\n", + rq_ctx->spb_aura_pass, rq_ctx->spb_aura_drop); + seq_printf(m, "W3: wqe_pool_pass \t\t%d\nW3: wqe_pool_drop \t\t%d\n", + rq_ctx->wqe_pool_pass, rq_ctx->wqe_pool_drop); + seq_printf(m, "W3: xqe_pass \t\t\t%d\nW3: xqe_drop \t\t\t%d\n\n", + rq_ctx->xqe_pass, rq_ctx->xqe_drop); + + seq_printf(m, "W4: qint_idx \t\t\t%d\nW4: rq_int_ena \t\t\t%d\n", + rq_ctx->qint_idx, rq_ctx->rq_int_ena); + seq_printf(m, "W4: rq_int \t\t\t%d\nW4: lpb_pool_pass \t\t%d\n", + rq_ctx->rq_int, rq_ctx->lpb_pool_pass); + seq_printf(m, "W4: lpb_pool_drop \t\t%d\nW4: lpb_aura_pass \t\t%d\n", + rq_ctx->lpb_pool_drop, rq_ctx->lpb_aura_pass); + seq_printf(m, "W4: lpb_aura_drop \t\t%d\n\n", rq_ctx->lpb_aura_drop); + + seq_printf(m, "W5: flow_tagw \t\t\t%d\nW5: bad_utag \t\t\t%d\n", + rq_ctx->flow_tagw, rq_ctx->bad_utag); + seq_printf(m, "W5: good_utag \t\t\t%d\nW5: ltag \t\t\t%d\n\n", + rq_ctx->good_utag, rq_ctx->ltag); + + seq_printf(m, "W6: octs \t\t\t%llu\n\n", (u64)rq_ctx->octs); + seq_printf(m, "W7: pkts \t\t\t%llu\n\n", (u64)rq_ctx->pkts); + seq_printf(m, "W8: drop_octs \t\t\t%llu\n\n", (u64)rq_ctx->drop_octs); + seq_printf(m, "W9: drop_pkts \t\t\t%llu\n\n", (u64)rq_ctx->drop_pkts); + seq_printf(m, "W10: re_pkts \t\t\t%llu\n", (u64)rq_ctx->re_pkts); +} + +/* Dumps given nix_cq's context */ +static void print_nix_cq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) +{ + struct nix_cq_ctx_s *cq_ctx = &rsp->cq; + + seq_printf(m, "W0: base \t\t\t%llx\n\n", cq_ctx->base); + + seq_printf(m, "W1: wrptr \t\t\t%llx\n", (u64)cq_ctx->wrptr); + seq_printf(m, "W1: avg_con \t\t\t%d\nW1: cint_idx \t\t\t%d\n", + cq_ctx->avg_con, cq_ctx->cint_idx); + seq_printf(m, "W1: cq_err \t\t\t%d\nW1: qint_idx \t\t\t%d\n", + cq_ctx->cq_err, cq_ctx->qint_idx); + seq_printf(m, "W1: bpid \t\t\t%d\nW1: bp_ena \t\t\t%d\n\n", + cq_ctx->bpid, cq_ctx->bp_ena); + + seq_printf(m, "W2: update_time \t\t%d\nW2:avg_level \t\t\t%d\n", + cq_ctx->update_time, cq_ctx->avg_level); + seq_printf(m, "W2: head \t\t\t%d\nW2:tail \t\t\t%d\n\n", + cq_ctx->head, cq_ctx->tail); + + seq_printf(m, "W3: cq_err_int_ena \t\t%d\nW3:cq_err_int \t\t\t%d\n", + cq_ctx->cq_err_int_ena, cq_ctx->cq_err_int); + seq_printf(m, "W3: qsize \t\t\t%d\nW3:caching \t\t\t%d\n", + cq_ctx->qsize, cq_ctx->caching); + seq_printf(m, "W3: substream \t\t\t0x%03x\nW3: ena \t\t\t%d\n", + cq_ctx->substream, cq_ctx->ena); + seq_printf(m, "W3: drop_ena \t\t\t%d\nW3: drop \t\t\t%d\n", + cq_ctx->drop_ena, cq_ctx->drop); + seq_printf(m, "W3: bp \t\t\t\t%d\n\n", cq_ctx->bp); +} + +static int rvu_dbg_nix_queue_ctx_display(struct seq_file *filp, + void *unused, int ctype) +{ + void (*print_nix_ctx)(struct seq_file *filp, + struct nix_aq_enq_rsp *rsp) = NULL; + struct rvu *rvu = filp->private; + struct nix_aq_enq_req aq_req; + struct nix_aq_enq_rsp rsp; + char *ctype_string = NULL; + int qidx, rc, max_id = 0; + struct rvu_pfvf *pfvf; + int nixlf, id, all; + u16 pcifunc; + + switch (ctype) { + case NIX_AQ_CTYPE_CQ: + nixlf = rvu->rvu_dbg.nix_cq_ctx.lf; + id = rvu->rvu_dbg.nix_cq_ctx.id; + all = rvu->rvu_dbg.nix_cq_ctx.all; + break; + + case NIX_AQ_CTYPE_SQ: + nixlf = rvu->rvu_dbg.nix_sq_ctx.lf; + id = rvu->rvu_dbg.nix_sq_ctx.id; + all = rvu->rvu_dbg.nix_sq_ctx.all; + break; + + case NIX_AQ_CTYPE_RQ: + nixlf = rvu->rvu_dbg.nix_rq_ctx.lf; + id = rvu->rvu_dbg.nix_rq_ctx.id; + all = rvu->rvu_dbg.nix_rq_ctx.all; + break; + + default: + return -EINVAL; + } + + if (!rvu_dbg_is_valid_lf(rvu, BLKTYPE_NIX, nixlf, &pcifunc)) + return -EINVAL; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + if (ctype == NIX_AQ_CTYPE_SQ && !pfvf->sq_ctx) { + seq_puts(filp, "SQ context is not initialized\n"); + return -EINVAL; + } else if (ctype == NIX_AQ_CTYPE_RQ && !pfvf->rq_ctx) { + seq_puts(filp, "RQ context is not initialized\n"); + return -EINVAL; + } else if (ctype == NIX_AQ_CTYPE_CQ && !pfvf->cq_ctx) { + seq_puts(filp, "CQ context is not initialized\n"); + return -EINVAL; + } + + if (ctype == NIX_AQ_CTYPE_SQ) { + max_id = pfvf->sq_ctx->qsize; + ctype_string = "sq"; + print_nix_ctx = print_nix_sq_ctx; + } else if (ctype == NIX_AQ_CTYPE_RQ) { + max_id = pfvf->rq_ctx->qsize; + ctype_string = "rq"; + print_nix_ctx = print_nix_rq_ctx; + } else if (ctype == NIX_AQ_CTYPE_CQ) { + max_id = pfvf->cq_ctx->qsize; + ctype_string = "cq"; + print_nix_ctx = print_nix_cq_ctx; + } + + memset(&aq_req, 0, sizeof(struct nix_aq_enq_req)); + aq_req.hdr.pcifunc = pcifunc; + aq_req.ctype = ctype; + aq_req.op = NIX_AQ_INSTOP_READ; + if (all) + id = 0; + else + max_id = id + 1; + for (qidx = id; qidx < max_id; qidx++) { + aq_req.qidx = qidx; + seq_printf(filp, "=====%s_ctx for nixlf:%d and qidx:%d is=====\n", + ctype_string, nixlf, aq_req.qidx); + rc = rvu_mbox_handler_nix_aq_enq(rvu, &aq_req, &rsp); + if (rc) { + seq_puts(filp, "Failed to read the context\n"); + return -EINVAL; + } + print_nix_ctx(filp, &rsp); + } + return 0; +} + +static int write_nix_queue_ctx(struct rvu *rvu, bool all, int nixlf, + int id, int ctype, char *ctype_string) +{ + struct rvu_pfvf *pfvf; + int max_id = 0; + u16 pcifunc; + + if (!rvu_dbg_is_valid_lf(rvu, BLKTYPE_NIX, nixlf, &pcifunc)) + return -EINVAL; + + pfvf = rvu_get_pfvf(rvu, pcifunc); + + if (ctype == NIX_AQ_CTYPE_SQ) { + if (!pfvf->sq_ctx) { + dev_warn(rvu->dev, "SQ context is not initialized\n"); + return -EINVAL; + } + max_id = pfvf->sq_ctx->qsize; + } else if (ctype == NIX_AQ_CTYPE_RQ) { + if (!pfvf->rq_ctx) { + dev_warn(rvu->dev, "RQ context is not initialized\n"); + return -EINVAL; + } + max_id = pfvf->rq_ctx->qsize; + } else if (ctype == NIX_AQ_CTYPE_CQ) { + if (!pfvf->cq_ctx) { + dev_warn(rvu->dev, "CQ context is not initialized\n"); + return -EINVAL; + } + max_id = pfvf->cq_ctx->qsize; + } + + if (id < 0 || id >= max_id) { + dev_warn(rvu->dev, "Invalid %s_ctx valid range 0-%d\n", + ctype_string, max_id - 1); + return -EINVAL; + } + switch (ctype) { + case NIX_AQ_CTYPE_CQ: + rvu->rvu_dbg.nix_cq_ctx.lf = nixlf; + rvu->rvu_dbg.nix_cq_ctx.id = id; + rvu->rvu_dbg.nix_cq_ctx.all = all; + break; + + case NIX_AQ_CTYPE_SQ: + rvu->rvu_dbg.nix_sq_ctx.lf = nixlf; + rvu->rvu_dbg.nix_sq_ctx.id = id; + rvu->rvu_dbg.nix_sq_ctx.all = all; + break; + + case NIX_AQ_CTYPE_RQ: + rvu->rvu_dbg.nix_rq_ctx.lf = nixlf; + rvu->rvu_dbg.nix_rq_ctx.id = id; + rvu->rvu_dbg.nix_rq_ctx.all = all; + break; + default: + return -EINVAL; + } + return 0; +} + +static ssize_t rvu_dbg_nix_queue_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos, + int ctype) +{ + struct seq_file *m = filp->private_data; + struct rvu *rvu = m->private; + char *cmd_buf, *ctype_string; + int nixlf, id = 0, ret; + bool all = false; + + if ((*ppos != 0) || !count) + return -EINVAL; + + switch (ctype) { + case NIX_AQ_CTYPE_SQ: + ctype_string = "sq"; + break; + case NIX_AQ_CTYPE_RQ: + ctype_string = "rq"; + break; + case NIX_AQ_CTYPE_CQ: + ctype_string = "cq"; + break; + default: + return -EINVAL; + } + + cmd_buf = kzalloc(count + 1, GFP_KERNEL); + + if (!cmd_buf) + return count; + + ret = parse_cmd_buffer_ctx(cmd_buf, &count, buffer, + &nixlf, &id, &all); + if (ret < 0) { + dev_info(rvu->dev, + "Usage: echo [%s number/all] > %s_ctx\n", + ctype_string, ctype_string); + goto done; + } else { + ret = write_nix_queue_ctx(rvu, all, nixlf, id, ctype, + ctype_string); + } +done: + kfree(cmd_buf); + return ret ? ret : count; +} + +static ssize_t rvu_dbg_nix_sq_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_nix_queue_ctx_write(filp, buffer, count, ppos, + NIX_AQ_CTYPE_SQ); +} + +static int rvu_dbg_nix_sq_ctx_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_nix_queue_ctx_display(filp, unused, NIX_AQ_CTYPE_SQ); +} + +RVU_DEBUG_SEQ_FOPS(nix_sq_ctx, nix_sq_ctx_display, nix_sq_ctx_write); + +static ssize_t rvu_dbg_nix_rq_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_nix_queue_ctx_write(filp, buffer, count, ppos, + NIX_AQ_CTYPE_RQ); +} + +static int rvu_dbg_nix_rq_ctx_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_nix_queue_ctx_display(filp, unused, NIX_AQ_CTYPE_RQ); +} + +RVU_DEBUG_SEQ_FOPS(nix_rq_ctx, nix_rq_ctx_display, nix_rq_ctx_write); + +static ssize_t rvu_dbg_nix_cq_ctx_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_nix_queue_ctx_write(filp, buffer, count, ppos, + NIX_AQ_CTYPE_CQ); +} + +static int rvu_dbg_nix_cq_ctx_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_nix_queue_ctx_display(filp, unused, NIX_AQ_CTYPE_CQ); +} + +RVU_DEBUG_SEQ_FOPS(nix_cq_ctx, nix_cq_ctx_display, nix_cq_ctx_write); + +static void print_nix_qctx_qsize(struct seq_file *filp, int qsize, + unsigned long *bmap, char *qtype) +{ + char *buf; + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + + bitmap_print_to_pagebuf(false, buf, bmap, qsize); + seq_printf(filp, "%s context count : %d\n", qtype, qsize); + seq_printf(filp, "%s context ena/dis bitmap : %s\n", + qtype, buf); + kfree(buf); +} + +static void print_nix_qsize(struct seq_file *filp, struct rvu_pfvf *pfvf) +{ + if (!pfvf->cq_ctx) + seq_puts(filp, "cq context is not initialized\n"); + else + print_nix_qctx_qsize(filp, pfvf->cq_ctx->qsize, pfvf->cq_bmap, + "cq"); + + if (!pfvf->rq_ctx) + seq_puts(filp, "rq context is not initialized\n"); + else + print_nix_qctx_qsize(filp, pfvf->rq_ctx->qsize, pfvf->rq_bmap, + "rq"); + + if (!pfvf->sq_ctx) + seq_puts(filp, "sq context is not initialized\n"); + else + print_nix_qctx_qsize(filp, pfvf->sq_ctx->qsize, pfvf->sq_bmap, + "sq"); +} + +static ssize_t rvu_dbg_nix_qsize_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + return rvu_dbg_qsize_write(filp, buffer, count, ppos, + BLKTYPE_NIX); +} + +static int rvu_dbg_nix_qsize_display(struct seq_file *filp, void *unused) +{ + return rvu_dbg_qsize_display(filp, unused, BLKTYPE_NIX); +} + +RVU_DEBUG_SEQ_FOPS(nix_qsize, nix_qsize_display, nix_qsize_write); + +static void rvu_dbg_nix_init(struct rvu *rvu) +{ + const struct device *dev = &rvu->pdev->dev; + struct dentry *pfile; + + rvu->rvu_dbg.nix = debugfs_create_dir("nix", rvu->rvu_dbg.root); + if (!rvu->rvu_dbg.nix) { + dev_err(rvu->dev, "create debugfs dir failed for nix\n"); + return; + } + + pfile = debugfs_create_file("sq_ctx", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_sq_ctx_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("rq_ctx", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_rq_ctx_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("cq_ctx", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_cq_ctx_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("qsize", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_qsize_fops); + if (!pfile) + goto create_failed; + + return; +create_failed: + dev_err(dev, "Failed to create debugfs dir/file for NIX\n"); + debugfs_remove_recursive(rvu->rvu_dbg.nix); +} + static void rvu_dbg_npa_init(struct rvu *rvu) { const struct device *dev = &rvu->pdev->dev; @@ -646,6 +1145,7 @@ void rvu_dbg_init(struct rvu *rvu) goto create_failed; rvu_dbg_npa_init(rvu); + rvu_dbg_nix_init(rvu); return; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index f920dac74e6c..92aac444cd0a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -474,9 +474,9 @@ struct nix_cq_ctx_s { u64 ena : 1; u64 drop_ena : 1; u64 drop : 8; - u64 dp : 8; + u64 bp : 8; #else - u64 dp : 8; + u64 bp : 8; u64 drop : 8; u64 drop_ena : 1; u64 ena : 1; -- cgit v1.2.3-59-g8ed1b From c5a797e081dad713fd3b23a660c80a77d1d5583e Mon Sep 17 00:00:00 2001 From: Prakash Brahmajyosyula Date: Thu, 14 Nov 2019 10:56:19 +0530 Subject: octeontx2-af: Add NDC block stats to debugfs. NDC is a data cache unit which caches NPA and NIX block's aura/pool/RQ/SQ/CQ/etc contexts to reduce number of costly DRAM accesses. This patch adds support to dump cache's performance stats like cache line hit/miss counters, average cycles taken for accessing cached and non-cached data. This will help in checking if NPA/NIX context reads/writes are having NDC cache misses which inturn might effect performance. Also changed NDC enums to reflect correct NDC hardware instance. Signed-off-by: Prakash Brahmajyosyula Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/common.h | 16 +++ drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 6 +- .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 140 +++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu_reg.h | 27 +++- .../net/ethernet/marvell/octeontx2/af/rvu_struct.h | 32 ++--- 5 files changed, 201 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/common.h b/drivers/net/ethernet/marvell/octeontx2/af/common.h index e332e82fc066..baec832962df 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/common.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/common.h @@ -196,4 +196,20 @@ enum nix_scheduler { #define DEFAULT_RSS_CONTEXT_GROUP 0 #define MAX_RSS_INDIR_TBL_SIZE 256 /* 1 << Max adder bits */ +/* NDC info */ +enum ndc_idx_e { + NIX0_RX = 0x0, + NIX0_TX = 0x1, + NPA0_U = 0x2, +}; + +enum ndc_ctype_e { + CACHING = 0x0, + BYPASS = 0x1, +}; + +#define NDC_MAX_PORT 6 +#define NDC_READ_TRANS 0 +#define NDC_WRITE_TRANS 1 + #endif /* COMMON_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 8ed54989dd68..cf8741db1549 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -433,9 +433,9 @@ static void rvu_reset_all_blocks(struct rvu *rvu) rvu_block_reset(rvu, BLKADDR_SSO, SSO_AF_BLK_RST); rvu_block_reset(rvu, BLKADDR_TIM, TIM_AF_BLK_RST); rvu_block_reset(rvu, BLKADDR_CPT0, CPT_AF_BLK_RST); - rvu_block_reset(rvu, BLKADDR_NDC0, NDC_AF_BLK_RST); - rvu_block_reset(rvu, BLKADDR_NDC1, NDC_AF_BLK_RST); - rvu_block_reset(rvu, BLKADDR_NDC2, NDC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC_NIX0_RX, NDC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC_NIX0_TX, NDC_AF_BLK_RST); + rvu_block_reset(rvu, BLKADDR_NDC_NPA0, NDC_AF_BLK_RST); } static void rvu_scan_block(struct rvu *rvu, struct rvu_block *block) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 125b94fc9f92..581b61184ffe 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -21,6 +21,9 @@ #define DEBUGFS_DIR_NAME "octeontx2" +#define NDC_MAX_BANK(rvu, blk_addr) (rvu_read64(rvu, \ + blk_addr, NDC_AF_CONST) & 0xFF) + #define rvu_dbg_NULL NULL #define rvu_dbg_open_NULL NULL @@ -609,6 +612,113 @@ static int rvu_dbg_npa_pool_ctx_display(struct seq_file *filp, void *unused) RVU_DEBUG_SEQ_FOPS(npa_pool_ctx, npa_pool_ctx_display, npa_pool_ctx_write); +static void ndc_cache_stats(struct seq_file *s, int blk_addr, + int ctype, int transaction) +{ + u64 req, out_req, lat, cant_alloc; + struct rvu *rvu = s->private; + int port; + + for (port = 0; port < NDC_MAX_PORT; port++) { + req = rvu_read64(rvu, blk_addr, NDC_AF_PORTX_RTX_RWX_REQ_PC + (port, ctype, transaction)); + lat = rvu_read64(rvu, blk_addr, NDC_AF_PORTX_RTX_RWX_LAT_PC + (port, ctype, transaction)); + out_req = rvu_read64(rvu, blk_addr, + NDC_AF_PORTX_RTX_RWX_OSTDN_PC + (port, ctype, transaction)); + cant_alloc = rvu_read64(rvu, blk_addr, + NDC_AF_PORTX_RTX_CANT_ALLOC_PC + (port, transaction)); + seq_printf(s, "\nPort:%d\n", port); + seq_printf(s, "\tTotal Requests:\t\t%lld\n", req); + seq_printf(s, "\tTotal Time Taken:\t%lld cycles\n", lat); + seq_printf(s, "\tAvg Latency:\t\t%lld cycles\n", lat / req); + seq_printf(s, "\tOutstanding Requests:\t%lld\n", out_req); + seq_printf(s, "\tCant Alloc Requests:\t%lld\n", cant_alloc); + } +} + +static int ndc_blk_cache_stats(struct seq_file *s, int idx, int blk_addr) +{ + seq_puts(s, "\n***** CACHE mode read stats *****\n"); + ndc_cache_stats(s, blk_addr, CACHING, NDC_READ_TRANS); + seq_puts(s, "\n***** CACHE mode write stats *****\n"); + ndc_cache_stats(s, blk_addr, CACHING, NDC_WRITE_TRANS); + seq_puts(s, "\n***** BY-PASS mode read stats *****\n"); + ndc_cache_stats(s, blk_addr, BYPASS, NDC_READ_TRANS); + seq_puts(s, "\n***** BY-PASS mode write stats *****\n"); + ndc_cache_stats(s, blk_addr, BYPASS, NDC_WRITE_TRANS); + return 0; +} + +static int rvu_dbg_npa_ndc_cache_display(struct seq_file *filp, void *unused) +{ + return ndc_blk_cache_stats(filp, NPA0_U, BLKADDR_NDC_NPA0); +} + +RVU_DEBUG_SEQ_FOPS(npa_ndc_cache, npa_ndc_cache_display, NULL); + +static int ndc_blk_hits_miss_stats(struct seq_file *s, int idx, int blk_addr) +{ + struct rvu *rvu = s->private; + int bank, max_bank; + + max_bank = NDC_MAX_BANK(rvu, blk_addr); + for (bank = 0; bank < max_bank; bank++) { + seq_printf(s, "BANK:%d\n", bank); + seq_printf(s, "\tHits:\t%lld\n", + (u64)rvu_read64(rvu, blk_addr, + NDC_AF_BANKX_HIT_PC(bank))); + seq_printf(s, "\tMiss:\t%lld\n", + (u64)rvu_read64(rvu, blk_addr, + NDC_AF_BANKX_MISS_PC(bank))); + } + return 0; +} + +static int rvu_dbg_nix_ndc_rx_cache_display(struct seq_file *filp, void *unused) +{ + return ndc_blk_cache_stats(filp, NIX0_RX, + BLKADDR_NDC_NIX0_RX); +} + +RVU_DEBUG_SEQ_FOPS(nix_ndc_rx_cache, nix_ndc_rx_cache_display, NULL); + +static int rvu_dbg_nix_ndc_tx_cache_display(struct seq_file *filp, void *unused) +{ + return ndc_blk_cache_stats(filp, NIX0_TX, + BLKADDR_NDC_NIX0_TX); +} + +RVU_DEBUG_SEQ_FOPS(nix_ndc_tx_cache, nix_ndc_tx_cache_display, NULL); + +static int rvu_dbg_npa_ndc_hits_miss_display(struct seq_file *filp, + void *unused) +{ + return ndc_blk_hits_miss_stats(filp, NPA0_U, BLKADDR_NDC_NPA0); +} + +RVU_DEBUG_SEQ_FOPS(npa_ndc_hits_miss, npa_ndc_hits_miss_display, NULL); + +static int rvu_dbg_nix_ndc_rx_hits_miss_display(struct seq_file *filp, + void *unused) +{ + return ndc_blk_hits_miss_stats(filp, + NPA0_U, BLKADDR_NDC_NIX0_RX); +} + +RVU_DEBUG_SEQ_FOPS(nix_ndc_rx_hits_miss, nix_ndc_rx_hits_miss_display, NULL); + +static int rvu_dbg_nix_ndc_tx_hits_miss_display(struct seq_file *filp, + void *unused) +{ + return ndc_blk_hits_miss_stats(filp, + NPA0_U, BLKADDR_NDC_NIX0_TX); +} + +RVU_DEBUG_SEQ_FOPS(nix_ndc_tx_hits_miss, nix_ndc_tx_hits_miss_display, NULL); + /* Dumps given nix_sq's context */ static void print_nix_sq_ctx(struct seq_file *m, struct nix_aq_enq_rsp *rsp) { @@ -1087,6 +1197,26 @@ static void rvu_dbg_nix_init(struct rvu *rvu) if (!pfile) goto create_failed; + pfile = debugfs_create_file("ndc_tx_cache", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_ndc_tx_cache_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("ndc_rx_cache", 0600, rvu->rvu_dbg.nix, rvu, + &rvu_dbg_nix_ndc_rx_cache_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("ndc_tx_hits_miss", 0600, rvu->rvu_dbg.nix, + rvu, &rvu_dbg_nix_ndc_tx_hits_miss_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("ndc_rx_hits_miss", 0600, rvu->rvu_dbg.nix, + rvu, &rvu_dbg_nix_ndc_rx_hits_miss_fops); + if (!pfile) + goto create_failed; + pfile = debugfs_create_file("qsize", 0600, rvu->rvu_dbg.nix, rvu, &rvu_dbg_nix_qsize_fops); if (!pfile) @@ -1122,6 +1252,16 @@ static void rvu_dbg_npa_init(struct rvu *rvu) if (!pfile) goto create_failed; + pfile = debugfs_create_file("ndc_cache", 0600, rvu->rvu_dbg.npa, rvu, + &rvu_dbg_npa_ndc_cache_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("ndc_hits_miss", 0600, rvu->rvu_dbg.npa, + rvu, &rvu_dbg_npa_ndc_hits_miss_fops); + if (!pfile) + goto create_failed; + return; create_failed: diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 09a8d61f3144..3d7b293c9e1d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -435,7 +435,6 @@ #define CPT_AF_LF_RST (0x44000) #define CPT_AF_BLK_RST (0x46000) -#define NDC_AF_BLK_RST (0x002F0) #define NPC_AF_BLK_RST (0x00040) /* NPC */ @@ -499,4 +498,30 @@ #define NPC_AF_DBG_DATAX(a) (0x3001400 | (a) << 4) #define NPC_AF_DBG_RESULTX(a) (0x3001800 | (a) << 4) +/* NDC */ +#define NDC_AF_CONST (0x00000) +#define NDC_AF_CLK_EN (0x00020) +#define NDC_AF_CTL (0x00030) +#define NDC_AF_BANK_CTL (0x00040) +#define NDC_AF_BANK_CTL_DONE (0x00048) +#define NDC_AF_INTR (0x00058) +#define NDC_AF_INTR_W1S (0x00060) +#define NDC_AF_INTR_ENA_W1S (0x00068) +#define NDC_AF_INTR_ENA_W1C (0x00070) +#define NDC_AF_ACTIVE_PC (0x00078) +#define NDC_AF_BP_TEST_ENABLE (0x001F8) +#define NDC_AF_BP_TEST(a) (0x00200 | (a) << 3) +#define NDC_AF_BLK_RST (0x002F0) +#define NDC_PRIV_AF_INT_CFG (0x002F8) +#define NDC_AF_HASHX(a) (0x00300 | (a) << 3) +#define NDC_AF_PORTX_RTX_RWX_REQ_PC(a, b, c) \ + (0x00C00 | (a) << 5 | (b) << 4 | (c) << 3) +#define NDC_AF_PORTX_RTX_RWX_OSTDN_PC(a, b, c) \ + (0x00D00 | (a) << 5 | (b) << 4 | (c) << 3) +#define NDC_AF_PORTX_RTX_RWX_LAT_PC(a, b, c) \ + (0x00E00 | (a) << 5 | (b) << 4 | (c) << 3) +#define NDC_AF_PORTX_RTX_CANT_ALLOC_PC(a, b) \ + (0x00F00 | (a) << 5 | (b) << 4) +#define NDC_AF_BANKX_HIT_PC(a) (0x01000 | (a) << 3) +#define NDC_AF_BANKX_MISS_PC(a) (0x01100 | (a) << 3) #endif /* RVU_REG_H */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h index 92aac444cd0a..f6a260d419fd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_struct.h @@ -13,22 +13,22 @@ /* RVU Block Address Enumeration */ enum rvu_block_addr_e { - BLKADDR_RVUM = 0x0ULL, - BLKADDR_LMT = 0x1ULL, - BLKADDR_MSIX = 0x2ULL, - BLKADDR_NPA = 0x3ULL, - BLKADDR_NIX0 = 0x4ULL, - BLKADDR_NIX1 = 0x5ULL, - BLKADDR_NPC = 0x6ULL, - BLKADDR_SSO = 0x7ULL, - BLKADDR_SSOW = 0x8ULL, - BLKADDR_TIM = 0x9ULL, - BLKADDR_CPT0 = 0xaULL, - BLKADDR_CPT1 = 0xbULL, - BLKADDR_NDC0 = 0xcULL, - BLKADDR_NDC1 = 0xdULL, - BLKADDR_NDC2 = 0xeULL, - BLK_COUNT = 0xfULL, + BLKADDR_RVUM = 0x0ULL, + BLKADDR_LMT = 0x1ULL, + BLKADDR_MSIX = 0x2ULL, + BLKADDR_NPA = 0x3ULL, + BLKADDR_NIX0 = 0x4ULL, + BLKADDR_NIX1 = 0x5ULL, + BLKADDR_NPC = 0x6ULL, + BLKADDR_SSO = 0x7ULL, + BLKADDR_SSOW = 0x8ULL, + BLKADDR_TIM = 0x9ULL, + BLKADDR_CPT0 = 0xaULL, + BLKADDR_CPT1 = 0xbULL, + BLKADDR_NDC_NIX0_RX = 0xcULL, + BLKADDR_NDC_NIX0_TX = 0xdULL, + BLKADDR_NDC_NPA0 = 0xeULL, + BLK_COUNT = 0xfULL, }; /* RVU Block Type Enumeration */ -- cgit v1.2.3-59-g8ed1b From c57211b53682c6681d94137f6733dff3e6ea317e Mon Sep 17 00:00:00 2001 From: Prakash Brahmajyosyula Date: Thu, 14 Nov 2019 10:56:20 +0530 Subject: octeontx2-af: Add CGX LMAC stats to debugfs This patch adds CGX LMAC physical interface or serdes Rx/Tx packet stats to debugfs. 'cat cgx/lmac/stats' dumps the current interface link status and Rx/Tx stats. Stats include pkt received/transmitted, dropped, pause frames etc etc. Signed-off-by: Prakash Brahmajyosyula Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 3 + .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 160 +++++++++++++++++++++ 2 files changed, 163 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 269c43fd1f78..2fb871da9308 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -44,6 +44,9 @@ struct dump_ctx { struct rvu_debugfs { struct dentry *root; + struct dentry *cgx_root; + struct dentry *cgx; + struct dentry *lmac; struct dentry *npa; struct dentry *nix; struct dump_ctx npa_aura_ctx; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 581b61184ffe..c01a85ea754f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -18,9 +18,69 @@ #include "rvu_struct.h" #include "rvu_reg.h" #include "rvu.h" +#include "cgx.h" #define DEBUGFS_DIR_NAME "octeontx2" +enum { + CGX_STAT0, + CGX_STAT1, + CGX_STAT2, + CGX_STAT3, + CGX_STAT4, + CGX_STAT5, + CGX_STAT6, + CGX_STAT7, + CGX_STAT8, + CGX_STAT9, + CGX_STAT10, + CGX_STAT11, + CGX_STAT12, + CGX_STAT13, + CGX_STAT14, + CGX_STAT15, + CGX_STAT16, + CGX_STAT17, + CGX_STAT18, +}; + +static char *cgx_rx_stats_fields[] = { + [CGX_STAT0] = "Received packets", + [CGX_STAT1] = "Octets of received packets", + [CGX_STAT2] = "Received PAUSE packets", + [CGX_STAT3] = "Received PAUSE and control packets", + [CGX_STAT4] = "Filtered DMAC0 (NIX-bound) packets", + [CGX_STAT5] = "Filtered DMAC0 (NIX-bound) octets", + [CGX_STAT6] = "Packets dropped due to RX FIFO full", + [CGX_STAT7] = "Octets dropped due to RX FIFO full", + [CGX_STAT8] = "Error packets", + [CGX_STAT9] = "Filtered DMAC1 (NCSI-bound) packets", + [CGX_STAT10] = "Filtered DMAC1 (NCSI-bound) octets", + [CGX_STAT11] = "NCSI-bound packets dropped", + [CGX_STAT12] = "NCSI-bound octets dropped", +}; + +static char *cgx_tx_stats_fields[] = { + [CGX_STAT0] = "Packets dropped due to excessive collisions", + [CGX_STAT1] = "Packets dropped due to excessive deferral", + [CGX_STAT2] = "Multiple collisions before successful transmission", + [CGX_STAT3] = "Single collisions before successful transmission", + [CGX_STAT4] = "Total octets sent on the interface", + [CGX_STAT5] = "Total frames sent on the interface", + [CGX_STAT6] = "Packets sent with an octet count < 64", + [CGX_STAT7] = "Packets sent with an octet count == 64", + [CGX_STAT8] = "Packets sent with an octet count of 65–127", + [CGX_STAT9] = "Packets sent with an octet count of 128-255", + [CGX_STAT10] = "Packets sent with an octet count of 256-511", + [CGX_STAT11] = "Packets sent with an octet count of 512-1023", + [CGX_STAT12] = "Packets sent with an octet count of 1024-1518", + [CGX_STAT13] = "Packets sent with an octet count of > 1518", + [CGX_STAT14] = "Packets sent to a broadcast DMAC", + [CGX_STAT15] = "Packets sent to the multicast DMAC", + [CGX_STAT16] = "Transmit underflow and were truncated", + [CGX_STAT17] = "Control/PAUSE packets sent", +}; + #define NDC_MAX_BANK(rvu, blk_addr) (rvu_read64(rvu, \ blk_addr, NDC_AF_CONST) & 0xFF) @@ -1269,6 +1329,105 @@ create_failed: debugfs_remove_recursive(rvu->rvu_dbg.npa); } +static int cgx_print_stats(struct seq_file *s, int lmac_id) +{ + struct cgx_link_user_info linfo; + void *cgxd = s->private; + int stat = 0, err = 0; + u64 tx_stat, rx_stat; + + /* Link status */ + seq_puts(s, "\n=======Link Status======\n\n"); + err = cgx_get_link_info(cgxd, lmac_id, &linfo); + if (err) + seq_puts(s, "Failed to read link status\n"); + seq_printf(s, "\nLink is %s %d Mbps\n\n", + linfo.link_up ? "UP" : "DOWN", linfo.speed); + + /* Rx stats */ + seq_puts(s, "\n=======CGX RX_STATS======\n\n"); + while (stat < CGX_RX_STATS_COUNT) { + err = cgx_get_rx_stats(cgxd, lmac_id, stat, &rx_stat); + if (err) + return err; + seq_printf(s, "%s: %llu\n", cgx_rx_stats_fields[stat], rx_stat); + stat++; + } + + /* Tx stats */ + stat = 0; + seq_puts(s, "\n=======CGX TX_STATS======\n\n"); + while (stat < CGX_TX_STATS_COUNT) { + err = cgx_get_tx_stats(cgxd, lmac_id, stat, &tx_stat); + if (err) + return err; + seq_printf(s, "%s: %llu\n", cgx_tx_stats_fields[stat], tx_stat); + stat++; + } + + return err; +} + +static int rvu_dbg_cgx_stat_display(struct seq_file *filp, void *unused) +{ + struct dentry *current_dir; + int err, lmac_id; + char *buf; + + current_dir = filp->file->f_path.dentry->d_parent; + buf = strrchr(current_dir->d_name.name, 'c'); + if (!buf) + return -EINVAL; + + err = kstrtoint(buf + 1, 10, &lmac_id); + if (!err) { + err = cgx_print_stats(filp, lmac_id); + if (err) + return err; + } + return err; +} + +RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); + +static void rvu_dbg_cgx_init(struct rvu *rvu) +{ + const struct device *dev = &rvu->pdev->dev; + struct dentry *pfile; + int i, lmac_id; + char dname[20]; + void *cgx; + + rvu->rvu_dbg.cgx_root = debugfs_create_dir("cgx", rvu->rvu_dbg.root); + + for (i = 0; i < cgx_get_cgxcnt_max(); i++) { + cgx = rvu_cgx_pdata(i, rvu); + if (!cgx) + continue; + /* cgx debugfs dir */ + sprintf(dname, "cgx%d", i); + rvu->rvu_dbg.cgx = debugfs_create_dir(dname, + rvu->rvu_dbg.cgx_root); + for (lmac_id = 0; lmac_id < cgx_get_lmac_cnt(cgx); lmac_id++) { + /* lmac debugfs dir */ + sprintf(dname, "lmac%d", lmac_id); + rvu->rvu_dbg.lmac = + debugfs_create_dir(dname, rvu->rvu_dbg.cgx); + + pfile = debugfs_create_file("stats", 0600, + rvu->rvu_dbg.lmac, cgx, + &rvu_dbg_cgx_stat_fops); + if (!pfile) + goto create_failed; + } + } + return; + +create_failed: + dev_err(dev, "Failed to create debugfs dir/file for CGX\n"); + debugfs_remove_recursive(rvu->rvu_dbg.cgx_root); +} + void rvu_dbg_init(struct rvu *rvu) { struct device *dev = &rvu->pdev->dev; @@ -1286,6 +1445,7 @@ void rvu_dbg_init(struct rvu *rvu) rvu_dbg_npa_init(rvu); rvu_dbg_nix_init(rvu); + rvu_dbg_cgx_init(rvu); return; -- cgit v1.2.3-59-g8ed1b From f967488d095ef30d62771a84d86211b44825a743 Mon Sep 17 00:00:00 2001 From: Linu Cherian Date: Thu, 14 Nov 2019 10:56:21 +0530 Subject: octeontx2-af: Add per CGX port level NIX Rx/Tx counters A CGX port is shared by a RVU PF and it's VFs. These per CGX port level NIX Rx/Tx counters are cumilative stats of all NIXLFs sharing this port. These stats when compared to CGX Rx/Tx stats helps in identifying pkts dropped within the system, if any. Signed-off-by: Linu Cherian Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 10 +++ drivers/net/ethernet/marvell/octeontx2/af/cgx.h | 6 ++ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 + .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 62 +++++++++++++- .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 95 ++++++++++++++++++++++ 5 files changed, 173 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index 6d55e3d0b7ea..d94e68254c43 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -138,6 +138,16 @@ void *cgx_get_pdata(int cgx_id) } EXPORT_SYMBOL(cgx_get_pdata); +int cgx_get_cgxid(void *cgxd) +{ + struct cgx *cgx = cgxd; + + if (!cgx) + return -EINVAL; + + return cgx->cgx_id; +} + /* Ensure the required lock for event queue(where asynchronous events are * posted) is acquired before calling this API. Else an asynchronous event(with * latest link status) can reach the destination before this function returns diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index 206dc5dc1df8..c0306b275c5b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -63,6 +63,11 @@ #define CGX_NVEC 37 #define CGX_LMAC_FWI 0 +enum cgx_nix_stat_type { + NIX_STATS_RX, + NIX_STATS_TX, +}; + enum LMAC_TYPE { LMAC_MODE_SGMII = 0, LMAC_MODE_XAUI = 1, @@ -96,6 +101,7 @@ struct cgx_event_cb { extern struct pci_driver cgx_driver; int cgx_get_cgxcnt_max(void); +int cgx_get_cgxid(void *cgxd); int cgx_get_lmac_cnt(void *cgxd); void *cgx_get_pdata(int cgx_id); int cgx_set_pkind(void *cgxd, u8 lmac_id, int pkind); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 2fb871da9308..0451c2b772e0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -374,6 +374,8 @@ int rvu_cgx_init(struct rvu *rvu); int rvu_cgx_exit(struct rvu *rvu); void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu); int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start); +int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, + int rxtxflag, u64 *stat); int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req, struct msg_rsp *rsp); int rvu_mbox_handler_cgx_stop_rxtx(struct rvu *rvu, struct msg_req *req, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 7d7133c5f799..65d01e52dc3a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -14,6 +14,7 @@ #include "rvu.h" #include "cgx.h" +#include "rvu_reg.h" struct cgx_evq_entry { struct list_head evq_node; @@ -40,12 +41,25 @@ MBOX_UP_CGX_MESSAGES #undef M /* Returns bitmap of mapped PFs */ -static inline u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id) +static u16 cgxlmac_to_pfmap(struct rvu *rvu, u8 cgx_id, u8 lmac_id) { return rvu->cgxlmac2pf_map[CGX_OFFSET(cgx_id) + lmac_id]; } -static inline u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id) +static int cgxlmac_to_pf(struct rvu *rvu, int cgx_id, int lmac_id) +{ + unsigned long pfmap; + + pfmap = cgxlmac_to_pfmap(rvu, cgx_id, lmac_id); + + /* Assumes only one pf mapped to a cgx lmac port */ + if (!pfmap) + return -ENODEV; + else + return find_first_bit(&pfmap, 16); +} + +static u8 cgxlmac_id_to_bmap(u8 cgx_id, u8 lmac_id) { return ((cgx_id & 0xF) << 4) | (lmac_id & 0xF); } @@ -562,3 +576,47 @@ int rvu_mbox_handler_cgx_intlbk_disable(struct rvu *rvu, struct msg_req *req, rvu_cgx_config_intlbk(rvu, req->hdr.pcifunc, false); return 0; } + +/* Finds cumulative status of NIX rx/tx counters from LF of a PF and those + * from its VFs as well. ie. NIX rx/tx counters at the CGX port level + */ +int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, + int index, int rxtxflag, u64 *stat) +{ + struct rvu_block *block; + int blkaddr; + u16 pcifunc; + int pf, lf; + + if (!cgxd || !rvu) + return -EINVAL; + + pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id); + if (pf < 0) + return pf; + + /* Assumes LF of a PF and all of its VF belongs to the same + * NIX block + */ + pcifunc = pf << RVU_PFVF_PF_SHIFT; + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); + if (blkaddr < 0) + return 0; + block = &rvu->hw->block[blkaddr]; + + *stat = 0; + for (lf = 0; lf < block->lf.max; lf++) { + /* Check if a lf is attached to this PF or one of its VFs */ + if (!((block->fn_map[lf] & ~RVU_PFVF_FUNC_MASK) == (pcifunc & + ~RVU_PFVF_FUNC_MASK))) + continue; + if (rxtxflag == NIX_STATS_RX) + *stat += rvu_read64(rvu, blkaddr, + NIX_AF_LFX_RX_STATX(lf, index)); + else + *stat += rvu_read64(rvu, blkaddr, + NIX_AF_LFX_TX_STATX(lf, index)); + } + + return 0; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index c01a85ea754f..023f3e5e2191 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -44,6 +44,33 @@ enum { CGX_STAT18, }; +/* NIX TX stats */ +enum nix_stat_lf_tx { + TX_UCAST = 0x0, + TX_BCAST = 0x1, + TX_MCAST = 0x2, + TX_DROP = 0x3, + TX_OCTS = 0x4, + TX_STATS_ENUM_LAST, +}; + +/* NIX RX stats */ +enum nix_stat_lf_rx { + RX_OCTS = 0x0, + RX_UCAST = 0x1, + RX_BCAST = 0x2, + RX_MCAST = 0x3, + RX_DROP = 0x4, + RX_DROP_OCTS = 0x5, + RX_FCS = 0x6, + RX_ERR = 0x7, + RX_DRP_BCAST = 0x8, + RX_DRP_MCAST = 0x9, + RX_DRP_L3BCAST = 0xa, + RX_DRP_L3MCAST = 0xb, + RX_STATS_ENUM_LAST, +}; + static char *cgx_rx_stats_fields[] = { [CGX_STAT0] = "Received packets", [CGX_STAT1] = "Octets of received packets", @@ -1329,12 +1356,39 @@ create_failed: debugfs_remove_recursive(rvu->rvu_dbg.npa); } +#define PRINT_CGX_CUML_NIXRX_STATUS(idx, name) \ + ({ \ + u64 cnt; \ + err = rvu_cgx_nix_cuml_stats(rvu, cgxd, lmac_id, (idx), \ + NIX_STATS_RX, &(cnt)); \ + if (!err) \ + seq_printf(s, "%s: %llu\n", name, cnt); \ + cnt; \ + }) + +#define PRINT_CGX_CUML_NIXTX_STATUS(idx, name) \ + ({ \ + u64 cnt; \ + err = rvu_cgx_nix_cuml_stats(rvu, cgxd, lmac_id, (idx), \ + NIX_STATS_TX, &(cnt)); \ + if (!err) \ + seq_printf(s, "%s: %llu\n", name, cnt); \ + cnt; \ + }) + static int cgx_print_stats(struct seq_file *s, int lmac_id) { struct cgx_link_user_info linfo; void *cgxd = s->private; + u64 ucast, mcast, bcast; int stat = 0, err = 0; u64 tx_stat, rx_stat; + struct rvu *rvu; + + rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, + PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); + if (!rvu) + return -ENODEV; /* Link status */ seq_puts(s, "\n=======Link Status======\n\n"); @@ -1344,6 +1398,47 @@ static int cgx_print_stats(struct seq_file *s, int lmac_id) seq_printf(s, "\nLink is %s %d Mbps\n\n", linfo.link_up ? "UP" : "DOWN", linfo.speed); + /* Rx stats */ + seq_puts(s, "\n=======NIX RX_STATS(CGX port level)======\n\n"); + ucast = PRINT_CGX_CUML_NIXRX_STATUS(RX_UCAST, "rx_ucast_frames"); + if (err) + return err; + mcast = PRINT_CGX_CUML_NIXRX_STATUS(RX_MCAST, "rx_mcast_frames"); + if (err) + return err; + bcast = PRINT_CGX_CUML_NIXRX_STATUS(RX_BCAST, "rx_bcast_frames"); + if (err) + return err; + seq_printf(s, "rx_frames: %llu\n", ucast + mcast + bcast); + PRINT_CGX_CUML_NIXRX_STATUS(RX_OCTS, "rx_bytes"); + if (err) + return err; + PRINT_CGX_CUML_NIXRX_STATUS(RX_DROP, "rx_drops"); + if (err) + return err; + PRINT_CGX_CUML_NIXRX_STATUS(RX_ERR, "rx_errors"); + if (err) + return err; + + /* Tx stats */ + seq_puts(s, "\n=======NIX TX_STATS(CGX port level)======\n\n"); + ucast = PRINT_CGX_CUML_NIXTX_STATUS(TX_UCAST, "tx_ucast_frames"); + if (err) + return err; + mcast = PRINT_CGX_CUML_NIXTX_STATUS(TX_MCAST, "tx_mcast_frames"); + if (err) + return err; + bcast = PRINT_CGX_CUML_NIXTX_STATUS(TX_BCAST, "tx_bcast_frames"); + if (err) + return err; + seq_printf(s, "tx_frames: %llu\n", ucast + mcast + bcast); + PRINT_CGX_CUML_NIXTX_STATUS(TX_OCTS, "tx_bytes"); + if (err) + return err; + PRINT_CGX_CUML_NIXTX_STATUS(TX_DROP, "tx_drops"); + if (err) + return err; + /* Rx stats */ seq_puts(s, "\n=======CGX RX_STATS======\n\n"); while (stat < CGX_RX_STATS_COUNT) { -- cgit v1.2.3-59-g8ed1b From e07fb507aeb1f1552abfa352801eddab1bd1999d Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Thu, 14 Nov 2019 10:56:22 +0530 Subject: octeontx2-af: Add NPC MCAM entry allocation status to debugfs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added support to display current NPC MCAM entries and counter's allocation status ín debugfs. cat /sys/kernel/debug/octeontx2/npc/mcam_info' will dump following info - MCAM Rx and Tx keysize - Total MCAM entries and counters - Current available count - Count of number of MCAM entries and counters allocated by a RVU PF/VF device. Also, one NPC MCAM counter (last one) is reserved and mapped to NPC RX_INTF's MISS_ACTION to count dropped packets due to no MCAM entry match. This pkt drop counter can be checked via debugfs. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 8 ++ .../ethernet/marvell/octeontx2/af/rvu_debugfs.c | 154 +++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 52 ++++++- 3 files changed, 213 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 0451c2b772e0..63b6bbc60f8f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -49,6 +49,7 @@ struct rvu_debugfs { struct dentry *lmac; struct dentry *npa; struct dentry *nix; + struct dentry *npc; struct dump_ctx npa_aura_ctx; struct dump_ctx npa_pool_ctx; struct dump_ctx nix_cq_ctx; @@ -123,6 +124,7 @@ struct npc_mcam { u16 lprio_start; u16 hprio_count; u16 hprio_end; + u16 rx_miss_act_cntr; /* Counter for RX MISS action */ }; /* Structure for per RVU func info ie PF/VF */ @@ -498,6 +500,12 @@ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_enable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf, int group, int alg_idx, int mcam_index); +void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc, + int blkaddr, int *alloc_cnt, + int *enable_cnt); +void rvu_npc_get_mcam_counter_alloc_info(struct rvu *rvu, u16 pcifunc, + int blkaddr, int *alloc_cnt, + int *enable_cnt); int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu, struct npc_mcam_alloc_entry_req *req, struct npc_mcam_alloc_entry_rsp *rsp); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c index 023f3e5e2191..77adad4adb1b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c @@ -19,6 +19,7 @@ #include "rvu_reg.h" #include "rvu.h" #include "cgx.h" +#include "npc.h" #define DEBUGFS_DIR_NAME "octeontx2" @@ -1523,6 +1524,158 @@ create_failed: debugfs_remove_recursive(rvu->rvu_dbg.cgx_root); } +/* NPC debugfs APIs */ +static void rvu_print_npc_mcam_info(struct seq_file *s, + u16 pcifunc, int blkaddr) +{ + struct rvu *rvu = s->private; + int entry_acnt, entry_ecnt; + int cntr_acnt, cntr_ecnt; + + /* Skip PF0 */ + if (!pcifunc) + return; + rvu_npc_get_mcam_entry_alloc_info(rvu, pcifunc, blkaddr, + &entry_acnt, &entry_ecnt); + rvu_npc_get_mcam_counter_alloc_info(rvu, pcifunc, blkaddr, + &cntr_acnt, &cntr_ecnt); + if (!entry_acnt && !cntr_acnt) + return; + + if (!(pcifunc & RVU_PFVF_FUNC_MASK)) + seq_printf(s, "\n\t\t Device \t\t: PF%d\n", + rvu_get_pf(pcifunc)); + else + seq_printf(s, "\n\t\t Device \t\t: PF%d VF%d\n", + rvu_get_pf(pcifunc), + (pcifunc & RVU_PFVF_FUNC_MASK) - 1); + + if (entry_acnt) { + seq_printf(s, "\t\t Entries allocated \t: %d\n", entry_acnt); + seq_printf(s, "\t\t Entries enabled \t: %d\n", entry_ecnt); + } + if (cntr_acnt) { + seq_printf(s, "\t\t Counters allocated \t: %d\n", cntr_acnt); + seq_printf(s, "\t\t Counters enabled \t: %d\n", cntr_ecnt); + } +} + +static int rvu_dbg_npc_mcam_info_display(struct seq_file *filp, void *unsued) +{ + struct rvu *rvu = filp->private; + int pf, vf, numvfs, blkaddr; + struct npc_mcam *mcam; + u16 pcifunc; + u64 cfg; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return -ENODEV; + + mcam = &rvu->hw->mcam; + + seq_puts(filp, "\nNPC MCAM info:\n"); + /* MCAM keywidth on receive and transmit sides */ + cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_RX)); + cfg = (cfg >> 32) & 0x07; + seq_printf(filp, "\t\t RX keywidth \t: %s\n", (cfg == NPC_MCAM_KEY_X1) ? + "112bits" : ((cfg == NPC_MCAM_KEY_X2) ? + "224bits" : "448bits")); + cfg = rvu_read64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX)); + cfg = (cfg >> 32) & 0x07; + seq_printf(filp, "\t\t TX keywidth \t: %s\n", (cfg == NPC_MCAM_KEY_X1) ? + "112bits" : ((cfg == NPC_MCAM_KEY_X2) ? + "224bits" : "448bits")); + + mutex_lock(&mcam->lock); + /* MCAM entries */ + seq_printf(filp, "\n\t\t MCAM entries \t: %d\n", mcam->total_entries); + seq_printf(filp, "\t\t Reserved \t: %d\n", + mcam->total_entries - mcam->bmap_entries); + seq_printf(filp, "\t\t Available \t: %d\n", mcam->bmap_fcnt); + + /* MCAM counters */ + cfg = rvu_read64(rvu, blkaddr, NPC_AF_CONST); + cfg = (cfg >> 48) & 0xFFFF; + seq_printf(filp, "\n\t\t MCAM counters \t: %lld\n", cfg); + seq_printf(filp, "\t\t Reserved \t: %lld\n", cfg - mcam->counters.max); + seq_printf(filp, "\t\t Available \t: %d\n", + rvu_rsrc_free_count(&mcam->counters)); + + if (mcam->bmap_entries == mcam->bmap_fcnt) { + mutex_unlock(&mcam->lock); + return 0; + } + + seq_puts(filp, "\n\t\t Current allocation\n"); + seq_puts(filp, "\t\t====================\n"); + for (pf = 0; pf < rvu->hw->total_pfs; pf++) { + pcifunc = (pf << RVU_PFVF_PF_SHIFT); + rvu_print_npc_mcam_info(filp, pcifunc, blkaddr); + + cfg = rvu_read64(rvu, BLKADDR_RVUM, RVU_PRIV_PFX_CFG(pf)); + numvfs = (cfg >> 12) & 0xFF; + for (vf = 0; vf < numvfs; vf++) { + pcifunc = (pf << RVU_PFVF_PF_SHIFT) | (vf + 1); + rvu_print_npc_mcam_info(filp, pcifunc, blkaddr); + } + } + + mutex_unlock(&mcam->lock); + return 0; +} + +RVU_DEBUG_SEQ_FOPS(npc_mcam_info, npc_mcam_info_display, NULL); + +static int rvu_dbg_npc_rx_miss_stats_display(struct seq_file *filp, + void *unused) +{ + struct rvu *rvu = filp->private; + struct npc_mcam *mcam; + int blkaddr; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return -ENODEV; + + mcam = &rvu->hw->mcam; + + seq_puts(filp, "\nNPC MCAM RX miss action stats\n"); + seq_printf(filp, "\t\tStat %d: \t%lld\n", mcam->rx_miss_act_cntr, + rvu_read64(rvu, blkaddr, + NPC_AF_MATCH_STATX(mcam->rx_miss_act_cntr))); + + return 0; +} + +RVU_DEBUG_SEQ_FOPS(npc_rx_miss_act, npc_rx_miss_stats_display, NULL); + +static void rvu_dbg_npc_init(struct rvu *rvu) +{ + const struct device *dev = &rvu->pdev->dev; + struct dentry *pfile; + + rvu->rvu_dbg.npc = debugfs_create_dir("npc", rvu->rvu_dbg.root); + if (!rvu->rvu_dbg.npc) + return; + + pfile = debugfs_create_file("mcam_info", 0444, rvu->rvu_dbg.npc, + rvu, &rvu_dbg_npc_mcam_info_fops); + if (!pfile) + goto create_failed; + + pfile = debugfs_create_file("rx_miss_act_stats", 0444, rvu->rvu_dbg.npc, + rvu, &rvu_dbg_npc_rx_miss_act_fops); + if (!pfile) + goto create_failed; + + return; + +create_failed: + dev_err(dev, "Failed to create debugfs dir/file for NPC\n"); + debugfs_remove_recursive(rvu->rvu_dbg.npc); +} + void rvu_dbg_init(struct rvu *rvu) { struct device *dev = &rvu->pdev->dev; @@ -1541,6 +1694,7 @@ void rvu_dbg_init(struct rvu *rvu) rvu_dbg_npa_init(rvu); rvu_dbg_nix_init(rvu); rvu_dbg_cgx_init(rvu); + rvu_dbg_npc_init(rvu); return; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index 15f70273e29c..e300abbd3697 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -1064,6 +1064,13 @@ static int npc_mcam_rsrcs_init(struct rvu *rvu, int blkaddr) mcam->hprio_count = mcam->lprio_count; mcam->hprio_end = mcam->hprio_count; + /* Reserve last counter for MCAM RX miss action which is set to + * drop pkt. This way we will know how many pkts didn't match + * any MCAM entry. + */ + mcam->counters.max--; + mcam->rx_miss_act_cntr = mcam->counters.max; + /* Allocate bitmap for managing MCAM counters and memory * for saving counter to RVU PFFUNC allocation mapping. */ @@ -1101,6 +1108,7 @@ free_mem: int rvu_npc_init(struct rvu *rvu) { struct npc_pkind *pkind = &rvu->hw->pkind; + struct npc_mcam *mcam = &rvu->hw->mcam; u64 keyz = NPC_MCAM_KEY_X2; int blkaddr, entry, bank, err; u64 cfg, nibble_ena; @@ -1183,9 +1191,13 @@ int rvu_npc_init(struct rvu *rvu) rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_ACT(NIX_INTF_TX), NIX_TX_ACTIONOP_UCAST_DEFAULT); - /* If MCAM lookup doesn't result in a match, drop the received packet */ + /* If MCAM lookup doesn't result in a match, drop the received packet. + * And map this action to a counter to count dropped pkts. + */ rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_ACT(NIX_INTF_RX), NIX_RX_ACTIONOP_DROP); + rvu_write64(rvu, blkaddr, NPC_AF_INTFX_MISS_STAT_ACT(NIX_INTF_RX), + BIT_ULL(9) | mcam->rx_miss_act_cntr); return 0; } @@ -1200,6 +1212,44 @@ void rvu_npc_freemem(struct rvu *rvu) mutex_destroy(&mcam->lock); } +void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc, + int blkaddr, int *alloc_cnt, + int *enable_cnt) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + int entry; + + *alloc_cnt = 0; + *enable_cnt = 0; + + for (entry = 0; entry < mcam->bmap_entries; entry++) { + if (mcam->entry2pfvf_map[entry] == pcifunc) { + (*alloc_cnt)++; + if (is_mcam_entry_enabled(rvu, mcam, blkaddr, entry)) + (*enable_cnt)++; + } + } +} + +void rvu_npc_get_mcam_counter_alloc_info(struct rvu *rvu, u16 pcifunc, + int blkaddr, int *alloc_cnt, + int *enable_cnt) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + int cntr; + + *alloc_cnt = 0; + *enable_cnt = 0; + + for (cntr = 0; cntr < mcam->counters.max; cntr++) { + if (mcam->cntr2pfvf_map[cntr] == pcifunc) { + (*alloc_cnt)++; + if (mcam->cntr_refcnt[cntr]) + (*enable_cnt)++; + } + } +} + static int npc_mcam_verify_entry(struct npc_mcam *mcam, u16 pcifunc, int entry) { -- cgit v1.2.3-59-g8ed1b From a36740f614d3875708cc7a72779924d4f1d8730d Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Thu, 14 Nov 2019 10:56:23 +0530 Subject: octeontx2-af: Add mbox API to validate all responses Added a new mailbox API which goes through all responses to check their IDs and response codes. Also added logic to prevent queuing multiple works to process the same mailbox message. This scenario happens when AF is processing a PF's request and menawhile PF sends ACK to AF sent UP message, then mbox_hdr->num_msgs in the PF->AF DOWN mbox region will be nonzero and AF will end up processing PF's request again. This is fixed by taking a backup of num_msgs counter and clearing the same in the mbox region before scheduling work. Signed-off-by: Subbaraya Sundeep Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.c | 47 ++++++++++++++++++++++-- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 1 + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 32 ++++++++++++---- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 + 4 files changed, 70 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c index d6f9ed8ea966..81c83d27a424 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c @@ -236,8 +236,10 @@ struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, struct otx2_mbox_dev *mdev = &mbox->dev[devid]; u16 msgs; + spin_lock(&mdev->mbox_lock); + if (mdev->num_msgs != mdev->msgs_acked) - return ERR_PTR(-ENODEV); + goto error; for (msgs = 0; msgs < mdev->msgs_acked; msgs++) { struct mbox_msghdr *pmsg = mdev->mbase + imsg; @@ -245,18 +247,55 @@ struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, if (msg == pmsg) { if (pmsg->id != prsp->id) - return ERR_PTR(-ENODEV); + goto error; + spin_unlock(&mdev->mbox_lock); return prsp; } - imsg = pmsg->next_msgoff; - irsp = prsp->next_msgoff; + imsg = mbox->tx_start + pmsg->next_msgoff; + irsp = mbox->rx_start + prsp->next_msgoff; } +error: + spin_unlock(&mdev->mbox_lock); return ERR_PTR(-ENODEV); } EXPORT_SYMBOL(otx2_mbox_get_rsp); +int otx2_mbox_check_rsp_msgs(struct otx2_mbox *mbox, int devid) +{ + unsigned long ireq = mbox->tx_start + msgs_offset; + unsigned long irsp = mbox->rx_start + msgs_offset; + struct otx2_mbox_dev *mdev = &mbox->dev[devid]; + int rc = -ENODEV; + u16 msgs; + + spin_lock(&mdev->mbox_lock); + + if (mdev->num_msgs != mdev->msgs_acked) + goto exit; + + for (msgs = 0; msgs < mdev->msgs_acked; msgs++) { + struct mbox_msghdr *preq = mdev->mbase + ireq; + struct mbox_msghdr *prsp = mdev->mbase + irsp; + + if (preq->id != prsp->id) + goto exit; + if (prsp->rc) { + rc = prsp->rc; + goto exit; + } + + ireq = mbox->tx_start + preq->next_msgoff; + irsp = mbox->rx_start + prsp->next_msgoff; + } + rc = 0; +exit: + spin_unlock(&mdev->mbox_lock); + return rc; +} +EXPORT_SYMBOL(otx2_mbox_check_rsp_msgs); + int otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 76a4575d18ff..25f0e6f7fb39 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -103,6 +103,7 @@ struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, int size, int size_rsp); struct mbox_msghdr *otx2_mbox_get_rsp(struct otx2_mbox *mbox, int devid, struct mbox_msghdr *msg); +int otx2_mbox_check_rsp_msgs(struct otx2_mbox *mbox, int devid); int otx2_reply_invalid_msg(struct otx2_mbox *mbox, int devid, u16 pcifunc, u16 id); bool otx2_mbox_nonempty(struct otx2_mbox *mbox, int devid); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index cf8741db1549..f5e6acaa865e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -1440,12 +1440,12 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type) /* Process received mbox messages */ req_hdr = mdev->mbase + mbox->rx_start; - if (req_hdr->num_msgs == 0) + if (mw->mbox_wrk[devid].num_msgs == 0) return; offset = mbox->rx_start + ALIGN(sizeof(*req_hdr), MBOX_MSG_ALIGN); - for (id = 0; id < req_hdr->num_msgs; id++) { + for (id = 0; id < mw->mbox_wrk[devid].num_msgs; id++) { msg = mdev->mbase + offset; /* Set which PF/VF sent this message based on mbox IRQ */ @@ -1471,13 +1471,14 @@ static void __rvu_mbox_handler(struct rvu_work *mwork, int type) if (msg->pcifunc & RVU_PFVF_FUNC_MASK) dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d:VF%d\n", err, otx2_mbox_id2name(msg->id), - msg->id, devid, + msg->id, rvu_get_pf(msg->pcifunc), (msg->pcifunc & RVU_PFVF_FUNC_MASK) - 1); else dev_warn(rvu->dev, "Error %d when processing message %s (0x%x) from PF%d\n", err, otx2_mbox_id2name(msg->id), msg->id, devid); } + mw->mbox_wrk[devid].num_msgs = 0; /* Send mbox responses to VF/PF */ otx2_mbox_msg_send(mbox, devid); @@ -1523,14 +1524,14 @@ static void __rvu_mbox_up_handler(struct rvu_work *mwork, int type) mdev = &mbox->dev[devid]; rsp_hdr = mdev->mbase + mbox->rx_start; - if (rsp_hdr->num_msgs == 0) { + if (mw->mbox_wrk_up[devid].up_num_msgs == 0) { dev_warn(rvu->dev, "mbox up handler: num_msgs = 0\n"); return; } offset = mbox->rx_start + ALIGN(sizeof(*rsp_hdr), MBOX_MSG_ALIGN); - for (id = 0; id < rsp_hdr->num_msgs; id++) { + for (id = 0; id < mw->mbox_wrk_up[devid].up_num_msgs; id++) { msg = mdev->mbase + offset; if (msg->id >= MBOX_MSG_MAX) { @@ -1560,6 +1561,7 @@ end: offset = mbox->rx_start + msg->next_msgoff; mdev->msgs_acked++; } + mw->mbox_wrk_up[devid].up_num_msgs = 0; otx2_mbox_reset(mbox, devid); } @@ -1697,14 +1699,28 @@ static void rvu_queue_work(struct mbox_wq_info *mw, int first, mbox = &mw->mbox; mdev = &mbox->dev[i]; hdr = mdev->mbase + mbox->rx_start; - if (hdr->num_msgs) - queue_work(mw->mbox_wq, &mw->mbox_wrk[i].work); + /*The hdr->num_msgs is set to zero immediately in the interrupt + * handler to ensure that it holds a correct value next time + * when the interrupt handler is called. + * pf->mbox.num_msgs holds the data for use in pfaf_mbox_handler + * pf>mbox.up_num_msgs holds the data for use in + * pfaf_mbox_up_handler. + */ + + if (hdr->num_msgs) { + mw->mbox_wrk[i].num_msgs = hdr->num_msgs; + hdr->num_msgs = 0; + queue_work(mw->mbox_wq, &mw->mbox_wrk[i].work); + } mbox = &mw->mbox_up; mdev = &mbox->dev[i]; hdr = mdev->mbase + mbox->rx_start; - if (hdr->num_msgs) + if (hdr->num_msgs) { + mw->mbox_wrk_up[i].up_num_msgs = hdr->num_msgs; + hdr->num_msgs = 0; queue_work(mw->mbox_wq, &mw->mbox_wrk_up[i].work); + } } } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 63b6bbc60f8f..e81b0ed5a7c2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -63,6 +63,8 @@ struct rvu_debugfs { struct rvu_work { struct work_struct work; struct rvu *rvu; + int num_msgs; + int up_num_msgs; }; struct rsrc_bmap { -- cgit v1.2.3-59-g8ed1b From fdb9029814825c3055c104c630fc5958ff441668 Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Thu, 14 Nov 2019 10:56:24 +0530 Subject: octeontx2-af: Sync hw mbox with bounce buffer. If mailbox client has a bounce buffer or a intermediate buffer where mbox messages are framed then copy them from there to HW buffer. If 'mbase' and 'hw_mbase' are not same then assume 'mbase' points to bounce buffer. This patch also adds msg_size field to mbox header to copy only valid data instead of whole buffer. Signed-off-by: Geetha sowjanya Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.c | 40 +++++++++++++++++------- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 3 +- 2 files changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c index 81c83d27a424..387e33fa417a 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.c @@ -19,17 +19,20 @@ static const u16 msgs_offset = ALIGN(sizeof(struct mbox_hdr), MBOX_MSG_ALIGN); void otx2_mbox_reset(struct otx2_mbox *mbox, int devid) { + void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE); struct otx2_mbox_dev *mdev = &mbox->dev[devid]; struct mbox_hdr *tx_hdr, *rx_hdr; - tx_hdr = mdev->mbase + mbox->tx_start; - rx_hdr = mdev->mbase + mbox->rx_start; + tx_hdr = hw_mbase + mbox->tx_start; + rx_hdr = hw_mbase + mbox->rx_start; spin_lock(&mdev->mbox_lock); mdev->msg_size = 0; mdev->rsp_size = 0; tx_hdr->num_msgs = 0; + tx_hdr->msg_size = 0; rx_hdr->num_msgs = 0; + rx_hdr->msg_size = 0; spin_unlock(&mdev->mbox_lock); } EXPORT_SYMBOL(otx2_mbox_reset); @@ -133,16 +136,17 @@ EXPORT_SYMBOL(otx2_mbox_init); int otx2_mbox_wait_for_rsp(struct otx2_mbox *mbox, int devid) { + unsigned long timeout = jiffies + msecs_to_jiffies(MBOX_RSP_TIMEOUT); struct otx2_mbox_dev *mdev = &mbox->dev[devid]; - int timeout = 0, sleep = 1; + struct device *sender = &mbox->pdev->dev; - while (mdev->num_msgs != mdev->msgs_acked) { - msleep(sleep); - timeout += sleep; - if (timeout >= MBOX_RSP_TIMEOUT) - return -EIO; + while (!time_after(jiffies, timeout)) { + if (mdev->num_msgs == mdev->msgs_acked) + return 0; + usleep_range(800, 1000); } - return 0; + dev_dbg(sender, "timed out while waiting for rsp\n"); + return -EIO; } EXPORT_SYMBOL(otx2_mbox_wait_for_rsp); @@ -162,13 +166,25 @@ EXPORT_SYMBOL(otx2_mbox_busy_poll_for_rsp); void otx2_mbox_msg_send(struct otx2_mbox *mbox, int devid) { + void *hw_mbase = mbox->hwbase + (devid * MBOX_SIZE); struct otx2_mbox_dev *mdev = &mbox->dev[devid]; struct mbox_hdr *tx_hdr, *rx_hdr; - tx_hdr = mdev->mbase + mbox->tx_start; - rx_hdr = mdev->mbase + mbox->rx_start; + tx_hdr = hw_mbase + mbox->tx_start; + rx_hdr = hw_mbase + mbox->rx_start; + + /* If bounce buffer is implemented copy mbox messages from + * bounce buffer to hw mbox memory. + */ + if (mdev->mbase != hw_mbase) + memcpy(hw_mbase + mbox->tx_start + msgs_offset, + mdev->mbase + mbox->tx_start + msgs_offset, + mdev->msg_size); spin_lock(&mdev->mbox_lock); + + tx_hdr->msg_size = mdev->msg_size; + /* Reset header for next messages */ mdev->msg_size = 0; mdev->rsp_size = 0; @@ -215,7 +231,7 @@ struct mbox_msghdr *otx2_mbox_alloc_msg_rsp(struct otx2_mbox *mbox, int devid, msghdr = mdev->mbase + mbox->tx_start + msgs_offset + mdev->msg_size; /* Clear the whole msg region */ - memset(msghdr, 0, sizeof(*msghdr) + size); + memset(msghdr, 0, size); /* Init message header with reset values */ msghdr->ver = OTX2_MBOX_VERSION; mdev->msg_size += size; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 25f0e6f7fb39..94c198a34ecd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -36,7 +36,7 @@ #define INTR_MASK(pfvfs) ((pfvfs < 64) ? (BIT_ULL(pfvfs) - 1) : (~0ull)) -#define MBOX_RSP_TIMEOUT 1000 /* in ms, Time to wait for mbox response */ +#define MBOX_RSP_TIMEOUT 2000 /* Time(ms) to wait for mbox response */ #define MBOX_MSG_ALIGN 16 /* Align mbox msg start to 16bytes */ @@ -75,6 +75,7 @@ struct otx2_mbox { /* Header which preceeds all mbox messages */ struct mbox_hdr { + u64 msg_size; /* Total msgs size embedded */ u16 num_msgs; /* No of msgs embedded */ }; -- cgit v1.2.3-59-g8ed1b From c6614738a89ce7feea70bdc89c74953d007b1a2f Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 14 Nov 2019 10:56:25 +0530 Subject: octeontx2-af: Add macro to generate mbox handlers declarations For every mailbox handler added to rvu, we are adding a function declaration in rvu header file. Cleaned this up by adding a macro to generate these declarations automatically. Signed-off-by: Subbaraya Sundeep Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 24 ++--- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 127 +----------------------- 2 files changed, 17 insertions(+), 134 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index f5e6acaa865e..49e48b6d322e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -877,8 +877,8 @@ int rvu_aq_alloc(struct rvu *rvu, struct admin_queue **ad_queue, return 0; } -static int rvu_mbox_handler_ready(struct rvu *rvu, struct msg_req *req, - struct ready_msg_rsp *rsp) +int rvu_mbox_handler_ready(struct rvu *rvu, struct msg_req *req, + struct ready_msg_rsp *rsp) { return 0; } @@ -1023,9 +1023,9 @@ static int rvu_detach_rsrcs(struct rvu *rvu, struct rsrc_detach *detach, return 0; } -static int rvu_mbox_handler_detach_resources(struct rvu *rvu, - struct rsrc_detach *detach, - struct msg_rsp *rsp) +int rvu_mbox_handler_detach_resources(struct rvu *rvu, + struct rsrc_detach *detach, + struct msg_rsp *rsp) { return rvu_detach_rsrcs(rvu, detach, detach->hdr.pcifunc); } @@ -1171,9 +1171,9 @@ fail: return -ENOSPC; } -static int rvu_mbox_handler_attach_resources(struct rvu *rvu, - struct rsrc_attach *attach, - struct msg_rsp *rsp) +int rvu_mbox_handler_attach_resources(struct rvu *rvu, + struct rsrc_attach *attach, + struct msg_rsp *rsp) { u16 pcifunc = attach->hdr.pcifunc; int err; @@ -1294,8 +1294,8 @@ static void rvu_clear_msix_offset(struct rvu *rvu, struct rvu_pfvf *pfvf, rvu_free_rsrc_contig(&pfvf->msix, nvecs, offset); } -static int rvu_mbox_handler_msix_offset(struct rvu *rvu, struct msg_req *req, - struct msix_offset_rsp *rsp) +int rvu_mbox_handler_msix_offset(struct rvu *rvu, struct msg_req *req, + struct msix_offset_rsp *rsp) { struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; @@ -1343,8 +1343,8 @@ static int rvu_mbox_handler_msix_offset(struct rvu *rvu, struct msg_req *req, return 0; } -static int rvu_mbox_handler_vf_flr(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp) +int rvu_mbox_handler_vf_flr(struct rvu *rvu, struct msg_req *req, + struct msg_rsp *rsp) { u16 pcifunc = req->hdr.pcifunc; u16 vf, numvfs; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index e81b0ed5a7c2..7e990bbfc336 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -374,56 +374,23 @@ static inline void rvu_get_cgx_lmac_id(u8 map, u8 *cgx_id, u8 *lmac_id) *lmac_id = (map & 0xF); } +#define M(_name, _id, fn_name, req, rsp) \ +int rvu_mbox_handler_ ## fn_name(struct rvu *, struct req *, struct rsp *); +MBOX_MESSAGES +#undef M + int rvu_cgx_init(struct rvu *rvu); int rvu_cgx_exit(struct rvu *rvu); void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu); int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start); int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, int rxtxflag, u64 *stat); -int rvu_mbox_handler_cgx_start_rxtx(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_stop_rxtx(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_stats(struct rvu *rvu, struct msg_req *req, - struct cgx_stats_rsp *rsp); -int rvu_mbox_handler_cgx_mac_addr_set(struct rvu *rvu, - struct cgx_mac_addr_set_or_get *req, - struct cgx_mac_addr_set_or_get *rsp); -int rvu_mbox_handler_cgx_mac_addr_get(struct rvu *rvu, - struct cgx_mac_addr_set_or_get *req, - struct cgx_mac_addr_set_or_get *rsp); -int rvu_mbox_handler_cgx_promisc_enable(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_promisc_disable(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_start_linkevents(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_stop_linkevents(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_get_linkinfo(struct rvu *rvu, struct msg_req *req, - struct cgx_link_info_msg *rsp); -int rvu_mbox_handler_cgx_intlbk_enable(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_cgx_intlbk_disable(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); - /* NPA APIs */ int rvu_npa_init(struct rvu *rvu); void rvu_npa_freemem(struct rvu *rvu); void rvu_npa_lf_teardown(struct rvu *rvu, u16 pcifunc, int npalf); int rvu_npa_aq_enq_inst(struct rvu *rvu, struct npa_aq_enq_req *req, struct npa_aq_enq_rsp *rsp); -int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu, - struct npa_aq_enq_req *req, - struct npa_aq_enq_rsp *rsp); -int rvu_mbox_handler_npa_hwctx_disable(struct rvu *rvu, - struct hwctx_disable_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu, - struct npa_lf_alloc_req *req, - struct npa_lf_alloc_rsp *rsp); -int rvu_mbox_handler_npa_lf_free(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); /* NIX APIs */ bool is_nixlf_attached(struct rvu *rvu, u16 pcifunc); @@ -433,55 +400,6 @@ int rvu_nix_reserve_mark_format(struct rvu *rvu, struct nix_hw *nix_hw, void rvu_nix_freemem(struct rvu *rvu); int rvu_get_nixlf_count(struct rvu *rvu); void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf); -int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, - struct nix_lf_alloc_req *req, - struct nix_lf_alloc_rsp *rsp); -int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_aq_enq(struct rvu *rvu, - struct nix_aq_enq_req *req, - struct nix_aq_enq_rsp *rsp); -int rvu_mbox_handler_nix_hwctx_disable(struct rvu *rvu, - struct hwctx_disable_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, - struct nix_txsch_alloc_req *req, - struct nix_txsch_alloc_rsp *rsp); -int rvu_mbox_handler_nix_txsch_free(struct rvu *rvu, - struct nix_txsch_free_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, - struct nix_txschq_config *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_stats_rst(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_vtag_cfg(struct rvu *rvu, - struct nix_vtag_config *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_rxvlan_alloc(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_rss_flowkey_cfg(struct rvu *rvu, - struct nix_rss_flowkey_cfg *req, - struct nix_rss_flowkey_cfg_rsp *rsp); -int rvu_mbox_handler_nix_set_mac_addr(struct rvu *rvu, - struct nix_set_mac_addr *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_set_hw_frs(struct rvu *rvu, struct nix_frs_cfg *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_mark_format_cfg(struct rvu *rvu, - struct nix_mark_format_cfg *req, - struct nix_mark_format_cfg_rsp *rsp); -int rvu_mbox_handler_nix_set_rx_cfg(struct rvu *rvu, struct nix_rx_cfg *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_nix_lso_format_cfg(struct rvu *rvu, - struct nix_lso_format_cfg *req, - struct nix_lso_format_cfg_rsp *rsp); /* NPC APIs */ int rvu_npc_init(struct rvu *rvu); @@ -508,41 +426,6 @@ void rvu_npc_get_mcam_entry_alloc_info(struct rvu *rvu, u16 pcifunc, void rvu_npc_get_mcam_counter_alloc_info(struct rvu *rvu, u16 pcifunc, int blkaddr, int *alloc_cnt, int *enable_cnt); -int rvu_mbox_handler_npc_mcam_alloc_entry(struct rvu *rvu, - struct npc_mcam_alloc_entry_req *req, - struct npc_mcam_alloc_entry_rsp *rsp); -int rvu_mbox_handler_npc_mcam_free_entry(struct rvu *rvu, - struct npc_mcam_free_entry_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_write_entry(struct rvu *rvu, - struct npc_mcam_write_entry_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_ena_entry(struct rvu *rvu, - struct npc_mcam_ena_dis_entry_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_dis_entry(struct rvu *rvu, - struct npc_mcam_ena_dis_entry_req *req, - struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_shift_entry(struct rvu *rvu, - struct npc_mcam_shift_entry_req *req, - struct npc_mcam_shift_entry_rsp *rsp); -int rvu_mbox_handler_npc_mcam_alloc_counter(struct rvu *rvu, - struct npc_mcam_alloc_counter_req *req, - struct npc_mcam_alloc_counter_rsp *rsp); -int rvu_mbox_handler_npc_mcam_free_counter(struct rvu *rvu, - struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_clear_counter(struct rvu *rvu, - struct npc_mcam_oper_counter_req *req, struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_unmap_counter(struct rvu *rvu, - struct npc_mcam_unmap_counter_req *req, struct msg_rsp *rsp); -int rvu_mbox_handler_npc_mcam_counter_stats(struct rvu *rvu, - struct npc_mcam_oper_counter_req *req, - struct npc_mcam_oper_counter_rsp *rsp); -int rvu_mbox_handler_npc_mcam_alloc_and_write_entry(struct rvu *rvu, - struct npc_mcam_alloc_and_write_entry_req *req, - struct npc_mcam_alloc_and_write_entry_rsp *rsp); -int rvu_mbox_handler_npc_get_kex_cfg(struct rvu *rvu, struct msg_req *req, - struct npc_get_kex_cfg_rsp *rsp); #ifdef CONFIG_DEBUG_FS void rvu_dbg_init(struct rvu *rvu); -- cgit v1.2.3-59-g8ed1b From 922584f607525982e5c99a772bae408ad9407c69 Mon Sep 17 00:00:00 2001 From: Hao Zheng Date: Thu, 14 Nov 2019 10:56:26 +0530 Subject: octeontx2-af: Update NPC KPU packet parsing profile Updated NPC KPU packet parsing profile with support for following - Fragmentation support for IPv4 IPv6 outer header - NIX instruction header support - QinQ with TPID of 0x8100 as non inner most vlan tag, as legacy network equipments still generate QinQ packets with this configuration. - To better support RSS for tunnelled packets, udp based tunnel protocols such as vxlan, vxlan-gpe, geneve and gtpu are now captured into a separate layer E. Consequently, the inner packet headers are pushed one layer down to LF, LG, and LH accordingly. - Support for rfc7510 mpls in udp. Up to 4 MPLS labels can be parsed and captured in one layer LE. - Parser support for DSA, extended DSA and eDSA tags right after ethernet header by Marvell SOHO and Falcon switches. For extended DSA and eDSA tags, a special PKIND of 62 is used, as these tags don't contain a tpid field. - Higig2 protocol header parsing support, added a NPC_LT_LA_HIGIG2_ETHER for a combined header of HIGIG2 and Ethernet. Add a NPC_LT_LA_IH_NIX_HIGIG2_ETHER for a combined header of nix_ih, HIGIG2 and Ethernet on egress side. Also added 2 upper flags in LA to indicate the presence of nix_ih and HIGIG2. Other changes include - IPv4.TTL==0 IPv6.HLIM==0 check - Per RFC 1858, mark fragment offset == 1 as error - TCP invalid flags check - Separate error codes for outer and inner IPv4 checksum errors. - Fix a parser error when KPU parses incoming IPSec ESP and AH packets - NPC vtag capture/strip hardware expect tag pointer to point to tpid/ethertype instead of tci. So move lb_ptr to point to tpid/ethertype. - Fix npc parser error when parsing udp packets that don't have any payload. - For a single MCAM entry to match on packets with one or stacked vlan tags combine NPC_LT_LB_STAG and NPC_LT_LB_QINQ to NPC_LT_LB_STAG_QINQ. - NVGRE to have a separate ltype LD_NVGRE instead of combined with LD_GRE. - Reserve top LD/LTYPEs to support custom KPU profile fields. Signed-off-by: Hao Zheng Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/npc.h | 95 +- .../ethernet/marvell/octeontx2/af/npc_profile.h | 14946 ++++++++++++++----- .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 10 +- .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 9 +- 4 files changed, 11252 insertions(+), 3808 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h index 8d6d90fdfb73..168fb4ea6ab6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -27,26 +27,45 @@ enum NPC_LID_E { enum npc_kpu_la_ltype { NPC_LT_LA_8023 = 1, NPC_LT_LA_ETHER, + NPC_LT_LA_IH_NIX_ETHER, + NPC_LT_LA_IH_8_ETHER, + NPC_LT_LA_IH_4_ETHER, + NPC_LT_LA_IH_2_ETHER, + NPC_LT_LA_HIGIG2_ETHER, + NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_LT_LA_CUSTOM0 = 0xE, + NPC_LT_LA_CUSTOM1 = 0xF, }; enum npc_kpu_lb_ltype { NPC_LT_LB_ETAG = 1, NPC_LT_LB_CTAG, - NPC_LT_LB_STAG, + NPC_LT_LB_STAG_QINQ, NPC_LT_LB_BTAG, - NPC_LT_LB_QINQ, NPC_LT_LB_ITAG, + NPC_LT_LB_DSA, + NPC_LT_LB_DSA_VLAN, + NPC_LT_LB_EDSA, + NPC_LT_LB_EDSA_VLAN, + NPC_LT_LB_EXDSA, + NPC_LT_LB_EXDSA_VLAN, + NPC_LT_LB_CUSTOM0 = 0xE, + NPC_LT_LB_CUSTOM1 = 0xF, }; enum npc_kpu_lc_ltype { NPC_LT_LC_IP = 1, + NPC_LT_LC_IP_OPT, NPC_LT_LC_IP6, + NPC_LT_LC_IP6_EXT, NPC_LT_LC_ARP, NPC_LT_LC_RARP, NPC_LT_LC_MPLS, NPC_LT_LC_NSH, NPC_LT_LC_PTP, NPC_LT_LC_FCOE, + NPC_LT_LC_CUSTOM0 = 0xE, + NPC_LT_LC_CUSTOM1 = 0xF, }; /* Don't modify Ltypes upto SCTP, otherwise it will @@ -57,49 +76,67 @@ enum npc_kpu_ld_ltype { NPC_LT_LD_UDP, NPC_LT_LD_ICMP, NPC_LT_LD_SCTP, - NPC_LT_LD_IGMP, NPC_LT_LD_ICMP6, + NPC_LT_LD_IGMP = 8, NPC_LT_LD_ESP, NPC_LT_LD_AH, NPC_LT_LD_GRE, - NPC_LT_LD_GRE_MPLS, - NPC_LT_LD_GRE_NSH, - NPC_LT_LD_TU_MPLS, + NPC_LT_LD_NVGRE, + NPC_LT_LD_NSH, + NPC_LT_LD_TU_MPLS_IN_NSH, + NPC_LT_LD_TU_MPLS_IN_IP, + NPC_LT_LD_CUSTOM0 = 0xE, + NPC_LT_LD_CUSTOM1 = 0xF, }; enum npc_kpu_le_ltype { - NPC_LT_LE_TU_ETHER = 1, - NPC_LT_LE_TU_PPP, - NPC_LT_LE_TU_MPLS_IN_NSH, - NPC_LT_LE_TU_3RD_NSH, + NPC_LT_LE_VXLAN = 1, + NPC_LT_LE_GENEVE, + NPC_LT_LE_GTPU = 4, + NPC_LT_LE_VXLANGPE, + NPC_LT_LE_GTPC, + NPC_LT_LE_NSH, + NPC_LT_LE_TU_MPLS_IN_GRE, + NPC_LT_LE_TU_NSH_IN_GRE, + NPC_LT_LE_TU_MPLS_IN_UDP, + NPC_LT_LE_CUSTOM0 = 0xE, + NPC_LT_LE_CUSTOM1 = 0xF, }; enum npc_kpu_lf_ltype { - NPC_LT_LF_TU_IP = 1, - NPC_LT_LF_TU_IP6, - NPC_LT_LF_TU_ARP, - NPC_LT_LF_TU_MPLS_IP, - NPC_LT_LF_TU_MPLS_IP6, - NPC_LT_LF_TU_MPLS_ETHER, + NPC_LT_LF_TU_ETHER = 1, + NPC_LT_LF_TU_PPP, + NPC_LT_LF_TU_MPLS_IN_VXLANGPE, + NPC_LT_LF_TU_NSH_IN_VXLANGPE, + NPC_LT_LF_TU_MPLS_IN_NSH, + NPC_LT_LF_TU_3RD_NSH, + NPC_LT_LF_CUSTOM0 = 0xE, + NPC_LT_LF_CUSTOM1 = 0xF, }; enum npc_kpu_lg_ltype { - NPC_LT_LG_TU_TCP = 1, - NPC_LT_LG_TU_UDP, - NPC_LT_LG_TU_SCTP, - NPC_LT_LG_TU_ICMP, - NPC_LT_LG_TU_IGMP, - NPC_LT_LG_TU_ICMP6, - NPC_LT_LG_TU_ESP, - NPC_LT_LG_TU_AH, + NPC_LT_LG_TU_IP = 1, + NPC_LT_LG_TU_IP6, + NPC_LT_LG_TU_ARP, + NPC_LT_LG_TU_ETHER_IN_NSH, + NPC_LT_LG_CUSTOM0 = 0xE, + NPC_LT_LG_CUSTOM1 = 0xF, }; +/* Don't modify Ltypes upto SCTP, otherwise it will + * effect flow tag calculation and thus RSS. + */ enum npc_kpu_lh_ltype { - NPC_LT_LH_TCP_DATA = 1, - NPC_LT_LH_HTTP_DATA, - NPC_LT_LH_HTTPS_DATA, - NPC_LT_LH_PPTP_DATA, - NPC_LT_LH_UDP_DATA, + NPC_LT_LH_TU_TCP = 1, + NPC_LT_LH_TU_UDP, + NPC_LT_LH_TU_ICMP, + NPC_LT_LH_TU_SCTP, + NPC_LT_LH_TU_ICMP6, + NPC_LT_LH_TU_IGMP = 8, + NPC_LT_LH_TU_ESP, + NPC_LT_LH_TU_AH, + NPC_LT_LH_CUSTOM0 = 0xE, + NPC_LT_LH_CUSTOM1 = 0xF, }; struct npc_kpu_profile_cam { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h index b2ce957605bb..832810ad6b02 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h @@ -11,6 +11,11 @@ #ifndef NPC_PROFILE_H #define NPC_PROFILE_H +#define NPC_KPU_PROFILE_VER 0x0000000100050000 + +#define NPC_IH_W 0x8000 +#define NPC_IH_UTAG 0x2000 + #define NPC_ETYPE_IP 0x0800 #define NPC_ETYPE_IP6 0x86dd #define NPC_ETYPE_ARP 0x0806 @@ -27,6 +32,7 @@ #define NPC_ETYPE_TRANS_ETH_BR 0x6558 #define NPC_ETYPE_PPP 0x880b #define NPC_ETYPE_NSH 0x894f +#define NPC_ETYPE_DSA 0xdada #define NPC_IPNH_HOP 0 #define NPC_IPNH_ICMP 1 @@ -44,13 +50,19 @@ #define NPC_IPNH_NONH 59 #define NPC_IPNH_DEST 60 #define NPC_IPNH_SCTP 132 +#define NPC_IPNH_MOBILITY 135 #define NPC_IPNH_MPLS 137 +#define NPC_IPNH_HOSTID 139 +#define NPC_IPNH_SHIM6 140 +#define NPC_UDP_PORT_PTP_E 319 +#define NPC_UDP_PORT_PTP_G 320 #define NPC_UDP_PORT_GTPC 2123 #define NPC_UDP_PORT_GTPU 2152 #define NPC_UDP_PORT_VXLAN 4789 #define NPC_UDP_PORT_VXLANGPE 4790 #define NPC_UDP_PORT_GENEVE 6081 +#define NPC_UDP_PORT_MPLS 6635 #define NPC_VXLANGPE_NP_IP 0x1 #define NPC_VXLANGPE_NP_IP6 0x2 @@ -72,11 +84,17 @@ #define NPC_MPLS_S 0x0100 +#define NPC_IP_TTL_MASK 0xff00 #define NPC_IP_VER_4 0x4000 #define NPC_IP_VER_6 0x6000 #define NPC_IP_VER_MASK 0xf000 #define NPC_IP_HDR_LEN_5 0x0500 #define NPC_IP_HDR_LEN_MASK 0x0f00 +#define NPC_IP_HDR_MF 0x2000 +#define NPC_IP_HDR_FRAGOFF 0x1fff + +#define NPC_IP6_HOP_MASK 0x00ff +#define NPC_IP6_FRAG_FRAGOFF 0xfff8 #define NPC_GRE_F_CSUM (0x1 << 15) #define NPC_GRE_F_ROUTE (0x1 << 14) @@ -108,22 +126,44 @@ #define NPC_GTP_MT_G_PDU 0xff #define NPC_GTP_MT_MASK 0xff +#define NPC_TCP_FLAGS_FIN 0x0001 +#define NPC_TCP_FLAGS_SYN 0x0002 +#define NPC_TCP_FLAGS_RST 0x0004 +#define NPC_TCP_FLAGS_PSH 0x0008 +#define NPC_TCP_FLAGS_ACK 0x0010 +#define NPC_TCP_FLAGS_URG 0x0020 +#define NPC_TCP_FLAGS_MASK 0x003f + #define NPC_TCP_DATA_OFFSET_5 0x5000 #define NPC_TCP_DATA_OFFSET_MASK 0xf000 +#define NPC_DSA_EXTEND 0x1000 +#define NPC_DSA_EDSA 0x8000 + enum npc_kpu_parser_state { NPC_S_NA = 0, NPC_S_KPU1_ETHER, - NPC_S_KPU1_PKI, + NPC_S_KPU1_IH_NIX, + NPC_S_KPU1_IH, + NPC_S_KPU1_EXDSA, + NPC_S_KPU1_HIGIG2, + NPC_S_KPU1_IH_NIX_HIGIG2, NPC_S_KPU2_CTAG, + NPC_S_KPU2_CTAG2, NPC_S_KPU2_SBTAG, NPC_S_KPU2_QINQ, NPC_S_KPU2_ETAG, NPC_S_KPU2_ITAG, + NPC_S_KPU2_PREHEADER, + NPC_S_KPU2_EXDSA, NPC_S_KPU3_CTAG, NPC_S_KPU3_STAG, NPC_S_KPU3_QINQ, NPC_S_KPU3_ITAG, + NPC_S_KPU3_CTAG_C, + NPC_S_KPU3_STAG_C, + NPC_S_KPU3_QINQ_C, + NPC_S_KPU3_DSA, NPC_S_KPU4_MPLS, NPC_S_KPU4_NSH, NPC_S_KPU5_IP, @@ -136,7 +176,12 @@ enum npc_kpu_parser_state { NPC_S_KPU5_MPLS_PL, NPC_S_KPU5_NSH, NPC_S_KPU6_IP6_EXT, + NPC_S_KPU6_IP6_HOP_DEST, + NPC_S_KPU6_IP6_ROUT, + NPC_S_KPU6_IP6_FRAG, NPC_S_KPU7_IP6_EXT, + NPC_S_KPU7_IP6_ROUT, + NPC_S_KPU7_IP6_FRAG, NPC_S_KPU8_TCP, NPC_S_KPU8_UDP, NPC_S_KPU8_SCTP, @@ -146,16 +191,26 @@ enum npc_kpu_parser_state { NPC_S_KPU8_GRE, NPC_S_KPU8_ESP, NPC_S_KPU8_AH, - NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, - NPC_S_KPU9_TU_MPLS, - NPC_S_KPU9_TU_NSH, + NPC_S_KPU9_TU_MPLS_IN_GRE, + NPC_S_KPU9_TU_MPLS_IN_NSH, + NPC_S_KPU9_TU_MPLS_IN_IP, + NPC_S_KPU9_TU_MPLS_IN_UDP, + NPC_S_KPU9_TU_NSH_IN_GRE, + NPC_S_KPU9_VXLAN, + NPC_S_KPU9_VXLANGPE, + NPC_S_KPU9_GENEVE, + NPC_S_KPU9_GTPC, + NPC_S_KPU9_GTPU, + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, NPC_S_KPU10_TU_MPLS_PL, NPC_S_KPU10_TU_MPLS, - NPC_S_KPU10_TU_NSH, + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, NPC_S_KPU11_TU_ETHER, NPC_S_KPU11_TU_PPP, NPC_S_KPU11_TU_MPLS_IN_NSH, - NPC_S_KPU11_TU_3RD_NSH, + NPC_S_KPU11_TU_MPLS_PL, + NPC_S_KPU11_TU_MPLS, + NPC_S_KPU11_TU_ETHER_IN_NSH, NPC_S_KPU12_TU_IP, NPC_S_KPU12_TU_IP6, NPC_S_KPU12_TU_ARP, @@ -174,135 +229,172 @@ enum npc_kpu_parser_state { NPC_S_KPU16_PPTP_DATA, NPC_S_KPU16_TCP_DATA, NPC_S_KPU16_UDP_DATA, + NPC_S_KPU16_UDP_PTP, NPC_S_LAST /* has to be the last item */ }; -enum npc_kpu_parser_flag { - NPC_F_NA = 0, - NPC_F_PKI, - NPC_F_PKI_VLAN, - NPC_F_PKI_ETAG, - NPC_F_PKI_ITAG, - NPC_F_PKI_MPLS, - NPC_F_PKI_NSH, - NPC_F_ETYPE_UNK, - NPC_F_ETHER_VLAN, - NPC_F_ETHER_ETAG, - NPC_F_ETHER_ITAG, - NPC_F_ETHER_MPLS, - NPC_F_ETHER_NSH, - NPC_F_STAG_CTAG, - NPC_F_STAG_CTAG_UNK, - NPC_F_STAG_STAG_CTAG, - NPC_F_STAG_STAG_STAG, - NPC_F_QINQ_CTAG, - NPC_F_QINQ_CTAG_UNK, - NPC_F_QINQ_QINQ_CTAG, - NPC_F_QINQ_QINQ_QINQ, - NPC_F_BTAG_ITAG, - NPC_F_BTAG_ITAG_STAG, - NPC_F_BTAG_ITAG_CTAG, - NPC_F_BTAG_ITAG_UNK, - NPC_F_ETAG_CTAG, - NPC_F_ETAG_BTAG_ITAG, - NPC_F_ETAG_STAG, - NPC_F_ETAG_QINQ, - NPC_F_ETAG_ITAG, - NPC_F_ETAG_ITAG_STAG, - NPC_F_ETAG_ITAG_CTAG, - NPC_F_ETAG_ITAG_UNK, - NPC_F_ITAG_STAG_CTAG, - NPC_F_ITAG_STAG, - NPC_F_ITAG_CTAG, - NPC_F_MPLS_4_LABELS, - NPC_F_MPLS_3_LABELS, - NPC_F_MPLS_2_LABELS, - NPC_F_IP_HAS_OPTIONS, - NPC_F_IP_IP_IN_IP, - NPC_F_IP_6TO4, - NPC_F_IP_MPLS_IN_IP, - NPC_F_IP_UNK_PROTO, - NPC_F_IP_IP_IN_IP_HAS_OPTIONS, - NPC_F_IP_6TO4_HAS_OPTIONS, - NPC_F_IP_MPLS_IN_IP_HAS_OPTIONS, - NPC_F_IP_UNK_PROTO_HAS_OPTIONS, - NPC_F_IP6_HAS_EXT, - NPC_F_IP6_TUN_IP6, - NPC_F_IP6_MPLS_IN_IP, - NPC_F_TCP_HAS_OPTIONS, - NPC_F_TCP_HTTP, - NPC_F_TCP_HTTPS, - NPC_F_TCP_PPTP, - NPC_F_TCP_UNK_PORT, - NPC_F_TCP_HTTP_HAS_OPTIONS, - NPC_F_TCP_HTTPS_HAS_OPTIONS, - NPC_F_TCP_PPTP_HAS_OPTIONS, - NPC_F_TCP_UNK_PORT_HAS_OPTIONS, - NPC_F_UDP_VXLAN, - NPC_F_UDP_VXLAN_NOVNI, - NPC_F_UDP_VXLAN_NOVNI_NSH, - NPC_F_UDP_VXLANGPE, - NPC_F_UDP_VXLANGPE_NSH, - NPC_F_UDP_VXLANGPE_MPLS, - NPC_F_UDP_VXLANGPE_NOVNI, - NPC_F_UDP_VXLANGPE_NOVNI_NSH, - NPC_F_UDP_VXLANGPE_NOVNI_MPLS, - NPC_F_UDP_VXLANGPE_UNK, - NPC_F_UDP_VXLANGPE_NONP, - NPC_F_UDP_GTP_GTPC, - NPC_F_UDP_GTP_GTPU_G_PDU, - NPC_F_UDP_GTP_GTPU_UNK, - NPC_F_UDP_UNK_PORT, - NPC_F_UDP_GENEVE, - NPC_F_UDP_GENEVE_OAM, - NPC_F_UDP_GENEVE_CRI_OPT, - NPC_F_UDP_GENEVE_OAM_CRI_OPT, - NPC_F_GRE_NVGRE, - NPC_F_GRE_HAS_SRE, - NPC_F_GRE_HAS_CSUM, - NPC_F_GRE_HAS_KEY, - NPC_F_GRE_HAS_SEQ, - NPC_F_GRE_HAS_CSUM_KEY, - NPC_F_GRE_HAS_CSUM_SEQ, - NPC_F_GRE_HAS_KEY_SEQ, - NPC_F_GRE_HAS_CSUM_KEY_SEQ, - NPC_F_GRE_HAS_ROUTE, - NPC_F_GRE_UNK_PROTO, - NPC_F_GRE_VER1, - NPC_F_GRE_VER1_HAS_SEQ, - NPC_F_GRE_VER1_HAS_ACK, - NPC_F_GRE_VER1_HAS_SEQ_ACK, - NPC_F_GRE_VER1_UNK_PROTO, - NPC_F_TU_ETHER_UNK, - NPC_F_TU_ETHER_CTAG, - NPC_F_TU_ETHER_CTAG_UNK, - NPC_F_TU_ETHER_STAG_CTAG, - NPC_F_TU_ETHER_STAG_CTAG_UNK, - NPC_F_TU_ETHER_STAG, - NPC_F_TU_ETHER_STAG_UNK, - NPC_F_TU_ETHER_QINQ_CTAG, - NPC_F_TU_ETHER_QINQ_CTAG_UNK, - NPC_F_TU_ETHER_QINQ, - NPC_F_TU_ETHER_QINQ_UNK, - NPC_F_LAST /* has to be the last item */ +enum npc_kpu_la_uflag { + NPC_F_LA_U_HAS_TAG = 0x10, + NPC_F_LA_U_HAS_IH_NIX = 0x20, + NPC_F_LA_U_HAS_HIGIG2 = 0x40, +}; +enum npc_kpu_la_lflag { + NPC_F_LA_L_UNK_ETYPE = 1, + NPC_F_LA_L_WITH_VLAN, + NPC_F_LA_L_WITH_ETAG, + NPC_F_LA_L_WITH_ITAG, + NPC_F_LA_L_WITH_MPLS, + NPC_F_LA_L_WITH_NSH, +}; + +enum npc_kpu_lb_uflag { + NPC_F_LB_U_UNK_ETYPE = 0x80, + NPC_F_LB_U_MORE_TAG = 0x40, +}; +enum npc_kpu_lb_lflag { + NPC_F_LB_L_WITH_CTAG = 1, + NPC_F_LB_L_WITH_CTAG_UNK, + NPC_F_LB_L_WITH_STAG_CTAG, + NPC_F_LB_L_WITH_STAG_STAG, + NPC_F_LB_L_WITH_QINQ_CTAG, + NPC_F_LB_L_WITH_QINQ_QINQ, + NPC_F_LB_L_WITH_ITAG, + NPC_F_LB_L_WITH_ITAG_STAG, + NPC_F_LB_L_WITH_ITAG_CTAG, + NPC_F_LB_L_WITH_ITAG_UNK, + NPC_F_LB_L_WITH_BTAG_ITAG, + NPC_F_LB_L_WITH_STAG, + NPC_F_LB_L_WITH_QINQ, + NPC_F_LB_L_DSA, + NPC_F_LB_L_DSA_VLAN, + NPC_F_LB_L_EDSA, + NPC_F_LB_L_EDSA_VLAN, + NPC_F_LB_L_EXDSA, + NPC_F_LB_L_EXDSA_VLAN, +}; + +enum npc_kpu_lc_uflag { + NPC_F_LC_U_UNK_PROTO = 0x10, + NPC_F_LC_U_IP_FRAG = 0x20, + NPC_F_LC_U_IP6_FRAG = 0x40, +}; +enum npc_kpu_lc_lflag { + NPC_F_LC_L_IP_IN_IP = 1, + NPC_F_LC_L_6TO4, + NPC_F_LC_L_MPLS_IN_IP, + NPC_F_LC_L_IP6_TUN_IP6, + NPC_F_LC_L_IP6_MPLS_IN_IP, + NPC_F_LC_L_MPLS_4_LABELS, + NPC_F_LC_L_MPLS_3_LABELS, + NPC_F_LC_L_MPLS_2_LABELS, + NPC_F_LC_L_EXT_HOP, + NPC_F_LC_L_EXT_DEST, + NPC_F_LC_L_EXT_ROUT, + NPC_F_LC_L_EXT_MOBILITY, + NPC_F_LC_L_EXT_HOSTID, + NPC_F_LC_L_EXT_SHIM6, +}; + +enum npc_kpu_ld_lflag { + NPC_F_LD_L_TCP_UNK_PORT = 1, + NPC_F_LD_L_TCP_HAS_OPTIONS, + NPC_F_LD_L_TCP_UNK_PORT_HAS_OPTIONS, + NPC_F_LD_L_UDP_UNK_PORT, + NPC_F_LD_L_GRE_NVGRE, + NPC_F_LD_L_GRE_HAS_SRE, + NPC_F_LD_L_GRE_HAS_CSUM, + NPC_F_LD_L_GRE_HAS_KEY, + NPC_F_LD_L_GRE_HAS_SEQ, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + NPC_F_LD_L_GRE_HAS_ROUTE, + NPC_F_LD_L_GRE_UNK_PROTO, + NPC_F_LD_L_GRE_VER1, + NPC_F_LD_L_GRE_VER1_HAS_SEQ, + NPC_F_LD_L_GRE_VER1_HAS_ACK, + NPC_F_LD_L_GRE_VER1_HAS_SEQ_ACK, + NPC_F_LD_L_GRE_VER1_UNK_PROTO, + NPC_F_LD_L_MPLS_4_LABELS, + NPC_F_LD_L_MPLS_3_LABELS, + NPC_F_LD_L_MPLS_2_LABELS, +}; + +enum npc_kpu_le_lflag { + NPC_F_LE_L_VXLAN_NOVNI, + NPC_F_LE_L_VXLANGPE_NOVNI, + NPC_F_LE_L_VXLANGPE_UNK, + NPC_F_LE_L_VXLANGPE_NONP, + NPC_F_LE_L_GENEVE_OAM, + NPC_F_LE_L_GENEVE_CRI_OPT, + NPC_F_LE_L_GENEVE_OAM_CRI_OPT, + NPC_F_LE_L_GTPU_G_PDU, + NPC_F_LE_L_GTPU_UNK, +}; + +enum npc_kpu_lf_uflag { + NPC_F_LF_U_UNK_ETYPE = 0x10, + NPC_F_LF_U_HAS_TAG = 0x20, +}; + +enum npc_kpu_lf_lflag { + NPC_F_LF_L_WITH_CTAG = 1, + NPC_F_LF_L_WITH_STAG_CTAG, + NPC_F_LF_L_WITH_STAG, + NPC_F_LF_L_WITH_QINQ_CTAG, + NPC_F_LF_L_WITH_QINQ, +}; + +enum npc_kpu_lg_uflag { + NPC_F_LG_U_UNK_IP_PROTO = 0x10, + NPC_F_LG_U_IP_HAS_OPTIONS = 0x20, + NPC_F_LG_U_IP6_HAS_EXT = 0x40, +}; + +enum npc_kpu_lh_uflag { + NPC_F_LH_U_TCP_HAS_OPTIONS = 0x80, +}; + +enum npc_kpu_lh_lflag { + NPC_F_LH_L_TCP_HTTP = 1, + NPC_F_LH_L_TCP_HTTPS, + NPC_F_LH_L_TCP_PPTP, + NPC_F_LH_L_TCP_UNK_PORT, + NPC_F_LH_L_UDP_UNK_PORT, }; enum npc_kpu_err_code { NPC_EC_NOERR = 0, /* has to be zero */ NPC_EC_UNK, + NPC_EC_IH_LENGTH, + NPC_EC_EDSA_UNK, NPC_EC_L2_K1, NPC_EC_L2_K2, NPC_EC_L2_K3, NPC_EC_L2_K3_ETYPE_UNK, - NPC_EC_L2_MPLS_2MANY, NPC_EC_L2_K4, + NPC_EC_MPLS_2MANY, + NPC_EC_MPLS_UNK, + NPC_EC_NSH_UNK, + NPC_EC_IP_TTL_0, + NPC_EC_IP_FRAG_OFFSET_1, NPC_EC_IP_VER, + NPC_EC_IP6_HOP_0, NPC_EC_IP6_VER, + NPC_EC_TCP_FLAGS_FIN_ONLY, + NPC_EC_TCP_FLAGS_ZERO, + NPC_EC_TCP_FLAGS_RST_FIN, + NPC_EC_TCP_FLAGS_URG_SYN, + NPC_EC_TCP_FLAGS_RST_SYN, + NPC_EC_TCP_FLAGS_SYN_FIN, NPC_EC_VXLAN, NPC_EC_NVGRE, NPC_EC_GRE, NPC_EC_GRE_VER1, NPC_EC_L4, + NPC_EC_OIP4_CSUM, + NPC_EC_IIP4_CSUM, NPC_EC_LAST /* has to be the last item */ }; @@ -328,5282 +420,12598 @@ enum NPC_ERRLEV_E { static struct npc_kpu_profile_action ikpu_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_ETHER, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 36, 40, 44, 0, 0, + NPC_S_KPU1_IH_NIX_HIGIG2, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 28, 32, 36, 0, 0, + NPC_S_KPU1_HIGIG2, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU1_EXDSA, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 14, 16, - 0, 0, NPC_S_KPU1_ETHER, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 1, 0xff, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 20, 24, 28, 0, 0, + NPC_S_KPU1_IH_NIX, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, }; static struct npc_kpu_profile_cam kpu1_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_ETAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + NPC_ETYPE_DSA, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + 0x0000, + 0xfc00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + 0x0400, + 0xfe00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_ETHER, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_ETAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH, 0xff, + NPC_IH_W|NPC_IH_UTAG, + NPC_IH_W|NPC_IH_UTAG, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH, 0xff, + NPC_IH_W, + NPC_IH_W|NPC_IH_UTAG, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH, 0xff, + 0x0000, + NPC_IH_W|NPC_IH_UTAG, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_EXDSA, 0xff, + NPC_DSA_EXTEND, + NPC_DSA_EXTEND, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_EXDSA, 0xff, + 0x0000, + NPC_DSA_EXTEND, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_ETAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_HIGIG2, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_ETAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU1_IH_NIX_HIGIG2, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, +}; + +static struct npc_kpu_profile_cam kpu2_cam_entries[] = { + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_RARP, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_PTP, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_FCOE, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_MPLSU, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_MPLSM, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_NSH, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_SBTAG, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_CTAG, + 0xffff, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_SBTAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_QINQ, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_SBTAG, + 0xffff, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + NPC_ETYPE_CTAG, + 0xffff, + }, + { + NPC_S_KPU2_ETAG, 0xff, + NPC_ETYPE_ITAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ETAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_ITAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_CTAG2, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_PREHEADER, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_RARP, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_PTP, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_FCOE, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + NPC_ETYPE_CTAG, + 0xffff, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + NPC_DSA_EDSA, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_EXDSA, 0xff, + 0x0000, + NPC_DSA_EDSA, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu3_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_ITAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_CTAG_C, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_STAG_C, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_QINQ_C, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_RARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_PTP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_FCOE, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU3_DSA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu4_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU4_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU4_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_KPU4_NSH, 0xff, + NPC_NSH_NP_IP, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_NSH, 0xff, + NPC_NSH_NP_IP6, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_NSH, 0xff, + NPC_NSH_NP_ETH, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_NSH, 0xff, + NPC_NSH_NP_MPLS, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU4_NSH, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu5_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU5_IP, 0xff, + 0x0000, + NPC_IP_TTL_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0001, + NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_TCP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_UDP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_SCTP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_ICMP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IGMP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_ESP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_AH, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_GRE, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IP6, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_MPLS, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_TCP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_UDP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_SCTP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_ICMP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IGMP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_ESP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_AH, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_GRE, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_IP6, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + NPC_IPNH_MPLS, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + NPC_IP_HDR_MF|NPC_IP_HDR_FRAGOFF, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_ARP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_RARP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_PTP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_FCOE, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + 0x0000, + NPC_IP6_HOP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_HOP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_DEST << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_FRAG << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_MOBILITY << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_HOSTID << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_SHIM6 << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_IP6, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS_PL, 0xff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS_PL, 0xff, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS_PL, 0xff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_MPLS_PL, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu6_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU6_IP6_EXT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_FRAG << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_FRAG << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu7_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU7_IP6_EXT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_GRE << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_IP6 << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_MPLS << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu8_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN, + NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_HTTP, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_HTTPS, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_PPTP, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_HTTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_HTTPS, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + NPC_TCP_PORT_PPTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_TCP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_VXLAN, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_VXLANGPE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_GENEVE, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_GTPC, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_GTPU, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_PTP_E, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_PTP_G, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_MPLS, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_UDP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_SCTP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_ICMP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_IGMP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_ICMP6, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_ESP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_AH, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSU, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_MPLSM, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_NSH, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_IP6, + 0xffff, + NPC_GRE_F_CSUM|NPC_GRE_F_KEY|NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + 0x0000, + 0xffff, + NPC_GRE_F_ROUTE, + 0x4fff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + 0x0000, + 0xffff, + 0x0000, + 0x4fff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + 0x0000, + 0xffff, + 0x0000, + 0x0003, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_PPP, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_VER_1, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_PPP, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ|NPC_GRE_VER_1, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_PPP, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_ACK|NPC_GRE_VER_1, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_PPP, + 0xffff, + NPC_GRE_F_KEY|NPC_GRE_F_SEQ|NPC_GRE_F_ACK|NPC_GRE_VER_1, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + 0x0000, + 0xffff, + 0x2001, + 0xef7f, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + 0x0000, + 0xffff, + 0x0001, + 0x0003, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu9_cam_entries[] = { { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_TU_MPLS_IN_GRE, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_GRE, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_GRE, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_GRE, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_NSH, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_NSH, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_NSH, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_NSH, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_IP, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_IP, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_IP, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_IP, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_NSH_IN_GRE, 0xff, + NPC_NSH_NP_IP, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_NSH_IN_GRE, 0xff, + NPC_NSH_NP_IP6, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_NSH_IN_GRE, 0xff, + NPC_NSH_NP_ETH, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_NSH_IN_GRE, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_VXLAN, 0xff, + 0x0000, + 0x0000, + NPC_VXLAN_I, + NPC_VXLAN_I, + 0x0000, + 0xffff, + }, + { + NPC_S_KPU9_VXLAN, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0xffff, + 0x0000, + 0xffff, + }, + { + NPC_S_KPU9_VXLAN, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_IP, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_IP6, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ETAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_ETH, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_NSH, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_MPLS, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_IP, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_IP6, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, 0x0000, 0xfc00, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_ETH, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, 0x0400, 0xfe00, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_NSH, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_ETHER, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P | NPC_VXLANGPE_I, + NPC_VXLANGPE_NP_MPLS, + NPC_VXLANGPE_NP_MASK, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + NPC_VXLANGPE_P, + 0x0000, + 0x0000, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_VXLANGPE, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_VXLANGPE_P, + 0x0000, + 0x0000, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_TRANS_ETH_BR, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_QINQ, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ETAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP6, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0010, 0x0010, 0x0000, 0xffff, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP6, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0010, 0x0010, 0x0000, 0xffff, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP6, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GENEVE, 0xff, + 0x0000, + 0x0000, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, + NPC_ETYPE_IP6, + 0xffff, }, { - NPC_S_KPU1_PKI, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GTPC, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU9_GTPU, 0xff, + 0x0000, + 0x0000, + NPC_GTP_PT_GTP | NPC_GTP_VER1 | NPC_GTP_MT_G_PDU, + NPC_GTP_PT_MASK | NPC_GTP_VER_MASK | NPC_GTP_MT_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_GTPU, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_UDP, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_UDP, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_TU_MPLS_IN_UDP, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU9_TU_MPLS_IN_UDP, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, }; -static struct npc_kpu_profile_cam kpu2_cam_entries[] = { +static struct npc_kpu_profile_cam kpu10_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU10_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_PL, 0xff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_PL, 0xff, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_PL, 0xff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_PL, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 0xff, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_MPLS_S, + }, + { + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + 0x0000, + NPC_MPLS_S, + }, + { + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 0xff, + NPC_NSH_NP_IP, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 0xff, + NPC_NSH_NP_IP6, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 0xff, + NPC_NSH_NP_ETH, + NPC_NSH_NP_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu11_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_SBTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_IP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_IP6, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + NPC_ETYPE_ARP, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + NPC_ETYPE_QINQ, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_PPP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS, 0xff, + NPC_MPLS_S, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS, 0xff, + 0x0000, + NPC_MPLS_S, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS_PL, 0xff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS_PL, 0xff, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_MPLS_PL, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU11_TU_ETHER_IN_NSH, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu12_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_TCP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_UDP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_SCTP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_ICMP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_IGMP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_ESP, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_AH, + 0x00ff, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4|NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK|NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_TCP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_UDP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_SCTP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_ICMP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_IGMP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_ESP, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + NPC_IPNH_AH, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_ARP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_TCP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_UDP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_SCTP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_ICMP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_ICMP6 << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_ESP << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + NPC_IPNH_AH << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + 0x0000, + 0x0000, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU12_TU_IP6, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu13_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU13_TU_IP6_EXT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu14_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU14_TU_IP6_EXT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu15_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_FIN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN, + NPC_TCP_FLAGS_URG|NPC_TCP_FLAGS_SYN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN, + NPC_TCP_FLAGS_RST|NPC_TCP_FLAGS_SYN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN, + NPC_TCP_FLAGS_SYN|NPC_TCP_FLAGS_FIN, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_HTTP, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_HTTPS, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_PPTP, + 0xffff, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + NPC_TCP_DATA_OFFSET_5, + NPC_TCP_DATA_OFFSET_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_HTTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_HTTPS, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + NPC_TCP_PORT_PPTP, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_TCP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_UDP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_SCTP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_ICMP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_IGMP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_ICMP6, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_ESP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU15_TU_AH, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_NA, 0X00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_cam kpu16_cam_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_S_KPU16_TCP_DATA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU16_HTTP_DATA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU16_HTTPS_DATA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU16_PPTP_DATA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU16_UDP_DATA, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU16_UDP_PTP, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, }, +}; + +static struct npc_kpu_profile_action kpu1_action_entries[] = { { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU5_IP, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_CTAG, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU5_IP6, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_CTAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_ARP, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_RARP, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_PTP, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_FCOE, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 0, 0, 0, + NPC_S_KPU2_CTAG2, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_CTAG, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 22, 0, 0, + NPC_S_KPU2_SBTAG, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_QINQ, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 26, 0, 0, + NPC_S_KPU2_ETAG, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ETAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 18, 22, 26, 0, 0, + NPC_S_KPU2_ITAG, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_SBTAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU4_NSH, 14, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_L_WITH_NSH, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_IP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 0, 1, 0, + NPC_S_KPU3_DSA, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_IP6, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_8023, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_ARP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_8023, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_RARP, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_PTP, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_FCOE, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_MPLSU, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_MPLSM, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_NSH, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_SBTAG, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_CTAG, 0xffff, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_SBTAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_L_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU5_IP, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU5_IP6, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_ARP, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_RARP, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_PTP, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_FCOE, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_QINQ, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 0, 0, 0, + NPC_S_KPU2_CTAG2, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_CTAG, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 22, 0, 0, + NPC_S_KPU2_SBTAG, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_QINQ, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 26, 0, 0, + NPC_S_KPU2_ETAG, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_ETAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 18, 22, 26, 0, 0, + NPC_S_KPU2_ITAG, 20, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU4_NSH, 22, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_L_WITH_NSH, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_L_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU2_QINQ, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 14, 16, 0, 0, + NPC_S_KPU2_PREHEADER, 8, 1, + NPC_LID_LA, NPC_LT_LA_IH_8_ETHER, + 0, + 1, 0xff, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 14, 16, 0, 0, + NPC_S_KPU2_PREHEADER, 4, 1, + NPC_LID_LA, NPC_LT_LA_IH_4_ETHER, + 0, + 1, 0xff, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 14, 16, 0, 0, + NPC_S_KPU2_PREHEADER, 2, 1, + NPC_LID_LA, NPC_LT_LA_IH_2_ETHER, + 0, + 1, 0xff, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_LA, NPC_EC_IH_LENGTH, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + NPC_F_LA_L_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 16, 0, 0, + NPC_S_KPU2_EXDSA, 12, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_LA, NPC_EC_EDSA_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU5_IP, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU5_IP6, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_ARP, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_RARP, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_PTP, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_ITAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_FCOE, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 0, 0, 0, + NPC_S_KPU2_CTAG2, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_QINQ, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_CTAG, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_IP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 22, 0, 0, + NPC_S_KPU2_SBTAG, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_IP6, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_QINQ, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_ARP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 26, 0, 0, + NPC_S_KPU2_ETAG, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_ETAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_SBTAG, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 18, 22, 26, 0, 0, + NPC_S_KPU2_ITAG, 28, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_U_HAS_TAG + | NPC_F_LA_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, NPC_ETYPE_CTAG, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, NPC_ETYPE_ITAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ETAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU4_NSH, 30, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_L_WITH_NSH, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, + NPC_F_LA_U_HAS_HIGIG2 | NPC_F_LA_L_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU5_IP, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU5_IP6, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_ARP, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_RARP, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_PTP, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 3, 0, + NPC_S_KPU5_FCOE, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 0, 0, 0, + NPC_S_KPU2_CTAG2, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_CTAG, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 22, 0, 0, + NPC_S_KPU2_SBTAG, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU2_QINQ, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 12, 26, 0, 0, + NPC_S_KPU2_ETAG, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ETAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 18, 22, 26, 0, 0, + NPC_S_KPU2_ITAG, 36, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_U_HAS_TAG | NPC_F_LA_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU4_MPLS, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_L_WITH_MPLS, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU4_NSH, 38, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_L_WITH_NSH, + 0, 0, 0, 0, }, { - NPC_S_KPU2_ITAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, + NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2 + | NPC_F_LA_L_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_LA, NPC_EC_L2_K1, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LA, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; -static struct npc_kpu_profile_cam kpu3_cam_entries[] = { - { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, +static struct npc_kpu_profile_action kpu2_action_entries[] = { { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_CTAG, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_CTAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 6, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_F_LB_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG_UNK, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_CTAG, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_STAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_STAG, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_RARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_PTP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_FCOE, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSU, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_MPLSM, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_NSH, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU3_STAG, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU3_CTAG, 24, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_BTAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_UNK, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_PTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_FCOE, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_QINQ, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_RARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG_UNK, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_CTAG, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_QINQ_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_QINQ, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_QINQ_QINQ, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 1, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 2, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_NSH, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + 2, + 0, 0, 0, 0, }, { - NPC_S_KPU3_ITAG, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU3_CTAG, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 16, 20, 24, 0, 0, + NPC_S_KPU3_ITAG, 14, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_BTAG_ITAG, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_cam kpu4_cam_entries[] = { { - NPC_S_KPU4_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_STAG, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S, - NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_QINQ, 10, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_QINQ, + 0, 0, 0, 0, }, { - NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 28, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 28, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 28, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU3_STAG, 28, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU3_CTAG, 28, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_ITAG_UNK, + 0, 0, 0, 0, }, { - NPC_S_KPU4_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_ETAG, + NPC_F_LB_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 20, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_cam kpu5_cam_entries[] = { { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_TCP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 20, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_UDP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 20, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_SCTP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 20, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_ICMP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 28, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IGMP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 28, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_ESP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 28, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_AH, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_GRE, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP6, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_STAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_MPLS, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, 0x0000, 0x0000, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_TCP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_UDP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 24, 1, + NPC_LID_LB, NPC_LT_LB_ITAG, + NPC_F_LB_U_MORE_TAG|NPC_F_LB_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_SCTP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_ICMP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IGMP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_ESP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_AH, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_GRE, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_IP6, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, NPC_IPNH_MPLS, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, 0x0000, 0x0000, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_ARP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_QINQ, 10, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_QINQ_QINQ, + 0, 0, 0, 0, }, { - NPC_S_KPU5_RARP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + NPC_F_LB_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_S_KPU5_PTP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_FCOE, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_TCP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_UDP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_SCTP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ICMP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ICMP6 << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_CTAG_C, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_ESP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 20, 0, 0, + NPC_S_KPU3_STAG_C, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_AH << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 0, 0, 0, + NPC_S_KPU3_QINQ_C, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_GRE << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_IP6 << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU4_MPLS, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, NPC_IPNH_MPLS << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 1, 0, + NPC_S_KPU4_NSH, 14, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, 0x0000, 0x0000, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_IP6, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_RARP, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0xffff, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 18, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU3_CTAG, 16, 1, + NPC_LID_LB, NPC_LT_LB_EDSA_VLAN, + NPC_F_LB_L_EDSA_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS_PL, 0xff, NPC_IP_VER_4, NPC_IP_VER_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_EDSA, + NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_EDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS_PL, 0xff, NPC_IP_VER_6, NPC_IP_VER_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS_PL, 0xff, 0x0000, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_MPLS_PL, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 8, 0, 0, 0, + NPC_S_KPU3_CTAG, 8, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA_VLAN, + NPC_F_LB_L_EXDSA_VLAN, + 0, 0, 0, 0, }, { - NPC_S_KPU5_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_EXDSA, + NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_EXDSA, + 0, 0, 0, 0, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; -static struct npc_kpu_profile_cam kpu6_cam_entries[] = { +static struct npc_kpu_profile_action kpu3_action_entries[] = { { - NPC_S_KPU6_IP6_EXT, 0xff, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_cam kpu7_cam_entries[] = { { - NPC_S_KPU7_IP6_EXT, 0xff, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_cam kpu8_cam_entries[] = { { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU8_TCP, 0xff, 0x0000, 0x0000, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_TCP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff, - NPC_VXLAN_I, NPC_VXLAN_I, 0x0000, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff, - 0x0000, 0xffff, 0x0000, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLAN, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_IP, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_IP6, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_ETH, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_NSH, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_MPLS, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_IP, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_IP6, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_ETH, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_NSH, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P | NPC_VXLANGPE_I, - NPC_VXLANGPE_NP_MPLS, NPC_VXLANGPE_NP_MASK, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - NPC_VXLANGPE_P, NPC_VXLANGPE_P, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_VXLANGPE, 0xffff, - 0x0000, NPC_VXLANGPE_P, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_TRANS_ETH_BR, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_TRANS_ETH_BR, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_CRI_OPT, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_TRANS_ETH_BR, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_TRANS_ETH_BR, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_CRI_OPT, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - 0x0000, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM, NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_CRI_OPT, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GENEVE, 0xffff, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, - NPC_GENEVE_F_OAM | NPC_GENEVE_F_CRI_OPT, NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPC, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPU, 0xffff, - NPC_GTP_PT_GTP | NPC_GTP_VER1 | NPC_GTP_MT_G_PDU, - NPC_GTP_PT_MASK | NPC_GTP_VER_MASK | NPC_GTP_MT_MASK, - 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, NPC_UDP_PORT_GTPU, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_UDP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_SCTP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_ICMP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_IGMP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_ICMP6, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_ESP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_AH, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_TRANS_ETH_BR, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_TRANS_ETH_BR, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSU, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_MPLSM, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_NSH, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_CSUM, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_IP6, 0xffff, - NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, - NPC_GRE_F_ROUTE, 0x4fff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, - 0x0000, 0x4fff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, - 0x0000, 0x0003, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_VER_1, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_VER_1, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_ACK | NPC_GRE_VER_1, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, NPC_ETYPE_PPP, 0xffff, - NPC_GRE_F_KEY | NPC_GRE_F_SEQ | NPC_GRE_F_ACK | NPC_GRE_VER_1, - 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, - 0x2001, 0xef7f, 0x0000, 0x0000, - }, - { - NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, - 0x0001, 0x0003, 0x0000, 0x0000, - }, - { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu9_cam_entries[] = { - { - NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S, - NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S, - }, - { - NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S, - }, - { - NPC_S_KPU9_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S, - NPC_MPLS_S, NPC_MPLS_S, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, NPC_MPLS_S, NPC_MPLS_S, - }, - { - NPC_S_KPU9_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, NPC_MPLS_S, 0x0000, NPC_MPLS_S, - }, - { - NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU9_TU_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu10_cam_entries[] = { - { - NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS, 0xff, NPC_MPLS_S, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS, 0xff, 0x0000, NPC_MPLS_S, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS_PL, 0xff, NPC_IP_VER_4, NPC_IP_VER_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS_PL, 0xff, NPC_IP_VER_6, NPC_IP_VER_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS_PL, 0xff, 0x0000, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_MPLS_PL, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_IP, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_IP6, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_ETH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_NSH, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU10_TU_NSH, 0xff, NPC_NSH_NP_MPLS, NPC_NSH_NP_MASK, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu11_cam_entries[] = { - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_IP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_IP6, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_ARP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_CTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_SBTAG, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_IP6, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_CTAG, 0xffff, NPC_ETYPE_ARP, 0xffff, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_CTAG, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_IP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_IP6, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - NPC_ETYPE_ARP, 0xffff, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, NPC_ETYPE_QINQ, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_ETHER, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_PPP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_MPLS_IN_NSH, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU11_TU_3RD_NSH, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu12_cam_entries[] = { - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_TCP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_UDP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_SCTP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ICMP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_IGMP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ESP, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_AH, 0x00ff, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, 0x0000, 0x0000, - NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, - NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_TCP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_UDP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_SCTP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ICMP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_IGMP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_ESP, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, NPC_IPNH_AH, 0x00ff, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, 0x0000, 0x0000, - NPC_IP_VER_4, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_ARP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_TCP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_UDP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_SCTP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ICMP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ICMP6 << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_ESP << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, NPC_IPNH_AH << 8, 0xff00, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, 0x0000, 0x0000, - NPC_IP_VER_6, NPC_IP_VER_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU12_TU_IP6, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu13_cam_entries[] = { - { - NPC_S_KPU13_TU_IP6_EXT, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu14_cam_entries[] = { - { - NPC_S_KPU14_TU_IP6_EXT, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - }, -}; - -static struct npc_kpu_profile_cam kpu15_cam_entries[] = { - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, 0x0000, 0x0000, - NPC_TCP_DATA_OFFSET_5, NPC_TCP_DATA_OFFSET_MASK, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_HTTPS, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, NPC_TCP_PORT_PPTP, 0xffff, - 0x0000, 0x0000, 0x0000, 0x0000, - }, - { - NPC_S_KPU15_TU_TCP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_UDP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_SCTP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_ICMP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_IGMP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_ICMP6, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_ESP, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU15_TU_AH, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_NA, 0X00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_cam kpu16_cam_entries[] = { { - NPC_S_KPU16_TCP_DATA, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU16_HTTP_DATA, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU16_HTTPS_DATA, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU16_PPTP_DATA, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_S_KPU16_UDP_DATA, 0xff, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu1_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU5_IP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU5_IP6, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_ARP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_RARP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_PTP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_FCOE, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU2_CTAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 20, - 0, 0, NPC_S_KPU2_SBTAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU2_QINQ, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 10, 24, - 0, 0, NPC_S_KPU2_ETAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_ETAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24, - 0, 0, NPC_S_KPU2_ITAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 2, 0, NPC_S_KPU4_MPLS, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 2, 0, NPC_S_KPU4_MPLS, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU4_NSH, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETHER_NSH, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LA, NPC_LT_LA_8023, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LA, NPC_LT_LA_8023, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU5_IP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU5_IP6, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_ARP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_RARP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_PTP, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU5_FCOE, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU2_CTAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 20, - 0, 0, NPC_S_KPU2_SBTAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU2_QINQ, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_VLAN, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 10, 24, - 0, 0, NPC_S_KPU2_ETAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_ETAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU5_IP, 18, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24, - 0, 0, NPC_S_KPU2_ITAG, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU5_IP6, 18, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 2, 0, NPC_S_KPU4_MPLS, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_ARP, 18, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 2, 0, NPC_S_KPU4_MPLS, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU5_RARP, 18, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 2, 0, NPC_S_KPU4_NSH, 14, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_PKI_NSH, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 26, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LA, NPC_LT_LA_ETHER, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 26, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LA, NPC_EC_L2_K1, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LA, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 26, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu2_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 22, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_CTAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_CTAG, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_STAG, 8, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_STAG_STAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU3_STAG, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU3_CTAG, 22, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_BTAG_ITAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 4, 1, - NPC_LID_LB, NPC_LT_LB_STAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_STAG, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 8, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_CTAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU4_MPLS, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_CTAG, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU4_NSH, 4, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_QINQ, 8, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_QINQ_QINQ_QINQ, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_STAG_QINQ, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 10, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU5_IP, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU5_IP6, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 1, 0, NPC_S_KPU4_NSH, 4, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_ARP, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_QINQ, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_RARP, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_PTP, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU5_FCOE, 14, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_DSA_VLAN, + NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_DSA, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LB, NPC_LT_LB_DSA, + NPC_F_LB_U_UNK_ETYPE | NPC_F_LB_L_DSA_VLAN, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_PTP, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K3, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu4_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_FCOE, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU5_MPLS_PL, 4, 1, + NPC_LID_LC, NPC_LT_LC_MPLS, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 1, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU5_MPLS_PL, 8, 1, + NPC_LID_LC, NPC_LT_LC_MPLS, + NPC_F_LC_L_MPLS_2_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_MPLS, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 2, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU5_MPLS_PL, 12, 1, + NPC_LID_LC, NPC_LT_LC_MPLS, + NPC_F_LC_L_MPLS_3_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 1, 0, NPC_S_KPU4_NSH, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, 2, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU5_MPLS, 12, 1, + NPC_LID_LC, NPC_LT_LC_MPLS, + NPC_F_LC_L_MPLS_4_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU3_CTAG, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 7, 0, + NPC_S_KPU12_TU_IP, 0, 1, + NPC_LID_LC, NPC_LT_LC_NSH, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 16, 20, 24, - 0, 0, NPC_S_KPU3_ITAG, 12, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_BTAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 7, 0, + NPC_S_KPU12_TU_IP6, 0, 1, + NPC_LID_LC, NPC_LT_LC_NSH, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_STAG, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 6, 0, + NPC_S_KPU11_TU_ETHER, 0, 1, + NPC_LID_LC, NPC_LT_LC_NSH, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 0, - 0, 0, NPC_S_KPU3_QINQ, 8, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_QINQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 4, 0, + NPC_S_KPU9_TU_MPLS_IN_NSH, 0, 1, + NPC_LID_LC, NPC_LT_LC_NSH, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 26, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_NSH_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_NSH, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 26, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_L2_K4, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu5_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 26, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_IP_TTL_0, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU3_STAG, 26, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_IP_FRAG_OFFSET_1, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_U_IP_FRAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU3_CTAG, 26, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU8_TCP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETAG_ITAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU8_UDP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_ETYPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_SCTP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 18, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ICMP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 18, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_IGMP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 18, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ESP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 18, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_AH, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 26, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU8_GRE, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 26, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 6, 0, + NPC_S_KPU12_TU_IP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_L_IP_IN_IP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 26, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 6, 0, + NPC_S_KPU12_TU_IP6, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_L_6TO4, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 3, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_L_MPLS_IN_IP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_U_UNK_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP, + NPC_F_LC_U_IP_FRAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU8_TCP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 2, 0, + NPC_S_KPU8_UDP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_SCTP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ICMP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 22, 1, - NPC_LID_LB, NPC_LT_LB_ITAG, NPC_F_ITAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_IGMP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ESP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_AH, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU8_GRE, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, }, -}; - -static struct npc_kpu_profile_action kpu3_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 6, 0, + NPC_S_KPU12_TU_IP, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + NPC_F_LC_L_IP_IN_IP, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 6, 0, + NPC_S_KPU12_TU_IP6, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + NPC_F_LC_L_6TO4, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 3, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + NPC_F_LC_L_MPLS_IN_IP, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_RARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + NPC_F_LC_U_UNK_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_PTP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + NPC_F_LC_U_IP_FRAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_FCOE, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_IP_VER, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_ARP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_RARP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU4_NSH, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_PTP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_FCOE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_IP6_HOP_0, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU8_TCP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU8_UDP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_RARP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_SCTP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_PTP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ICMP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_FCOE, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ICMP6, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_GRE, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 6, 0, + NPC_S_KPU12_TU_IP6, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + NPC_F_LC_L_IP6_TUN_IP6, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU4_NSH, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 3, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + NPC_F_LC_L_IP6_MPLS_IN_IP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_HOP_DEST, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_HOP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_HOP_DEST, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_DEST, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_ROUT, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_ROUT, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_RARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 2, 0, 0, 0, + NPC_S_KPU6_IP6_FRAG, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_U_IP6_FRAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_ESP, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_AH, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU4_NSH, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_MOBILITY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_HOSTID, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_EXT_SHIM6, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + NPC_F_LC_U_UNK_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_IP6_VER, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_RARP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 6, 0, + NPC_S_KPU12_TU_IP, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_PTP, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 6, 0, + NPC_S_KPU12_TU_IP6, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_FCOE, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 5, 0, + NPC_S_KPU11_TU_ETHER, 8, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 5, 0, + NPC_S_KPU11_TU_ETHER, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LB, NPC_EC_MPLS_2MANY, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU4_NSH, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 6, 0, + NPC_S_KPU12_TU_IP, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 6, 0, + NPC_S_KPU12_TU_IP6, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 5, 0, + NPC_S_KPU11_TU_ETHER, 4, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 5, 0, + NPC_S_KPU11_TU_ETHER, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_RARP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu6_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_PTP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_FCOE, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 1, 0, + NPC_S_KPU8_TCP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 1, 0, + NPC_S_KPU8_UDP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU4_MPLS, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_SCTP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU4_NSH, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU5_IP, 18, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ESP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU5_IP6, 18, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_AH, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_ARP, 18, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_GRE, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU5_RARP, 18, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 5, 0, + NPC_S_KPU12_TU_IP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 26, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 26, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 26, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 1, 0, + NPC_S_KPU8_TCP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 1, 0, + NPC_S_KPU8_UDP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_SCTP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ESP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU5_IP, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_AH, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU5_IP6, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_GRE, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU5_ARP, 22, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 5, 0, + NPC_S_KPU12_TU_IP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU7_IP6_ROUT, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K3, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 2, 0, 0, 0, + NPC_S_KPU7_IP6_FRAG, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, -}; - -static struct npc_kpu_profile_action kpu4_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU5_MPLS_PL, 4, 1, - NPC_LID_LC, NPC_LT_LC_MPLS, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU5_MPLS_PL, 8, 1, - NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_2_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 1, 0, + NPC_S_KPU8_TCP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU5_MPLS_PL, 12, 1, - NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_3_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 1, 0, + NPC_S_KPU8_UDP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0, - 0, 0, NPC_S_KPU5_MPLS, 12, 1, - NPC_LID_LC, NPC_LT_LC_MPLS, NPC_F_MPLS_4_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_SCTP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 7, 0, NPC_S_KPU12_TU_IP, 0, 1, - NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 7, 0, NPC_S_KPU12_TU_IP6, 0, 1, - NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ICMP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 6, 0, NPC_S_KPU11_TU_ETHER, 0, 1, - NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_ESP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU5_NSH, 0, 1, - NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_AH, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 4, 0, NPC_S_KPU9_TU_MPLS, 0, 1, - NPC_LID_LC, NPC_LT_LC_NSH, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_GRE, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_LB, NPC_EC_L2_K4, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 5, 0, + NPC_S_KPU12_TU_IP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, -}; - -static struct npc_kpu_profile_action kpu5_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU8_TCP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 2, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 8, 10, - 2, 0, NPC_S_KPU8_UDP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 2, 0, 0, 0, + NPC_S_KPU7_IP6_FRAG, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_SCTP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_ICMP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu7_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_IGMP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU8_ESP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 0, 0, + NPC_S_KPU8_TCP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU8_AH, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 0, 0, + NPC_S_KPU8_UDP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU8_GRE, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_SCTP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_IP_IN_IP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ICMP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_6TO4, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ICMP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 3, 0, NPC_S_KPU9_TU_MPLS, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_MPLS_IN_IP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ESP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_UNK_PROTO, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_AH, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU8_TCP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_GRE, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 8, 10, - 2, 0, NPC_S_KPU8_UDP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 4, 0, + NPC_S_KPU12_TU_IP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_SCTP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_ICMP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_IGMP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 0, 0, + NPC_S_KPU8_TCP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU8_ESP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 8, 10, 0, 0, + NPC_S_KPU8_UDP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU8_AH, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_SCTP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU8_GRE, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ICMP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_IP_IN_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ICMP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_6TO4_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_ESP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 3, 0, NPC_S_KPU9_TU_MPLS, 20, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_MPLS_IN_IP_HAS_OPTIONS, - 0, 0xf, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_AH, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, NPC_F_IP_UNK_PROTO_HAS_OPTIONS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_GRE, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LC, NPC_EC_IP_VER, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 4, 0, + NPC_S_KPU12_TU_IP6, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_ARP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 1, 0, + NPC_S_KPU9_TU_MPLS_IN_IP, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_RARP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_PTP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LC, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu8_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_FCOE, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_FIN_ONLY, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU8_TCP, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_ZERO, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 8, 10, - 2, 0, NPC_S_KPU8_UDP, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_RST_FIN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_SCTP, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_URG_SYN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_ICMP, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_RST_SYN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_ICMP6, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_TCP_FLAGS_SYN_FIN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_ESP, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_HTTP_DATA, 20, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_AH, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_HTTPS_DATA, 20, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU8_GRE, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_PPTP_DATA, 20, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, NPC_F_IP6_TUN_IP6, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_TCP_DATA, 20, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + NPC_F_LD_L_TCP_UNK_PORT, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 3, 0, NPC_S_KPU9_TU_MPLS, 40, 1, - NPC_LID_LC, NPC_LT_LC_IP6, NPC_F_IP6_MPLS_IN_IP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_HTTP_DATA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + NPC_F_LD_L_TCP_HAS_OPTIONS, + 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU6_IP6_EXT, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP6, NPC_F_IP6_HAS_EXT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_HTTPS_DATA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + NPC_F_LD_L_TCP_HAS_OPTIONS, + 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_LC, NPC_EC_IP6_VER, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LC, NPC_LT_LC_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_PPTP_DATA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + NPC_F_LD_L_TCP_HAS_OPTIONS, + 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_TCP_DATA, 0, 1, + NPC_LID_LD, NPC_LT_LD_TCP, + NPC_F_LD_L_TCP_UNK_PORT_HAS_OPTIONS, + 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 2, 0, 0, + NPC_S_KPU9_VXLAN, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 5, 0, NPC_S_KPU11_TU_ETHER, 8, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 2, 0, 0, + NPC_S_KPU9_VXLANGPE, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 5, 0, NPC_S_KPU11_TU_ETHER, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 2, 0, 0, + NPC_S_KPU9_GENEVE, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_MPLS_2MANY, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 2, 0, 0, + NPC_S_KPU9_GTPC, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 2, 0, 0, + NPC_S_KPU9_GTPU, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_KPU16_UDP_PTP, 0, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 5, 0, NPC_S_KPU11_TU_ETHER, 4, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_KPU16_UDP_PTP, 0, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 5, 0, NPC_S_KPU11_TU_ETHER, 0, 0, - NPC_LID_LB, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_UDP, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 7, 0, + NPC_S_KPU16_UDP_DATA, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 6, 0, NPC_S_KPU12_TU_IP6, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_SCTP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 5, 0, NPC_S_KPU11_TU_ETHER, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_ICMP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 5, 0, NPC_S_KPU11_TU_3RD_NSH, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_IGMP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 3, 0, NPC_S_KPU9_TU_MPLS, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_ICMP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LC, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_ESP, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu6_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_AH, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu7_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LD, NPC_LT_LD_NVGRE, + NPC_F_LD_L_GRE_NVGRE, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu8_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_HTTP_DATA, 20, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTP, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_NVGRE, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LD, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_HTTPS_DATA, 20, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTPS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 4, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_PPTP_DATA, 20, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_PPTP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_TCP_DATA, 20, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_UNK_PORT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_HTTP_DATA, 0, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTP_HAS_OPTIONS, - 12, 0xf0, 1, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_HTTPS_DATA, 0, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_HTTPS_HAS_OPTIONS, - 12, 0xf0, 1, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_PPTP_DATA, 0, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_PPTP_HAS_OPTIONS, - 12, 0xf0, 1, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_TCP_DATA, 0, 1, - NPC_LID_LD, NPC_LT_LD_TCP, NPC_F_TCP_UNK_PORT_HAS_OPTIONS, - 12, 0xf0, 1, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLAN, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLAN_NOVNI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 4, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LD, NPC_EC_VXLAN, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NSH, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU9_TU_MPLS_IN_GRE, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 4, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI_NSH, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NOVNI_MPLS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_VXLANGPE_NONP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU9_TU_NSH_IN_GRE, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 4, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM, 8, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 3, 0, + NPC_S_KPU12_TU_IP, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_CRI_OPT, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 4, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GENEVE_OAM_CRI_OPT, - 8, 0x3f, 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPC, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPU_G_PDU, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_GTP_GTPU_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 7, 0, NPC_S_KPU16_UDP_DATA, 8, 1, - NPC_LID_LD, NPC_LT_LD_UDP, NPC_F_UDP_UNK_PORT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_SCTP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_ICMP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 3, 0, + NPC_S_KPU12_TU_IP6, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_IGMP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_ROUTE, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_ICMP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_UNK_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_ESP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_GRE, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LD, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_AH, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU11_TU_PPP, 8, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_VER1, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 2, 0, NPC_S_KPU11_TU_ETHER, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_NVGRE, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU11_TU_PPP, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_VER1_HAS_SEQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LD, NPC_EC_NVGRE, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU11_TU_PPP, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_VER1_HAS_ACK, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 4, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU11_TU_PPP, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_VER1_HAS_SEQ_ACK, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_VER1_UNK_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_GRE_VER1, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LD, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_LD, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LD, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu9_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 4, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 8, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 12, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY_SEQ, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU10_TU_MPLS, 12, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_GRE, + 0, 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 4, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 4, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_NSH, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 8, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_NSH, + NPC_F_LD_L_MPLS_2_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 12, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_NSH, + NPC_F_LD_L_MPLS_3_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU10_TU_MPLS, 12, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_NSH, + NPC_F_LD_L_MPLS_4_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 4, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 8, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_IP, + NPC_F_LD_L_MPLS_2_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 12, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_IP, + NPC_F_LD_L_MPLS_3_LABELS, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, - 0, 0, NPC_S_KPU9_TU_MPLS_IN_GRE_VXLAN, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE_MPLS, NPC_F_GRE_HAS_CSUM_KEY_SEQ, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU10_TU_MPLS, 12, 1, + NPC_LID_LD, NPC_LT_LD_TU_MPLS_IN_IP, + NPC_F_LD_L_MPLS_4_LABELS, 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 4, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 0, 1, + NPC_LID_LE, NPC_LT_LE_TU_NSH_IN_GRE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 0, 1, + NPC_LID_LE, NPC_LT_LE_TU_NSH_IN_GRE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 0, 1, + NPC_LID_LE, NPC_LT_LE_TU_NSH_IN_GRE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_LE, NPC_EC_NSH_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LE, NPC_LT_LE_TU_NSH_IN_GRE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLAN, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLAN, + NPC_F_LE_L_VXLAN_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_LE, NPC_EC_VXLAN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU9_TU_NSH, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE_NSH, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 4, 1, - NPC_LID_LD, NPC_LT_LD_GRE, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU10_TU_NSH_IN_VXLANGPE, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 4, 1, - NPC_LID_LD, NPC_LT_LD_GRE, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 6, 10, 0, 0, + NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, 8, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NOVNI, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_UNK, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LE, NPC_LT_LE_VXLANGPE, + NPC_F_LE_L_VXLANGPE_NONP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + 0, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 1, 0, + NPC_S_KPU11_TU_ETHER, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 3, 0, NPC_S_KPU12_TU_IP6, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_CSUM_KEY_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + 0, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_HAS_ROUTE, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_UNK_PROTO, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_LD, NPC_EC_GRE, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU11_TU_PPP, 8, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + 0, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU11_TU_PPP, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_SEQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU11_TU_PPP, 12, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_ACK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU11_TU_PPP, 16, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_HAS_SEQ_ACK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 8, 1, + NPC_LID_LE, NPC_LT_LE_GENEVE, + NPC_F_LE_L_GENEVE_OAM_CRI_OPT, + 0, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LD, NPC_LT_LD_GRE, NPC_F_GRE_VER1_UNK_PROTO, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LE, NPC_LT_LE_GTPC, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LD, NPC_EC_GRE_VER1, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 8, 1, + NPC_LID_LE, NPC_LT_LE_GTPU, + NPC_F_LE_L_GTPU_G_PDU, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LD, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LE, NPC_LT_LE_GTPU, + NPC_F_LE_L_GTPU_UNK, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu9_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 4, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 4, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 8, 0, - NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_2_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 8, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 12, 0, - NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_3_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU10_TU_MPLS_PL, 12, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0, - 0, 0, NPC_S_KPU10_TU_MPLS, 12, 0, - NPC_LID_LD, NPC_LT_NA, NPC_F_MPLS_4_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU10_TU_MPLS, 12, 1, + NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_UDP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 4, 1, - NPC_LID_LD, NPC_LT_LD_TU_MPLS, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LE, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu10_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 8, 1, - NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_2_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU12_TU_IP, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU10_TU_MPLS_PL, 12, 1, - NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_3_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU12_TU_IP6, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 4, 0, - 0, 0, NPC_S_KPU10_TU_MPLS, 12, 1, - NPC_LID_LD, NPC_LT_LD_TU_MPLS, NPC_F_MPLS_4_LABELS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU11_TU_ETHER, 8, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 2, 0, NPC_S_KPU12_TU_IP, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU11_TU_ETHER, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 2, 0, NPC_S_KPU12_TU_IP6, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_LE, NPC_EC_MPLS_2MANY, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 1, 0, NPC_S_KPU11_TU_ETHER, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU12_TU_IP, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU10_TU_NSH, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU12_TU_IP6, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 1, 0, NPC_S_KPU11_TU_MPLS_IN_NSH, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU11_TU_ETHER, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 0, 0, + NPC_S_KPU11_TU_ETHER, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu10_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP, 4, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU11_TU_MPLS_PL, 4, 1, + NPC_LID_LF, NPC_LT_LF_TU_MPLS_IN_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP6, 4, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU11_TU_MPLS_PL, 8, 1, + NPC_LID_LF, NPC_LT_LF_TU_MPLS_IN_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 0, 0, NPC_S_KPU11_TU_ETHER, 8, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU11_TU_MPLS_PL, 12, 1, + NPC_LID_LF, NPC_LT_LF_TU_MPLS_IN_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 0, 0, NPC_S_KPU11_TU_ETHER, 4, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 4, 0, 0, 0, + NPC_S_KPU11_TU_MPLS, 12, 1, + NPC_LID_LF, NPC_LT_LF_TU_MPLS_IN_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LB, NPC_EC_L2_MPLS_2MANY, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 1, 0, + NPC_S_KPU12_TU_IP, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_NSH_IN_VXLANGPE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 1, 0, + NPC_S_KPU12_TU_IP6, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_NSH_IN_VXLANGPE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP6, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU11_TU_ETHER_IN_NSH, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_NSH_IN_VXLANGPE, + 0, + 1, 0x3f, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 0, 0, NPC_S_KPU11_TU_ETHER, 4, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_NSH_UNK, + 6, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_NSH_IN_VXLANGPE, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 0, 0, NPC_S_KPU11_TU_ETHER, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LE, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, +}; + +static struct npc_kpu_profile_action kpu11_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 14, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 1, 0, NPC_S_KPU12_TU_IP6, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 14, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, - 0, 0, NPC_S_KPU11_TU_ETHER, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 14, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU11_TU_3RD_NSH, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU11_TU_MPLS_IN_NSH, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 1, 0x3f, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LD, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, -}; - -static struct npc_kpu_profile_action kpu11_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 14, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE | NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 14, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 14, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE | NPC_F_LF_L_WITH_STAG_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_CTAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE | NPC_F_LF_L_WITH_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, - NPC_F_TU_ETHER_STAG_CTAG_UNK, 0, 0, 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 22, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE | NPC_F_LF_L_WITH_QINQ_CTAG, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_STAG_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU12_TU_ARP, 18, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_L_WITH_QINQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE | NPC_F_LF_L_WITH_QINQ, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 22, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_CTAG, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_ETHER, + NPC_F_LF_U_UNK_ETYPE, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, - NPC_F_TU_ETHER_QINQ_CTAG_UNK, 0, 0, 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LF, NPC_LT_LF_TU_PPP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 6, 0, 0, - 0, 0, NPC_S_KPU12_TU_IP6, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 4, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU12_TU_ARP, 18, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_MPLS_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_QINQ_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_MPLS_2MANY, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_ETHER, NPC_F_TU_ETHER_UNK, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 0, 0, + NPC_S_KPU12_TU_IP, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_PPP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 0, 0, + NPC_S_KPU12_TU_IP6, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_MPLS_IN_NSH, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_MPLS_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LE, NPC_LT_LE_TU_3RD_NSH, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_ETHER_IN_NSH, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LE, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LF, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; static struct npc_kpu_profile_action kpu12_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU15_TU_TCP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU15_TU_TCP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU15_TU_UDP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU15_TU_UDP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_SCTP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_SCTP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ICMP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ICMP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_IGMP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_IGMP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ESP, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ESP, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_AH, 20, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_AH, 20, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_UNK_PROTO, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_UNK_IP_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU15_TU_TCP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU15_TU_TCP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU15_TU_UDP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU15_TU_UDP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_SCTP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_SCTP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ICMP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ICMP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_IGMP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_IGMP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ESP, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ESP, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_AH, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, NPC_F_IP_HAS_OPTIONS, 0, 0xf, - 0, 2, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_AH, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS, + 0, 0xf, 0, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, - NPC_F_IP_UNK_PROTO_HAS_OPTIONS, 0, 0, 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + NPC_F_LG_U_IP_HAS_OPTIONS | NPC_F_LG_U_UNK_IP_PROTO, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LF, NPC_EC_IP_VER, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_IP_VER, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_ARP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_ARP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 12, 0, - 2, 0, NPC_S_KPU15_TU_TCP, 40, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 12, 0, 2, 0, + NPC_S_KPU15_TU_TCP, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 2, 0, NPC_S_KPU15_TU_UDP, 40, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 2, 0, + NPC_S_KPU15_TU_UDP, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_SCTP, 40, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_SCTP, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ICMP, 40, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ICMP, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ICMP6, 40, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ICMP6, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_ESP, 40, 1, - NPC_LID_LC, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_ESP, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 2, 0, NPC_S_KPU15_TU_AH, 40, 1, - NPC_LID_LC, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU15_TU_AH, 40, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, - 0, 0, NPC_S_KPU13_TU_IP6_EXT, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, NPC_F_IP6_HAS_EXT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 2, 0, 0, 0, 0, + NPC_S_KPU13_TU_IP6_EXT, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + NPC_F_LG_U_IP6_HAS_EXT, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LF, NPC_EC_IP6_VER, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LF, NPC_LT_LF_TU_IP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_IP6_VER, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LG, NPC_LT_LG_TU_IP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LF, NPC_EC_UNK, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LF, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LF, NPC_EC_UNK, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LG, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; static struct npc_kpu_profile_action kpu13_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; static struct npc_kpu_profile_action kpu14_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LC, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; static struct npc_kpu_profile_action kpu15_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_HTTP_DATA, 20, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTP, 0, 0, - 0, 0, + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_FIN_ONLY, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_ZERO, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_RST_FIN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_URG_SYN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_RST_SYN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_LG, NPC_EC_TCP_FLAGS_SYN_FIN, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_HTTP_DATA, 20, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_L_TCP_HTTP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_HTTPS_DATA, 20, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTPS, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_HTTPS_DATA, 20, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_L_TCP_HTTP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_PPTP_DATA, 20, 1, - NPC_LID_LD, NPC_LT_LG_TU_TCP, NPC_F_TCP_PPTP, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_PPTP_DATA, 20, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_L_TCP_PPTP, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_TCP_DATA, 20, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_UNK_PORT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_TCP_DATA, 20, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_L_TCP_UNK_PORT, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_HTTP_DATA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTP_HAS_OPTIONS, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_HTTP_DATA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_U_TCP_HAS_OPTIONS | NPC_F_LH_L_TCP_HTTP, 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_HTTPS_DATA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_HTTPS_HAS_OPTIONS, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_HTTPS_DATA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_U_TCP_HAS_OPTIONS | NPC_F_LH_L_TCP_HTTPS, 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_PPTP_DATA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_PPTP_HAS_OPTIONS, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_PPTP_DATA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_U_TCP_HAS_OPTIONS | NPC_F_LH_L_TCP_PPTP, 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_TCP_DATA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_TCP, NPC_F_TCP_UNK_PORT_HAS_OPTIONS, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_TCP_DATA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_TCP, + NPC_F_LH_U_TCP_HAS_OPTIONS | NPC_F_LH_L_TCP_UNK_PORT, 12, 0xf0, 1, 2, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 0, NPC_S_KPU16_UDP_DATA, 8, 1, - NPC_LID_LG, NPC_LT_LG_TU_UDP, NPC_F_UDP_UNK_PORT, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU16_UDP_DATA, 8, 1, + NPC_LID_LH, NPC_LT_LH_TU_UDP, + NPC_F_LH_L_UDP_UNK_PORT, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_SCTP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_SCTP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_ICMP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_ICMP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_IGMP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_IGMP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_ICMP6, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_ICMP6, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_ESP, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_ESP, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LG, NPC_LT_LG_TU_AH, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 1, + NPC_LID_LH, NPC_LT_LH_TU_AH, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_LG, NPC_EC_L4, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 0, - NPC_LID_LG, NPC_LT_NA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_LG, NPC_EC_L4, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; static struct npc_kpu_profile_action kpu16_action_entries[] = { { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LH, NPC_LT_LH_TCP_DATA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LH, NPC_LT_LH_HTTP_DATA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LH, NPC_LT_LH_HTTPS_DATA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LH, NPC_LT_LH_PPTP_DATA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, { - NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, - 0, 1, NPC_S_NA, 0, 1, - NPC_LID_LH, NPC_LT_LH_UDP_DATA, 0, 0, 0, - 0, 0, + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 0, 0, + NPC_LID_LH, NPC_LT_NA, + 0, + 0, 0, 0, 0, }, }; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 4a7609fd6dd0..b88180885f31 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -2763,23 +2763,23 @@ int rvu_nix_init(struct rvu *rvu) rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OIP4, (NPC_LID_LC << 8) | (NPC_LT_LC_IP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_IIP4, - (NPC_LID_LF << 8) | (NPC_LT_LF_TU_IP << 4) | 0x0F); + (NPC_LID_LG << 8) | (NPC_LT_LG_TU_IP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OIP6, (NPC_LID_LC << 8) | (NPC_LT_LC_IP6 << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_IIP6, - (NPC_LID_LF << 8) | (NPC_LT_LF_TU_IP6 << 4) | 0x0F); + (NPC_LID_LG << 8) | (NPC_LT_LG_TU_IP6 << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OTCP, (NPC_LID_LD << 8) | (NPC_LT_LD_TCP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_ITCP, - (NPC_LID_LG << 8) | (NPC_LT_LG_TU_TCP << 4) | 0x0F); + (NPC_LID_LH << 8) | (NPC_LT_LH_TU_TCP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OUDP, (NPC_LID_LD << 8) | (NPC_LT_LD_UDP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_IUDP, - (NPC_LID_LG << 8) | (NPC_LT_LG_TU_UDP << 4) | 0x0F); + (NPC_LID_LH << 8) | (NPC_LT_LH_TU_UDP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_OSCTP, (NPC_LID_LD << 8) | (NPC_LT_LD_SCTP << 4) | 0x0F); rvu_write64(rvu, blkaddr, NIX_AF_RX_DEF_ISCTP, - (NPC_LID_LG << 8) | (NPC_LT_LG_TU_SCTP << 4) | + (NPC_LID_LH << 8) | (NPC_LT_LH_TU_SCTP << 4) | 0x0F); err = nix_rx_flowkey_alg_cfg(rvu, blkaddr); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index e300abbd3697..ce4472915c98 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -354,8 +354,8 @@ void rvu_npc_install_ucast_entry(struct rvu *rvu, u16 pcifunc, NIX_INTF_RX, &entry, true); /* add VLAN matching, setup action and save entry back for later */ - entry.kw[0] |= (NPC_LT_LB_STAG | NPC_LT_LB_CTAG) << 20; - entry.kw_mask[0] |= (NPC_LT_LB_STAG & NPC_LT_LB_CTAG) << 20; + entry.kw[0] |= (NPC_LT_LB_STAG_QINQ | NPC_LT_LB_CTAG) << 20; + entry.kw_mask[0] |= (NPC_LT_LB_STAG_QINQ & NPC_LT_LB_CTAG) << 20; entry.vtag_action = VTAG0_VALID_BIT | FIELD_PREP(VTAG0_TYPE_MASK, 0) | @@ -704,8 +704,7 @@ static void npc_config_ldata_extract(struct rvu *rvu, int blkaddr) /* Layer B: Stacked VLAN (STAG|QinQ) */ /* CTAG VLAN[2..3] + Ethertype, 4 bytes, KW0[63:32] */ cfg = KEX_LD_CFG(0x03, 0x4, 0x1, 0x0, 0x4); - SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_STAG, 0, cfg); - SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_QINQ, 0, cfg); + SET_KEX_LD(NIX_INTF_RX, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, cfg); /* Layer C: IPv4 */ /* SIP+DIP: 8 bytes, KW2[63:0] */ @@ -1151,7 +1150,7 @@ int rvu_npc_init(struct rvu *rvu) /* Config Inner IPV4 NPC layer info */ rvu_write64(rvu, blkaddr, NPC_AF_PCK_DEF_IIP4, - (NPC_LID_LF << 8) | (NPC_LT_LF_TU_IP << 4) | 0x0F); + (NPC_LID_LG << 8) | (NPC_LT_LG_TU_IP << 4) | 0x0F); /* Enable below for Rx pkts. * - Outer IPv4 header checksum validation. -- cgit v1.2.3-59-g8ed1b From 8cc89ae92518cac06afc0faf58d15322d88043e2 Mon Sep 17 00:00:00 2001 From: Nithin Dabilpuram Date: Thu, 14 Nov 2019 10:56:27 +0530 Subject: octeontx2-af: Clear NPC MCAM entries before update Writing into NPC MCAM1 and MCAM0 registers are suppressed if they happened to form a reserved combination. Hence clear and disable MCAM entries before update. For HRM: [CAM(1)]=1, [CAM(0)]=1: Reserved. The reserved combination is not allowed. Hardware suppresses any write to CAM(0) or CAM(1) that would result in the reserved combination for any CAM bit. Signed-off-by: Nithin Dabilpuram Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 33 ++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index ce4472915c98..a3b43159be38 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -120,6 +120,31 @@ static void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, } } +static void npc_clear_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, + int blkaddr, int index) +{ + int bank = npc_get_bank(mcam, index); + int actbank = bank; + + index &= (mcam->banksize - 1); + for (; bank < (actbank + mcam->banks_per_entry); bank++) { + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_INTF(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_INTF(index, bank, 0), 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_W0(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_W0(index, bank, 0), 0); + + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_W1(index, bank, 1), 0); + rvu_write64(rvu, blkaddr, + NPC_AF_MCAMEX_BANKX_CAMX_W1(index, bank, 0), 0); + } +} + static void npc_get_keyword(struct mcam_entry *entry, int idx, u64 *cam0, u64 *cam1) { @@ -211,6 +236,12 @@ static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, actindex = index; index &= (mcam->banksize - 1); + /* Disable before mcam entry update */ + npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, false); + + /* Clear mcam entry to avoid writes being suppressed by NPC */ + npc_clear_mcam_entry(rvu, mcam, blkaddr, actindex); + /* CAM1 takes the comparison value and * CAM0 specifies match for a bit in key being '0' or '1' or 'dontcare'. * CAM1 = 0 & CAM0 = 1 => match if key = 0 @@ -251,8 +282,6 @@ static void npc_config_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, /* Enable the entry */ if (enable) npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, true); - else - npc_enable_mcam_entry(rvu, mcam, blkaddr, actindex, false); } static void npc_copy_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam, -- cgit v1.2.3-59-g8ed1b From 206ff848a1abaa1755310fdb4b20a3303ccf23d9 Mon Sep 17 00:00:00 2001 From: Kiran Kumar K Date: Thu, 14 Nov 2019 10:56:28 +0530 Subject: octeontx2-af: Add more RSS algorithms This patch adds support for few more RSS key types for flow key algorithm to compute rss hash index. Following flow key types have been added. - Tunnel types like NVGRE, VXLAN, GENEVE. - L2 offload type ETH_DMAC, Here we will consider only DMAC 6 bytes. - And extension header IPV6_EXT (1 byte followed by IPV6 header - Hashing inner protocol fields for inner DMAC, IPv4/v6, TCP, UDP, SCTP. Signed-off-by: Kiran Kumar K Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 12 +++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 113 +++++++++++++++++++-- 2 files changed, 114 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index 94c198a34ecd..de3fe2559a3c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -580,6 +580,18 @@ struct nix_rss_flowkey_cfg { #define NIX_FLOW_KEY_TYPE_TCP BIT(3) #define NIX_FLOW_KEY_TYPE_UDP BIT(4) #define NIX_FLOW_KEY_TYPE_SCTP BIT(5) +#define NIX_FLOW_KEY_TYPE_NVGRE BIT(6) +#define NIX_FLOW_KEY_TYPE_VXLAN BIT(7) +#define NIX_FLOW_KEY_TYPE_GENEVE BIT(8) +#define NIX_FLOW_KEY_TYPE_ETH_DMAC BIT(9) +#define NIX_FLOW_KEY_TYPE_IPV6_EXT BIT(10) +#define NIX_FLOW_KEY_TYPE_GTPU BIT(11) +#define NIX_FLOW_KEY_TYPE_INNR_IPV4 BIT(12) +#define NIX_FLOW_KEY_TYPE_INNR_IPV6 BIT(13) +#define NIX_FLOW_KEY_TYPE_INNR_TCP BIT(14) +#define NIX_FLOW_KEY_TYPE_INNR_UDP BIT(15) +#define NIX_FLOW_KEY_TYPE_INNR_SCTP BIT(16) +#define NIX_FLOW_KEY_TYPE_INNR_ETH_DMAC BIT(17) 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 b88180885f31..994ed71859a4 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -2032,51 +2032,82 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) if (field_marker) memset(&tmp, 0, sizeof(tmp)); + field_marker = true; + keyoff_marker = true; switch (key_type) { case NIX_FLOW_KEY_TYPE_PORT: field->sel_chan = true; /* This should be set to 1, when SEL_CHAN is set */ field->bytesm1 = 1; - field_marker = true; - keyoff_marker = true; break; case NIX_FLOW_KEY_TYPE_IPV4: + case NIX_FLOW_KEY_TYPE_INNR_IPV4: field->lid = NPC_LID_LC; field->ltype_match = NPC_LT_LC_IP; + if (key_type == NIX_FLOW_KEY_TYPE_INNR_IPV4) { + field->lid = NPC_LID_LG; + field->ltype_match = NPC_LT_LG_TU_IP; + } field->hdr_offset = 12; /* SIP offset */ field->bytesm1 = 7; /* SIP + DIP, 8 bytes */ field->ltype_mask = 0xF; /* Match only IPv4 */ - field_marker = true; keyoff_marker = false; break; case NIX_FLOW_KEY_TYPE_IPV6: + case NIX_FLOW_KEY_TYPE_INNR_IPV6: field->lid = NPC_LID_LC; field->ltype_match = NPC_LT_LC_IP6; + if (key_type == NIX_FLOW_KEY_TYPE_INNR_IPV6) { + field->lid = NPC_LID_LG; + field->ltype_match = NPC_LT_LG_TU_IP6; + } field->hdr_offset = 8; /* SIP offset */ field->bytesm1 = 31; /* SIP + DIP, 32 bytes */ field->ltype_mask = 0xF; /* Match only IPv6 */ - field_marker = true; - keyoff_marker = true; break; case NIX_FLOW_KEY_TYPE_TCP: case NIX_FLOW_KEY_TYPE_UDP: case NIX_FLOW_KEY_TYPE_SCTP: + case NIX_FLOW_KEY_TYPE_INNR_TCP: + case NIX_FLOW_KEY_TYPE_INNR_UDP: + case NIX_FLOW_KEY_TYPE_INNR_SCTP: field->lid = NPC_LID_LD; + if (key_type == NIX_FLOW_KEY_TYPE_INNR_TCP || + key_type == NIX_FLOW_KEY_TYPE_INNR_UDP || + key_type == NIX_FLOW_KEY_TYPE_INNR_SCTP) + field->lid = NPC_LID_LH; field->bytesm1 = 3; /* Sport + Dport, 4 bytes */ - if (key_type == NIX_FLOW_KEY_TYPE_TCP && valid_key) { + + /* 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 + */ + BUILD_BUG_ON((int)NPC_LT_LD_TCP != + (int)NPC_LT_LH_TU_TCP); + BUILD_BUG_ON((int)NPC_LT_LD_UDP != + (int)NPC_LT_LH_TU_UDP); + BUILD_BUG_ON((int)NPC_LT_LD_SCTP != + (int)NPC_LT_LH_TU_SCTP); + + if ((key_type == NIX_FLOW_KEY_TYPE_TCP || + key_type == NIX_FLOW_KEY_TYPE_INNR_TCP) && + valid_key) { field->ltype_match |= NPC_LT_LD_TCP; group_member = true; - } else if (key_type == NIX_FLOW_KEY_TYPE_UDP && + } else if ((key_type == NIX_FLOW_KEY_TYPE_UDP || + key_type == NIX_FLOW_KEY_TYPE_INNR_UDP) && valid_key) { field->ltype_match |= NPC_LT_LD_UDP; group_member = true; - } else if (key_type == NIX_FLOW_KEY_TYPE_SCTP && + } else if ((key_type == NIX_FLOW_KEY_TYPE_SCTP || + key_type == NIX_FLOW_KEY_TYPE_INNR_SCTP) && valid_key) { field->ltype_match |= NPC_LT_LD_SCTP; group_member = true; } field->ltype_mask = ~field->ltype_match; - if (key_type == NIX_FLOW_KEY_TYPE_SCTP) { + if (key_type == NIX_FLOW_KEY_TYPE_SCTP || + key_type == NIX_FLOW_KEY_TYPE_INNR_SCTP) { /* Handle the case where any of the group item * is enabled in the group but not the final one */ @@ -2084,13 +2115,73 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) valid_key = true; group_member = false; } - field_marker = true; - keyoff_marker = true; } else { field_marker = false; keyoff_marker = false; } break; + case NIX_FLOW_KEY_TYPE_NVGRE: + field->lid = NPC_LID_LD; + field->hdr_offset = 4; /* VSID offset */ + field->bytesm1 = 2; + field->ltype_match = NPC_LT_LD_NVGRE; + field->ltype_mask = 0xF; + break; + case NIX_FLOW_KEY_TYPE_VXLAN: + case NIX_FLOW_KEY_TYPE_GENEVE: + field->lid = NPC_LID_LE; + field->bytesm1 = 2; + field->hdr_offset = 4; + field->ltype_mask = 0xF; + field_marker = false; + keyoff_marker = false; + + if (key_type == NIX_FLOW_KEY_TYPE_VXLAN && valid_key) { + field->ltype_match |= NPC_LT_LE_VXLAN; + group_member = true; + } + + if (key_type == NIX_FLOW_KEY_TYPE_GENEVE && valid_key) { + field->ltype_match |= NPC_LT_LE_GENEVE; + group_member = true; + } + + if (key_type == NIX_FLOW_KEY_TYPE_GENEVE) { + if (group_member) { + field->ltype_mask = ~field->ltype_match; + field_marker = true; + keyoff_marker = true; + valid_key = true; + group_member = false; + } + } + break; + case NIX_FLOW_KEY_TYPE_ETH_DMAC: + case NIX_FLOW_KEY_TYPE_INNR_ETH_DMAC: + field->lid = NPC_LID_LA; + field->ltype_match = NPC_LT_LA_ETHER; + if (key_type == NIX_FLOW_KEY_TYPE_INNR_ETH_DMAC) { + field->lid = NPC_LID_LF; + field->ltype_match = NPC_LT_LF_TU_ETHER; + } + field->hdr_offset = 0; + field->bytesm1 = 5; /* DMAC 6 Byte */ + field->ltype_mask = 0xF; + break; + case NIX_FLOW_KEY_TYPE_IPV6_EXT: + field->lid = NPC_LID_LC; + field->hdr_offset = 40; /* IPV6 hdr */ + field->bytesm1 = 0; /* 1 Byte ext hdr*/ + field->ltype_match = NPC_LT_LC_IP6_EXT; + field->ltype_mask = 0xF; + break; + case NIX_FLOW_KEY_TYPE_GTPU: + field->lid = NPC_LID_LE; + field->hdr_offset = 4; + field->bytesm1 = 3; /* 4 bytes TID*/ + field->ltype_match = NPC_LT_LE_GTPU; + field->ltype_mask = 0xF; + break; } field->ena = 1; -- cgit v1.2.3-59-g8ed1b From 5d9b976d4480dc0dcfa3719b645636d2f0f9f156 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Thu, 14 Nov 2019 10:56:29 +0530 Subject: octeontx2-af: Support fixed transmit scheduler topology CN96xx initial silicon doesn't support all features pertaining to NIX transmit scheduling and shaping. - It supports a fixed topology of 1:1 mapped transmit limiters at all levels. - Supports DWRR only at SMQ/MDQ and TL1. - Doesn't support shaping and coloring. This patch adds HW capability structure by which each variant and skew of silicon can be differentiated by their supported features. And adds support for A0 silicon's transmit scheduler capabilities or rather limitations. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/cgx.c | 50 ++ drivers/net/ethernet/marvell/octeontx2/af/cgx.h | 7 + drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 10 + drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 35 +- drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 33 +- .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 18 + .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 612 ++++++++++++--------- .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 6 +- .../net/ethernet/marvell/octeontx2/af/rvu_reg.h | 1 + 9 files changed, 513 insertions(+), 259 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c index d94e68254c43..5ca788691911 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.c @@ -291,6 +291,35 @@ void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable) } EXPORT_SYMBOL(cgx_lmac_promisc_config); +/* Enable or disable forwarding received pause frames to Tx block */ +void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable) +{ + struct cgx *cgx = cgxd; + u64 cfg; + + if (!cgx) + return; + + if (enable) { + cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL); + cfg |= CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK; + cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg); + + cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL); + cfg |= CGX_SMUX_RX_FRM_CTL_CTL_BCK; + cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg); + } else { + cfg = cgx_read(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL); + cfg &= ~CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK; + cgx_write(cgx, lmac_id, CGXX_GMP_GMI_RXX_FRM_CTL, cfg); + + cfg = cgx_read(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL); + cfg &= ~CGX_SMUX_RX_FRM_CTL_CTL_BCK; + cgx_write(cgx, lmac_id, CGXX_SMUX_RX_FRM_CTL, cfg); + } +} +EXPORT_SYMBOL(cgx_lmac_enadis_rx_pause_fwding); + int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat) { struct cgx *cgx = cgxd; @@ -331,6 +360,27 @@ int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable) } EXPORT_SYMBOL(cgx_lmac_rx_tx_enable); +int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable) +{ + struct cgx *cgx = cgxd; + u64 cfg, last; + + if (!cgx || lmac_id >= cgx->lmac_count) + return -ENODEV; + + cfg = cgx_read(cgx, lmac_id, CGXX_CMRX_CFG); + last = cfg; + if (enable) + cfg |= DATA_PKT_TX_EN; + else + cfg &= ~DATA_PKT_TX_EN; + + if (cfg != last) + cgx_write(cgx, lmac_id, CGXX_CMRX_CFG, cfg); + return !!(last & DATA_PKT_TX_EN); +} +EXPORT_SYMBOL(cgx_lmac_tx_enable); + /* CGX Firmware interface low level support */ static int cgx_fwi_cmd_send(u64 req, u64 *resp, struct lmac *lmac) { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h index c0306b275c5b..096a04a2f3e1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/cgx.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/cgx.h @@ -56,6 +56,11 @@ #define CGXX_GMP_PCS_MRX_CTL 0x30000 #define CGXX_GMP_PCS_MRX_CTL_LBK BIT_ULL(14) +#define CGXX_SMUX_RX_FRM_CTL 0x20020 +#define CGX_SMUX_RX_FRM_CTL_CTL_BCK BIT_ULL(3) +#define CGXX_GMP_GMI_RXX_FRM_CTL 0x38028 +#define CGX_GMP_GMI_RXX_FRM_CTL_CTL_BCK BIT_ULL(3) + #define CGX_COMMAND_REG CGXX_SCRATCH1_REG #define CGX_EVENT_REG CGXX_SCRATCH0_REG #define CGX_CMD_TIMEOUT 2200 /* msecs */ @@ -110,9 +115,11 @@ int cgx_lmac_evh_unregister(void *cgxd, int lmac_id); int cgx_get_tx_stats(void *cgxd, int lmac_id, int idx, u64 *tx_stat); int cgx_get_rx_stats(void *cgxd, int lmac_id, int idx, u64 *rx_stat); int cgx_lmac_rx_tx_enable(void *cgxd, int lmac_id, bool enable); +int cgx_lmac_tx_enable(void *cgxd, int lmac_id, bool enable); int cgx_lmac_addr_set(u8 cgx_id, u8 lmac_id, u8 *mac_addr); u64 cgx_lmac_addr_get(u8 cgx_id, u8 lmac_id); void cgx_lmac_promisc_config(int cgx_id, int lmac_id, bool enable); +void cgx_lmac_enadis_rx_pause_fwding(void *cgxd, int lmac_id, bool enable); int cgx_lmac_internal_loopback(void *cgxd, int lmac_id, bool enable); int cgx_get_link_info(void *cgxd, int lmac_id, struct cgx_link_user_info *linfo); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index de3fe2559a3c..fc9c731856d2 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -127,6 +127,7 @@ M(ATTACH_RESOURCES, 0x002, attach_resources, rsrc_attach, msg_rsp) \ M(DETACH_RESOURCES, 0x003, detach_resources, rsrc_detach, msg_rsp) \ M(MSIX_OFFSET, 0x004, msix_offset, msg_req, msix_offset_rsp) \ M(VF_FLR, 0x006, vf_flr, msg_req, msg_rsp) \ +M(GET_HW_CAP, 0x008, get_hw_cap, msg_req, get_hw_cap_rsp) \ /* CGX mbox IDs (range 0x200 - 0x3FF) */ \ M(CGX_START_RXTX, 0x200, cgx_start_rxtx, msg_req, msg_rsp) \ M(CGX_STOP_RXTX, 0x201, cgx_stop_rxtx, msg_req, msg_rsp) \ @@ -302,6 +303,12 @@ struct msix_offset_rsp { u16 cptlf_msixoff[MAX_RVU_BLKLF_CNT]; }; +struct get_hw_cap_rsp { + struct mbox_msghdr hdr; + u8 nix_fixed_txschq_mapping; /* Schq mapping fixed or flexible */ + u8 nix_shaping; /* Is shaping and coloring supported */ +}; + /* CGX mbox message formats */ struct cgx_stats_rsp { @@ -514,6 +521,9 @@ struct nix_txsch_alloc_rsp { /* Scheduler queue list allocated at each level */ u16 schq_contig_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; u16 schq_list[NIX_TXSCH_LVL_CNT][MAX_TXSCHQ_PER_FUNC]; + u8 aggr_level; /* Traffic aggregation scheduler level */ + u8 aggr_lvl_rr_prio; /* Aggregation lvl's RR_PRIO config */ + u8 link_cfg_lvl; /* LINKX_CFG CSRs mapped to TL3 or TL2's index ? */ }; struct nix_txsch_free_req { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 49e48b6d322e..bf9272fafd69 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -56,12 +56,31 @@ static char *mkex_profile; /* MKEX profile name */ module_param(mkex_profile, charp, 0000); MODULE_PARM_DESC(mkex_profile, "MKEX profile name string"); +static void rvu_setup_hw_capabilities(struct rvu *rvu) +{ + struct rvu_hwinfo *hw = rvu->hw; + + hw->cap.nix_tx_aggr_lvl = NIX_TXSCH_LVL_TL1; + hw->cap.nix_fixed_txschq_mapping = false; + hw->cap.nix_shaping = true; + hw->cap.nix_tx_link_bp = true; + + if (is_rvu_96xx_B0(rvu)) { + hw->cap.nix_fixed_txschq_mapping = true; + hw->cap.nix_txsch_per_cgx_lmac = 4; + hw->cap.nix_txsch_per_lbk_lmac = 132; + hw->cap.nix_txsch_per_sdp_lmac = 76; + hw->cap.nix_shaping = false; + hw->cap.nix_tx_link_bp = false; + } +} + /* Poll a RVU block's register 'offset', for a 'zero' * or 'nonzero' at bits specified by 'mask' */ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) { - unsigned long timeout = jiffies + usecs_to_jiffies(100); + unsigned long timeout = jiffies + usecs_to_jiffies(10000); void __iomem *reg; u64 reg_val; @@ -73,7 +92,6 @@ int rvu_poll_reg(struct rvu *rvu, u64 block, u64 offset, u64 mask, bool zero) if (!zero && (reg_val & mask)) return 0; usleep_range(1, 5); - timeout--; } return -EBUSY; } @@ -1363,6 +1381,17 @@ int rvu_mbox_handler_vf_flr(struct rvu *rvu, struct msg_req *req, return 0; } +int rvu_mbox_handler_get_hw_cap(struct rvu *rvu, struct msg_req *req, + struct get_hw_cap_rsp *rsp) +{ + struct rvu_hwinfo *hw = rvu->hw; + + rsp->nix_fixed_txschq_mapping = hw->cap.nix_fixed_txschq_mapping; + rsp->nix_shaping = hw->cap.nix_shaping; + + return 0; +} + static int rvu_process_mbox_msg(struct otx2_mbox *mbox, int devid, struct mbox_msghdr *req) { @@ -2448,6 +2477,8 @@ static int rvu_probe(struct pci_dev *pdev, const struct pci_device_id *id) rvu_reset_all_blocks(rvu); + rvu_setup_hw_capabilities(rvu); + err = rvu_setup_hw_resources(rvu); if (err) goto err_release_regions; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 7e990bbfc336..000d02bb2ccf 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -184,10 +184,12 @@ struct rvu_pfvf { struct nix_txsch { struct rsrc_bmap schq; u8 lvl; -#define NIX_TXSCHQ_TL1_CFG_DONE BIT_ULL(0) +#define NIX_TXSCHQ_FREE BIT_ULL(1) +#define NIX_TXSCHQ_CFG_DONE BIT_ULL(0) #define TXSCH_MAP_FUNC(__pfvf_map) ((__pfvf_map) & 0xFFFF) #define TXSCH_MAP_FLAGS(__pfvf_map) ((__pfvf_map) >> 16) #define TXSCH_MAP(__func, __flags) (((__func) & 0xFFFF) | ((__flags) << 16)) +#define TXSCH_SET_FLAG(__pfvf_map, flag) ((__pfvf_map) | ((flag) << 16)) u32 *pfvf_map; }; @@ -221,6 +223,20 @@ struct nix_hw { struct nix_lso lso; }; +/* RVU block's capabilities or functionality, + * which vary by silicon version/skew. + */ +struct hw_cap { + /* Transmit side supported functionality */ + u8 nix_tx_aggr_lvl; /* Tx link's traffic aggregation level */ + u16 nix_txsch_per_cgx_lmac; /* Max Q's transmitting to CGX LMAC */ + u16 nix_txsch_per_lbk_lmac; /* Max Q's transmitting to LBK LMAC */ + u16 nix_txsch_per_sdp_lmac; /* Max Q's transmitting to SDP LMAC */ + bool nix_fixed_txschq_mapping; /* Schq mapping fixed or flexible */ + bool nix_shaping; /* Is shaping and coloring supported */ + bool nix_tx_link_bp; /* Can link backpressure TL queues ? */ +}; + struct rvu_hwinfo { u8 total_pfs; /* MAX RVU PFs HW supports */ u16 total_vfs; /* Max RVU VFs HW supports */ @@ -232,7 +248,7 @@ struct rvu_hwinfo { u8 sdp_links; u8 npc_kpus; /* No of parser units */ - + struct hw_cap cap; struct rvu_block block[BLK_COUNT]; /* Block info */ struct nix_hw *nix0; struct npc_pkind pkind; @@ -317,7 +333,8 @@ static inline u64 rvupf_read64(struct rvu *rvu, u64 offset) return readq(rvu->pfreg_base + offset); } -static inline bool is_rvu_9xxx_A0(struct rvu *rvu) +/* Silicon revisions */ +static inline bool is_rvu_96xx_A0(struct rvu *rvu) { struct pci_dev *pdev = rvu->pdev; @@ -325,6 +342,14 @@ static inline bool is_rvu_9xxx_A0(struct rvu *rvu) (pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX); } +static inline bool is_rvu_96xx_B0(struct rvu *rvu) +{ + struct pci_dev *pdev = rvu->pdev; + + return ((pdev->revision == 0x00) || (pdev->revision == 0x01)) && + (pdev->subsystem_device == PCI_SUBSYS_DEVID_96XX); +} + /* Function Prototypes * RVU */ @@ -383,6 +408,7 @@ int rvu_cgx_init(struct rvu *rvu); int rvu_cgx_exit(struct rvu *rvu); void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu); int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start); +void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable); int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, int rxtxflag, u64 *stat); /* NPA APIs */ @@ -400,6 +426,7 @@ int rvu_nix_reserve_mark_format(struct rvu *rvu, struct nix_hw *nix_hw, void rvu_nix_freemem(struct rvu *rvu); int rvu_get_nixlf_count(struct rvu *rvu); void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int npalf); +int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf); /* NPC APIs */ int rvu_npc_init(struct rvu *rvu); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 65d01e52dc3a..7e110b772aa5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -348,6 +348,24 @@ int rvu_cgx_exit(struct rvu *rvu) return 0; } +void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable) +{ + u8 cgx_id, lmac_id; + void *cgxd; + + if (!is_pf_cgxmapped(rvu, pf)) + return; + + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + cgxd = rvu_cgx_pdata(cgx_id, rvu); + + /* Set / clear CTL_BCK to control pause frame forwarding to NIX */ + if (enable) + cgx_lmac_enadis_rx_pause_fwding(cgxd, lmac_id, true); + else + cgx_lmac_enadis_rx_pause_fwding(cgxd, lmac_id, false); +} + int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start) { int pf = rvu_get_pf(pcifunc); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 994ed71859a4..3b32e91482fc 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -127,17 +127,12 @@ static void nix_rx_sync(struct rvu *rvu, int blkaddr) err = rvu_poll_reg(rvu, blkaddr, NIX_AF_RX_SW_SYNC, BIT_ULL(0), true); if (err) dev_err(rvu->dev, "NIX RX software sync failed\n"); - - /* As per a HW errata in 9xxx A0 silicon, HW may clear SW_SYNC[ENA] - * bit too early. Hence wait for 50us more. - */ - if (is_rvu_9xxx_A0(rvu)) - usleep_range(50, 60); } static bool is_valid_txschq(struct rvu *rvu, int blkaddr, int lvl, u16 pcifunc, u16 schq) { + struct rvu_hwinfo *hw = rvu->hw; struct nix_txsch *txsch; struct nix_hw *nix_hw; u16 map_func; @@ -155,13 +150,15 @@ static bool is_valid_txschq(struct rvu *rvu, int blkaddr, map_func = TXSCH_MAP_FUNC(txsch->pfvf_map[schq]); mutex_unlock(&rvu->rsrc_lock); - /* For TL1 schq, sharing across VF's of same PF is ok */ - if (lvl == NIX_TXSCH_LVL_TL1 && - rvu_get_pf(map_func) != rvu_get_pf(pcifunc)) - return false; + /* TLs aggegating traffic are shared across PF and VFs */ + if (lvl >= hw->cap.nix_tx_aggr_lvl) { + if (rvu_get_pf(map_func) != rvu_get_pf(pcifunc)) + return false; + else + return true; + } - if (lvl != NIX_TXSCH_LVL_TL1 && - map_func != pcifunc) + if (map_func != pcifunc) return false; return true; @@ -1048,6 +1045,9 @@ static void nix_reset_tx_linkcfg(struct rvu *rvu, int blkaddr, struct rvu_hwinfo *hw = rvu->hw; int link; + if (lvl >= hw->cap.nix_tx_aggr_lvl) + return; + /* Reset TL4's SDP link config */ if (lvl == NIX_TXSCH_LVL_TL4) rvu_write64(rvu, blkaddr, NIX_AF_TL4X_SDP_LINK_CFG(schq), 0x00); @@ -1061,83 +1061,185 @@ static void nix_reset_tx_linkcfg(struct rvu *rvu, int blkaddr, NIX_AF_TL3_TL2X_LINKX_CFG(schq, link), 0x00); } -static int -rvu_get_tl1_schqs(struct rvu *rvu, int blkaddr, u16 pcifunc, - u16 *schq_list, u16 *schq_cnt) +static int nix_get_tx_link(struct rvu *rvu, u16 pcifunc) { - struct nix_txsch *txsch; - struct nix_hw *nix_hw; - struct rvu_pfvf *pfvf; - u8 cgx_id, lmac_id; - u16 schq_base; - u32 *pfvf_map; - int pf, intf; + struct rvu_hwinfo *hw = rvu->hw; + int pf = rvu_get_pf(pcifunc); + u8 cgx_id = 0, lmac_id = 0; - nix_hw = get_nix_hw(rvu->hw, blkaddr); - if (!nix_hw) - return -ENODEV; + if (is_afvf(pcifunc)) {/* LBK links */ + return hw->cgx_links; + } else if (is_pf_cgxmapped(rvu, pf)) { + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + return (cgx_id * hw->lmac_per_cgx) + lmac_id; + } - pfvf = rvu_get_pfvf(rvu, pcifunc); - txsch = &nix_hw->txsch[NIX_TXSCH_LVL_TL1]; - pfvf_map = txsch->pfvf_map; - pf = rvu_get_pf(pcifunc); + /* SDP link */ + return hw->cgx_links + hw->lbk_links; +} - /* static allocation as two TL1's per link */ - intf = is_afvf(pcifunc) ? NIX_INTF_TYPE_LBK : NIX_INTF_TYPE_CGX; +static void nix_get_txschq_range(struct rvu *rvu, u16 pcifunc, + int link, int *start, int *end) +{ + struct rvu_hwinfo *hw = rvu->hw; + int pf = rvu_get_pf(pcifunc); - switch (intf) { - case NIX_INTF_TYPE_CGX: - rvu_get_cgx_lmac_id(pfvf->cgx_lmac, &cgx_id, &lmac_id); - schq_base = (cgx_id * MAX_LMAC_PER_CGX + lmac_id) * 2; - break; - case NIX_INTF_TYPE_LBK: - schq_base = rvu->cgx_cnt_max * MAX_LMAC_PER_CGX * 2; - break; - default: - return -ENODEV; + if (is_afvf(pcifunc)) { /* LBK links */ + *start = hw->cap.nix_txsch_per_cgx_lmac * link; + *end = *start + hw->cap.nix_txsch_per_lbk_lmac; + } else if (is_pf_cgxmapped(rvu, pf)) { /* CGX links */ + *start = hw->cap.nix_txsch_per_cgx_lmac * link; + *end = *start + hw->cap.nix_txsch_per_cgx_lmac; + } else { /* SDP link */ + *start = (hw->cap.nix_txsch_per_cgx_lmac * hw->cgx_links) + + (hw->cap.nix_txsch_per_lbk_lmac * hw->lbk_links); + *end = *start + hw->cap.nix_txsch_per_sdp_lmac; } +} - if (schq_base + 1 > txsch->schq.max) - return -ENODEV; +static int nix_check_txschq_alloc_req(struct rvu *rvu, int lvl, u16 pcifunc, + struct nix_hw *nix_hw, + struct nix_txsch_alloc_req *req) +{ + struct rvu_hwinfo *hw = rvu->hw; + int schq, req_schq, free_cnt; + struct nix_txsch *txsch; + int link, start, end; + + txsch = &nix_hw->txsch[lvl]; + req_schq = req->schq_contig[lvl] + req->schq[lvl]; - /* init pfvf_map as we store flags */ - if (pfvf_map[schq_base] == U32_MAX) { - pfvf_map[schq_base] = - TXSCH_MAP((pf << RVU_PFVF_PF_SHIFT), 0); - pfvf_map[schq_base + 1] = - TXSCH_MAP((pf << RVU_PFVF_PF_SHIFT), 0); + if (!req_schq) + return 0; - /* Onetime reset for TL1 */ - nix_reset_tx_linkcfg(rvu, blkaddr, - NIX_TXSCH_LVL_TL1, schq_base); - nix_reset_tx_shaping(rvu, blkaddr, - NIX_TXSCH_LVL_TL1, schq_base); + link = nix_get_tx_link(rvu, pcifunc); - nix_reset_tx_linkcfg(rvu, blkaddr, - NIX_TXSCH_LVL_TL1, schq_base + 1); - nix_reset_tx_shaping(rvu, blkaddr, - NIX_TXSCH_LVL_TL1, schq_base + 1); + /* For traffic aggregating scheduler level, one queue is enough */ + if (lvl >= hw->cap.nix_tx_aggr_lvl) { + if (req_schq != 1) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + return 0; } - if (schq_list && schq_cnt) { - schq_list[0] = schq_base; - schq_list[1] = schq_base + 1; - *schq_cnt = 2; + /* Get free SCHQ count and check if request can be accomodated */ + if (hw->cap.nix_fixed_txschq_mapping) { + nix_get_txschq_range(rvu, pcifunc, link, &start, &end); + schq = start + (pcifunc & RVU_PFVF_FUNC_MASK); + if (end <= txsch->schq.max && schq < end && + !test_bit(schq, txsch->schq.bmap)) + free_cnt = 1; + else + free_cnt = 0; + } else { + free_cnt = rvu_rsrc_free_count(&txsch->schq); } + if (free_cnt < req_schq || req_schq > MAX_TXSCHQ_PER_FUNC) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + + /* If contiguous queues are needed, check for availability */ + if (!hw->cap.nix_fixed_txschq_mapping && req->schq_contig[lvl] && + !rvu_rsrc_check_contig(&txsch->schq, req->schq_contig[lvl])) + return NIX_AF_ERR_TLX_ALLOC_FAIL; + return 0; } +static void nix_txsch_alloc(struct rvu *rvu, struct nix_txsch *txsch, + struct nix_txsch_alloc_rsp *rsp, + int lvl, int start, int end) +{ + struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = rsp->hdr.pcifunc; + int idx, schq; + + /* For traffic aggregating levels, queue alloc is based + * on transmit link to which PF_FUNC is mapped to. + */ + if (lvl >= hw->cap.nix_tx_aggr_lvl) { + /* A single TL queue is allocated */ + if (rsp->schq_contig[lvl]) { + rsp->schq_contig[lvl] = 1; + rsp->schq_contig_list[lvl][0] = start; + } + + /* Both contig and non-contig reqs doesn't make sense here */ + if (rsp->schq_contig[lvl]) + rsp->schq[lvl] = 0; + + if (rsp->schq[lvl]) { + rsp->schq[lvl] = 1; + rsp->schq_list[lvl][0] = start; + } + return; + } + + /* Adjust the queue request count if HW supports + * only one queue per level configuration. + */ + if (hw->cap.nix_fixed_txschq_mapping) { + idx = pcifunc & RVU_PFVF_FUNC_MASK; + schq = start + idx; + if (idx >= (end - start) || test_bit(schq, txsch->schq.bmap)) { + rsp->schq_contig[lvl] = 0; + rsp->schq[lvl] = 0; + return; + } + + if (rsp->schq_contig[lvl]) { + rsp->schq_contig[lvl] = 1; + set_bit(schq, txsch->schq.bmap); + rsp->schq_contig_list[lvl][0] = schq; + rsp->schq[lvl] = 0; + } else if (rsp->schq[lvl]) { + rsp->schq[lvl] = 1; + set_bit(schq, txsch->schq.bmap); + rsp->schq_list[lvl][0] = schq; + } + return; + } + + /* Allocate contiguous queue indices requesty first */ + if (rsp->schq_contig[lvl]) { + schq = bitmap_find_next_zero_area(txsch->schq.bmap, + txsch->schq.max, start, + rsp->schq_contig[lvl], 0); + if (schq >= end) + rsp->schq_contig[lvl] = 0; + for (idx = 0; idx < rsp->schq_contig[lvl]; idx++) { + set_bit(schq, txsch->schq.bmap); + rsp->schq_contig_list[lvl][idx] = schq; + schq++; + } + } + + /* Allocate non-contiguous queue indices */ + if (rsp->schq[lvl]) { + idx = 0; + for (schq = start; schq < end; schq++) { + if (!test_bit(schq, txsch->schq.bmap)) { + set_bit(schq, txsch->schq.bmap); + rsp->schq_list[lvl][idx++] = schq; + } + if (idx == rsp->schq[lvl]) + break; + } + /* Update how many were allocated */ + rsp->schq[lvl] = idx; + } +} + int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, struct nix_txsch_alloc_req *req, struct nix_txsch_alloc_rsp *rsp) { + struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; + int link, blkaddr, rc = 0; + int lvl, idx, start, end; struct nix_txsch *txsch; - int lvl, idx, req_schq; struct rvu_pfvf *pfvf; struct nix_hw *nix_hw; - int blkaddr, rc = 0; u32 *pfvf_map; u16 schq; @@ -1151,83 +1253,66 @@ int rvu_mbox_handler_nix_txsch_alloc(struct rvu *rvu, return -EINVAL; mutex_lock(&rvu->rsrc_lock); - for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { - txsch = &nix_hw->txsch[lvl]; - req_schq = req->schq_contig[lvl] + req->schq[lvl]; - pfvf_map = txsch->pfvf_map; - - if (!req_schq) - continue; - /* There are only 28 TL1s */ - if (lvl == NIX_TXSCH_LVL_TL1) { - if (req->schq_contig[lvl] || - req->schq[lvl] > 2 || - rvu_get_tl1_schqs(rvu, blkaddr, - pcifunc, NULL, NULL)) - goto err; - continue; - } - - /* Check if request is valid */ - if (req_schq > MAX_TXSCHQ_PER_FUNC) - goto err; - - /* If contiguous queues are needed, check for availability */ - if (req->schq_contig[lvl] && - !rvu_rsrc_check_contig(&txsch->schq, req->schq_contig[lvl])) - goto err; - - /* Check if full request can be accommodated */ - if (req_schq >= rvu_rsrc_free_count(&txsch->schq)) + /* Check if request is valid as per HW capabilities + * and can be accomodated. + */ + for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { + rc = nix_check_txschq_alloc_req(rvu, lvl, pcifunc, nix_hw, req); + if (rc) goto err; } + /* Allocate requested Tx scheduler queues */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { txsch = &nix_hw->txsch[lvl]; - rsp->schq_contig[lvl] = req->schq_contig[lvl]; pfvf_map = txsch->pfvf_map; - rsp->schq[lvl] = req->schq[lvl]; if (!req->schq[lvl] && !req->schq_contig[lvl]) continue; - /* Handle TL1 specially as it is - * allocation is restricted to 2 TL1's - * per link - */ + rsp->schq[lvl] = req->schq[lvl]; + rsp->schq_contig[lvl] = req->schq_contig[lvl]; - if (lvl == NIX_TXSCH_LVL_TL1) { - rsp->schq_contig[lvl] = 0; - rvu_get_tl1_schqs(rvu, blkaddr, pcifunc, - &rsp->schq_list[lvl][0], - &rsp->schq[lvl]); - continue; + link = nix_get_tx_link(rvu, pcifunc); + + if (lvl >= hw->cap.nix_tx_aggr_lvl) { + start = link; + end = link; + } else if (hw->cap.nix_fixed_txschq_mapping) { + nix_get_txschq_range(rvu, pcifunc, link, &start, &end); + } else { + start = 0; + end = txsch->schq.max; } - /* Alloc contiguous queues first */ - if (req->schq_contig[lvl]) { - schq = rvu_alloc_rsrc_contig(&txsch->schq, - req->schq_contig[lvl]); + nix_txsch_alloc(rvu, txsch, rsp, lvl, start, end); - for (idx = 0; idx < req->schq_contig[lvl]; idx++) { + /* Reset queue config */ + for (idx = 0; idx < req->schq_contig[lvl]; idx++) { + schq = rsp->schq_contig_list[lvl][idx]; + if (!(TXSCH_MAP_FLAGS(pfvf_map[schq]) & + NIX_TXSCHQ_CFG_DONE)) pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); - nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); - nix_reset_tx_shaping(rvu, blkaddr, lvl, schq); - rsp->schq_contig_list[lvl][idx] = schq; - schq++; - } + nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); + nix_reset_tx_shaping(rvu, blkaddr, lvl, schq); } - /* Alloc non-contiguous queues */ for (idx = 0; idx < req->schq[lvl]; idx++) { - schq = rvu_alloc_rsrc(&txsch->schq); - pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); + schq = rsp->schq_list[lvl][idx]; + if (!(TXSCH_MAP_FLAGS(pfvf_map[schq]) & + NIX_TXSCHQ_CFG_DONE)) + pfvf_map[schq] = TXSCH_MAP(pcifunc, 0); nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq); nix_reset_tx_shaping(rvu, blkaddr, lvl, schq); - rsp->schq_list[lvl][idx] = schq; } } + + rsp->aggr_level = hw->cap.nix_tx_aggr_lvl; + rsp->aggr_lvl_rr_prio = TXSCH_TL1_DFLT_RR_PRIO; + rsp->link_cfg_lvl = rvu_read64(rvu, blkaddr, + NIX_AF_PSE_CHANNEL_LEVEL) & 0x01 ? + NIX_TXSCH_LVL_TL3 : NIX_TXSCH_LVL_TL2; goto exit; err: rc = NIX_AF_ERR_TLX_ALLOC_FAIL; @@ -1236,13 +1321,50 @@ exit: return rc; } +static void nix_smq_flush(struct rvu *rvu, int blkaddr, + int smq, u16 pcifunc, int nixlf) +{ + int pf = rvu_get_pf(pcifunc); + u8 cgx_id = 0, lmac_id = 0; + int err, restore_tx_en = 0; + u64 cfg; + + /* enable cgx tx if disabled */ + if (is_pf_cgxmapped(rvu, pf)) { + rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_id, &lmac_id); + restore_tx_en = !cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), + lmac_id, true); + } + + cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(smq)); + /* Do SMQ flush and set enqueue xoff */ + cfg |= BIT_ULL(50) | BIT_ULL(49); + rvu_write64(rvu, blkaddr, NIX_AF_SMQX_CFG(smq), cfg); + + /* Disable backpressure from physical link, + * otherwise SMQ flush may stall. + */ + rvu_cgx_enadis_rx_bp(rvu, pf, false); + + /* Wait for flush to complete */ + 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); + + rvu_cgx_enadis_rx_bp(rvu, pf, true); + /* restore cgx tx state */ + if (restore_tx_en) + cgx_lmac_tx_enable(rvu_cgx_pdata(cgx_id, rvu), lmac_id, false); +} + static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) { int blkaddr, nixlf, lvl, schq, err; struct rvu_hwinfo *hw = rvu->hw; struct nix_txsch *txsch; struct nix_hw *nix_hw; - u64 cfg; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); if (blkaddr < 0) @@ -1275,26 +1397,15 @@ 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; - cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq)); - /* Do SMQ flush and set enqueue xoff */ - cfg |= BIT_ULL(50) | BIT_ULL(49); - rvu_write64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq), cfg); - - /* Wait for flush to complete */ - err = rvu_poll_reg(rvu, blkaddr, - NIX_AF_SMQX_CFG(schq), BIT_ULL(49), true); - if (err) { - dev_err(rvu->dev, - "NIXLF%d: SMQ%d flush failed\n", nixlf, schq); - } + nix_smq_flush(rvu, blkaddr, schq, pcifunc, nixlf); } /* Now free scheduler queues to free pool */ for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) { - /* Free all SCHQ's except TL1 as - * TL1 is shared across all VF's for a RVU PF - */ - if (lvl == NIX_TXSCH_LVL_TL1) + /* TLs above aggregation level are shared across all PF + * and it's VFs, hence skip freeing them. + */ + if (lvl >= hw->cap.nix_tx_aggr_lvl) continue; txsch = &nix_hw->txsch[lvl]; @@ -1302,7 +1413,7 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) if (TXSCH_MAP_FUNC(txsch->pfvf_map[schq]) != pcifunc) continue; rvu_free_rsrc(&txsch->schq, schq); - txsch->pfvf_map[schq] = 0; + txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); } } mutex_unlock(&rvu->rsrc_lock); @@ -1319,13 +1430,12 @@ static int nix_txschq_free(struct rvu *rvu, u16 pcifunc) static int nix_txschq_free_one(struct rvu *rvu, struct nix_txsch_free_req *req) { - int lvl, schq, nixlf, blkaddr, rc; struct rvu_hwinfo *hw = rvu->hw; u16 pcifunc = req->hdr.pcifunc; + int lvl, schq, nixlf, blkaddr; struct nix_txsch *txsch; struct nix_hw *nix_hw; u32 *pfvf_map; - u64 cfg; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); if (blkaddr < 0) @@ -1343,10 +1453,8 @@ static int nix_txschq_free_one(struct rvu *rvu, schq = req->schq; txsch = &nix_hw->txsch[lvl]; - /* Don't allow freeing TL1 */ - if (lvl > NIX_TXSCH_LVL_TL2 || - schq >= txsch->schq.max) - goto err; + if (lvl >= hw->cap.nix_tx_aggr_lvl || schq >= txsch->schq.max) + return 0; pfvf_map = txsch->pfvf_map; mutex_lock(&rvu->rsrc_lock); @@ -1359,24 +1467,12 @@ static int nix_txschq_free_one(struct rvu *rvu, /* Flush if it is a SMQ. Onus of disabling * TL2/3 queue links before SMQ flush is on user */ - if (lvl == NIX_TXSCH_LVL_SMQ) { - cfg = rvu_read64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq)); - /* Do SMQ flush and set enqueue xoff */ - cfg |= BIT_ULL(50) | BIT_ULL(49); - rvu_write64(rvu, blkaddr, NIX_AF_SMQX_CFG(schq), cfg); - - /* Wait for flush to complete */ - rc = rvu_poll_reg(rvu, blkaddr, - NIX_AF_SMQX_CFG(schq), BIT_ULL(49), true); - if (rc) { - dev_err(rvu->dev, - "NIXLF%d: SMQ%d flush failed\n", nixlf, schq); - } - } + if (lvl == NIX_TXSCH_LVL_SMQ) + nix_smq_flush(rvu, blkaddr, schq, pcifunc, nixlf); /* Free the resource */ rvu_free_rsrc(&txsch->schq, schq); - txsch->pfvf_map[schq] = 0; + txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); mutex_unlock(&rvu->rsrc_lock); return 0; err: @@ -1393,8 +1489,8 @@ int rvu_mbox_handler_nix_txsch_free(struct rvu *rvu, return nix_txschq_free_one(rvu, req); } -static bool is_txschq_config_valid(struct rvu *rvu, u16 pcifunc, int blkaddr, - int lvl, u64 reg, u64 regval) +static bool is_txschq_hierarchy_valid(struct rvu *rvu, u16 pcifunc, int blkaddr, + int lvl, u64 reg, u64 regval) { u64 regbase = reg & 0xFFFF; u16 schq, parent; @@ -1431,79 +1527,82 @@ static bool is_txschq_config_valid(struct rvu *rvu, u16 pcifunc, int blkaddr, return true; } -static int -nix_tl1_default_cfg(struct rvu *rvu, u16 pcifunc) +static bool is_txschq_shaping_valid(struct rvu_hwinfo *hw, int lvl, u64 reg) { - u16 schq_list[2], schq_cnt, schq; - int blkaddr, idx, err = 0; - u16 map_func, map_flags; - struct nix_hw *nix_hw; - u64 reg, regval; - u32 *pfvf_map; - - blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); - if (blkaddr < 0) - return NIX_AF_ERR_AF_LF_INVALID; - - nix_hw = get_nix_hw(rvu->hw, blkaddr); - if (!nix_hw) - return -EINVAL; + u64 regbase; - pfvf_map = nix_hw->txsch[NIX_TXSCH_LVL_TL1].pfvf_map; - - mutex_lock(&rvu->rsrc_lock); + if (hw->cap.nix_shaping) + return true; - err = rvu_get_tl1_schqs(rvu, blkaddr, - pcifunc, schq_list, &schq_cnt); - if (err) - goto unlock; - - for (idx = 0; idx < schq_cnt; idx++) { - schq = schq_list[idx]; - map_func = TXSCH_MAP_FUNC(pfvf_map[schq]); - map_flags = TXSCH_MAP_FLAGS(pfvf_map[schq]); + /* If shaping and coloring is not supported, then + * *_CIR and *_PIR registers should not be configured. + */ + regbase = reg & 0xFFFF; - /* check if config is already done or this is pf */ - if (map_flags & NIX_TXSCHQ_TL1_CFG_DONE) - continue; + switch (lvl) { + case NIX_TXSCH_LVL_TL1: + if (regbase == NIX_AF_TL1X_CIR(0)) + return false; + break; + case NIX_TXSCH_LVL_TL2: + if (regbase == NIX_AF_TL2X_CIR(0) || + regbase == NIX_AF_TL2X_PIR(0)) + return false; + break; + case NIX_TXSCH_LVL_TL3: + if (regbase == NIX_AF_TL3X_CIR(0) || + regbase == NIX_AF_TL3X_PIR(0)) + return false; + break; + case NIX_TXSCH_LVL_TL4: + if (regbase == NIX_AF_TL4X_CIR(0) || + regbase == NIX_AF_TL4X_PIR(0)) + return false; + break; + } + return true; +} - /* default configuration */ - reg = NIX_AF_TL1X_TOPOLOGY(schq); - regval = (TXSCH_TL1_DFLT_RR_PRIO << 1); - rvu_write64(rvu, blkaddr, reg, regval); - reg = NIX_AF_TL1X_SCHEDULE(schq); - regval = TXSCH_TL1_DFLT_RR_QTM; - rvu_write64(rvu, blkaddr, reg, regval); - reg = NIX_AF_TL1X_CIR(schq); - regval = 0; - rvu_write64(rvu, blkaddr, reg, regval); +static void nix_tl1_default_cfg(struct rvu *rvu, struct nix_hw *nix_hw, + u16 pcifunc, int blkaddr) +{ + u32 *pfvf_map; + int schq; - map_flags |= NIX_TXSCHQ_TL1_CFG_DONE; - pfvf_map[schq] = TXSCH_MAP(map_func, map_flags); - } -unlock: - mutex_unlock(&rvu->rsrc_lock); - return err; + schq = nix_get_tx_link(rvu, pcifunc); + pfvf_map = nix_hw->txsch[NIX_TXSCH_LVL_TL1].pfvf_map; + /* Skip if PF has already done the config */ + if (TXSCH_MAP_FLAGS(pfvf_map[schq]) & NIX_TXSCHQ_CFG_DONE) + return; + rvu_write64(rvu, blkaddr, NIX_AF_TL1X_TOPOLOGY(schq), + (TXSCH_TL1_DFLT_RR_PRIO << 1)); + rvu_write64(rvu, blkaddr, NIX_AF_TL1X_SCHEDULE(schq), + TXSCH_TL1_DFLT_RR_QTM); + rvu_write64(rvu, blkaddr, NIX_AF_TL1X_CIR(schq), 0x00); + pfvf_map[schq] = TXSCH_SET_FLAG(pfvf_map[schq], NIX_TXSCHQ_CFG_DONE); } int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, struct nix_txschq_config *req, struct msg_rsp *rsp) { - u16 schq, pcifunc = req->hdr.pcifunc; struct rvu_hwinfo *hw = rvu->hw; + u16 pcifunc = req->hdr.pcifunc; u64 reg, regval, schq_regbase; struct nix_txsch *txsch; - u16 map_func, map_flags; struct nix_hw *nix_hw; int blkaddr, idx, err; + int nixlf, schq; u32 *pfvf_map; - int nixlf; if (req->lvl >= NIX_TXSCH_LVL_CNT || req->num_regs > MAX_REGS_PER_MBOX_MSG) return NIX_AF_INVAL_TXSCHQ_CFG; + err = nix_get_nixlf(rvu, pcifunc, &nixlf); + if (err) + return NIX_AF_ERR_AF_LF_INVALID; + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); if (blkaddr < 0) return NIX_AF_ERR_AF_LF_INVALID; @@ -1512,19 +1611,16 @@ int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, if (!nix_hw) return -EINVAL; - nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], pcifunc, 0); - if (nixlf < 0) - return NIX_AF_ERR_AF_LF_INVALID; - txsch = &nix_hw->txsch[req->lvl]; pfvf_map = txsch->pfvf_map; - /* VF is only allowed to trigger - * setting default cfg on TL1 - */ - if (pcifunc & RVU_PFVF_FUNC_MASK && - req->lvl == NIX_TXSCH_LVL_TL1) { - return nix_tl1_default_cfg(rvu, pcifunc); + if (req->lvl >= hw->cap.nix_tx_aggr_lvl && + pcifunc & RVU_PFVF_FUNC_MASK) { + mutex_lock(&rvu->rsrc_lock); + if (req->lvl == NIX_TXSCH_LVL_TL1) + nix_tl1_default_cfg(rvu, nix_hw, pcifunc, blkaddr); + mutex_unlock(&rvu->rsrc_lock); + return 0; } for (idx = 0; idx < req->num_regs; idx++) { @@ -1532,10 +1628,14 @@ int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, regval = req->regval[idx]; schq_regbase = reg & 0xFFFF; - if (!is_txschq_config_valid(rvu, pcifunc, blkaddr, - txsch->lvl, reg, regval)) + if (!is_txschq_hierarchy_valid(rvu, pcifunc, blkaddr, + txsch->lvl, reg, regval)) return NIX_AF_INVAL_TXSCHQ_CFG; + /* Check if shaping and coloring is supported */ + if (!is_txschq_shaping_valid(hw, req->lvl, reg)) + continue; + /* Replace PF/VF visible NIXLF slot with HW NIXLF id */ if (schq_regbase == NIX_AF_SMQX_CFG(0)) { nixlf = rvu_get_lf(rvu, &hw->block[blkaddr], @@ -1544,32 +1644,36 @@ int rvu_mbox_handler_nix_txschq_cfg(struct rvu *rvu, regval |= ((u64)nixlf << 24); } + /* Clear 'BP_ENA' config, if it's not allowed */ + if (!hw->cap.nix_tx_link_bp) { + if (schq_regbase == NIX_AF_TL4X_SDP_LINK_CFG(0) || + (schq_regbase & 0xFF00) == + NIX_AF_TL3_TL2X_LINKX_CFG(0, 0)) + regval &= ~BIT_ULL(13); + } + /* Mark config as done for TL1 by PF */ if (schq_regbase >= NIX_AF_TL1X_SCHEDULE(0) && schq_regbase <= NIX_AF_TL1X_GREEN_BYTES(0)) { schq = TXSCHQ_IDX(reg, TXSCHQ_IDX_SHIFT); - mutex_lock(&rvu->rsrc_lock); - - map_func = TXSCH_MAP_FUNC(pfvf_map[schq]); - map_flags = TXSCH_MAP_FLAGS(pfvf_map[schq]); - - map_flags |= NIX_TXSCHQ_TL1_CFG_DONE; - pfvf_map[schq] = TXSCH_MAP(map_func, map_flags); + pfvf_map[schq] = TXSCH_SET_FLAG(pfvf_map[schq], + NIX_TXSCHQ_CFG_DONE); mutex_unlock(&rvu->rsrc_lock); } - rvu_write64(rvu, blkaddr, reg, regval); - - /* Check for SMQ flush, if so, poll for its completion */ + /* SMQ flush is special hence split register writes such + * that flush first and write rest of the bits later. + */ if (schq_regbase == NIX_AF_SMQX_CFG(0) && (regval & BIT_ULL(49))) { - err = rvu_poll_reg(rvu, blkaddr, - reg, BIT_ULL(49), true); - if (err) - return NIX_AF_SMQ_FLUSH_FAILED; + schq = TXSCHQ_IDX(reg, TXSCHQ_IDX_SHIFT); + nix_smq_flush(rvu, blkaddr, schq, pcifunc, nixlf); + regval &= ~BIT_ULL(49); } + rvu_write64(rvu, blkaddr, reg, regval); } + return 0; } @@ -1849,8 +1953,8 @@ static int nix_setup_mcast(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) { struct nix_txsch *txsch; + int err, lvl, schq; u64 cfg, reg; - int err, lvl; /* Get scheduler queue count of each type and alloc * bitmap for each for alloc/free/attach operations. @@ -1888,7 +1992,8 @@ static int nix_setup_txschq(struct rvu *rvu, struct nix_hw *nix_hw, int blkaddr) sizeof(u32), GFP_KERNEL); if (!txsch->pfvf_map) return -ENOMEM; - memset(txsch->pfvf_map, U8_MAX, txsch->schq.max * sizeof(u32)); + for (schq = 0; schq < txsch->schq.max; schq++) + txsch->pfvf_map[schq] = TXSCH_MAP(0, NIX_TXSCHQ_FREE); } return 0; } @@ -2540,8 +2645,6 @@ linkcfg: cfg &= ~(0xFFFFFULL << 12); cfg |= ((lmac_fifo_len - req->maxlen) / 16) << 12; rvu_write64(rvu, blkaddr, NIX_AF_TX_LINKX_NORM_CREDIT(link), cfg); - rvu_write64(rvu, blkaddr, NIX_AF_TX_LINKX_EXPR_CREDIT(link), cfg); - return 0; } @@ -2682,9 +2785,6 @@ static void nix_link_config(struct rvu *rvu, int blkaddr) rvu_write64(rvu, blkaddr, NIX_AF_TX_LINKX_NORM_CREDIT(link), tx_credits); - rvu_write64(rvu, blkaddr, - NIX_AF_TX_LINKX_EXPR_CREDIT(link), - tx_credits); } } @@ -2696,8 +2796,6 @@ static void nix_link_config(struct rvu *rvu, int blkaddr) tx_credits = (tx_credits << 12) | (0x1FF << 2) | BIT_ULL(1); rvu_write64(rvu, blkaddr, NIX_AF_TX_LINKX_NORM_CREDIT(link), tx_credits); - rvu_write64(rvu, blkaddr, - NIX_AF_TX_LINKX_EXPR_CREDIT(link), tx_credits); } } @@ -2795,13 +2893,25 @@ int rvu_nix_init(struct rvu *rvu) return 0; block = &hw->block[blkaddr]; - /* As per a HW errata in 9xxx A0 silicon, NIX may corrupt - * internal state when conditional clocks are turned off. - * Hence enable them. - */ - if (is_rvu_9xxx_A0(rvu)) + if (is_rvu_96xx_B0(rvu)) { + /* As per a HW errata in 96xx A0/B0 silicon, NIX may corrupt + * internal state when conditional clocks are turned off. + * Hence enable them. + */ rvu_write64(rvu, blkaddr, NIX_AF_CFG, - rvu_read64(rvu, blkaddr, NIX_AF_CFG) | 0x5EULL); + rvu_read64(rvu, blkaddr, NIX_AF_CFG) | 0x40ULL); + + /* Set chan/link to backpressure TL3 instead of TL2 */ + rvu_write64(rvu, blkaddr, NIX_AF_PSE_CHANNEL_LEVEL, 0x01); + + /* Disable SQ manager's sticky mode operation (set TM6 = 0) + * This sticky mode is known to cause SQ stalls when multiple + * SQs are mapped to same SMQ and transmitting pkts at a time. + */ + cfg = rvu_read64(rvu, blkaddr, NIX_AF_SQM_DBG_CTL_STATUS); + cfg &= ~BIT_ULL(15); + rvu_write64(rvu, blkaddr, NIX_AF_SQM_DBG_CTL_STATUS, cfg); + } /* Calibrate X2P bus to check if CGX/LBK links are fine */ err = nix_calibrate_x2p(rvu, blkaddr); @@ -2916,7 +3026,7 @@ void rvu_nix_freemem(struct rvu *rvu) } } -static int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf) +int nix_get_nixlf(struct rvu *rvu, u16 pcifunc, int *nixlf) { struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc); struct rvu_hwinfo *hw = rvu->hw; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index a3b43159be38..f0363d08c36d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -834,11 +834,11 @@ static void npc_load_mkex_profile(struct rvu *rvu, int blkaddr) /* Compare with mkex mod_param name string */ if (mcam_kex->mkex_sign == MKEX_SIGN && !strncmp(mcam_kex->name, mkex_profile, MKEX_NAME_LEN)) { - /* Due to an errata (35786) in A0 pass silicon, + /* Due to an errata (35786) in A0/B0 pass silicon, * parse nibble enable configuration has to be * identical for both Rx and Tx interfaces. */ - if (is_rvu_9xxx_A0(rvu) && + if (is_rvu_96xx_B0(rvu) && mcam_kex->keyx_cfg[NIX_INTF_RX] != mcam_kex->keyx_cfg[NIX_INTF_TX]) goto load_default; @@ -1201,7 +1201,7 @@ int rvu_npc_init(struct rvu *rvu) /* Due to an errata (35786) in A0 pass silicon, parse nibble enable * configuration has to be identical for both Rx and Tx interfaces. */ - if (!is_rvu_9xxx_A0(rvu)) + if (!is_rvu_96xx_B0(rvu)) nibble_ena = (1ULL << 19) - 1; rvu_write64(rvu, blkaddr, NPC_AF_INTFX_KEX_CFG(NIX_INTF_TX), ((keyz & 0x3) << 32) | nibble_ena); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h index 3d7b293c9e1d..be758c19648d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_reg.h @@ -246,6 +246,7 @@ #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_PSE_CHANNEL_LEVEL (0x800) #define NIX_AF_PSE_SHAPER_CFG (0x810) #define NIX_AF_TX_EXPR_CREDIT (0x830) -- cgit v1.2.3-59-g8ed1b From 561e8752a17bbd0a29c770df3d4c9963c41ae873 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Thu, 14 Nov 2019 10:56:30 +0530 Subject: octeontx2-af: Enable broadcast packet replication Ingress packet replication support has been added to 96xx B0 silicon. This patch enables using that feature to replicate ingress broadcast packets to PF and it's VFs. Also fixed below issues - VFs can also install NPC MCAM entry to forward broadcast pkts. Otherwise, unless PF's interface is UP, VFs will not receive bcast packets. - NPC MCAM entry is disabled when PF and all it's VFs are down. - Few corner cases in installing multicast entry list. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 3 + drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 2 + .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 36 +++++---- .../net/ethernet/marvell/octeontx2/af/rvu_npc.c | 87 ++++++++++++---------- 4 files changed, 69 insertions(+), 59 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index bf9272fafd69..3985053fa217 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -64,6 +64,7 @@ static void rvu_setup_hw_capabilities(struct rvu *rvu) hw->cap.nix_fixed_txschq_mapping = false; hw->cap.nix_shaping = true; hw->cap.nix_tx_link_bp = true; + hw->cap.nix_rx_multicast = true; if (is_rvu_96xx_B0(rvu)) { hw->cap.nix_fixed_txschq_mapping = true; @@ -72,6 +73,8 @@ static void rvu_setup_hw_capabilities(struct rvu *rvu) hw->cap.nix_txsch_per_sdp_lmac = 76; hw->cap.nix_shaping = false; hw->cap.nix_tx_link_bp = false; + if (is_rvu_96xx_A0(rvu)) + hw->cap.nix_rx_multicast = false; } } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 000d02bb2ccf..7370864c546c 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -235,6 +235,7 @@ struct hw_cap { bool nix_fixed_txschq_mapping; /* Schq mapping fixed or flexible */ bool nix_shaping; /* Is shaping and coloring supported */ bool nix_tx_link_bp; /* Can link backpressure TL queues ? */ + bool nix_rx_multicast; /* Rx packet replication support */ }; struct rvu_hwinfo { @@ -441,6 +442,7 @@ void rvu_npc_disable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_enable_promisc_entry(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc, int nixlf, u64 chan); +void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc); int rvu_npc_update_rxvlan(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf); void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf); diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 3b32e91482fc..4519d80212ca 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -64,7 +64,6 @@ enum nix_makr_fmt_indexes { struct mce { struct hlist_node node; - u16 idx; u16 pcifunc; }; @@ -1754,7 +1753,7 @@ static int nix_setup_mce(struct rvu *rvu, int mce, u8 op, } static int nix_update_mce_list(struct nix_mce_list *mce_list, - u16 pcifunc, int idx, bool add) + u16 pcifunc, bool add) { struct mce *mce, *tail = NULL; bool delete = false; @@ -1783,7 +1782,6 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list, mce = kzalloc(sizeof(*mce), GFP_KERNEL); if (!mce) return -ENOMEM; - mce->idx = idx; mce->pcifunc = pcifunc; if (!tail) hlist_add_head(&mce->node, &mce_list->head); @@ -1795,12 +1793,12 @@ static int nix_update_mce_list(struct nix_mce_list *mce_list, static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add) { - int err = 0, idx, next_idx, count; + int err = 0, idx, next_idx, last_idx; struct nix_mce_list *mce_list; - struct mce *mce, *next_mce; struct nix_mcast *mcast; struct nix_hw *nix_hw; struct rvu_pfvf *pfvf; + struct mce *mce; int blkaddr; /* Broadcast pkt replication is not needed for AF's VFs, hence skip */ @@ -1832,31 +1830,31 @@ static int nix_update_bcast_mce_list(struct rvu *rvu, u16 pcifunc, bool add) mutex_lock(&mcast->mce_lock); - err = nix_update_mce_list(mce_list, pcifunc, idx, add); + err = nix_update_mce_list(mce_list, pcifunc, add); if (err) goto end; /* Disable MCAM entry in NPC */ - - if (!mce_list->count) + if (!mce_list->count) { + rvu_npc_disable_bcast_entry(rvu, pcifunc); goto end; - count = mce_list->count; + } /* Dump the updated list to HW */ + idx = pfvf->bcast_mce_idx; + last_idx = idx + mce_list->count - 1; hlist_for_each_entry(mce, &mce_list->head, node) { - next_idx = 0; - count--; - if (count) { - next_mce = hlist_entry(mce->node.next, - struct mce, node); - next_idx = next_mce->idx; - } + if (idx > last_idx) + break; + + next_idx = idx + 1; /* EOL should be set in last MCE */ - err = nix_setup_mce(rvu, mce->idx, - NIX_AQ_INSTOP_WRITE, mce->pcifunc, - next_idx, count ? false : true); + err = nix_setup_mce(rvu, idx, NIX_AQ_INSTOP_WRITE, + mce->pcifunc, next_idx, + (next_idx > last_idx) ? true : false); if (err) goto end; + idx++; } end: diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c index f0363d08c36d..40e431debbe9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c @@ -477,68 +477,75 @@ void rvu_npc_install_bcast_match_entry(struct rvu *rvu, u16 pcifunc, { struct npc_mcam *mcam = &rvu->hw->mcam; struct mcam_entry entry = { {0} }; + struct rvu_hwinfo *hw = rvu->hw; struct nix_rx_action action; -#ifdef MCAST_MCE struct rvu_pfvf *pfvf; -#endif int blkaddr, index; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); if (blkaddr < 0) return; - /* Only PF can add a bcast match entry */ - if (pcifunc & RVU_PFVF_FUNC_MASK) + /* Skip LBK VFs */ + if (is_afvf(pcifunc)) + return; + + /* If pkt replication is not supported, + * then only PF is allowed to add a bcast match entry. + */ + if (!hw->cap.nix_rx_multicast && pcifunc & RVU_PFVF_FUNC_MASK) return; -#ifdef MCAST_MCE - pfvf = rvu_get_pfvf(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK); -#endif + /* Get 'pcifunc' of PF device */ + pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK; index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf, NIXLF_BCAST_ENTRY); - /* Check for L2B bit and LMAC channel - * NOTE: Since MKEX default profile(a reduced version intended to - * accommodate more capability but igoring few bits) a stap-gap - * approach. - * Since we care for L2B which by HRM NPC_PARSE_KEX_S at BIT_POS[25], So - * moved to BIT_POS[13], ignoring ERRCODE, ERRLEV as we'll loose out - * on capability features needed for CoS (/from ODP PoV) e.g: VLAN, - * DSCP. - * - * Reduced layout of MKEX default profile - - * Includes following are (i.e.CHAN, L2/3{B/M}, LA, LB, LC, LD): - * - * BIT_POS[31:28] : LD - * BIT_POS[27:24] : LC - * BIT_POS[23:20] : LB - * BIT_POS[19:16] : LA - * BIT_POS[15:12] : L3B, L3M, L2B, L2M - * BIT_POS[11:00] : CHAN - * + /* Match ingress channel */ + entry.kw[0] = chan; + entry.kw_mask[0] = 0xfffull; + + /* Match broadcast MAC address. + * DMAC is extracted at 0th bit of PARSE_KEX::KW1 */ - entry.kw[0] = BIT_ULL(13) | chan; - entry.kw_mask[0] = BIT_ULL(13) | 0xFFFULL; + entry.kw[1] = 0xffffffffffffull; + entry.kw_mask[1] = 0xffffffffffffull; *(u64 *)&action = 0x00; -#ifdef MCAST_MCE - /* Early silicon doesn't support pkt replication, - * so install entry with UCAST action, so that PF - * receives all broadcast packets. - */ - action.op = NIX_RX_ACTIONOP_MCAST; - action.pf_func = pcifunc; - action.index = pfvf->bcast_mce_idx; -#else - action.op = NIX_RX_ACTIONOP_UCAST; - action.pf_func = pcifunc; -#endif + if (!hw->cap.nix_rx_multicast) { + /* Early silicon doesn't support pkt replication, + * so install entry with UCAST action, so that PF + * receives all broadcast packets. + */ + action.op = NIX_RX_ACTIONOP_UCAST; + action.pf_func = pcifunc; + } else { + pfvf = rvu_get_pfvf(rvu, pcifunc); + action.index = pfvf->bcast_mce_idx; + action.op = NIX_RX_ACTIONOP_MCAST; + } entry.action = *(u64 *)&action; npc_config_mcam_entry(rvu, mcam, blkaddr, index, NIX_INTF_RX, &entry, true); } +void rvu_npc_disable_bcast_entry(struct rvu *rvu, u16 pcifunc) +{ + struct npc_mcam *mcam = &rvu->hw->mcam; + int blkaddr, index; + + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0); + if (blkaddr < 0) + return; + + /* Get 'pcifunc' of PF device */ + pcifunc = pcifunc & ~RVU_PFVF_FUNC_MASK; + + index = npc_get_nixlf_mcam_index(mcam, pcifunc, 0, NIXLF_BCAST_ENTRY); + npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false); +} + void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf, int group, int alg_idx, int mcam_index) { -- cgit v1.2.3-59-g8ed1b From ee1e75915f4ff00e125adf98c9684c57cae4a88f Mon Sep 17 00:00:00 2001 From: Geetha sowjanya Date: Thu, 14 Nov 2019 10:56:31 +0530 Subject: octeontx2-af: Support configurable NDC cache way_mask Each of the NIX/NPA LFs can choose which ways of their respective NDC caches should be used to cache their contexts. This enables flexible configurations like disabling caching for a LF, limiting it's context to a certain set of ways etc etc. Separate way_mask for NIX-TX and NIX-RX is not supported. Signed-off-by: Geetha sowjanya Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/mbox.h | 2 ++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 28 +++++++++++++++------- .../net/ethernet/marvell/octeontx2/af/rvu_npa.c | 9 +++++-- 3 files changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index fc9c731856d2..f143d7b31d73 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -361,6 +361,7 @@ struct npa_lf_alloc_req { int node; int aura_sz; /* No of auras */ u32 nr_pools; /* No of pools */ + u64 way_mask; }; struct npa_lf_alloc_rsp { @@ -451,6 +452,7 @@ struct nix_lf_alloc_req { u16 npa_func; u16 sso_func; u64 rx_cfg; /* See NIX_AF_LF(0..127)_RX_CFG */ + u64 way_mask; }; struct nix_lf_alloc_rsp { diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 4519d80212ca..86042a74f6dd 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -378,7 +378,8 @@ static void nix_ctx_free(struct rvu *rvu, struct rvu_pfvf *pfvf) static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr, struct rvu_pfvf *pfvf, int nixlf, - int rss_sz, int rss_grps, int hwctx_size) + int rss_sz, int rss_grps, int hwctx_size, + u64 way_mask) { int err, grp, num_indices; @@ -398,7 +399,8 @@ static int nixlf_rss_ctx_init(struct rvu *rvu, int blkaddr, /* Config full RSS table size, enable RSS and caching */ rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_CFG(nixlf), BIT_ULL(36) | BIT_ULL(4) | - ilog2(num_indices / MAX_RSS_INDIR_TBL_SIZE)); + ilog2(num_indices / MAX_RSS_INDIR_TBL_SIZE) | + way_mask << 20); /* Config RSS group offset and sizes */ for (grp = 0; grp < rss_grps; grp++) rvu_write64(rvu, blkaddr, NIX_AF_LFX_RSS_GRPX(nixlf, grp), @@ -741,6 +743,9 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, if (!req->rq_cnt || !req->sq_cnt || !req->cq_cnt) return NIX_AF_ERR_PARAM; + if (req->way_mask) + req->way_mask &= 0xFFFF; + pfvf = rvu_get_pfvf(rvu, pcifunc); blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); if (!pfvf->nixlf || blkaddr < 0) @@ -806,7 +811,7 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, (u64)pfvf->rq_ctx->iova); /* Set caching and queue count in HW */ - cfg = BIT_ULL(36) | (req->rq_cnt - 1); + cfg = BIT_ULL(36) | (req->rq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_CFG(nixlf), cfg); /* Alloc NIX SQ HW context memory and config the base */ @@ -821,7 +826,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf), (u64)pfvf->sq_ctx->iova); - cfg = BIT_ULL(36) | (req->sq_cnt - 1); + + cfg = BIT_ULL(36) | (req->sq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_CFG(nixlf), cfg); /* Alloc NIX CQ HW context memory and config the base */ @@ -836,13 +842,14 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf), (u64)pfvf->cq_ctx->iova); - cfg = BIT_ULL(36) | (req->cq_cnt - 1); + + cfg = BIT_ULL(36) | (req->cq_cnt - 1) | req->way_mask << 20; rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_CFG(nixlf), cfg); /* Initialize receive side scaling (RSS) */ hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF); - err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, - req->rss_sz, req->rss_grps, hwctx_size); + err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz, + req->rss_grps, hwctx_size, req->way_mask); if (err) goto free_mem; @@ -856,7 +863,9 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf), (u64)pfvf->cq_ints_ctx->iova); - rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), BIT_ULL(36)); + + rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_CFG(nixlf), + BIT_ULL(36) | req->way_mask << 20); /* Alloc memory for QINT's HW contexts */ cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2); @@ -868,7 +877,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu, rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf), (u64)pfvf->nix_qints_ctx->iova); - rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), BIT_ULL(36)); + rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_CFG(nixlf), + BIT_ULL(36) | req->way_mask << 20); /* Setup VLANX TPID's. * Use VLAN1 for 802.1Q diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index e702a1159de9..a8f9376f6a0b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -289,6 +289,9 @@ int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu, req->aura_sz == NPA_AURA_SZ_0 || !req->nr_pools) return NPA_AF_ERR_PARAM; + if (req->way_mask) + req->way_mask &= 0xFFFF; + pfvf = rvu_get_pfvf(rvu, pcifunc); blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, pcifunc); if (!pfvf->npalf || blkaddr < 0) @@ -345,7 +348,8 @@ int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu, /* Clear way partition mask and set aura offset to '0' */ cfg &= ~(BIT_ULL(34) - 1); /* Set aura size & enable caching of contexts */ - cfg |= (req->aura_sz << 16) | BIT_ULL(34); + cfg |= (req->aura_sz << 16) | BIT_ULL(34) | req->way_mask; + rvu_write64(rvu, blkaddr, NPA_AF_LFX_AURAS_CFG(npalf), cfg); /* Configure aura HW context's base */ @@ -353,7 +357,8 @@ int rvu_mbox_handler_npa_lf_alloc(struct rvu *rvu, (u64)pfvf->aura_ctx->iova); /* Enable caching of qints hw context */ - rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_CFG(npalf), BIT_ULL(36)); + rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_CFG(npalf), + BIT_ULL(36) | req->way_mask << 20); rvu_write64(rvu, blkaddr, NPA_AF_LFX_QINTS_BASE(npalf), (u64)pfvf->npa_qints_ctx->iova); -- cgit v1.2.3-59-g8ed1b From a02917663112b3569fd01dd90c2502802c5ed3cf Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Thu, 14 Nov 2019 10:56:32 +0530 Subject: octeontx2-af: Add option to disable dynamic entry caching in NDC A config option is added to disable caching of dynamic entries like SQEs and stack pages. Also locks down all HW contexts in NDC, preventing them from being evicted. This option is useful when the queue count is large and there are huge NDC cache misses. It's trade off between SQ context misses and dynamically changing entries like SQE and stack page pointers. Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/Kconfig | 9 +++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 64 +++++++++++++++++++++- .../net/ethernet/marvell/octeontx2/af/rvu_npa.c | 42 ++++++++++++++ 3 files changed, 112 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/Kconfig b/drivers/net/ethernet/marvell/octeontx2/Kconfig index 711ada7139d3..fb34fbd62088 100644 --- a/drivers/net/ethernet/marvell/octeontx2/Kconfig +++ b/drivers/net/ethernet/marvell/octeontx2/Kconfig @@ -16,3 +16,12 @@ config OCTEONTX2_AF Unit's admin function manager which manages all RVU HW resources and provides a medium to other PF/VFs to configure HW. Should be enabled for other RVU device drivers to work. + +config NDC_DIS_DYNAMIC_CACHING + bool "Disable caching of dynamic entries in NDC" + depends on OCTEONTX2_AF + default n + ---help--- + This config option disables caching of dynamic entries such as NIX SQEs + , NPA stack pages etc in NDC. Also locks down NIX SQ/CQ/RQ/RSS and + NPA Aura/Pool contexts. diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 86042a74f6dd..63190b89f709 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -661,6 +661,21 @@ static int rvu_nix_aq_enq_inst(struct rvu *rvu, struct nix_aq_enq_req *req, return 0; } +static const char *nix_get_ctx_name(int ctype) +{ + switch (ctype) { + case NIX_AQ_CTYPE_CQ: + return "CQ"; + case NIX_AQ_CTYPE_SQ: + return "SQ"; + case NIX_AQ_CTYPE_RQ: + return "RQ"; + case NIX_AQ_CTYPE_RSS: + return "RSS"; + } + return ""; +} + static int nix_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req) { struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, req->hdr.pcifunc); @@ -705,21 +720,60 @@ static int nix_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req) if (rc) { err = rc; dev_err(rvu->dev, "Failed to disable %s:%d context\n", - (req->ctype == NIX_AQ_CTYPE_CQ) ? - "CQ" : ((req->ctype == NIX_AQ_CTYPE_RQ) ? - "RQ" : "SQ"), qidx); + nix_get_ctx_name(req->ctype), qidx); } } return err; } +#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING +static int nix_lf_hwctx_lockdown(struct rvu *rvu, struct nix_aq_enq_req *req) +{ + struct nix_aq_enq_req lock_ctx_req; + int err; + + if (req->op != NIX_AQ_INSTOP_INIT) + return 0; + + if (req->ctype == NIX_AQ_CTYPE_MCE || + req->ctype == NIX_AQ_CTYPE_DYNO) + return 0; + + memset(&lock_ctx_req, 0, sizeof(struct nix_aq_enq_req)); + lock_ctx_req.hdr.pcifunc = req->hdr.pcifunc; + lock_ctx_req.ctype = req->ctype; + lock_ctx_req.op = NIX_AQ_INSTOP_LOCK; + lock_ctx_req.qidx = req->qidx; + err = rvu_nix_aq_enq_inst(rvu, &lock_ctx_req, NULL); + if (err) + dev_err(rvu->dev, + "PFUNC 0x%x: Failed to lock NIX %s:%d context\n", + req->hdr.pcifunc, + nix_get_ctx_name(req->ctype), req->qidx); + return err; +} + +int rvu_mbox_handler_nix_aq_enq(struct rvu *rvu, + struct nix_aq_enq_req *req, + struct nix_aq_enq_rsp *rsp) +{ + int err; + + err = rvu_nix_aq_enq_inst(rvu, req, rsp); + if (!err) + err = nix_lf_hwctx_lockdown(rvu, req); + return err; +} +#else + int rvu_mbox_handler_nix_aq_enq(struct rvu *rvu, struct nix_aq_enq_req *req, struct nix_aq_enq_rsp *rsp) { return rvu_nix_aq_enq_inst(rvu, req, rsp); } +#endif int rvu_mbox_handler_nix_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req, @@ -2871,6 +2925,10 @@ static int nix_aq_init(struct rvu *rvu, struct rvu_block *block) /* Do not bypass NDC cache */ cfg = rvu_read64(rvu, block->addr, NIX_AF_NDC_CFG); cfg &= ~0x3FFEULL; +#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING + /* Disable caching of SQB aka SQEs */ + cfg |= 0x04ULL; +#endif rvu_write64(rvu, block->addr, NIX_AF_NDC_CFG, cfg); /* Result structure can be followed by RQ/SQ/CQ context at diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c index a8f9376f6a0b..6e7c7f459f74 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npa.c @@ -241,12 +241,50 @@ static int npa_lf_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req) return err; } +#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING +static int npa_lf_hwctx_lockdown(struct rvu *rvu, struct npa_aq_enq_req *req) +{ + struct npa_aq_enq_req lock_ctx_req; + int err; + + if (req->op != NPA_AQ_INSTOP_INIT) + return 0; + + memset(&lock_ctx_req, 0, sizeof(struct npa_aq_enq_req)); + lock_ctx_req.hdr.pcifunc = req->hdr.pcifunc; + lock_ctx_req.ctype = req->ctype; + lock_ctx_req.op = NPA_AQ_INSTOP_LOCK; + lock_ctx_req.aura_id = req->aura_id; + err = rvu_npa_aq_enq_inst(rvu, &lock_ctx_req, NULL); + if (err) + dev_err(rvu->dev, + "PFUNC 0x%x: Failed to lock NPA context %s:%d\n", + req->hdr.pcifunc, + (req->ctype == NPA_AQ_CTYPE_AURA) ? + "Aura" : "Pool", req->aura_id); + return err; +} + +int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu, + struct npa_aq_enq_req *req, + struct npa_aq_enq_rsp *rsp) +{ + int err; + + err = rvu_npa_aq_enq_inst(rvu, req, rsp); + if (!err) + err = npa_lf_hwctx_lockdown(rvu, req); + return err; +} +#else + int rvu_mbox_handler_npa_aq_enq(struct rvu *rvu, struct npa_aq_enq_req *req, struct npa_aq_enq_rsp *rsp) { return rvu_npa_aq_enq_inst(rvu, req, rsp); } +#endif int rvu_mbox_handler_npa_hwctx_disable(struct rvu *rvu, struct hwctx_disable_req *req, @@ -427,6 +465,10 @@ static int npa_aq_init(struct rvu *rvu, struct rvu_block *block) /* Do not bypass NDC cache */ cfg = rvu_read64(rvu, block->addr, NPA_AF_NDC_CFG); cfg &= ~0x03DULL; +#ifdef CONFIG_NDC_DIS_DYNAMIC_CACHING + /* Disable caching of stack pages */ + cfg |= 0x10ULL; +#endif rvu_write64(rvu, block->addr, NPA_AF_NDC_CFG, cfg); /* Result structure can be followed by Aura/Pool context at -- cgit v1.2.3-59-g8ed1b From a7faa68b4e7feb3cd4dc746d1cb91217641246d3 Mon Sep 17 00:00:00 2001 From: Subbaraya Sundeep Date: Thu, 14 Nov 2019 10:56:33 +0530 Subject: octeontx2-af: Start/Stop traffic in CGX along with NPC Traffic for a CGX mapped NIXLF can be stopped by disabling entries in NPC MCAM or by configuring CGX and mailbox messages exist for the two options. If traffic is stopped at CGX then VFs of that PF are also effected hence CGX traffic should be started/stopped by tracking all the users of it. This patch implements that CGX users tracking. CGX is also configured along with NPC if required. Also removed a check which mandates even number of LBK VFs. Signed-off-by: Subbaraya Sundeep Signed-off-by: Sunil Goutham Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu.c | 12 ------ drivers/net/ethernet/marvell/octeontx2/af/rvu.h | 5 +++ .../net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 49 ++++++++++++++++++++++ .../net/ethernet/marvell/octeontx2/af/rvu_nix.c | 13 +++++- 4 files changed, 65 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c index 3985053fa217..5c190c3ce898 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c @@ -2364,18 +2364,6 @@ static int rvu_enable_sriov(struct rvu *rvu) if (vfs > chans) vfs = chans; - /* AF's VFs work in pairs and talk over consecutive loopback channels. - * Thus we want to enable maximum even number of VFs. In case - * odd number of VFs are available then the last VF on the list - * remains disabled. - */ - if (vfs & 0x1) { - dev_warn(&pdev->dev, - "Number of VFs should be even. Enabling %d out of %d.\n", - vfs - 1, vfs); - vfs--; - } - if (!vfs) return 0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h index 7370864c546c..b252d8683aa7 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h @@ -179,6 +179,9 @@ struct rvu_pfvf { struct mcam_entry entry; int rxvlan_index; bool rxvlan; + + bool cgx_in_use; /* this PF/VF using CGX? */ + int cgx_users; /* number of cgx users - used only by PFs */ }; struct nix_txsch { @@ -306,6 +309,7 @@ struct rvu { struct workqueue_struct *cgx_evh_wq; spinlock_t cgx_evq_lock; /* cgx event queue lock */ struct list_head cgx_evq_head; /* cgx event queue head */ + struct mutex cgx_cfg_lock; /* serialize cgx configuration */ char mkex_pfl_name[MKEX_NAME_LEN]; /* Configured MKEX profile name */ @@ -410,6 +414,7 @@ int rvu_cgx_exit(struct rvu *rvu); void *rvu_cgx_pdata(u8 cgx_id, struct rvu *rvu); int rvu_cgx_config_rxtx(struct rvu *rvu, u16 pcifunc, bool start); void rvu_cgx_enadis_rx_bp(struct rvu *rvu, int pf, bool enable); +int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start); int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, int index, int rxtxflag, u64 *stat); /* NPA APIs */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 7e110b772aa5..0bbb2eb1446e 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -308,6 +308,8 @@ int rvu_cgx_init(struct rvu *rvu) if (err) return err; + mutex_init(&rvu->cgx_cfg_lock); + /* Ensure event handler registration is completed, before * we turn on the links */ @@ -638,3 +640,50 @@ int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, return 0; } + +int rvu_cgx_start_stop_io(struct rvu *rvu, u16 pcifunc, bool start) +{ + struct rvu_pfvf *parent_pf, *pfvf; + int cgx_users, err = 0; + + if (!is_pf_cgxmapped(rvu, rvu_get_pf(pcifunc))) + return 0; + + parent_pf = &rvu->pf[rvu_get_pf(pcifunc)]; + pfvf = rvu_get_pfvf(rvu, pcifunc); + + mutex_lock(&rvu->cgx_cfg_lock); + + if (start && pfvf->cgx_in_use) + goto exit; /* CGX is already started hence nothing to do */ + if (!start && !pfvf->cgx_in_use) + goto exit; /* CGX is already stopped hence nothing to do */ + + if (start) { + cgx_users = parent_pf->cgx_users; + parent_pf->cgx_users++; + } else { + parent_pf->cgx_users--; + cgx_users = parent_pf->cgx_users; + } + + /* Start CGX when first of all NIXLFs is started. + * Stop CGX when last of all NIXLFs is stopped. + */ + if (!cgx_users) { + err = rvu_cgx_config_rxtx(rvu, pcifunc & ~RVU_PFVF_FUNC_MASK, + start); + if (err) { + dev_err(rvu->dev, "Unable to %s CGX\n", + start ? "start" : "stop"); + /* Revert the usage count in case of error */ + parent_pf->cgx_users = start ? parent_pf->cgx_users - 1 + : parent_pf->cgx_users + 1; + goto exit; + } + } + pfvf->cgx_in_use = start; +exit: + mutex_unlock(&rvu->cgx_cfg_lock); + return err; +} diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 63190b89f709..8a59f7d53fbf 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -194,6 +194,11 @@ static int nix_interface_init(struct rvu *rvu, u16 pcifunc, int type, int nixlf) break; case NIX_INTF_TYPE_LBK: vf = (pcifunc & RVU_PFVF_FUNC_MASK) - 1; + + /* Note that AF's VFs work in pairs and talk over consecutive + * loopback channels.Therefore if odd number of AF VFs are + * enabled then the last VF remains with no pair. + */ pfvf->rx_chan_base = NIX_CHAN_LBK_CHX(0, vf); pfvf->tx_chan_base = vf & 0x1 ? NIX_CHAN_LBK_CHX(0, vf - 1) : NIX_CHAN_LBK_CHX(0, vf + 1); @@ -3120,7 +3125,8 @@ int rvu_mbox_handler_nix_lf_start_rx(struct rvu *rvu, struct msg_req *req, return err; rvu_npc_enable_default_entries(rvu, pcifunc, nixlf); - return 0; + + return rvu_cgx_start_stop_io(rvu, pcifunc, true); } int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, @@ -3134,7 +3140,8 @@ int rvu_mbox_handler_nix_lf_stop_rx(struct rvu *rvu, struct msg_req *req, return err; rvu_npc_disable_default_entries(rvu, pcifunc, nixlf); - return 0; + + return rvu_cgx_start_stop_io(rvu, pcifunc, false); } void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf) @@ -3150,6 +3157,8 @@ void rvu_nix_lf_teardown(struct rvu *rvu, u16 pcifunc, int blkaddr, int nixlf) nix_rx_sync(rvu, blkaddr); nix_txschq_free(rvu, pcifunc); + rvu_cgx_start_stop_io(rvu, pcifunc, false); + if (pfvf->sq_ctx) { ctx_req.ctype = NIX_AQ_CTYPE_SQ; err = nix_lf_hwctx_disable(rvu, &ctx_req); -- cgit v1.2.3-59-g8ed1b From f4fe2e53349f1072d33c69f484dbf9d77bb8f45a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 13 Nov 2019 12:26:44 -0800 Subject: ath10k: Revert "ath10k: add cleanup in ath10k_sta_state()" This reverts commit 334f5b61a6f29834e881923b98d1e27e5ce9620d. This caused ath10k_snoc on Qualcomm MSM8998, SDM845 and QCS404 platforms to trigger an assert in the firmware: err_qdi.c:456:EF:wlan_process:1:cmnos_thread.c:3900:Asserted in wlan_vdev.c:_wlan_vdev_up:3219 Revert the offending commit for now. Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 5e3450cfb07b..83cc8778ca1e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6639,12 +6639,8 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, spin_unlock_bh(&ar->data_lock); - if (!sta->tdls) { - ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); - ath10k_mac_dec_num_stations(arvif, sta); - kfree(arsta->tx_stats); + if (!sta->tdls) goto exit; - } ret = ath10k_wmi_update_fw_tdls_state(ar, arvif->vdev_id, WMI_TDLS_ENABLE_ACTIVE); -- cgit v1.2.3-59-g8ed1b From b70b3a36ec33a2c8d3292f3b33fe2047a8f57b9a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 13 Nov 2019 15:35:58 -0800 Subject: ath10k: qmi: Sleep for a while before assigning MSA memory Unless we sleep for a while before transitioning the MSA memory to WLAN the MPSS.AT.4.0.c2-01184-SDM845_GEN_PACK-1 firmware triggers a security violation fairly reliably. Unforutnately recovering from this failure always results in the entire system freezing. Signed-off-by: Bjorn Andersson Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/qmi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index 637f83ef65f8..a0ba07b85362 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -773,6 +773,13 @@ static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi) if (ret) return; + /* + * HACK: sleep for a while inbetween receiving the msa info response + * and the XPU update to prevent SDM845 from crashing due to a security + * violation, when running MPSS.AT.4.0.c2-01184-SDM845_GEN_PACK-1. + */ + msleep(20); + ret = ath10k_qmi_setup_msa_permissions(qmi); if (ret) return; -- cgit v1.2.3-59-g8ed1b From 3c33a11a291303db4b96b5e39dfd54831937bfa5 Mon Sep 17 00:00:00 2001 From: Eduardo Abinader Date: Fri, 8 Nov 2019 11:10:46 +0200 Subject: wcn36xx: fix typo Signed-off-by: Eduardo Abinader Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wcn36xx/hal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index 8abda2760e04..6ba0fd57c951 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -2091,7 +2091,7 @@ struct wcn36xx_hal_set_bss_key_rsp_msg { /* * This is used configure the key information on a given station. * When the sec_type is WEP40 or WEP104, the def_wep_idx is used to locate - * a preconfigured key from a BSS the station assoicated with; otherwise + * a preconfigured key from a BSS the station associated with; otherwise * a new key descriptor is created based on the key field. */ struct wcn36xx_hal_set_sta_key_req_msg { -- cgit v1.2.3-59-g8ed1b From bb99ff9baa02beb9216c86678999342197c849cc Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 15 Nov 2019 09:27:25 +0200 Subject: iwlwifi: mvm: fix support for single antenna diversity When the single antenna diversity support was sent upstream, only some definitions were sent, due to a bad revert. Fix this by adding the actual code. Fixes: 5952e0ec3f05 ("iwlwifi: mvm: add support for single antenna diversity") Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index d9eb2b286438..c59cbb8cbdd7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -514,6 +514,18 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) struct iwl_phy_cfg_cmd phy_cfg_cmd; enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; + if (iwl_mvm_has_unified_ucode(mvm) && + !mvm->trans->cfg->tx_with_siso_diversity) { + return 0; + } else if (mvm->trans->cfg->tx_with_siso_diversity) { + /* + * TODO: currently we don't set the antenna but letting the NIC + * to decide which antenna to use. This should come from BIOS. + */ + phy_cfg_cmd.phy_cfg = + cpu_to_le32(FW_PHY_CFG_CHAIN_SAD_ENABLED); + } + /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); @@ -1344,12 +1356,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ret = iwl_send_phy_db_data(mvm->phy_db); if (ret) goto error; - - ret = iwl_send_phy_cfg_cmd(mvm); - if (ret) - goto error; } + ret = iwl_send_phy_cfg_cmd(mvm); + if (ret) + goto error; + ret = iwl_mvm_send_bt_init_conf(mvm); if (ret) goto error; -- cgit v1.2.3-59-g8ed1b From d923b020dcecb70687391fd311fc0a8affc37857 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 15 Nov 2019 09:27:28 +0200 Subject: iwlwifi: mvm: remove else-if in iwl_send_phy_cfg_cmd() We return in the if block, so it's unnecessary to have an else statement. Remove it. Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index c59cbb8cbdd7..66e14f590b6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -515,9 +515,10 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) enum iwl_ucode_type ucode_type = mvm->fwrt.cur_fw_img; if (iwl_mvm_has_unified_ucode(mvm) && - !mvm->trans->cfg->tx_with_siso_diversity) { + !mvm->trans->cfg->tx_with_siso_diversity) return 0; - } else if (mvm->trans->cfg->tx_with_siso_diversity) { + + if (mvm->trans->cfg->tx_with_siso_diversity) { /* * TODO: currently we don't set the antenna but letting the NIC * to decide which antenna to use. This should come from BIOS. -- cgit v1.2.3-59-g8ed1b From 222ccf5e9f3779482ee1a6eb37ba8ce2c0519089 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Fri, 15 Nov 2019 09:27:31 +0200 Subject: iwlwifi: nvm: update iwl_uhb_nvm_channels Change the UHB channels to start from 1 to match the specs (11ax Draft 5.0). Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index b0a0901ce0f3..1e240a2a8329 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -156,11 +156,10 @@ static const u16 iwl_uhb_nvm_channels[] = { 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165, 169, 173, 177, 181, /* 6-7 GHz */ - 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233, 237, 241, - 245, 249, 253, 257, 261, 265, 269, 273, 277, 281, 285, 289, 293, 297, - 301, 305, 309, 313, 317, 321, 325, 329, 333, 337, 341, 345, 349, 353, - 357, 361, 365, 369, 373, 377, 381, 385, 389, 393, 397, 401, 405, 409, - 413, 417, 421 + 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, + 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, + 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, + 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 }; #define IWL_NVM_NUM_CHANNELS ARRAY_SIZE(iwl_nvm_channels) -- cgit v1.2.3-59-g8ed1b From 686d5c5708c97c7bddd2c4af61e3d9ebcdcfe7d9 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 15 Nov 2019 09:27:34 +0200 Subject: iwlwifi: mvm: in VHT connection use only VHT capabilities mac80211 limits amsdu size to the minimum of HT and VHT capabilities but since in a VHT connection we don't transmit HT frames we can discard HT limits. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 ++ drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 098d48153a38..10a08fae2942 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -384,7 +384,7 @@ out: rcu_read_unlock(); } -static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta) +u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta) { const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 42d525e46e80..0a442cb7f223 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1533,6 +1533,8 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); int i; + sta->max_amsdu_len = rs_fw_get_max_amsdu_len(sta); + /* * In case TLC offload is not active amsdu_enabled is either 0xFFFF * or 0, since there is no per-TID alg. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 7cd62c5622ce..32104c9f8f5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -452,4 +452,6 @@ int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, bool enable); void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); + +u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta); #endif /* __rs__ */ -- cgit v1.2.3-59-g8ed1b From bc4f65b2fc771a9704493d4115851f00a0eb3b15 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 15 Nov 2019 09:27:37 +0200 Subject: iwlwifi: pcie: make iwl_pcie_gen2_update_byte_tbl static It is called within tx-gen2.c only. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 3 --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 1047d48beaa5..fcef2806ebb1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -702,9 +702,6 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs); void iwl_trans_pcie_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr); void iwl_trans_pcie_tx_reset(struct iwl_trans *trans); -void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq, u16 byte_cnt, - int num_tbs); static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_trans *trans, void *_tfd, u8 idx) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 8894027429d6..1c69a2ddd7c7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -86,9 +86,9 @@ void iwl_pcie_gen2_tx_stop(struct iwl_trans *trans) /* * iwl_pcie_txq_update_byte_tbl - Set up entry in Tx byte-count array */ -void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, - struct iwl_txq *txq, u16 byte_cnt, - int num_tbs) +static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, + struct iwl_txq *txq, u16 byte_cnt, + int num_tbs) { struct iwlagn_scd_bc_tbl *scd_bc_tbl = txq->bc_tbl.addr; struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie); -- cgit v1.2.3-59-g8ed1b From 4d75a9eba2e7ff4de28436b5fdba2f17087a50da Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Fri, 15 Nov 2019 09:27:40 +0200 Subject: iwlwifi: dbg_ini: support dump collection upon assert during D3 add assert time point in the D3 resume flow in case there was an assert during D3. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 1a9d83d6230f..43ebb2149b63 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1939,6 +1939,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) if (iwl_mvm_check_rt_status(mvm, vif)) { set_bit(STATUS_FW_ERROR, &mvm->trans->status); iwl_mvm_dump_nic_error_log(mvm); + iwl_dbg_tlv_time_point(&mvm->fwrt, + IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, false, 0); ret = 1; -- cgit v1.2.3-59-g8ed1b From 508127b7629e1b5d01a44743e2ea1a9370b643ec Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Fri, 15 Nov 2019 09:27:42 +0200 Subject: iwlwifi: scan: create function for scan scheduling params In the next patch, this code will be used from different places. As preparation export this code into function. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 61 +++++++++++++++++---------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 0de5cf1c519d..29c636761f55 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1509,6 +1509,39 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, return flags; } +static int +iwl_mvm_fill_scan_sched_params(struct iwl_mvm_scan_params *params, + struct iwl_scan_umac_schedule *schedule, + __le16 *delay) +{ + int i; + if (WARN_ON(!params->n_scan_plans || + params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) + return -EINVAL; + + for (i = 0; i < params->n_scan_plans; i++) { + struct cfg80211_sched_scan_plan *scan_plan = + ¶ms->scan_plans[i]; + + schedule[i].iter_count = scan_plan->iterations; + schedule[i].interval = + cpu_to_le16(scan_plan->interval); + } + + /* + * If the number of iterations of the last scan plan is set to + * zero, it should run infinitely. However, this is not always the case. + * For example, when regular scan is requested the driver sets one scan + * plan with one iteration. + */ + if (!schedule[params->n_scan_plans - 1].iter_count) + schedule[params->n_scan_plans - 1].iter_count = 0xff; + + *delay = cpu_to_le16(params->delay); + + return 0; +} + static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_scan_params *params, int type) @@ -1522,7 +1555,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, (struct iwl_scan_req_umac_tail_v2 *)sec_part; struct iwl_scan_req_umac_tail_v1 *tail_v1; struct iwl_ssid_ie *direct_scan; - int uid, i; + int uid, ret = 0; u32 ssid_bitmap = 0; u8 channel_flags = 0; u16 gen_flags; @@ -1532,9 +1565,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, lockdep_assert_held(&mvm->mutex); - if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) - return -EINVAL; - uid = iwl_mvm_scan_uid_by_status(mvm, 0); if (uid < 0) return uid; @@ -1583,25 +1613,10 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, chan_param->flags = channel_flags; chan_param->count = params->n_channels; - for (i = 0; i < params->n_scan_plans; i++) { - struct cfg80211_sched_scan_plan *scan_plan = - ¶ms->scan_plans[i]; - - tail_v2->schedule[i].iter_count = scan_plan->iterations; - tail_v2->schedule[i].interval = - cpu_to_le16(scan_plan->interval); - } - - /* - * If the number of iterations of the last scan plan is set to - * zero, it should run infinitely. However, this is not always the case. - * For example, when regular scan is requested the driver sets one scan - * plan with one iteration. - */ - if (!tail_v2->schedule[i - 1].iter_count) - tail_v2->schedule[i - 1].iter_count = 0xff; - - tail_v2->delay = cpu_to_le16(params->delay); + ret = iwl_mvm_fill_scan_sched_params(params, tail_v2->schedule, + &tail_v2->delay); + if (ret) + return ret; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { tail_v2->preq = params->preq; -- cgit v1.2.3-59-g8ed1b From 51698293e3230796e38cd92c49e69650cacf66e5 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Fri, 15 Nov 2019 09:27:45 +0200 Subject: iwlwifi: scan: Create function to build scan cmd Currently, the code to build scan cmd is duplicated in iwl_mvm_reg_scan_start and iwl_mvm_sched_scan_start. Create a function to build this command, and call the function instead. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 32 ++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 29c636761f55..3e5455cef0ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1736,6 +1736,20 @@ static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, } } +static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct iwl_host_cmd *hcmd, + struct iwl_mvm_scan_params *params, + int type) +{ + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { + hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); + return iwl_mvm_scan_umac(mvm, vif, params, type); + } + hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; + return iwl_mvm_scan_lmac(mvm, vif, params); +} + int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) @@ -1793,14 +1807,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, - IWL_MVM_SCAN_REGULAR); - } else { - hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; - ret = iwl_mvm_scan_lmac(mvm, vif, ¶ms); - } + ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, + IWL_MVM_SCAN_REGULAR); if (ret) return ret; @@ -1898,13 +1906,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - ret = iwl_mvm_scan_umac(mvm, vif, ¶ms, type); - } else { - hcmd.id = SCAN_OFFLOAD_REQUEST_CMD; - ret = iwl_mvm_scan_lmac(mvm, vif, ¶ms); - } + ret = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 19ff9b2c6e3cdf1363ef0ec58e2089d750594d60 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Fri, 15 Nov 2019 09:27:48 +0200 Subject: iwlwifi: scan: adapt the code to use api ver 11 FW scan api ver 11 adds support for some new features, in this version the fw did also some cleanup in the api, which causes the driver not to be able to use the current scan req struct. Therefore, in this patch the driver has new version for the scan command code Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 157 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/img.h | 18 ++ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 9 + drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 202 ++++++++++++++++++++++- 4 files changed, 380 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index c0750ced5ac2..fa455d854d53 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -70,6 +70,9 @@ /* Max number of IEs for direct SSID scans in a command */ #define PROBE_OPTION_MAX 20 +#define SCAN_SHORT_SSID_MAX_SIZE 8 +#define SCAN_BSSID_MAX_SIZE 16 + /** * struct iwl_ssid_ie - directed scan network information element * @@ -278,6 +281,9 @@ enum iwl_scan_channel_flags { IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE = BIT(1), IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2), IWL_SCAN_CHANNEL_FLAG_EBS_FRAG = BIT(3), + IWL_SCAN_CHANNEL_FLAG_FORCE_EBS = BIT(4), + IWL_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER = BIT(5), + IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER = BIT(6), }; /* struct iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S @@ -637,6 +643,40 @@ enum iwl_umac_scan_general_flags2 { IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER = BIT(1), }; +/** + * enum iwl_umac_scan_general_flags_v22 - UMAC scan general flags ver 2 + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC: periodic or scheduled + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL: pass all probe responses and beacons + * during scan iterations + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE: send complete notification + * on every iteration instead of only once after the last iteration + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1: fragmented scan LMAC1 + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2: fragmented scan LMAC2 + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH: does this scan check for profile matching + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS: use all valid chains for RX + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL: works with adaptive dwell + * for active channel + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE: can be preempted by other requests + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START: send notification of scan start + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID: matching on multiple SSIDs + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE: all the channels scanned + * as passive + */ +enum iwl_umac_scan_general_flags_v2 { + IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC = BIT(0), + IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL = BIT(1), + IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE = BIT(2), + IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1 = BIT(3), + IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2 = BIT(4), + IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH = BIT(5), + IWL_UMAC_SCAN_GEN_FLAGS_V2_USE_ALL_RX_CHAINS = BIT(6), + IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL = BIT(7), + IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE = BIT(8), + IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START = BIT(9), + IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID = BIT(10), + IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE = BIT(11), +}; + /** * struct iwl_scan_channel_cfg_umac * @flags: bitmap - 0-19: directed scan to i'th ssid. @@ -830,6 +870,123 @@ struct iwl_scan_req_umac { #define IWL_SCAN_REQ_UMAC_SIZE_V6 44 #define IWL_SCAN_REQ_UMAC_SIZE_V1 36 +/** + * struct iwl_scan_probe_params + * @preq: scan probe request params + * @ssid_num: number of valid SSIDs in direct scan array + * @short_ssid_num: number of valid short SSIDs in short ssid array + * @bssid_num: number of valid bssid in bssids array + * @reserved: reserved + * @direct_scan: list of ssids + * @short_ssid: array of short ssids + * @bssid_array: array of bssids +*/ +struct iwl_scan_probe_params { + struct iwl_scan_probe_req preq; + u8 ssid_num; + u8 short_ssid_num; + u8 bssid_num; + u8 reserved; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; + __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; + u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; +} __packed; + +#define SCAN_MAX_NUM_CHANS_V3 67 + +/** + * struct iwl_scan_channel_params + * @flags: channel flags &enum iwl_scan_channel_flags + * @count: num of channels in scan request + * @reserved: for future use and alignment + * @channel_config: array of explicit channel configurations + * for 2.4Ghz and 5.2Ghz bands + */ +struct iwl_scan_channel_params { + u8 flags; + u8 count; + __le16 reserved; + struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; +} __packed; + + /** + * struct iwl_scan_general_params + * @flags: &enum iwl_umac_scan_flags + * @reserved: reserved for future + * @scan_start_mac_id: report the scan start TSF time according to this mac TSF + * @active_dwell: dwell time for active scan per LMAC + * @adwell_default_2g: adaptive dwell default number of APs + * for 2.4GHz channel + * @ddwell_default_5g: adaptive dwell default number of APs + * for 5GHz channels + * @adwell_default_social_chn: adaptive dwell default number of + * APs per social channel + * @reserved1: reserved for future + * @adwell_max_budget: the maximal number of TUs that adaptive dwell + * can add to the total scan time + * @max_out_of_time: max out of serving channel time, per LMAC + * @suspend_time: max suspend time, per LMAC + * @scan_priority: priority of the request + * @passive_dwell: continues dwell time for passive channel + * (without adaptive dwell) + * @num_of_fragments: number of fragments needed for full fragmented + * scan coverage. + * */ +struct iwl_scan_general_params { + __le16 flags; + u8 reserved; + u8 scan_start_mac_id; + u8 active_dwell[SCAN_TWO_LMACS]; + u8 adwell_default_2g; + u8 adwell_default_5g; + u8 adwell_default_social_chn; + u8 reserved1; + __le16 adwell_max_budget; + __le32 max_out_of_time[SCAN_TWO_LMACS]; + __le32 suspend_time[SCAN_TWO_LMACS]; + __le32 scan_priority; + u8 passive_dwell[SCAN_TWO_LMACS]; + u8 num_of_fragments[SCAN_TWO_LMACS]; +} __packed; + +/** + * struct iwl_scan_periodic_parms + * @schedule: can scheduling parameter + * @delay: initial delay of the periodic scan in seconds + * @reserved: reserved for future + * */ +struct iwl_scan_periodic_parms { + struct iwl_scan_umac_schedule schedule[IWL_MAX_SCHED_SCAN_PLANS]; + __le16 delay; + __le16 reserved; +} __packed; + +/** + * struct iwl_scan_req_params + * @general_params: &struct iwl_scan_general_params + * @channel_params: &struct iwl_scan_channel_params + * @periodic_params: &struct iwl_scan_periodic_parms + * @probe_params: &struct iwl_scan_probe_params + * */ +struct iwl_scan_req_params { + struct iwl_scan_general_params general_params; + struct iwl_scan_channel_params channel_params; + struct iwl_scan_periodic_parms periodic_params; + struct iwl_scan_probe_params probe_params; +} __packed; + +/** + * struct iwl_scan_req_umac_v2 + * @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_umac_req_v2 { + __le32 uid; + __le32 ooc_priority; + struct iwl_scan_req_params scan_params; +} __packed; + /** * struct iwl_umac_scan_abort * @uid: scan id, &enum iwl_umac_scan_uid_offsets diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index dbeab093171e..994880a83652 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -313,4 +313,22 @@ iwl_get_ucode_image(const struct iwl_fw *fw, enum iwl_ucode_type ucode_type) return &fw->img[ucode_type]; } +static inline u8 iwl_mvm_lookup_cmd_ver(const struct iwl_fw *fw, u8 grp, u8 cmd) +{ + const struct iwl_fw_cmd_version *entry; + unsigned int i; + + if (!fw->ucode_capa.cmd_versions || + !fw->ucode_capa.n_cmd_versions) + return IWL_FW_CMD_VER_UNKNOWN; + + entry = fw->ucode_capa.cmd_versions; + for (i = 0; i < fw->ucode_capa.n_cmd_versions; i++, entry++) { + if (entry->group == grp && entry->cmd == cmd) + return entry->cmd_ver; + } + + return IWL_FW_CMD_VER_UNKNOWN; +} + #endif /* __iwl_fw_img_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 735436f5253f..e300ea267b66 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1422,6 +1422,15 @@ static inline bool iwl_mvm_is_band_in_rx_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_BAND_IN_RX_DATA); } +static inline bool iwl_mvm_is_scan_ext_band_supported(struct iwl_mvm *mvm) +{ + u8 cmd_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC); + if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) + return false; + return (cmd_ver >= 11); +} + static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 3e5455cef0ee..1745f92490ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -539,6 +539,7 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, { int i, j; int index; + u32 tmp_bitmap = 0; /* * copy SSIDs from match list. @@ -558,7 +559,6 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, } /* add SSIDs from scan SSID list */ - *ssid_bitmap = 0; for (j = params->n_ssids - 1; j >= 0 && i < PROBE_OPTION_MAX; i++, j--) { @@ -570,11 +570,13 @@ static void iwl_scan_build_ssids(struct iwl_mvm_scan_params *params, ssids[i].len = params->ssids[j].ssid_len; memcpy(ssids[i].ssid, params->ssids[j].ssid, ssids[i].len); - *ssid_bitmap |= BIT(i); + tmp_bitmap |= BIT(i); } else { - *ssid_bitmap |= BIT(index); + tmp_bitmap |= BIT(index); } } + if (ssid_bitmap) + *ssid_bitmap = tmp_bitmap; } static int @@ -1405,16 +1407,76 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); } +static void iwl_mvm_scan_umac_dwell_v2(struct iwl_mvm *mvm, + struct iwl_scan_umac_req_v2 *cmd, + struct iwl_mvm_scan_params *params) +{ + struct iwl_mvm_scan_timing_params *timing, *hb_timing; + u8 active_dwell, passive_dwell; + + timing = &scan_timing[params->type]; + active_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_ACTIVE; + passive_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_PASSIVE; + + cmd->scan_params.general_params.adwell_default_social_chn = + IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; + cmd->scan_params.general_params.adwell_default_2g = + IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; + cmd->scan_params.general_params.adwell_default_5g = + IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; + + /* if custom max budget was configured with debugfs */ + if (IWL_MVM_ADWELL_MAX_BUDGET) + cmd->scan_params.general_params.adwell_max_budget = + cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); + else if (params->ssids && params->ssids[0].ssid_len) + cmd->scan_params.general_params.adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else + cmd->scan_params.general_params.adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); + + cmd->scan_params.general_params.scan_priority = + cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->scan_params.general_params.max_out_of_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + cmd->scan_params.general_params.suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); + + hb_timing = &scan_timing[params->hb_type]; + + cmd->scan_params.general_params.max_out_of_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(hb_timing->max_out_time); + cmd->scan_params.general_params.suspend_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(hb_timing->suspend_time); + + cmd->scan_params.general_params.active_dwell[SCAN_LB_LMAC_IDX] = + active_dwell; + cmd->scan_params.general_params.passive_dwell[SCAN_LB_LMAC_IDX] = + passive_dwell; + cmd->scan_params.general_params.active_dwell[SCAN_HB_LMAC_IDX] = + active_dwell; + cmd->scan_params.general_params.passive_dwell[SCAN_HB_LMAC_IDX] = + passive_dwell; + + if (iwl_mvm_is_regular_scan(params)) + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + else + cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); +} + static void iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, struct ieee80211_channel **channels, - int n_channels, u32 ssid_bitmap, + int n_channels, u32 flags, struct iwl_scan_channel_cfg_umac *channel_cfg) { int i; for (i = 0; i < n_channels; i++) { - channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); + channel_cfg[i].flags = cpu_to_le32(flags); channel_cfg[i].v1.channel_num = channels[i]->hw_value; if (iwl_mvm_is_scan_ext_chan_supported(mvm)) { enum nl80211_band band = channels[i]->band; @@ -1430,6 +1492,64 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, } } +static u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif) +{ + u8 flags = 0; + + flags |= IWL_SCAN_CHANNEL_FLAG_ENABLE_CHAN_ORDER; + + if (iwl_mvm_scan_use_ebs(mvm, vif)) + flags |= IWL_SCAN_CHANNEL_FLAG_EBS | + IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | + IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; + + /* set fragmented ebs for fragmented scan on HB channels */ + if (iwl_mvm_is_scan_fragmented(params->hb_type)) + flags |= IWL_SCAN_CHANNEL_FLAG_EBS_FRAG; + + return flags; +} + +static u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + int type) +{ + u16 flags = 0; + + if (params->n_ssids == 0) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE; + + if (iwl_mvm_is_scan_fragmented(params->type)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1; + + if (iwl_mvm_is_scan_fragmented(params->hb_type)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2; + + if (params->pass_all) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL; + else + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_MATCH; + + if (!iwl_mvm_is_regular_scan(params)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC; + + if (params->measurement_dwell || + mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE; + + if (IWL_MVM_ADWELL_ENABLE && + vif->type != NL80211_IFTYPE_P2P_DEVICE) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; + + if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_PREEMPTIVE; + + return flags; +} + static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -1634,6 +1754,71 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } +static int iwl_mvm_scan_umac_v2(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, + int type) +{ + struct iwl_scan_umac_req_v2 *cmd = mvm->scan_cmd; + int uid, ret = 0; + u8 channel_flags = 0; + u16 gen_flags; + struct iwl_scan_req_params *scan_params; + struct iwl_scan_periodic_parms *periodic_params; + struct iwl_scan_channel_params *channel_params; + + struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); + + scan_params = &cmd->scan_params; + periodic_params = &scan_params->periodic_params; + channel_params = &scan_params->channel_params; + lockdep_assert_held(&mvm->mutex); + + uid = iwl_mvm_scan_uid_by_status(mvm, 0); + if (uid < 0) + return uid; + + memset(cmd, 0, ksize(cmd)); + + iwl_mvm_scan_umac_dwell_v2(mvm, cmd, params); + + mvm->scan_uid_status[uid] = type; + + cmd->uid = cpu_to_le32(uid); + + gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); + scan_params->general_params.flags = cpu_to_le16(gen_flags); + + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) + scan_params->general_params.num_of_fragments[SCAN_LB_LMAC_IDX] = + IWL_SCAN_NUM_OF_FRAGS; + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) + scan_params->general_params.num_of_fragments[SCAN_HB_LMAC_IDX] = + IWL_SCAN_NUM_OF_FRAGS; + + scan_params->general_params.scan_start_mac_id = scan_vif->id; + + channel_flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); + channel_params->flags = channel_flags; + + channel_params->count = params->n_channels; + + ret = iwl_mvm_fill_scan_sched_params(params, + periodic_params->schedule, + &periodic_params->delay); + if (ret) + return ret; + + scan_params->probe_params.preq = params->preq; + scan_params->probe_params.ssid_num = params->n_ssids; + iwl_scan_build_ssids(params, scan_params->probe_params.direct_scan, + NULL); + + iwl_mvm_umac_scan_cfg_channels(mvm, params->channels, + params->n_channels, 0, + channel_params->channel_config); + return 0; +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -1744,7 +1929,9 @@ static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, { if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - return iwl_mvm_scan_umac(mvm, vif, params, type); + if (iwl_mvm_is_scan_ext_band_supported(mvm)) + return iwl_mvm_scan_umac_v2(mvm, vif, params, type); + return iwl_mvm_scan_umac(mvm, vif, params, type); } hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; return iwl_mvm_scan_lmac(mvm, vif, params); @@ -2062,6 +2249,9 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; int tail_size; + if (iwl_mvm_is_scan_ext_band_supported(mvm)) + return sizeof(struct iwl_scan_umac_req_v2); + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; else if (iwl_mvm_is_adaptive_dwell_supported(mvm)) -- cgit v1.2.3-59-g8ed1b From 6587ef6e22c5297ae22ddb5744d42c02b8df2741 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 15 Nov 2019 09:27:51 +0200 Subject: iwlwifi: mvm: print rate_n_flags in a pretty format Use the rs_pretty_print_rate() function to print the rate_n_flags in more human-readable format. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 6 ++++-- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 10a08fae2942..e2cf9e015ef8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -341,9 +341,11 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, lq_sta = &mvmsta->lq_sta.rs_fw; if (flags & IWL_TLC_NOTIF_FLAG_RATE) { + char pretty_rate[100]; lq_sta->last_rate_n_flags = le32_to_cpu(notif->rate); - IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n", - lq_sta->last_rate_n_flags); + rs_pretty_print_rate(pretty_rate, sizeof(pretty_rate), + lq_sta->last_rate_n_flags); + IWL_DEBUG_RATE(mvm, "new rate: %s\n", pretty_rate); } if (flags & IWL_TLC_NOTIF_FLAG_AMSDU && !mvmsta->orig_amsdu_len) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 0a442cb7f223..1a990ed9c3ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -3685,7 +3685,6 @@ static void rs_free_sta(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta) IWL_DEBUG_RATE(mvm, "leave\n"); } -#ifdef CONFIG_MAC80211_DEBUGFS int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) { @@ -3741,14 +3740,15 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) } return scnprintf(buf, bufsz, - "%s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s\n", - type, rs_pretty_ant(ant), bw, mcs, nss, + "0x%x: %s | ANT: %s BW: %s MCS: %d NSS: %d %s%s%s%s\n", + rate, type, rs_pretty_ant(ant), bw, mcs, nss, (rate & RATE_MCS_SGI_MSK) ? "SGI " : "NGI ", (rate & RATE_MCS_STBC_MSK) ? "STBC " : "", (rate & RATE_MCS_LDPC_MSK) ? "LDPC " : "", (rate & RATE_MCS_BF_MSK) ? "BF " : ""); } +#ifdef CONFIG_MAC80211_DEBUGFS /** * Program the device to use fixed rate for frame transmit * This is for debugging/testing only -- cgit v1.2.3-59-g8ed1b From 60d1794e284265d39a0b00603b34160c60f59a34 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2019 09:27:54 +0200 Subject: iwlwifi: FW API: reference enum in docs of modify_mask Add a reference to the correct enum rather than showing the pattern of the actual constants. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/api/sta.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h index 450227f81706..970e9e508ad0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/sta.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -288,8 +288,7 @@ struct iwl_mvm_keyinfo { * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table - * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave - * alone. 1 - modify, 0 - don't change. + * @modify_mask: from &enum iwl_sta_modify_flag, selects what to change * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, @@ -369,8 +368,7 @@ enum iwl_sta_type { * @addr: station's MAC address * @reserved2: reserved * @sta_id: index of station in uCode's station table - * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave - * alone. 1 - modify, 0 - don't change. + * @modify_mask: from &enum iwl_sta_modify_flag, selects what to change * @reserved3: reserved * @station_flags: look at &enum iwl_sta_flags * @station_flags_msk: what of %station_flags have changed, -- cgit v1.2.3-59-g8ed1b From ffe5619fd869a0721cedb66368323b656380d94c Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 15 Nov 2019 09:27:56 +0200 Subject: iwlwifi: bump FW API to 51 for 22000 series Start supporting API version 51 for 22000 series. Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 435cb8013a23..9ebb3376ffb9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -57,7 +57,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 50 +#define IWL_22000_UCODE_API_MAX 51 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 -- cgit v1.2.3-59-g8ed1b From eb3dc36eeca465a6a647afc7db8d00a5d4f2fb82 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Nov 2019 09:27:59 +0200 Subject: iwlwifi: remove redundant assignment to variable bufsz The variable bufsz is being initialized with a value that is never read and it is being updated later with a new value. The initialization is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 6aa89d9ea72c..9e8c47c30704 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2582,7 +2582,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); char *buf; int pos = 0, i, ret; - size_t bufsz = sizeof(buf); + size_t bufsz; bufsz = sizeof(char) * 121 * trans->num_rx_queues; -- cgit v1.2.3-59-g8ed1b From c5aaa8be29b25dfe1731e9a8b19fd91b7b789ee3 Mon Sep 17 00:00:00 2001 From: Wang Xuerui Date: Fri, 15 Nov 2019 09:28:02 +0200 Subject: iwlwifi: mvm: fix unaligned read of rx_pkt_status This is present since the introduction of iwlmvm. Example stack trace on MIPS: [] iwl_mvm_rx_rx_mpdu+0xa8/0xb88 [iwlmvm] [] iwl_pcie_rx_handle+0x420/0xc48 [iwlwifi] Tested with a Wireless AC 7265 for ~6 months, confirmed to fix the problem. No other unaligned accesses are spotted yet. Signed-off-by: Wang Xuerui Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 0ad8ed23a455..5ee33c8ae9d2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -60,6 +60,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ +#include #include #include #include "iwl-trans.h" @@ -357,7 +358,7 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data; hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res)); len = le16_to_cpu(rx_res->byte_count); - rx_pkt_status = le32_to_cpup((__le32 *) + rx_pkt_status = get_unaligned_le32((__le32 *) (pkt->data + sizeof(*rx_res) + len)); /* Dont use dev_alloc_skb(), we'll have enough headroom once -- cgit v1.2.3-59-g8ed1b From 687db6ff5b7075326a8a1fcd8b7c4037208663fc Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Fri, 15 Nov 2019 09:28:05 +0200 Subject: iwlwifi: scan: make new scan req versioning flow Implement a new versioning handling flow supported from version 11 onwards. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 113 ++++++----- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 9 - drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 248 ++++++++++++++--------- 3 files changed, 208 insertions(+), 162 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index fa455d854d53..8180bfe8c62e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -644,7 +644,10 @@ enum iwl_umac_scan_general_flags2 { }; /** - * enum iwl_umac_scan_general_flags_v22 - UMAC scan general flags ver 2 + * enum iwl_umac_scan_general_flags_v2 - UMAC scan general flags version 2 + * + * The FW flags were reordered and hence the driver introduce version 2 + * * @IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC: periodic or scheduled * @IWL_UMAC_SCAN_GEN_FLAGS_V2_PASS_ALL: pass all probe responses and beacons * during scan iterations @@ -871,7 +874,7 @@ struct iwl_scan_req_umac { #define IWL_SCAN_REQ_UMAC_SIZE_V1 36 /** - * struct iwl_scan_probe_params + * struct iwl_scan_probe_params_v3 * @preq: scan probe request params * @ssid_num: number of valid SSIDs in direct scan array * @short_ssid_num: number of valid short SSIDs in short ssid array @@ -880,8 +883,8 @@ struct iwl_scan_req_umac { * @direct_scan: list of ssids * @short_ssid: array of short ssids * @bssid_array: array of bssids -*/ -struct iwl_scan_probe_params { + */ +struct iwl_scan_probe_params_v3 { struct iwl_scan_probe_req preq; u8 ssid_num; u8 short_ssid_num; @@ -895,44 +898,44 @@ struct iwl_scan_probe_params { #define SCAN_MAX_NUM_CHANS_V3 67 /** - * struct iwl_scan_channel_params + * struct iwl_scan_channel_params_v3 * @flags: channel flags &enum iwl_scan_channel_flags * @count: num of channels in scan request * @reserved: for future use and alignment * @channel_config: array of explicit channel configurations * for 2.4Ghz and 5.2Ghz bands */ -struct iwl_scan_channel_params { +struct iwl_scan_channel_params_v3 { u8 flags; u8 count; __le16 reserved; struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; -} __packed; +} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_3 */ - /** - * struct iwl_scan_general_params - * @flags: &enum iwl_umac_scan_flags - * @reserved: reserved for future - * @scan_start_mac_id: report the scan start TSF time according to this mac TSF - * @active_dwell: dwell time for active scan per LMAC - * @adwell_default_2g: adaptive dwell default number of APs - * for 2.4GHz channel - * @ddwell_default_5g: adaptive dwell default number of APs - * for 5GHz channels - * @adwell_default_social_chn: adaptive dwell default number of - * APs per social channel - * @reserved1: reserved for future - * @adwell_max_budget: the maximal number of TUs that adaptive dwell - * can add to the total scan time - * @max_out_of_time: max out of serving channel time, per LMAC - * @suspend_time: max suspend time, per LMAC - * @scan_priority: priority of the request - * @passive_dwell: continues dwell time for passive channel - * (without adaptive dwell) - * @num_of_fragments: number of fragments needed for full fragmented - * scan coverage. - * */ -struct iwl_scan_general_params { +/** + * struct iwl_scan_general_params_v10 + * @flags: &enum iwl_umac_scan_flags + * @reserved: reserved for future + * @scan_start_mac_id: report the scan start TSF time according to this mac TSF + * @active_dwell: dwell time for active scan per LMAC + * @adwell_default_2g: adaptive dwell default number of APs + * for 2.4GHz channel + * @adwell_default_5g: adaptive dwell default number of APs + * for 5GHz channels + * @adwell_default_social_chn: adaptive dwell default number of + * APs per social channel + * @reserved1: reserved for future + * @adwell_max_budget: the maximal number of TUs that adaptive dwell + * can add to the total scan time + * @max_out_of_time: max out of serving channel time, per LMAC + * @suspend_time: max suspend time, per LMAC + * @scan_priority: priority of the request + * @passive_dwell: continues dwell time for passive channel + * (without adaptive dwell) + * @num_of_fragments: number of fragments needed for full fragmented + * scan coverage. + */ +struct iwl_scan_general_params_v10 { __le16 flags; u8 reserved; u8 scan_start_mac_id; @@ -947,45 +950,45 @@ struct iwl_scan_general_params { __le32 scan_priority; u8 passive_dwell[SCAN_TWO_LMACS]; u8 num_of_fragments[SCAN_TWO_LMACS]; -} __packed; +} __packed; /* SCAN_GENERAL_PARAMS_API_S_VER_10 */ /** - * struct iwl_scan_periodic_parms - * @schedule: can scheduling parameter - * @delay: initial delay of the periodic scan in seconds - * @reserved: reserved for future - * */ -struct iwl_scan_periodic_parms { + * struct iwl_scan_periodic_parms_v1 + * @schedule: can scheduling parameter + * @delay: initial delay of the periodic scan in seconds + * @reserved: reserved for future + */ +struct iwl_scan_periodic_parms_v1 { struct iwl_scan_umac_schedule schedule[IWL_MAX_SCHED_SCAN_PLANS]; __le16 delay; __le16 reserved; -} __packed; +} __packed; /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ /** - * struct iwl_scan_req_params - * @general_params: &struct iwl_scan_general_params - * @channel_params: &struct iwl_scan_channel_params - * @periodic_params: &struct iwl_scan_periodic_parms - * @probe_params: &struct iwl_scan_probe_params - * */ -struct iwl_scan_req_params { - struct iwl_scan_general_params general_params; - struct iwl_scan_channel_params channel_params; - struct iwl_scan_periodic_parms periodic_params; - struct iwl_scan_probe_params probe_params; -} __packed; + * struct iwl_scan_req_params_v11 + * @general_params: &struct iwl_scan_general_params_v10 + * @channel_params: &struct iwl_scan_channel_params_v3 + * @periodic_params: &struct iwl_scan_periodic_parms_v1 + * @probe_params: &struct iwl_scan_probe_params_v3 + */ +struct iwl_scan_req_params_v11 { + struct iwl_scan_general_params_v10 general_params; + struct iwl_scan_channel_params_v3 channel_params; + struct iwl_scan_periodic_parms_v1 periodic_params; + struct iwl_scan_probe_params_v3 probe_params; +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_11 */ /** - * struct iwl_scan_req_umac_v2 + * struct iwl_scan_req_umac_v11 * @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_umac_req_v2 { +struct iwl_scan_req_umac_v11 { __le32 uid; __le32 ooc_priority; - struct iwl_scan_req_params scan_params; -} __packed; + struct iwl_scan_req_params_v11 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_11 */ /** * struct iwl_umac_scan_abort diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index e300ea267b66..735436f5253f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1422,15 +1422,6 @@ static inline bool iwl_mvm_is_band_in_rx_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_BAND_IN_RX_DATA); } -static inline bool iwl_mvm_is_scan_ext_band_supported(struct iwl_mvm *mvm) -{ - u8 cmd_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, - SCAN_REQ_UMAC); - if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) - return false; - return (cmd_ver >= 11); -} - static inline bool iwl_mvm_has_new_rx_stats_api(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 1745f92490ed..e034418553f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -974,10 +974,6 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int i; u8 band; - lockdep_assert_held(&mvm->mutex); - - memset(cmd, 0, ksize(cmd)); - if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) return -EINVAL; @@ -1407,9 +1403,17 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); } -static void iwl_mvm_scan_umac_dwell_v2(struct iwl_mvm *mvm, - struct iwl_scan_umac_req_v2 *cmd, - struct iwl_mvm_scan_params *params) +static u32 iwl_mvm_scan_umac_ooc_priority(struct iwl_mvm_scan_params *params) +{ + return iwl_mvm_is_regular_scan(params) ? + IWL_SCAN_PRIORITY_EXT_6 : + IWL_SCAN_PRIORITY_EXT_2; +} + +static void +iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, + struct iwl_scan_general_params_v10 *general_params, + struct iwl_mvm_scan_params *params) { struct iwl_mvm_scan_timing_params *timing, *hb_timing; u8 active_dwell, passive_dwell; @@ -1420,51 +1424,39 @@ static void iwl_mvm_scan_umac_dwell_v2(struct iwl_mvm *mvm, passive_dwell = params->measurement_dwell ? params->measurement_dwell : IWL_SCAN_DWELL_PASSIVE; - cmd->scan_params.general_params.adwell_default_social_chn = + general_params->adwell_default_social_chn = IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; - cmd->scan_params.general_params.adwell_default_2g = - IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; - cmd->scan_params.general_params.adwell_default_5g = - IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; + general_params->adwell_default_2g = IWL_SCAN_ADWELL_DEFAULT_LB_N_APS; + general_params->adwell_default_5g = IWL_SCAN_ADWELL_DEFAULT_HB_N_APS; /* if custom max budget was configured with debugfs */ if (IWL_MVM_ADWELL_MAX_BUDGET) - cmd->scan_params.general_params.adwell_max_budget = + general_params->adwell_max_budget = cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); else if (params->ssids && params->ssids[0].ssid_len) - cmd->scan_params.general_params.adwell_max_budget = + general_params->adwell_max_budget = cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); else - cmd->scan_params.general_params.adwell_max_budget = + general_params->adwell_max_budget = cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); - cmd->scan_params.general_params.scan_priority = - cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - cmd->scan_params.general_params.max_out_of_time[SCAN_LB_LMAC_IDX] = + general_params->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + general_params->max_out_of_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->max_out_time); - cmd->scan_params.general_params.suspend_time[SCAN_LB_LMAC_IDX] = + general_params->suspend_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->suspend_time); hb_timing = &scan_timing[params->hb_type]; - cmd->scan_params.general_params.max_out_of_time[SCAN_HB_LMAC_IDX] = + general_params->max_out_of_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(hb_timing->max_out_time); - cmd->scan_params.general_params.suspend_time[SCAN_HB_LMAC_IDX] = + general_params->suspend_time[SCAN_HB_LMAC_IDX] = cpu_to_le32(hb_timing->suspend_time); - cmd->scan_params.general_params.active_dwell[SCAN_LB_LMAC_IDX] = - active_dwell; - cmd->scan_params.general_params.passive_dwell[SCAN_LB_LMAC_IDX] = - passive_dwell; - cmd->scan_params.general_params.active_dwell[SCAN_HB_LMAC_IDX] = - active_dwell; - cmd->scan_params.general_params.passive_dwell[SCAN_HB_LMAC_IDX] = - passive_dwell; - - if (iwl_mvm_is_regular_scan(params)) - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - else - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); + general_params->active_dwell[SCAN_LB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell; + general_params->active_dwell[SCAN_HB_LMAC_IDX] = active_dwell; + general_params->passive_dwell[SCAN_HB_LMAC_IDX] = passive_dwell; } static void @@ -1664,7 +1656,7 @@ iwl_mvm_fill_scan_sched_params(struct iwl_mvm_scan_params *params, static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_scan_params *params, - int type) + int type, int uid) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; struct iwl_scan_umac_chan_param *chan_param; @@ -1675,7 +1667,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, (struct iwl_scan_req_umac_tail_v2 *)sec_part; struct iwl_scan_req_umac_tail_v1 *tail_v1; struct iwl_ssid_ie *direct_scan; - int uid, ret = 0; + int ret = 0; u32 ssid_bitmap = 0; u8 channel_flags = 0; u16 gen_flags; @@ -1683,14 +1675,6 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, chan_param = iwl_mvm_get_scan_req_umac_channel(mvm); - lockdep_assert_held(&mvm->mutex); - - uid = iwl_mvm_scan_uid_by_status(mvm, 0); - if (uid < 0) - return uid; - - memset(cmd, 0, ksize(cmd)); - iwl_mvm_scan_umac_dwell(mvm, cmd, params); mvm->scan_uid_status[uid] = type; @@ -1754,68 +1738,79 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -static int iwl_mvm_scan_umac_v2(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_mvm_scan_params *params, - int type) +static void +iwl_mvm_scan_umac_fill_general_p_v10(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_general_params_v10 *gp, + u16 gen_flags) { - struct iwl_scan_umac_req_v2 *cmd = mvm->scan_cmd; - int uid, ret = 0; - u8 channel_flags = 0; - u16 gen_flags; - struct iwl_scan_req_params *scan_params; - struct iwl_scan_periodic_parms *periodic_params; - struct iwl_scan_channel_params *channel_params; - struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); - scan_params = &cmd->scan_params; - periodic_params = &scan_params->periodic_params; - channel_params = &scan_params->channel_params; - lockdep_assert_held(&mvm->mutex); + iwl_mvm_scan_umac_dwell_v10(mvm, gp, params); - uid = iwl_mvm_scan_uid_by_status(mvm, 0); - if (uid < 0) - return uid; + gp->flags = cpu_to_le16(gen_flags); - memset(cmd, 0, ksize(cmd)); + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) + gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) + gp->num_of_fragments[SCAN_HB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS; - iwl_mvm_scan_umac_dwell_v2(mvm, cmd, params); + gp->scan_start_mac_id = scan_vif->id; +} - mvm->scan_uid_status[uid] = type; +static void +iwl_mvm_scan_umac_fill_probe_p_v3(struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v3 *pp) +{ + pp->preq = params->preq; + pp->ssid_num = params->n_ssids; + iwl_scan_build_ssids(params, pp->direct_scan, NULL); +} - cmd->uid = cpu_to_le32(uid); +static void +iwl_mvm_scan_umac_fill_ch_p_v3(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_channel_params_v3 *cp) +{ + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); + cp->count = params->n_channels; - gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); - scan_params->general_params.flags = cpu_to_le16(gen_flags); + iwl_mvm_umac_scan_cfg_channels(mvm, params->channels, + params->n_channels, 0, + cp->channel_config); +} - if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1) - scan_params->general_params.num_of_fragments[SCAN_LB_LMAC_IDX] = - IWL_SCAN_NUM_OF_FRAGS; - if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC2) - scan_params->general_params.num_of_fragments[SCAN_HB_LMAC_IDX] = - IWL_SCAN_NUM_OF_FRAGS; +static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v11 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v11 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; - scan_params->general_params.scan_start_mac_id = scan_vif->id; + mvm->scan_uid_status[uid] = type; - channel_flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); - channel_params->flags = channel_flags; + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + cmd->uid = cpu_to_le32(uid); - channel_params->count = params->n_channels; + gen_flags = iwl_mvm_scan_umac_flags_v2(mvm, params, vif, type); + iwl_mvm_scan_umac_fill_general_p_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); ret = iwl_mvm_fill_scan_sched_params(params, - periodic_params->schedule, - &periodic_params->delay); + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; - scan_params->probe_params.preq = params->preq; - scan_params->probe_params.ssid_num = params->n_ssids; - iwl_scan_build_ssids(params, scan_params->probe_params.direct_scan, - NULL); + iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); + iwl_mvm_scan_umac_fill_ch_p_v3(mvm, params, vif, + &scan_p->channel_params); - iwl_mvm_umac_scan_cfg_channels(mvm, params->channels, - params->n_channels, 0, - channel_params->channel_config); return 0; } @@ -1921,20 +1916,59 @@ static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, } } +struct iwl_scan_umac_handler { + u8 version; + int (*handler)(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, int uid); +}; + +#define IWL_SCAN_UMAC_HANDLER(_ver) { \ + .version = _ver, \ + .handler = iwl_mvm_scan_umac_v##_ver, \ +} + +static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = { + IWL_SCAN_UMAC_HANDLER(11), +}; + static int iwl_mvm_build_scan_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_host_cmd *hcmd, struct iwl_mvm_scan_params *params, int type) { - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { - hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); - if (iwl_mvm_is_scan_ext_band_supported(mvm)) - return iwl_mvm_scan_umac_v2(mvm, vif, params, type); - return iwl_mvm_scan_umac(mvm, vif, params, type); + int uid, i; + u8 scan_ver; + + lockdep_assert_held(&mvm->mutex); + memset(mvm->scan_cmd, 0, ksize(mvm->scan_cmd)); + + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { + hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; + + return iwl_mvm_scan_lmac(mvm, vif, params); + } + + uid = iwl_mvm_scan_uid_by_status(mvm, 0); + if (uid < 0) + return uid; + + hcmd->id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0); + + scan_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC); + + for (i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) { + const struct iwl_scan_umac_handler *ver_handler = + &iwl_scan_umac_handlers[i]; + + if (ver_handler->version != scan_ver) + continue; + + return ver_handler->handler(mvm, vif, params, type, uid); } - hcmd->id = SCAN_OFFLOAD_REQUEST_CMD; - return iwl_mvm_scan_lmac(mvm, vif, params); + + return iwl_mvm_scan_umac(mvm, vif, params, type, uid); } int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2244,13 +2278,29 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) 1 * HZ); } +#define IWL_SCAN_REQ_UMAC_HANDLE_SIZE(_ver) { \ + case (_ver): return sizeof(struct iwl_scan_req_umac_v##_ver); \ +} + +static int iwl_scan_req_umac_get_size(u8 scan_ver) +{ + switch (scan_ver) { + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(11); + } + + return 0; +} + int iwl_mvm_scan_size(struct iwl_mvm *mvm) { - int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; - int tail_size; + int base_size, tail_size; + u8 scan_ver = iwl_mvm_lookup_cmd_ver(mvm->fw, IWL_ALWAYS_LONG_GROUP, + SCAN_REQ_UMAC); + + base_size = iwl_scan_req_umac_get_size(scan_ver); + if (base_size) + return base_size; - if (iwl_mvm_is_scan_ext_band_supported(mvm)) - return sizeof(struct iwl_scan_umac_req_v2); if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; @@ -2258,6 +2308,8 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; else if (iwl_mvm_cdb_scan_api(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; + else + base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { if (iwl_mvm_is_scan_ext_chan_supported(mvm)) -- cgit v1.2.3-59-g8ed1b From 5167ff45a503ee49ae314c0cff410efa1eb9a1b8 Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Fri, 15 Nov 2019 09:28:08 +0200 Subject: iwlwifi: scan: support scan req cmd ver 12 Implement scan request command version 12. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 48 ++++++ drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 180 +++++++++++++++++++++++ 2 files changed, 228 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 8180bfe8c62e..71883ca6a596 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -912,6 +912,28 @@ struct iwl_scan_channel_params_v3 { struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; } __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_3 */ +/** + * struct iwl_scan_channel_params_v4 + * @flags: channel flags &enum iwl_scan_channel_flags + * @count: num of channels in scan request + * @num_of_aps_override: override the number of APs the FW uses to calculate + * dwell time when adaptive dwell is used + * @reserved: for future use and alignment + * @channel_config: array of explicit channel configurations + * for 2.4Ghz and 5.2Ghz bands + * @adwell_ch_override_bitmap: when using adaptive dwell, override the number + * of APs value with &num_of_aps_override for the channel. + * To cast channel to index, use &iwl_mvm_scan_ch_and_band_to_idx + */ +struct iwl_scan_channel_params_v4 { + u8 flags; + u8 count; + u8 num_of_aps_override; + u8 reserved; + struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; + u8 adwell_ch_override_bitmap[16]; +} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */ + /** * struct iwl_scan_general_params_v10 * @flags: &enum iwl_umac_scan_flags @@ -978,6 +1000,20 @@ struct iwl_scan_req_params_v11 { struct iwl_scan_probe_params_v3 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_11 */ +/** + * struct iwl_scan_req_params_v12 + * @general_params: &struct iwl_scan_general_params_v10 + * @channel_params: &struct iwl_scan_channel_params_v4 + * @periodic_params: &struct iwl_scan_periodic_parms_v1 + * @probe_params: &struct iwl_scan_probe_params_v3 + */ +struct iwl_scan_req_params_v12 { + struct iwl_scan_general_params_v10 general_params; + struct iwl_scan_channel_params_v4 channel_params; + struct iwl_scan_periodic_parms_v1 periodic_params; + struct iwl_scan_probe_params_v3 probe_params; +} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ + /** * struct iwl_scan_req_umac_v11 * @uid: scan id, &enum iwl_umac_scan_uid_offsets @@ -990,6 +1026,18 @@ struct iwl_scan_req_umac_v11 { struct iwl_scan_req_params_v11 scan_params; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_11 */ +/** + * struct iwl_scan_req_umac_v12 + * @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_v12 { + __le32 uid; + __le32 ooc_priority; + struct iwl_scan_req_params_v12 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ + /** * struct iwl_umac_scan_abort * @uid: scan id, &enum iwl_umac_scan_uid_offsets diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index e034418553f9..60db911f1aac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -89,6 +89,10 @@ #define IWL_SCAN_ADWELL_DEFAULT_LB_N_APS 2 /* adaptive dwell default APs number in social channels (1, 6, 11) */ #define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 +/* number of scan channels */ +#define IWL_SCAN_NUM_CHANNELS 112 +/* adaptive dwell default number of APs override */ +#define IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE 10 struct iwl_mvm_scan_timing_params { u32 suspend_time; @@ -1459,6 +1463,104 @@ iwl_mvm_scan_umac_dwell_v10(struct iwl_mvm *mvm, general_params->passive_dwell[SCAN_HB_LMAC_IDX] = passive_dwell; } +struct iwl_mvm_scan_channel_segment { + u8 start_idx; + u8 end_idx; + u8 first_channel_id; + u8 last_channel_id; + u8 channel_spacing_shift; + u8 band; +}; + +static const struct iwl_mvm_scan_channel_segment scan_channel_segments[] = { + { + .start_idx = 0, + .end_idx = 13, + .first_channel_id = 1, + .last_channel_id = 14, + .channel_spacing_shift = 0, + .band = PHY_BAND_24 + }, + { + .start_idx = 14, + .end_idx = 41, + .first_channel_id = 36, + .last_channel_id = 144, + .channel_spacing_shift = 2, + .band = PHY_BAND_5 + }, + { + .start_idx = 42, + .end_idx = 50, + .first_channel_id = 149, + .last_channel_id = 181, + .channel_spacing_shift = 2, + .band = PHY_BAND_5 + }, +}; + +static int iwl_mvm_scan_ch_and_band_to_idx(u8 channel_id, u8 band) +{ + int i, index; + + if (!channel_id) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(scan_channel_segments); i++) { + const struct iwl_mvm_scan_channel_segment *ch_segment = + &scan_channel_segments[i]; + u32 ch_offset; + + if (ch_segment->band != band || + ch_segment->first_channel_id > channel_id || + ch_segment->last_channel_id < channel_id) + continue; + + ch_offset = (channel_id - ch_segment->first_channel_id) >> + ch_segment->channel_spacing_shift; + + index = scan_channel_segments[i].start_idx + ch_offset; + if (index < IWL_SCAN_NUM_CHANNELS) + return index; + + break; + } + + return -EINVAL; +} + +static void iwl_mvm_scan_ch_add_n_aps_override(enum nl80211_iftype vif_type, + u8 ch_id, u8 band, u8 *ch_bitmap, + size_t bitmap_n_entries) +{ + int i; + static const u8 p2p_go_friendly_chs[] = { + 36, 40, 44, 48, 149, 153, 157, 161, 165, + }; + + if (vif_type != NL80211_IFTYPE_P2P_DEVICE) + return; + + for (i = 0; i < ARRAY_SIZE(p2p_go_friendly_chs); i++) { + if (p2p_go_friendly_chs[i] == ch_id) { + int ch_idx, bitmap_idx; + + ch_idx = iwl_mvm_scan_ch_and_band_to_idx(ch_id, band); + if (ch_idx < 0) + return; + + bitmap_idx = ch_idx / 8; + if (bitmap_idx >= bitmap_n_entries) + return; + + ch_idx = ch_idx % 8; + ch_bitmap[bitmap_idx] |= BIT(ch_idx); + + return; + } + } +} + static void iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, struct ieee80211_channel **channels, @@ -1484,6 +1586,35 @@ iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, } } +static void +iwl_mvm_umac_scan_cfg_channels_v4(struct iwl_mvm *mvm, + struct ieee80211_channel **channels, + struct iwl_scan_channel_params_v4 *cp, + int n_channels, u32 flags, + enum nl80211_iftype vif_type) +{ + u8 *bitmap = cp->adwell_ch_override_bitmap; + size_t bitmap_n_entries = ARRAY_SIZE(cp->adwell_ch_override_bitmap); + int i; + + for (i = 0; i < n_channels; i++) { + enum nl80211_band band = channels[i]->band; + struct iwl_scan_channel_cfg_umac *cfg = + &cp->channel_config[i]; + + cfg->flags = cpu_to_le32(flags); + cfg->v2.channel_num = channels[i]->hw_value; + cfg->v2.band = iwl_mvm_phy_band_from_nl80211(band); + cfg->v2.iter_count = 1; + cfg->v2.iter_interval = 0; + + iwl_mvm_scan_ch_add_n_aps_override(vif_type, + cfg->v2.channel_num, + cfg->v2.band, bitmap, + bitmap_n_entries); + } +} + static u8 iwl_mvm_scan_umac_chan_flags_v2(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif) @@ -1782,6 +1913,20 @@ iwl_mvm_scan_umac_fill_ch_p_v3(struct iwl_mvm *mvm, cp->channel_config); } +static void +iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, + struct iwl_mvm_scan_params *params, + struct ieee80211_vif *vif, + struct iwl_scan_channel_params_v4 *cp) +{ + cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); + cp->count = params->n_channels; + cp->num_of_aps_override = IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE; + + iwl_mvm_umac_scan_cfg_channels_v4(mvm, params->channels, cp, + params->n_channels, 0, vif->type); +} + static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_scan_params *params, int type, int uid) @@ -1814,6 +1959,38 @@ static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } +static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v12 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v12 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; + + mvm->scan_uid_status[uid] = type; + + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + 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_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); + + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); + if (ret) + return ret; + + iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); + iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, + &scan_p->channel_params); + + return 0; +} + static int iwl_mvm_num_scans(struct iwl_mvm *mvm) { return hweight32(mvm->scan_status & IWL_MVM_SCAN_MASK); @@ -1928,6 +2105,8 @@ 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(12), IWL_SCAN_UMAC_HANDLER(11), }; @@ -2285,6 +2464,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) static int iwl_scan_req_umac_get_size(u8 scan_ver) { switch (scan_ver) { + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); IWL_SCAN_REQ_UMAC_HANDLE_SIZE(11); } -- cgit v1.2.3-59-g8ed1b From 39c1a9728f938c7255ce507c8d56b73e8a4ebddf Mon Sep 17 00:00:00 2001 From: Ihab Zhaika Date: Fri, 15 Nov 2019 09:28:11 +0200 Subject: iwlwifi: refactor the SAR tables from mvm to acpi Refactored the SAR related functions from iwlmvm to acpi in order to make it shared between different opmodes in addition to removing unused variable ppag_rev. Signed-off-by: Ihab Zhaika Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 287 ++++++++++++++++++ drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 84 ++++++ drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 11 + drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 366 +++-------------------- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 21 +- 6 files changed, 433 insertions(+), 338 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index c2db758b9d54..40fe2d667622 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -61,6 +61,7 @@ #include "iwl-drv.h" #include "iwl-debug.h" #include "acpi.h" +#include "fw/runtime.h" void *iwl_acpi_get_object(struct device *dev, acpi_string method) { @@ -245,3 +246,289 @@ out_free: return ret; } IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); + +int iwl_sar_set_profile(union acpi_object *table, + struct iwl_sar_profile *profile, + bool enabled) +{ + int i; + + profile->enabled = enabled; + + for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { + if (table[i].type != ACPI_TYPE_INTEGER || + table[i].integer.value > U8_MAX) + return -EINVAL; + + profile->table[i] = table[i].integer.value; + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_sar_set_profile); + +int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, + __le16 per_chain_restriction[][IWL_NUM_SUB_BANDS], + int prof_a, int prof_b) +{ + int i, j, idx; + int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; + + BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2); + BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS != + ACPI_SAR_TABLE_SIZE); + + for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { + struct iwl_sar_profile *prof; + + /* don't allow SAR to be disabled (profile 0 means disable) */ + if (profs[i] == 0) + return -EPERM; + + /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ + if (profs[i] > ACPI_SAR_PROFILE_NUM) + return -EINVAL; + + /* profiles go from 1 to 4, so decrement to access the array */ + prof = &fwrt->sar_profiles[profs[i] - 1]; + + /* if the profile is disabled, do nothing */ + if (!prof->enabled) { + IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", + profs[i]); + /* if one of the profiles is disabled, we fail all */ + return -ENOENT; + } + IWL_DEBUG_INFO(fwrt, + "SAR EWRD: chain %d profile index %d\n", + i, profs[i]); + IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); + for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { + idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j; + per_chain_restriction[i][j] = + cpu_to_le16(prof->table[idx]); + IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", + j, prof->table[idx]); + } + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_sar_select_profile); + +int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *wifi_pkg, *table, *data; + bool enabled; + int ret, tbl_rev; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); + if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out_free; + } + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + + /* position of the actual table */ + table = &wifi_pkg->package.elements[2]; + + /* The profile from WRDS is officially profile 1, but goes + * into sar_profiles[0] (because we don't have a profile 0). + */ + ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled); +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); + +int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *wifi_pkg, *data; + bool enabled; + int i, n_profiles, tbl_rev; + int ret = 0; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); + if (IS_ERR(wifi_pkg) || tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out_free; + } + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + n_profiles = wifi_pkg->package.elements[2].integer.value; + + /* + * Check the validity of n_profiles. The EWRD profiles start + * from index 1, so the maximum value allowed here is + * ACPI_SAR_PROFILES_NUM - 1. + */ + if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { + ret = -EINVAL; + goto out_free; + } + + for (i = 0; i < n_profiles; i++) { + /* the tables start at element 3 */ + int pos = 3; + + /* The EWRD profiles officially go from 2 to 4, but we + * save them in sar_profiles[1-3] (because we don't + * have profile 0). So in the array we start from 1. + */ + ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], + &fwrt->sar_profiles[i + 1], + enabled); + if (ret < 0) + break; + + /* go to the next table */ + pos += ACPI_SAR_TABLE_SIZE; + } + +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); + +int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *wifi_pkg, *data; + int i, j, ret, tbl_rev; + int idx = 1; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); + if (IS_ERR(wifi_pkg) || tbl_rev > 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + fwrt->geo_rev = tbl_rev; + for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { + for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { + union acpi_object *entry; + + entry = &wifi_pkg->package.elements[idx++]; + if (entry->type != ACPI_TYPE_INTEGER || + entry->integer.value > U8_MAX) { + ret = -EINVAL; + goto out_free; + } + + fwrt->geo_profiles[i].values[j] = entry->integer.value; + } + } + ret = 0; +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) +{ + /* + * The GEO_TX_POWER_LIMIT command is not supported on earlier + * firmware versions. Unfortunately, we don't have a TLV API + * flag to rely on, so rely on the major version which is in + * the first byte of ucode_ver. This was implemented + * initially on version 38 and then backported to 17. It was + * also backported to 29, but only for 7265D devices. The + * intention was to have it in 36 as well, but not all 8000 + * family got this feature enabled. The 8000 family is the + * only one using version 36, so skip this version entirely. + */ + return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || + IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 || + (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && + ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == + CSR_HW_REV_TYPE_7265D)); +} +IWL_EXPORT_SYMBOL(iwl_sar_geo_support); + +int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt, + struct iwl_host_cmd *cmd) +{ + struct iwl_geo_tx_power_profiles_resp *resp; + int ret; + + resp = (void *)cmd->resp_pkt->data; + ret = le32_to_cpu(resp->profile_idx); + if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES)) { + ret = -EIO; + IWL_WARN(fwrt, "Invalid geographic profile idx (%d)\n", ret); + } + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_validate_sar_geo_profile); + +void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset_group *table) +{ + int ret, i, j; + + if (!iwl_sar_geo_support(fwrt)) + return; + + ret = iwl_sar_get_wgds_table(fwrt); + if (ret < 0) { + IWL_DEBUG_RADIO(fwrt, + "Geo SAR BIOS table invalid or unavailable. (%d)\n", + ret); + /* we don't fail if the table is not available */ + return; + } + + BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS * + ACPI_WGDS_TABLE_SIZE + 1 != ACPI_WGDS_WIFI_DATA_SIZE); + + BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES > IWL_NUM_GEO_PROFILES); + + for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { + struct iwl_per_chain_offset *chain = + (struct iwl_per_chain_offset *)&table[i]; + + for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { + u8 *value; + + value = &fwrt->geo_profiles[i].values[j * + ACPI_GEO_PER_CHAIN_SIZE]; + chain[j].max_tx_power = cpu_to_le16(value[0]); + chain[j].chain_a = value[1]; + chain[j].chain_b = value[2]; + IWL_DEBUG_RADIO(fwrt, + "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", + i, j, value[1], value[2], value[0]); + } + } +} +IWL_EXPORT_SYMBOL(iwl_sar_geo_init); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 6cb2d1f5efea..4a6e8262974b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -61,6 +61,12 @@ #define __iwl_fw_acpi__ #include +#include "fw/api/commands.h" +#include "fw/api/power.h" +#include "fw/api/phy.h" +#include "fw/img.h" +#include "iwl-trans.h" + #define ACPI_WRDS_METHOD "WRDS" #define ACPI_EWRD_METHOD "EWRD" @@ -104,9 +110,21 @@ #define ACPI_PPAG_MIN_HB -16 #define ACPI_PPAG_MAX_HB 40 +struct iwl_sar_profile { + bool enabled; + u8 table[ACPI_SAR_TABLE_SIZE]; +}; + +struct iwl_geo_profile { + u8 values[ACPI_GEO_TABLE_SIZE]; +}; + #ifdef CONFIG_ACPI +struct iwl_fw_runtime; + void *iwl_acpi_get_object(struct device *dev, acpi_string method); + union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, union acpi_object *data, int data_size, int *tbl_rev); @@ -134,6 +152,27 @@ u64 iwl_acpi_get_pwr_limit(struct device *dev); */ int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk); +int iwl_sar_set_profile(union acpi_object *table, + struct iwl_sar_profile *profile, + bool enabled); + +int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, + __le16 per_chain_restriction[][IWL_NUM_SUB_BANDS], + int prof_a, int prof_b); + +int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt); + +int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt); + +int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt); + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); + +int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt, + struct iwl_host_cmd *cmd); + +void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset_group *table); #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method) @@ -164,5 +203,50 @@ static inline int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) return -ENOENT; } +static inline int iwl_sar_set_profile(union acpi_object *table, + struct iwl_sar_profile *profile, + bool enabled) +{ + return -ENOENT; +} + +static inline int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, + __le16 per_chain_restriction[][IWL_NUM_SUB_BANDS], + int prof_a, int prof_b) +{ + return -ENOENT; +} + +static inline int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) +{ + return false; +} + +static inline int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt, + struct iwl_host_cmd *cmd) +{ + return -ENOENT; +} + +static inline void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset_group *table) +{ +} + #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index ec2ab0281f18..c24575ff0e54 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -65,7 +65,9 @@ #include "img.h" #include "fw/api/debug.h" #include "fw/api/paging.h" +#include "fw/api/power.h" #include "iwl-eeprom-parse.h" +#include "fw/acpi.h" #define IWL_FW_DBG_DOMAIN IWL_FW_INI_DOMAIN_ALWAYS_ON @@ -203,7 +205,16 @@ struct iwl_fw_runtime { u32 delay; u64 seq; } timestamp; + bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ +#ifdef CONFIG_ACPI + struct iwl_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; + u8 sar_chain_a_profile; + u8 sar_chain_b_profile; + struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES]; + u32 geo_rev; + struct iwl_ppag_table_cmd ppag_table; +#endif }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index b6db1f8f40cc..754adc0146be 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -377,7 +377,7 @@ static ssize_t iwl_dbgfs_sar_geo_profile_read(struct file *file, pos = scnprintf(buf, bufsz, "SAR geographic profile disabled\n"); } else { - value = &mvm->geo_profiles[tbl_idx - 1].values[0]; + value = &mvm->fwrt.geo_profiles[tbl_idx - 1].values[0]; pos += scnprintf(buf + pos, bufsz - pos, "Use geographic profile %d\n", tbl_idx); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 66e14f590b6d..763907c6969c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -678,181 +678,14 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) } #ifdef CONFIG_ACPI -static inline int iwl_mvm_sar_set_profile(struct iwl_mvm *mvm, - union acpi_object *table, - struct iwl_mvm_sar_profile *profile, - bool enabled) -{ - int i; - - profile->enabled = enabled; - - for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { - if ((table[i].type != ACPI_TYPE_INTEGER) || - (table[i].integer.value > U8_MAX)) - return -EINVAL; - - profile->table[i] = table[i].integer.value; - } - - return 0; -} - -static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *table, *data; - bool enabled; - int ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WRDS_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - enabled = !!(wifi_pkg->package.elements[1].integer.value); - - /* position of the actual table */ - table = &wifi_pkg->package.elements[2]; - - /* The profile from WRDS is officially profile 1, but goes - * into sar_profiles[0] (because we don't have a profile 0). - */ - ret = iwl_mvm_sar_set_profile(mvm, table, &mvm->sar_profiles[0], - enabled); -out_free: - kfree(data); - return ret; -} - -static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *data; - bool enabled; - int i, n_profiles, ret, tbl_rev; - - data = iwl_acpi_get_object(mvm->dev, ACPI_EWRD_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if ((wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) || - (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) || - tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - enabled = !!(wifi_pkg->package.elements[1].integer.value); - n_profiles = wifi_pkg->package.elements[2].integer.value; - - /* - * Check the validity of n_profiles. The EWRD profiles start - * from index 1, so the maximum value allowed here is - * ACPI_SAR_PROFILES_NUM - 1. - */ - if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { - ret = -EINVAL; - goto out_free; - } - - for (i = 0; i < n_profiles; i++) { - /* the tables start at element 3 */ - int pos = 3; - - /* The EWRD profiles officially go from 2 to 4, but we - * save them in sar_profiles[1-3] (because we don't - * have profile 0). So in the array we start from 1. - */ - ret = iwl_mvm_sar_set_profile(mvm, - &wifi_pkg->package.elements[pos], - &mvm->sar_profiles[i + 1], - enabled); - if (ret < 0) - break; - - /* go to the next table */ - pos += ACPI_SAR_TABLE_SIZE; - } - -out_free: - kfree(data); - return ret; -} - -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) -{ - union acpi_object *wifi_pkg, *data; - int i, j, ret, tbl_rev; - int idx = 1; - - data = iwl_acpi_get_object(mvm->dev, ACPI_WGDS_METHOD); - if (IS_ERR(data)) - return PTR_ERR(data); - - wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, - ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); - if (IS_ERR(wifi_pkg)) { - ret = PTR_ERR(wifi_pkg); - goto out_free; - } - - if (tbl_rev != 0) { - ret = -EINVAL; - goto out_free; - } - - mvm->geo_rev = tbl_rev; - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { - union acpi_object *entry; - - entry = &wifi_pkg->package.elements[idx++]; - if ((entry->type != ACPI_TYPE_INTEGER) || - (entry->integer.value > U8_MAX)) { - ret = -EINVAL; - goto out_free; - } - - mvm->geo_profiles[i].values[j] = entry->integer.value; - } - } - ret = 0; -out_free: - kfree(data); - return ret; -} - int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { union { struct iwl_dev_tx_power_cmd v5; struct iwl_dev_tx_power_cmd_v4 v4; } cmd; - int i, j, idx; - int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; - int len; - BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS < 2); - BUILD_BUG_ON(ACPI_SAR_NUM_CHAIN_LIMITS * ACPI_SAR_NUM_SUB_BANDS != - ACPI_SAR_TABLE_SIZE); + u16 len = 0; cmd.v5.v3.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS); @@ -861,174 +694,76 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) len = sizeof(cmd.v5); else if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) - len = sizeof(cmd.v4); + len = sizeof(struct iwl_dev_tx_power_cmd_v4); else len = sizeof(cmd.v4.v3); - for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { - struct iwl_mvm_sar_profile *prof; - - /* don't allow SAR to be disabled (profile 0 means disable) */ - if (profs[i] == 0) - return -EPERM; - - /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ - if (profs[i] > ACPI_SAR_PROFILE_NUM) - return -EINVAL; - - /* profiles go from 1 to 4, so decrement to access the array */ - prof = &mvm->sar_profiles[profs[i] - 1]; - - /* if the profile is disabled, do nothing */ - if (!prof->enabled) { - IWL_DEBUG_RADIO(mvm, "SAR profile %d is disabled.\n", - profs[i]); - /* if one of the profiles is disabled, we fail all */ - return -ENOENT; - } - - IWL_DEBUG_INFO(mvm, - "SAR EWRD: chain %d profile index %d\n", - i, profs[i]); - IWL_DEBUG_RADIO(mvm, " Chain[%d]:\n", i); - for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS; j++) { - idx = (i * ACPI_SAR_NUM_SUB_BANDS) + j; - cmd.v5.v3.per_chain_restriction[i][j] = - cpu_to_le16(prof->table[idx]); - IWL_DEBUG_RADIO(mvm, " Band[%d] = %d * .125dBm\n", - j, prof->table[idx]); - } - } + if (iwl_sar_select_profile(&mvm->fwrt, cmd.v5.v3.per_chain_restriction, + prof_a, prof_b)) + return -ENOENT; IWL_DEBUG_RADIO(mvm, "Sending REDUCE_TX_POWER_CMD per chain\n"); - return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } -static bool iwl_mvm_sar_geo_support(struct iwl_mvm *mvm) -{ - /* - * The GEO_TX_POWER_LIMIT command is not supported on earlier - * firmware versions. Unfortunately, we don't have a TLV API - * flag to rely on, so rely on the major version which is in - * the first byte of ucode_ver. This was implemented - * initially on version 38 and then backported to 17. It was - * also backported to 29, but only for 7265D devices. The - * intention was to have it in 36 as well, but not all 8000 - * family got this feature enabled. The 8000 family is the - * only one using version 36, so skip this version entirely. - */ - return IWL_UCODE_SERIAL(mvm->fw->ucode_ver) >= 38 || - IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 17 || - (IWL_UCODE_SERIAL(mvm->fw->ucode_ver) == 29 && - ((mvm->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == - CSR_HW_REV_TYPE_7265D)); -} - int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) { - struct iwl_geo_tx_power_profiles_resp *resp; - int ret; + union geo_tx_power_profiles_cmd geo_tx_cmd; u16 len; - void *data; - struct iwl_geo_tx_power_profiles_cmd geo_cmd; - struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1; + int ret; struct iwl_host_cmd cmd; - if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { - geo_cmd.ops = + if (fw_has_api(&mvm->fwrt.fw->ucode_capa, + IWL_UCODE_TLV_API_SAR_TABLE_VER)) { + geo_tx_cmd.geo_cmd.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); - len = sizeof(geo_cmd); - data = &geo_cmd; + len = sizeof(geo_tx_cmd.geo_cmd); } else { - geo_cmd_v1.ops = + geo_tx_cmd.geo_cmd_v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_GET_CURRENT_TABLE); - len = sizeof(geo_cmd_v1); - data = &geo_cmd_v1; + len = sizeof(geo_tx_cmd.geo_cmd_v1); } + if (!iwl_sar_geo_support(&mvm->fwrt)) + return -EOPNOTSUPP; + cmd = (struct iwl_host_cmd){ .id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT), .len = { len, }, .flags = CMD_WANT_SKB, - .data = { data }, + .data = { &geo_tx_cmd }, }; - if (!iwl_mvm_sar_geo_support(mvm)) - return -EOPNOTSUPP; - ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret) { IWL_ERR(mvm, "Failed to get geographic profile info %d\n", ret); return ret; } - - resp = (void *)cmd.resp_pkt->data; - ret = le32_to_cpu(resp->profile_idx); - if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES)) { - ret = -EIO; - IWL_WARN(mvm, "Invalid geographic profile idx (%d)\n", ret); - } - + ret = iwl_validate_sar_geo_profile(&mvm->fwrt, &cmd); iwl_free_resp(&cmd); return ret; } static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) { - struct iwl_geo_tx_power_profiles_cmd cmd = { - .ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), - }; - int ret, i, j; u16 cmd_wide_id = WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT); + union geo_tx_power_profiles_cmd cmd; + u16 len; - if (!iwl_mvm_sar_geo_support(mvm)) - return 0; - - ret = iwl_mvm_sar_get_wgds_table(mvm); - if (ret < 0) { - IWL_DEBUG_RADIO(mvm, - "Geo SAR BIOS table invalid or unavailable. (%d)\n", - ret); - /* we don't fail if the table is not available */ - return 0; - } - - IWL_DEBUG_RADIO(mvm, "Sending GEO_TX_POWER_LIMIT\n"); - - BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS * - ACPI_WGDS_TABLE_SIZE + 1 != ACPI_WGDS_WIFI_DATA_SIZE); - - BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES > IWL_NUM_GEO_PROFILES); - - for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { - struct iwl_per_chain_offset *chain = - (struct iwl_per_chain_offset *)&cmd.table[i]; + cmd.geo_cmd.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); - for (j = 0; j < ACPI_WGDS_NUM_BANDS; j++) { - u8 *value; + iwl_sar_geo_init(&mvm->fwrt, cmd.geo_cmd.table); - value = &mvm->geo_profiles[i].values[j * - ACPI_GEO_PER_CHAIN_SIZE]; - chain[j].max_tx_power = cpu_to_le16(value[0]); - chain[j].chain_a = value[1]; - chain[j].chain_b = value[2]; - IWL_DEBUG_RADIO(mvm, - "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, value[1], value[2], value[0]); - } - } + cmd.geo_cmd.table_revision = cpu_to_le32(mvm->fwrt.geo_rev); - cmd.table_revision = cpu_to_le32(mvm->geo_rev); - - if (!fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_SAR_TABLE_VER)) { - return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, - sizeof(struct iwl_geo_tx_power_profiles_cmd_v1), - &cmd); + if (!fw_has_api(&mvm->fwrt.fw->ucode_capa, + IWL_UCODE_TLV_API_SAR_TABLE_VER)) { + len = sizeof(struct iwl_geo_tx_power_profiles_cmd_v1); + } else { + len = sizeof(cmd.geo_cmd); } - return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, sizeof(cmd), &cmd); + return iwl_mvm_send_cmd_pdu(mvm, cmd_wide_id, 0, len, &cmd); } static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) @@ -1037,7 +772,7 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) int i, j, ret, tbl_rev; int idx = 2; - mvm->ppag_table.enabled = cpu_to_le32(0); + mvm->fwrt.ppag_table.enabled = cpu_to_le32(0); data = iwl_acpi_get_object(mvm->dev, ACPI_PPAG_METHOD); if (IS_ERR(data)) return PTR_ERR(data); @@ -1062,8 +797,8 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) goto out_free; } - mvm->ppag_table.enabled = cpu_to_le32(enabled->integer.value); - if (!mvm->ppag_table.enabled) { + mvm->fwrt.ppag_table.enabled = cpu_to_le32(enabled->integer.value); + if (!mvm->fwrt.ppag_table.enabled) { ret = 0; goto out_free; } @@ -1083,11 +818,11 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) (j == 0 && ent->integer.value < ACPI_PPAG_MIN_LB) || (j != 0 && ent->integer.value > ACPI_PPAG_MAX_HB) || (j != 0 && ent->integer.value < ACPI_PPAG_MIN_HB)) { - mvm->ppag_table.enabled = cpu_to_le32(0); + mvm->fwrt.ppag_table.enabled = cpu_to_le32(0); ret = -EINVAL; goto out_free; } - mvm->ppag_table.gain[i][j] = ent->integer.value; + mvm->fwrt.ppag_table.gain[i][j] = ent->integer.value; } } ret = 0; @@ -1108,20 +843,20 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); IWL_DEBUG_RADIO(mvm, "PPAG is %s\n", - mvm->ppag_table.enabled ? "enabled" : "disabled"); + mvm->fwrt.ppag_table.enabled ? "enabled" : "disabled"); for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) { for (j = 0; j < ACPI_PPAG_NUM_SUB_BANDS; j++) { IWL_DEBUG_RADIO(mvm, "PPAG table: chain[%d] band[%d]: gain = %d\n", - i, j, mvm->ppag_table.gain[i][j]); + i, j, mvm->fwrt.ppag_table.gain[i][j]); } } ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), - 0, sizeof(mvm->ppag_table), - &mvm->ppag_table); + 0, sizeof(mvm->fwrt.ppag_table), + &mvm->fwrt.ppag_table); if (ret < 0) IWL_ERR(mvm, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", ret); @@ -1144,17 +879,14 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) } #else /* CONFIG_ACPI */ -static int iwl_mvm_sar_get_wrds_table(struct iwl_mvm *mvm) -{ - return -ENOENT; -} -static int iwl_mvm_sar_get_ewrd_table(struct iwl_mvm *mvm) +inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, + int prof_a, int prof_b) { return -ENOENT; } -static int iwl_mvm_sar_get_wgds_table(struct iwl_mvm *mvm) +inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) { return -ENOENT; } @@ -1164,13 +896,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) return 0; } -int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, - int prof_b) -{ - return -ENOENT; -} - -int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) +static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) { return -ENOENT; } @@ -1241,7 +967,7 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) { int ret; - ret = iwl_mvm_sar_get_wrds_table(mvm); + ret = iwl_sar_get_wrds_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "WRDS SAR BIOS table invalid or unavailable. (%d)\n", @@ -1253,16 +979,14 @@ static int iwl_mvm_sar_init(struct iwl_mvm *mvm) return 1; } - ret = iwl_mvm_sar_get_ewrd_table(mvm); + ret = iwl_sar_get_ewrd_table(&mvm->fwrt); /* if EWRD is not available, we can still use WRDS, so don't fail */ if (ret < 0) IWL_DEBUG_RADIO(mvm, "EWRD SAR BIOS table invalid or unavailable. (%d)\n", ret); - /* choose profile 1 (WRDS) as default for both chains */ ret = iwl_mvm_sar_select_profile(mvm, 1, 1); - /* * If we don't have profile 0 from BIOS, just skip it. This * means that SAR Geo will not be enabled either, even if we @@ -1493,7 +1217,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ret = iwl_mvm_sar_init(mvm); if (ret == 0) { ret = iwl_mvm_sar_geo_init(mvm); - } else if (ret > 0 && !iwl_mvm_sar_get_wgds_table(mvm)) { + } else if (ret > 0 && !iwl_sar_get_wgds_table(&mvm->fwrt)) { /* * If basic SAR is not available, we check for WGDS, * which should *not* be available either. If it is diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 735436f5253f..3ec8de00f3aa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -188,6 +188,11 @@ enum iwl_power_scheme { IWL_POWER_SCHEME_LP }; +union geo_tx_power_profiles_cmd { + struct iwl_geo_tx_power_profiles_cmd geo_cmd; + struct iwl_geo_tx_power_profiles_cmd_v1 geo_cmd_v1; +}; + #define IWL_CONN_MAX_LISTEN_INTERVAL 10 #define IWL_UAPSD_MAX_SP IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL @@ -774,14 +779,6 @@ enum iwl_mvm_queue_status { #define IWL_MVM_NUM_CIPHERS 10 -struct iwl_mvm_sar_profile { - bool enabled; - u8 table[ACPI_SAR_TABLE_SIZE]; -}; - -struct iwl_mvm_geo_profile { - u8 values[ACPI_GEO_TABLE_SIZE]; -}; struct iwl_mvm_txq { struct list_head list; @@ -1144,14 +1141,6 @@ struct iwl_mvm { /* sniffer data to include in radiotap */ __le16 cur_aid; u8 cur_bssid[ETH_ALEN]; - -#ifdef CONFIG_ACPI - struct iwl_mvm_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; - struct iwl_mvm_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES]; - u32 geo_rev; - struct iwl_ppag_table_cmd ppag_table; - u32 ppag_rev; -#endif }; /* Extract MVM priv from op_mode and _hw */ -- cgit v1.2.3-59-g8ed1b From 559897363ca84cf1e445aa237b56b1e531047c1b Mon Sep 17 00:00:00 2001 From: Shahar S Matityahu Date: Fri, 15 Nov 2019 09:28:14 +0200 Subject: iwlwifi: mvm: scan: enable adaptive dwell in p2p Align to the requirement update and support adaptive dwell in p2p scan. Signed-off-by: Shahar S Matityahu Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 60db911f1aac..60edba558c99 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1663,8 +1663,7 @@ static u16 iwl_mvm_scan_umac_flags_v2(struct iwl_mvm *mvm, mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTFY_ITER_COMPLETE; - if (IWL_MVM_ADWELL_ENABLE && - vif->type != NL80211_IFTYPE_P2P_DEVICE) + if (IWL_MVM_ADWELL_ENABLE) flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_ADAPTIVE_DWELL; if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) @@ -1716,8 +1715,7 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; - if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE && - vif->type != NL80211_IFTYPE_P2P_DEVICE) + if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL; /* -- cgit v1.2.3-59-g8ed1b From d66bd0c4840abc2d1793a1bf598ecc554d2376e1 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Fri, 15 Nov 2019 09:28:17 +0200 Subject: iwlwifi: mvm: don't skip mgmt tid when flushing all tids There are various of flows which require tids flushing (disconnection, suspend, etc...). Currently, when the driver instructs the FW to flush he masks all the data tids(0-7). However, the driver doesn't set the management tid (#15) which cause the FW not to flush it. When the FW tries to remove the mgmt queue he throws an assert since it is not an empty queue. instead of just set only the data tids set everything and let the FW ignore the invalid tids. Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 3 ++- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 754adc0146be..9970f61b9f9f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -148,7 +148,8 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, "FLUSHING all tids queues on sta_id = %d\n", flush_arg); mutex_lock(&mvm->mutex); - ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFF, 0) ? : count; + ret = iwl_mvm_flush_sta_tids(mvm, flush_arg, 0xFFFF, 0) + ? : count; mutex_unlock(&mvm->mutex); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 61c33b9335e3..473d56552e26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -4644,7 +4644,7 @@ static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) continue; if (drop) - iwl_mvm_flush_sta_tids(mvm, i, 0xFF, 0); + iwl_mvm_flush_sta_tids(mvm, i, 0xFFFF, 0); else iwl_mvm_wait_sta_queues_empty(mvm, iwl_mvm_sta_from_mac80211(sta)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index f4778a6a40b9..81a88a89ea74 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -2059,7 +2059,7 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) if (iwl_mvm_has_new_tx_api(mvm)) return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, - 0xff | BIT(IWL_MGMT_TID), flags); + 0xffff, flags); if (internal) return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, -- cgit v1.2.3-59-g8ed1b From 220089c720b0b8175961a320c29f55a2ada0bf31 Mon Sep 17 00:00:00 2001 From: Mordechay Goodstein Date: Fri, 15 Nov 2019 09:28:20 +0200 Subject: iwlwifi: mvm: start CTDP budget from 2400mA The current budget of 2000mA is preventing us from reaching maximum throughput. According to our system engineers, we can increase the maximum budget to 2400mA to solve this problem. Signed-off-by: Mordechay Goodstein Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 43 +++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index f0c539b37ea7..b5a16f00bada 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -8,6 +8,7 @@ * Copyright(c) 2013 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014, 2019 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH + * Copyright(c) 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -482,26 +484,27 @@ static const struct iwl_tt_params iwl_mvm_default_tt_params = { /* budget in mWatt */ static const u32 iwl_mvm_cdev_budgets[] = { - 2000, /* cooling state 0 */ - 1800, /* cooling state 1 */ - 1600, /* cooling state 2 */ - 1400, /* cooling state 3 */ - 1200, /* cooling state 4 */ - 1000, /* cooling state 5 */ - 900, /* cooling state 6 */ - 800, /* cooling state 7 */ - 700, /* cooling state 8 */ - 650, /* cooling state 9 */ - 600, /* cooling state 10 */ - 550, /* cooling state 11 */ - 500, /* cooling state 12 */ - 450, /* cooling state 13 */ - 400, /* cooling state 14 */ - 350, /* cooling state 15 */ - 300, /* cooling state 16 */ - 250, /* cooling state 17 */ - 200, /* cooling state 18 */ - 150, /* cooling state 19 */ + 2400, /* cooling state 0 */ + 2000, /* cooling state 1 */ + 1800, /* cooling state 2 */ + 1600, /* cooling state 3 */ + 1400, /* cooling state 4 */ + 1200, /* cooling state 5 */ + 1000, /* cooling state 6 */ + 900, /* cooling state 7 */ + 800, /* cooling state 8 */ + 700, /* cooling state 9 */ + 650, /* cooling state 10 */ + 600, /* cooling state 11 */ + 550, /* cooling state 12 */ + 500, /* cooling state 13 */ + 450, /* cooling state 14 */ + 400, /* cooling state 15 */ + 350, /* cooling state 16 */ + 300, /* cooling state 17 */ + 250, /* cooling state 18 */ + 200, /* cooling state 19 */ + 150, /* cooling state 20 */ }; int iwl_mvm_ctdp_command(struct iwl_mvm *mvm, u32 op, u32 state) -- cgit v1.2.3-59-g8ed1b From 4658d552e02c75bce90c515e1397e23464d68f3c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Fri, 15 Nov 2019 09:28:22 +0200 Subject: iwlwifi: mvm: sync the iwl_mvm_session_prot_notif layout The firmware API has changed a little bit but this change has no impact on the flow and is backward compatible. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net') 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 416e817d7b4d..a731f28e101a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -459,6 +459,7 @@ struct iwl_mvm_session_prot_cmd { * @mac_id: the mac id for which the session protection started / ended * @status: 1 means success, 0 means failure * @start: 1 means the session protection started, 0 means it ended + * @conf_id: the configuration id of the session that started / eneded * * Note that any session protection will always get two notifications: start * and end even the firmware could not schedule it. @@ -467,6 +468,7 @@ struct iwl_mvm_session_prot_notif { __le32 mac_id; __le32 status; __le32 start; -} __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_1 */ + __le32 conf_id; +} __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_2 */ #endif /* __iwl_fw_api_time_event_h__ */ -- cgit v1.2.3-59-g8ed1b From 3681021fc6af58bfacd1c6e7b1e03ea1da7681e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2019 09:28:25 +0200 Subject: iwlwifi: remove IWL_DEVICE_22560/IWL_DEVICE_FAMILY_22560 This is dead code, nothing uses the IWL_DEVICE_22560 macro and thus nothing every uses IWL_DEVICE_FAMILY_22560. Remove it all. While at it, remove some code and definitions used only in this case, and clean up some comments/names that still refer to it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 20 +------- drivers/net/wireless/intel/iwlwifi/fw/api/tx.h | 6 +-- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 - drivers/net/wireless/intel/iwlwifi/iwl-csr.h | 2 - drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-fh.h | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 6 +-- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 4 +- drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 2 +- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 53 +++++++--------------- .../net/wireless/intel/iwlwifi/pcie/trans-gen2.c | 4 +- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 29 ++---------- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 12 ++--- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 2 +- 16 files changed, 45 insertions(+), 106 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 9ebb3376ffb9..37bcf157f0bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -138,7 +138,7 @@ static const struct iwl_base_params iwl_22000_base_params = { .pcie_l1_allowed = true, }; -static const struct iwl_base_params iwl_22560_base_params = { +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, @@ -212,27 +212,11 @@ static const struct iwl_ht_params iwl_22000_ht_params = { }, \ } -#define IWL_DEVICE_22560 \ - IWL_DEVICE_22000_COMMON, \ - .trans.device_family = IWL_DEVICE_FAMILY_22560, \ - .trans.base_params = &iwl_22560_base_params, \ - .trans.csr = &iwl_csr_v2, \ - .mon_dram_regs = { \ - .write_ptr = { \ - .addr = MON_BUFF_WRPTR_VER2, \ - .mask = 0xffffffff, \ - }, \ - .cycle_cnt = { \ - .addr = MON_BUFF_CYCLE_CNT_VER2, \ - .mask = 0xffffffff, \ - }, \ - } - #define IWL_DEVICE_AX210 \ IWL_DEVICE_22000_COMMON, \ .trans.umac_prph_offset = 0x300000, \ .trans.device_family = IWL_DEVICE_FAMILY_AX210, \ - .trans.base_params = &iwl_22560_base_params, \ + .trans.base_params = &iwl_ax210_base_params, \ .trans.csr = &iwl_csr_v1, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 8511e735c374..f89a9e16a8c0 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -7,7 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -323,7 +323,7 @@ struct iwl_tx_cmd_gen2 { } __packed; /* TX_CMD_API_S_VER_7 */ /** - * struct iwl_tx_cmd_gen3 - TX command struct to FW for 22560 devices + * struct iwl_tx_cmd_gen3 - TX command struct to FW for AX210+ devices * ( TX_CMD = 0x1c ) * @len: in bytes of the payload, see below for details * @flags: combination of &enum iwl_tx_cmd_flags diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 1b027a138b6b..59bb960b460a 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -88,7 +88,6 @@ enum iwl_device_family { IWL_DEVICE_FAMILY_8000, IWL_DEVICE_FAMILY_9000, IWL_DEVICE_FAMILY_22000, - IWL_DEVICE_FAMILY_22560, IWL_DEVICE_FAMILY_AX210, }; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 695bbaa86273..92d9898ab7c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -603,9 +603,7 @@ enum msix_fh_int_causes { enum msix_hw_int_causes { MSIX_HW_INT_CAUSES_REG_ALIVE = BIT(0), MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1), - MSIX_HW_INT_CAUSES_REG_IPC = BIT(1), MSIX_HW_INT_CAUSES_REG_IML = BIT(2), - MSIX_HW_INT_CAUSES_REG_SW_ERR_V2 = BIT(5), MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6), MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7), MSIX_HW_INT_CAUSES_REG_PERIODIC = BIT(8), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index b0881e713b48..4096ccf58b07 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1804,7 +1804,7 @@ MODULE_PARM_DESC(11n_disable, "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, 0444); MODULE_PARM_DESC(amsdu_size, - "amsdu size 0: 12K for multi Rx queue devices, 2K for 22560 devices, " + "amsdu size 0: 12K for multi Rx queue devices, 2K for AX210 devices, " "4K for other devices 1:4K 2:8K 3:12K 4: 2K (default 0)"); module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, 0444); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h index 05c1c77c88a0..8836f85afe85 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fh.h @@ -768,7 +768,7 @@ struct iwlagn_scd_bc_tbl { /** * struct iwl_gen3_bc_tbl scheduler byte count table gen3 - * For 22560 and on: + * For AX210 and on: * @tfd_offset: 0-12 - tx command byte count * 12-13 - number of 64 byte chunks * 14-16 - reserved diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 9970f61b9f9f..aa659162a7c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1175,7 +1175,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, int bin_len = count / 2; int ret = -EINVAL; size_t mpdu_cmd_hdr_size = (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_rx_mpdu_desc) : IWL_RX_DESC_SIZE_V1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index dcdc195ac1d6..3b0637311e3c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -692,7 +692,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, op_mode->ops = &iwl_mvm_ops_mq; trans->rx_mpdu_cmd_hdr_size = (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_rx_mpdu_desc) : IWL_RX_DESC_SIZE_V1; } else { @@ -761,7 +761,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans_cfg.no_reclaim_cmds = no_reclaim_cmds; trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) rb_size_default = IWL_AMSDU_2K; else rb_size_default = IWL_AMSDU_4K; @@ -787,7 +787,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, trans->wide_cmd_header = true; trans_cfg.bc_table_dword = - mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_22560; + mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210; trans_cfg.command_groups = iwl_mvm_groups; trans_cfg.command_groups_size = ARRAY_SIZE(iwl_mvm_groups); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index b488cd702058..75a7af5ad7b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1578,7 +1578,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) return; - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { rate_n_flags = le32_to_cpu(desc->v3.rate_n_flags); channel = desc->v3.channel; gp2_on_air_rise = le32_to_cpu(desc->v3.gp2_on_air_rise); @@ -1680,7 +1680,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, u64 tsf_on_air_rise; if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) + IWL_DEVICE_FAMILY_AX210) tsf_on_air_rise = le64_to_cpu(desc->v3.tsf_on_air_rise); else tsf_on_air_rise = le64_to_cpu(desc->v1.tsf_on_air_rise); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index 81a88a89ea74..dc5c02fbc65a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -550,7 +550,7 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, } if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) { + IWL_DEVICE_FAMILY_AX210) { struct iwl_tx_cmd_gen3 *cmd = (void *)dev_cmd->payload; cmd->offload_assist |= cpu_to_le32(offload_assist); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index fcef2806ebb1..3da2c7e38ffa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -166,7 +166,7 @@ struct iwl_rx_completion_desc { * @id: queue index * @bd: driver's pointer to buffer of receive buffer descriptors (rbd). * Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices. - * In 22560 devices it is a pointer to a list of iwl_rx_transfer_desc's + * In AX210 devices it is a pointer to a list of iwl_rx_transfer_desc's * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd) * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd) @@ -264,7 +264,7 @@ static inline int iwl_queue_inc_wrap(struct iwl_trans *trans, int index) static inline __le16 iwl_get_closed_rb_stts(struct iwl_trans *trans, struct iwl_rxq *rxq) { - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { __le16 *rb_stts = rxq->rb_stts; return READ_ONCE(*rb_stts); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 19dd075f2f63..4bba6b8a863c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -200,8 +200,8 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr) */ int iwl_pcie_rx_stop(struct iwl_trans *trans) { - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { - /* TODO: remove this for 22560 once fw does it */ + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + /* TODO: remove this once fw does it */ iwl_write_umac_prph(trans, RFH_RXF_DMA_CFG_GEN3, 0); return iwl_poll_umac_prph_bit(trans, RFH_GEN_STATUS_GEN3, RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); @@ -247,11 +247,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, } rxq->write_actual = round_down(rxq->write, 8); - if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22560) - iwl_write32(trans, HBUS_TARG_WRPTR, - (rxq->write_actual | - ((FIRST_RX_QUEUE + rxq->id) << 16))); - else if (trans->trans_cfg->mq_rx_supported) + if (trans->trans_cfg->mq_rx_supported) iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id), rxq->write_actual); else @@ -279,7 +275,7 @@ static void iwl_pcie_restock_bd(struct iwl_trans *trans, struct iwl_rxq *rxq, struct iwl_rx_mem_buffer *rxb) { - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { struct iwl_rx_transfer_desc *bd = rxq->bd; BUILD_BUG_ON(sizeof(*bd) != 2 * sizeof(u64)); @@ -691,7 +687,7 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, { struct device *dev = trans->dev; bool use_rx_td = (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560); + IWL_DEVICE_FAMILY_AX210); int free_size = iwl_pcie_free_bd_size(trans, use_rx_td); if (rxq->bd) @@ -712,7 +708,7 @@ static void iwl_pcie_free_rxq_dma(struct iwl_trans *trans, rxq->used_bd_dma = 0; rxq->used_bd = NULL; - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; if (rxq->tr_tail) @@ -736,7 +732,7 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, int i; int free_size; bool use_rx_td = (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560); + IWL_DEVICE_FAMILY_AX210); size_t rb_stts_size = use_rx_td ? sizeof(__le16) : sizeof(struct iwl_rb_status); @@ -784,11 +780,6 @@ static int iwl_pcie_alloc_rxq_dma(struct iwl_trans *trans, &rxq->cr_tail_dma, GFP_KERNEL); if (!rxq->cr_tail) goto err; - /* - * W/A 22560 device step Z0 must be non zero bug - * TODO: remove this when stop supporting Z0 - */ - *rxq->cr_tail = cpu_to_le16(500); return 0; @@ -808,7 +799,7 @@ int iwl_pcie_rx_alloc(struct iwl_trans *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_22560 ? + IWL_DEVICE_FAMILY_AX210 ? sizeof(__le16) : sizeof(struct iwl_rb_status); if (WARN_ON(trans_pcie->rxq)) @@ -1074,8 +1065,9 @@ int _iwl_pcie_rx_init(struct iwl_trans *trans) rxq->read = 0; rxq->write = 0; rxq->write_actual = 0; - memset(rxq->rb_stts, 0, (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + memset(rxq->rb_stts, 0, + (trans->trans_cfg->device_family >= + IWL_DEVICE_FAMILY_AX210) ? sizeof(__le16) : sizeof(struct iwl_rb_status)); iwl_pcie_rx_init_rxb_lists(rxq); @@ -1152,7 +1144,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) struct iwl_rb_allocator *rba = &trans_pcie->rba; int i; size_t rb_stts_size = trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560 ? + IWL_DEVICE_FAMILY_AX210 ? sizeof(__le16) : sizeof(struct iwl_rb_status); /* @@ -1347,7 +1339,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, } page_stolen |= rxcb._page_stolen; - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) break; offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN); } @@ -1399,7 +1391,7 @@ static struct iwl_rx_mem_buffer *iwl_pcie_get_rxb(struct iwl_trans *trans, } /* used_bd is a 32/16 bit but only 12 are used to retrieve the vid */ - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) vid = le16_to_cpu(rxq->cd[i].rbid) & 0x0FFF; else vid = le32_to_cpu(rxq->bd_32[i]) & 0x0FFF; @@ -1515,7 +1507,7 @@ out: /* Backtrack one entry */ rxq->read = i; /* update cr tail with the rxq read pointer */ - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) *rxq->cr_tail = cpu_to_le16(r); spin_unlock(&rxq->lock); @@ -2152,8 +2144,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) /* Error detected by uCode */ if ((inta_fh & MSIX_FH_INT_CAUSES_FH_ERR) || - (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR) || - (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR_V2)) { + (inta_hw & MSIX_HW_INT_CAUSES_REG_SW_ERR)) { IWL_ERR(trans, "Microcode SW error detected. Restarting 0x%X.\n", inta_fh); @@ -2185,17 +2176,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) } } - if (trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_22560 && - inta_hw & MSIX_HW_INT_CAUSES_REG_IPC) { - /* Reflect IML transfer status */ - int res = iwl_read32(trans, CSR_IML_RESP_ADDR); - - IWL_DEBUG_ISR(trans, "IML transfer status: %d\n", res); - if (res == IWL_IMAGE_RESP_FAIL) { - isr_stats->sw++; - iwl_pcie_irq_handle_error(trans); - } - } else if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP) { + if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP) { u32 sleep_notif = le32_to_cpu(trans_pcie->prph_info->sleep_notif); if (sleep_notif == IWL_D3_SLEEP_STATUS_SUSPEND || diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index ca3bb4d65b00..0252716c0b24 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -193,7 +193,7 @@ void _iwl_trans_pcie_gen2_stop_device(struct iwl_trans *trans) } iwl_pcie_ctxt_info_free_paging(trans); - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) iwl_pcie_ctxt_info_gen3_free(trans); else iwl_pcie_ctxt_info_free(trans); @@ -365,7 +365,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, goto out; } - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) ret = iwl_pcie_ctxt_info_gen3_init(trans, fw); else ret = iwl_pcie_ctxt_info_init(trans, fw); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 9e8c47c30704..af9bc6b64542 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1135,30 +1135,12 @@ static struct iwl_causes_list causes_list[] = { {MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E}, }; -static struct iwl_causes_list causes_list_v2[] = { - {MSIX_FH_INT_CAUSES_D2S_CH0_NUM, CSR_MSIX_FH_INT_MASK_AD, 0}, - {MSIX_FH_INT_CAUSES_D2S_CH1_NUM, CSR_MSIX_FH_INT_MASK_AD, 0x1}, - {MSIX_FH_INT_CAUSES_S2D, CSR_MSIX_FH_INT_MASK_AD, 0x3}, - {MSIX_FH_INT_CAUSES_FH_ERR, CSR_MSIX_FH_INT_MASK_AD, 0x5}, - {MSIX_HW_INT_CAUSES_REG_ALIVE, CSR_MSIX_HW_INT_MASK_AD, 0x10}, - {MSIX_HW_INT_CAUSES_REG_IPC, CSR_MSIX_HW_INT_MASK_AD, 0x11}, - {MSIX_HW_INT_CAUSES_REG_SW_ERR_V2, CSR_MSIX_HW_INT_MASK_AD, 0x15}, - {MSIX_HW_INT_CAUSES_REG_CT_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x16}, - {MSIX_HW_INT_CAUSES_REG_RF_KILL, CSR_MSIX_HW_INT_MASK_AD, 0x17}, - {MSIX_HW_INT_CAUSES_REG_PERIODIC, CSR_MSIX_HW_INT_MASK_AD, 0x18}, - {MSIX_HW_INT_CAUSES_REG_SCD, CSR_MSIX_HW_INT_MASK_AD, 0x2A}, - {MSIX_HW_INT_CAUSES_REG_FH_TX, CSR_MSIX_HW_INT_MASK_AD, 0x2B}, - {MSIX_HW_INT_CAUSES_REG_HW_ERR, CSR_MSIX_HW_INT_MASK_AD, 0x2D}, - {MSIX_HW_INT_CAUSES_REG_HAP, CSR_MSIX_HW_INT_MASK_AD, 0x2E}, -}; - static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int val = trans_pcie->def_irq | MSIX_NON_AUTO_CLEAR_CAUSE; - int i, arr_size = - (trans->trans_cfg->device_family != IWL_DEVICE_FAMILY_22560) ? - ARRAY_SIZE(causes_list) : ARRAY_SIZE(causes_list_v2); + int i, arr_size = ARRAY_SIZE(causes_list); + struct iwl_causes_list *causes = causes_list; /* * Access all non RX causes and map them to the default irq. @@ -1166,11 +1148,6 @@ static void iwl_pcie_map_non_rx_causes(struct iwl_trans *trans) * the first interrupt vector will serve non-RX and FBQ causes. */ for (i = 0; i < arr_size; i++) { - struct iwl_causes_list *causes = - (trans->trans_cfg->device_family != - IWL_DEVICE_FAMILY_22560) ? - causes_list : causes_list_v2; - iwl_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val); iwl_clear_bit(trans, causes[i].mask_reg, causes[i].cause_num); @@ -1894,7 +1871,7 @@ static u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs) static u32 iwl_trans_pcie_prph_msk(struct iwl_trans *trans) { - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) return 0x00FFFFFF; else return 0x000FFFFF; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 1c69a2ddd7c7..4c9c78d1ba98 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -113,14 +113,14 @@ static void iwl_pcie_gen2_update_byte_tbl(struct iwl_trans_pcie *trans_pcie, */ num_fetch_chunks = DIV_ROUND_UP(filled_tfd_size, 64) - 1; - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { - /* Starting from 22560, the HW expects bytes */ + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + /* Starting from AX210, the HW expects bytes */ WARN_ON(trans_pcie->bc_table_dword); WARN_ON(len > 0x3FFF); bc_ent = cpu_to_le16(len | (num_fetch_chunks << 14)); scd_bc_tbl_gen3->tfd_offset[idx] = bc_ent; } else { - /* Until 22560, the HW expects DW */ + /* Before AX210, the HW expects DW */ WARN_ON(!trans_pcie->bc_table_dword); len = DIV_ROUND_UP(len, 4); WARN_ON(len > 0xFFF); @@ -547,7 +547,7 @@ struct iwl_tfh_tfd *iwl_pcie_gen2_build_tfd(struct iwl_trans *trans, memset(tfd, 0, sizeof(*tfd)); - if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_22560) + if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) len = sizeof(struct iwl_tx_cmd_gen2); else len = sizeof(struct iwl_tx_cmd_gen3); @@ -629,7 +629,7 @@ int iwl_trans_pcie_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, return -1; } - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22560) { + if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { struct iwl_tx_cmd_gen3 *tx_cmd_gen3 = (void *)dev_cmd->payload; @@ -1130,7 +1130,7 @@ int iwl_trans_pcie_dyn_txq_alloc_dma(struct iwl_trans *trans, return -ENOMEM; ret = iwl_pcie_alloc_dma_ptr(trans, &txq->bc_tbl, (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_gen3_bc_tbl) : sizeof(struct iwlagn_scd_bc_tbl)); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index 4806a04cec8c..b710b8a25b54 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -949,7 +949,7 @@ static int iwl_pcie_tx_alloc(struct iwl_trans *trans) u16 bc_tbls_size = trans->trans_cfg->base_params->num_of_queues; bc_tbls_size *= (trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_22560) ? + IWL_DEVICE_FAMILY_AX210) ? sizeof(struct iwl_gen3_bc_tbl) : sizeof(struct iwlagn_scd_bc_tbl); -- cgit v1.2.3-59-g8ed1b From bfc3e9fdbfb8c2fe8f7f2d7c41126c554579237f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2019 09:28:28 +0200 Subject: iwlwifi: 22000: fix some indentation Somehow two tabs snuck into this file where just one should be used, fix that. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 37bcf157f0bb..8ad771dadae2 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -317,39 +317,39 @@ const struct iwl_cfg iwl_ax101_cfg_quz_hr = { }; const struct iwl_cfg iwl_ax201_cfg_quz_hr = { - .name = "Intel(R) Wi-Fi 6 AX201 160MHz", - .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, - IWL_DEVICE_22500, - /* + .name = "Intel(R) Wi-Fi 6 AX201 160MHz", + .fw_name_pre = IWL_QUZ_A_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, + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; const struct iwl_cfg iwl_ax1650s_cfg_quz_hr = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", - .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, - IWL_DEVICE_22500, - /* + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .fw_name_pre = IWL_QUZ_A_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, + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; const struct iwl_cfg iwl_ax1650i_cfg_quz_hr = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", - .fw_name_pre = IWL_QUZ_A_HR_B_FW_PRE, - IWL_DEVICE_22500, - /* + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .fw_name_pre = IWL_QUZ_A_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, + .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT, }; const struct iwl_cfg iwl_ax200_cfg_cc = { -- cgit v1.2.3-59-g8ed1b From 7937fd3227055892e169f4b34d21157e57d919e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 15 Nov 2019 09:28:31 +0200 Subject: iwlwifi: mvm: fix non-ACPI function The code now compiles without ACPI, but there's a warning since iwl_mvm_get_ppag_table() isn't used, and iwl_mvm_ppag_init() must not unconditionally fail but return success instead. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 763907c6969c..dd685f7eb410 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -896,11 +896,6 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) return 0; } -static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) { return -ENOENT; @@ -908,7 +903,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { - return -ENOENT; + return 0; } #endif /* CONFIG_ACPI */ -- cgit v1.2.3-59-g8ed1b From 92fe0f81b64b1983f21e096a5b5b2bcb60294ca7 Mon Sep 17 00:00:00 2001 From: Eduardo Abinader Date: Thu, 7 Nov 2019 17:07:46 +0100 Subject: brcmsmac: remove unnecessary return Signed-off-by: Eduardo Abinader Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c index ff39773333db..3f09d89ba922 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c @@ -7376,9 +7376,7 @@ static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc, false, true); /* mark beacon0 valid */ bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD); - return; } - return; } /* -- cgit v1.2.3-59-g8ed1b From 38860bdf28b7b01e744834b7b1277812ad82786d Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Sun, 10 Nov 2019 18:49:55 +0800 Subject: rtl8xxxu: Remove set but not used variable 'rsr' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c: In function rtl8xxxu_gen2_config_channel: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:1266:13: warning: variable rsr set but not used [-Wunused-but-set-variable] rsr is never used, so remove it. Reported-by: Hulk Robot Signed-off-by: Zheng Yongjun Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 32a40b82c5f5..1d94cab6f71f 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1255,7 +1255,7 @@ void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw) void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw) { struct rtl8xxxu_priv *priv = hw->priv; - u32 val32, rsr; + u32 val32; u8 val8, subchannel; u16 rf_mode_bw; bool ht = true; @@ -1264,7 +1264,6 @@ void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw) rf_mode_bw = rtl8xxxu_read16(priv, REG_WMAC_TRXPTCL_CTL); rf_mode_bw &= ~WMAC_TRXPTCL_CTL_BW_MASK; - rsr = rtl8xxxu_read32(priv, REG_RESPONSE_RATE_SET); channel = hw->conf.chandef.chan->hw_value; /* Hack */ -- cgit v1.2.3-59-g8ed1b From 4f5969c36a4572dbaf8737dd9f486382d4e44b4a Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 11 Nov 2019 03:34:27 +0000 Subject: rtw88: remove duplicated include from ps.c Remove duplicated include. Signed-off-by: YueHaibing Reviewed-by: Simon Horman Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/ps.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 820e0a3a141c..2226e3e7d7f8 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -9,7 +9,6 @@ #include "mac.h" #include "coex.h" #include "debug.h" -#include "reg.h" static int rtw_ips_pwr_up(struct rtw_dev *rtwdev) { -- cgit v1.2.3-59-g8ed1b From 983db6198f0d0ee406f365069901387e7834c3c0 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 14 Nov 2019 11:54:19 +0200 Subject: mlxsw: spectrum_router: Allocate discard adjacency entry when needed Commit 0c3cbbf96def ("mlxsw: Add specific trap for packets routed via invalid nexthops") allocated an adjacency entry during driver initialization whose purpose is to discard packets hitting the route pointing to it. These adjacency entries are allocated from a resource called KVD linear (KVDL). There are situations in which the user can decide to set the size of this resource (via devlink-resource) to 0, in which case the driver will not be able to load. Therefore, instead of pre-allocating this adjacency entry, simply allocate it only when needed. A variable indicating the validity of the entry is added and is used to ensure it is only allocated and written once and that it is freed after all the routes were flushed. Fixes: 0c3cbbf96def ("mlxsw: Add specific trap for packets routed via invalid nexthops") Signed-off-by: Ido Schimmel Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 43 ++++++++++++++++------ 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 1aa436054490..517cb8b14b1d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -78,6 +78,7 @@ struct mlxsw_sp_router { const struct mlxsw_sp_rif_ops **rif_ops_arr; const struct mlxsw_sp_ipip_ops **ipip_ops_arr; u32 adj_discard_index; + bool adj_discard_index_valid; }; struct mlxsw_sp_rif { @@ -4203,13 +4204,33 @@ static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) u32 adj_discard_index = mlxsw_sp->router->adj_discard_index; enum mlxsw_reg_ratr_trap_action trap_action; char ratr_pl[MLXSW_REG_RATR_LEN]; + int err; + + if (mlxsw_sp->router->adj_discard_index_valid) + return 0; + + err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + &mlxsw_sp->router->adj_discard_index); + if (err) + return err; trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS; mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, MLXSW_REG_RATR_TYPE_ETHERNET, adj_discard_index, rif_index); mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); + if (err) + goto err_ratr_write; + + mlxsw_sp->router->adj_discard_index_valid = true; + + return 0; + +err_ratr_write: + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + mlxsw_sp->router->adj_discard_index); + return err; } static int mlxsw_sp_fib_entry_op_remote(struct mlxsw_sp *mlxsw_sp, @@ -5956,6 +5977,16 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp) continue; mlxsw_sp_vr_fib_flush(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6); } + + /* After flushing all the routes, it is not possible anyone is still + * using the adjacency index that is discarding packets, so free it in + * case it was allocated. + */ + if (!mlxsw_sp->router->adj_discard_index_valid) + return; + mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, + mlxsw_sp->router->adj_discard_index); + mlxsw_sp->router->adj_discard_index_valid = false; } static void mlxsw_sp_router_fib_abort(struct mlxsw_sp *mlxsw_sp) @@ -8170,11 +8201,6 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp, if (err) goto err_neigh_init; - err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, - &router->adj_discard_index); - if (err) - goto err_adj_discard_index_alloc; - mlxsw_sp->router->netevent_nb.notifier_call = mlxsw_sp_router_netevent_event; err = register_netevent_notifier(&mlxsw_sp->router->netevent_nb); @@ -8203,9 +8229,6 @@ err_dscp_init: err_mp_hash_init: unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); err_register_netevent_notifier: - mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, - router->adj_discard_index); -err_adj_discard_index_alloc: mlxsw_sp_neigh_fini(mlxsw_sp); err_neigh_init: mlxsw_sp_vrs_fini(mlxsw_sp); @@ -8237,8 +8260,6 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp) unregister_fib_notifier(mlxsw_sp_net(mlxsw_sp), &mlxsw_sp->router->fib_nb); unregister_netevent_notifier(&mlxsw_sp->router->netevent_nb); - mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ADJ, 1, - mlxsw_sp->router->adj_discard_index); mlxsw_sp_neigh_fini(mlxsw_sp); mlxsw_sp_vrs_fini(mlxsw_sp); mlxsw_sp_mr_fini(mlxsw_sp); -- cgit v1.2.3-59-g8ed1b From 09146abebc788a2f133a6eae9cd6dc8c91c05047 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:45 +0100 Subject: net: stmmac: Do not set RX IC bit if RX Coalesce is zero We may only want to use the RX Watchdog so lets check if RX Coalesce settings are non-zero and only set the RX Interrupt on Completion bit if its not. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 39b4efd521f9..7939ef7e23b7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3440,7 +3440,11 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) rx_q->rx_count_frames += priv->rx_coal_frames; if (rx_q->rx_count_frames > priv->rx_coal_frames) rx_q->rx_count_frames = 0; - use_rx_wd = priv->use_riwt && rx_q->rx_count_frames; + + use_rx_wd = !priv->rx_coal_frames; + use_rx_wd |= rx_q->rx_count_frames > 0; + if (!priv->use_riwt) + use_rx_wd = false; dma_wmb(); stmmac_set_rx_owner(priv, p, use_rx_wd); -- cgit v1.2.3-59-g8ed1b From 4e4337ccf780978881f8f41c5c30dad626a4a51e Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:46 +0100 Subject: net: stmmac: Setup a default RX Coalesce value instead of the minimum For performance reasons, sometimes using the minimum RX Coalesce value is not optimal. Lets setup a default value that is optimal in most of the use cases. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 912bbb6515b2..309ea12ea61f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -248,6 +248,7 @@ struct stmmac_safety_stats { /* Max/Min RI Watchdog Timer count value */ #define MAX_DMA_RIWT 0xff #define MIN_DMA_RIWT 0x10 +#define DEF_DMA_RIWT 0xa0 /* Tx coalesce parameters */ #define STMMAC_COAL_TX_TIMER 1000 #define STMMAC_MAX_COAL_TX_TICK 100000 diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7939ef7e23b7..400fbb727fd5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2605,9 +2605,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; if (priv->use_riwt) { - ret = stmmac_rx_watchdog(priv, priv->ioaddr, MIN_DMA_RIWT, rx_cnt); - if (!ret) - priv->rx_riwt = MIN_DMA_RIWT; + if (!priv->rx_riwt) + priv->rx_riwt = DEF_DMA_RIWT; + + ret = stmmac_rx_watchdog(priv, priv->ioaddr, priv->rx_riwt, rx_cnt); } if (priv->hw->pcs) -- cgit v1.2.3-59-g8ed1b From 854248e5ec810afe2c3dcf017bb76b7224b97c47 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:47 +0100 Subject: net: stmmac: gmac4+: Remove uneeded computation for RFA/RFD RFA and RFD should not be dependent on FIFO size. In fact, the more FIFO space we have, the later we can activate Flow Control. Let's use hard-coded values for RFA and RFD for all FIFO sizes with the exception of 4k, which is a special case. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 36a0af8bf89f..c15409030710 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -252,19 +252,9 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode, rfa = 0x01; /* Full-1.5K */ break; - case 8192: - rfd = 0x06; /* Full-4K */ - rfa = 0x0a; /* Full-6K */ - break; - - case 16384: - rfd = 0x06; /* Full-4K */ - rfa = 0x12; /* Full-10K */ - break; - default: - rfd = 0x06; /* Full-4K */ - rfa = 0x1e; /* Full-16K */ + rfd = 0x07; /* Full-4.5K */ + rfa = 0x04; /* Full-3K */ break; } -- cgit v1.2.3-59-g8ed1b From 52f96cd135b160d44db4cb62a5b614b3bca20fbc Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:48 +0100 Subject: net: stmmac: xgmac: Remove uneeded computation for RFA/RFD RFA and RFD should not be dependent on FIFO size. In fact, the more FIFO space we have, the later we can activate Flow Control. Let's use hard-coded values for RFA and RFD for all FIFO sizes with the exception of 4k, which is a special case. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index f148cb2061d8..22a7f0cc1b90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -183,19 +183,9 @@ static void dwxgmac2_dma_rx_mode(void __iomem *ioaddr, int mode, rfa = 0x01; /* Full-1.5K */ break; - case 8192: - rfd = 0x06; /* Full-4K */ - rfa = 0x0a; /* Full-6K */ - break; - - case 16384: - rfd = 0x06; /* Full-4K */ - rfa = 0x12; /* Full-10K */ - break; - default: - rfd = 0x06; /* Full-4K */ - rfa = 0x1e; /* Full-16K */ + rfd = 0x07; /* Full-4.5K */ + rfa = 0x04; /* Full-3K */ break; } -- cgit v1.2.3-59-g8ed1b From da20245100319b54af770df707f358f2ebc3b16d Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:49 +0100 Subject: net: stmmac: Tune-up default coalesce settings Tune-up the defalt coalesce settings for optimal values. This gives the best performance in most of the use-cases. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 309ea12ea61f..b210e987a1db 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -253,8 +253,8 @@ struct stmmac_safety_stats { #define STMMAC_COAL_TX_TIMER 1000 #define STMMAC_MAX_COAL_TX_TICK 100000 #define STMMAC_TX_MAX_FRAMES 256 -#define STMMAC_TX_FRAMES 1 -#define STMMAC_RX_FRAMES 25 +#define STMMAC_TX_FRAMES 25 +#define STMMAC_RX_FRAMES 0 /* Packets types */ enum packets_types { -- cgit v1.2.3-59-g8ed1b From c2837423cb54551302f037106830ee607b4563e0 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:50 +0100 Subject: net: stmmac: Rework TX Coalesce logic Coalesce logic currently increments the number of packets and sets the IC bit when the coalesced packets have passed a given limit. This does not reflect very well what coalesce was meant for as we can have a large number of packets that are coalesced and then a single one, sent later on that has the IC bit. Rework the logic so that it coalesces only upon a limit of packets and sets the IC bit for large number of packets. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 61 ++++++++++++++++------- 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 400fbb727fd5..4ba250a9008f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2916,16 +2916,17 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) struct stmmac_priv *priv = netdev_priv(dev); int nfrags = skb_shinfo(skb)->nr_frags; u32 queue = skb_get_queue_mapping(skb); + unsigned int first_entry, tx_packets; + int tmp_pay_len = 0, first_tx; struct stmmac_tx_queue *tx_q; - unsigned int first_entry; u8 proto_hdr_len, hdr; - int tmp_pay_len = 0; + bool has_vlan, set_ic; u32 pay_len, mss; dma_addr_t des; - bool has_vlan; int i; tx_q = &priv->tx_queue[queue]; + first_tx = tx_q->cur_tx; /* Compute header lengths */ if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { @@ -3033,16 +3034,27 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) tx_q->tx_skbuff[tx_q->cur_tx] = skb; /* Manage tx mitigation */ - tx_q->tx_count_frames += nfrags + 1; - if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) && - !((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - priv->hwts_tx_en)) { - stmmac_tx_timer_arm(priv, queue); - } else { + tx_packets = (tx_q->cur_tx + 1) - first_tx; + tx_q->tx_count_frames += tx_packets; + + if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) + set_ic = true; + else if (!priv->tx_coal_frames) + set_ic = false; + else if (tx_packets > priv->tx_coal_frames) + set_ic = true; + else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets) + set_ic = true; + else + set_ic = false; + + if (set_ic) { desc = &tx_q->dma_tx[tx_q->cur_tx]; tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, desc); priv->xstats.tx_set_ic_bit++; + } else { + stmmac_tx_timer_arm(priv, queue); } /* We've used all descriptors we need for this skb, however, @@ -3133,6 +3145,7 @@ dma_map_err: */ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) { + unsigned int first_entry, tx_packets, enh_desc; struct stmmac_priv *priv = netdev_priv(dev); unsigned int nopaged_len = skb_headlen(skb); int i, csum_insertion = 0, is_jumbo = 0; @@ -3141,13 +3154,12 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) int gso = skb_shinfo(skb)->gso_type; struct dma_desc *desc, *first; struct stmmac_tx_queue *tx_q; - unsigned int first_entry; - unsigned int enh_desc; + bool has_vlan, set_ic; + int entry, first_tx; dma_addr_t des; - bool has_vlan; - int entry; tx_q = &priv->tx_queue[queue]; + first_tx = tx_q->cur_tx; if (priv->tx_path_in_lpi_mode) stmmac_disable_eee_mode(priv); @@ -3241,12 +3253,21 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) * This approach takes care about the fragments: desc is the first * element in case of no SG. */ - tx_q->tx_count_frames += nfrags + 1; - if (likely(priv->tx_coal_frames > tx_q->tx_count_frames) && - !((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && - priv->hwts_tx_en)) { - stmmac_tx_timer_arm(priv, queue); - } else { + tx_packets = (entry + 1) - first_tx; + tx_q->tx_count_frames += tx_packets; + + if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en) + set_ic = true; + else if (!priv->tx_coal_frames) + set_ic = false; + else if (tx_packets > priv->tx_coal_frames) + set_ic = true; + else if ((tx_q->tx_count_frames % priv->tx_coal_frames) < tx_packets) + set_ic = true; + else + set_ic = false; + + if (set_ic) { if (likely(priv->extend_desc)) desc = &tx_q->dma_etx[entry].basic; else @@ -3255,6 +3276,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, desc); priv->xstats.tx_set_ic_bit++; + } else { + stmmac_tx_timer_arm(priv, queue); } /* We've used all descriptors we need for this skb, however, -- cgit v1.2.3-59-g8ed1b From 8d07a7930434afd7ca4faa90ed478552d4a84b17 Mon Sep 17 00:00:00 2001 From: Jose Abreu Date: Thu, 14 Nov 2019 12:42:51 +0100 Subject: net: stmmac: xgmac: Do not enable TBU interrupt Now that TX Coalesce has been rewritten we no longer need this additional interrupt enabled. This reduces CPU usage. Signed-off-by: Jose Abreu Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 99037386080a..e908d80a1d6f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -360,7 +360,7 @@ #define XGMAC_TBUE BIT(2) #define XGMAC_TIE BIT(0) #define XGMAC_DMA_INT_DEFAULT_EN (XGMAC_NIE | XGMAC_AIE | XGMAC_RBUE | \ - XGMAC_RIE | XGMAC_TBUE | XGMAC_TIE) + XGMAC_RIE | XGMAC_TIE) #define XGMAC_DMA_CH_Rx_WATCHDOG(x) (0x0000313c + (0x80 * (x))) #define XGMAC_RWT GENMASK(7, 0) #define XGMAC_DMA_CH_STATUS(x) (0x00003160 + (0x80 * (x))) -- cgit v1.2.3-59-g8ed1b From 259630e08c2135df6582040b20bd5bb1383964a3 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 14 Nov 2019 17:03:20 +0200 Subject: net: mscc: ocelot: move resource ioremap and regmap init to common code Let's make this ioremap and regmap init code common. It should not be platform dependent as it should be usable by PCI devices too. Use better names where necessary to avoid clashes. Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.h | 4 +--- drivers/net/ethernet/mscc/ocelot_board.c | 17 ++++++++++------- drivers/net/ethernet/mscc/ocelot_io.c | 14 +++++--------- 3 files changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 4d8e769ccad9..b5802cea7cc4 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -546,9 +546,7 @@ void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); int ocelot_regfields_init(struct ocelot *ocelot, const struct reg_field *const regfields); -struct regmap *ocelot_io_platform_init(struct ocelot *ocelot, - struct platform_device *pdev, - const char *name); +struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res); #define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val)) #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val)) diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 811599f32910..ddb34f17fa52 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -268,7 +268,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) enum ocelot_target id; char *name; u8 optional:1; - } res[] = { + } io_target[] = { { SYS, "sys" }, { REW, "rew" }, { QSYS, "qsys" }, @@ -288,20 +288,23 @@ static int mscc_ocelot_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ocelot); ocelot->dev = &pdev->dev; - for (i = 0; i < ARRAY_SIZE(res); i++) { + for (i = 0; i < ARRAY_SIZE(io_target); i++) { struct regmap *target; + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + io_target[i].name); - target = ocelot_io_platform_init(ocelot, pdev, res[i].name); + target = ocelot_regmap_init(ocelot, res); if (IS_ERR(target)) { - if (res[i].optional) { - ocelot->targets[res[i].id] = NULL; + if (io_target[i].optional) { + ocelot->targets[io_target[i].id] = NULL; continue; } - return PTR_ERR(target); } - ocelot->targets[res[i].id] = target; + ocelot->targets[io_target[i].id] = target; } hsio = syscon_regmap_lookup_by_compatible("mscc,ocelot-hsio"); diff --git a/drivers/net/ethernet/mscc/ocelot_io.c b/drivers/net/ethernet/mscc/ocelot_io.c index c6db8ad31fdf..b229b1cb68ef 100644 --- a/drivers/net/ethernet/mscc/ocelot_io.c +++ b/drivers/net/ethernet/mscc/ocelot_io.c @@ -97,20 +97,16 @@ static struct regmap_config ocelot_regmap_config = { .reg_stride = 4, }; -struct regmap *ocelot_io_platform_init(struct ocelot *ocelot, - struct platform_device *pdev, - const char *name) +struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res) { - struct resource *res; void __iomem *regs; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); regs = devm_ioremap_resource(ocelot->dev, res); if (IS_ERR(regs)) return ERR_CAST(regs); - ocelot_regmap_config.name = name; - return devm_regmap_init_mmio(ocelot->dev, regs, - &ocelot_regmap_config); + ocelot_regmap_config.name = res->name; + + return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config); } -EXPORT_SYMBOL(ocelot_io_platform_init); +EXPORT_SYMBOL(ocelot_regmap_init); -- cgit v1.2.3-59-g8ed1b From dc3de2a294eab8b1375f96eb4cf2a1d5edfcc9ab Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 14 Nov 2019 17:03:21 +0200 Subject: net: mscc: ocelot: filter out ocelot SoC specific PCS config from common path The adjust_link routine should be generic enough to be (re)used by any SoC that integrates a switch core compatible with the Ocelot core switch driver. Currently all configurations are generic except for the PCS settings that are SoC specific. Move these out to the Ocelot SoC/board instance. Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 19 ++----------------- drivers/net/ethernet/mscc/ocelot.h | 8 +++++++- drivers/net/ethernet/mscc/ocelot_board.c | 29 ++++++++++++++++++++++++++++- drivers/net/ethernet/mscc/ocelot_regs.c | 3 ++- 4 files changed, 39 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 3e7a2796c37d..2b6792ab0eda 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -455,23 +455,8 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), DEV_MAC_HDX_CFG); - /* Disable HDX fast control */ - ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS, - DEV_PORT_MISC); - - /* SGMII only for now */ - ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA, - PCS1G_MODE_CFG); - ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); - - /* Enable PCS */ - ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); - - /* No aneg on SGMII */ - ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG); - - /* No loopback */ - ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); + if (ocelot->ops->pcs_init) + ocelot->ops->pcs_init(ocelot, port); /* Set Max Length and maximum tags allowed */ ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN, diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index b5802cea7cc4..7e28434c22c1 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -435,13 +435,19 @@ enum ocelot_tag_prefix { }; struct ocelot_port; +struct ocelot; struct ocelot_stat_layout { u32 offset; char name[ETH_GSTRING_LEN]; }; +struct ocelot_ops { + void (*pcs_init)(struct ocelot *ocelot, int port); +}; + struct ocelot { + const struct ocelot_ops *ops; struct device *dev; struct regmap *targets[TARGET_MAX]; @@ -553,7 +559,7 @@ struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res); int ocelot_init(struct ocelot *ocelot); void ocelot_deinit(struct ocelot *ocelot); -int ocelot_chip_init(struct ocelot *ocelot); +int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops); int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, struct phy_device *phy); diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index ddb34f17fa52..de2da6d33d43 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -254,6 +254,33 @@ static const struct of_device_id mscc_ocelot_match[] = { }; MODULE_DEVICE_TABLE(of, mscc_ocelot_match); +static void ocelot_port_pcs_init(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + /* Disable HDX fast control */ + ocelot_port_writel(ocelot_port, DEV_PORT_MISC_HDX_FAST_DIS, + DEV_PORT_MISC); + + /* SGMII only for now */ + ocelot_port_writel(ocelot_port, PCS1G_MODE_CFG_SGMII_MODE_ENA, + PCS1G_MODE_CFG); + ocelot_port_writel(ocelot_port, PCS1G_SD_CFG_SD_SEL, PCS1G_SD_CFG); + + /* Enable PCS */ + ocelot_port_writel(ocelot_port, PCS1G_CFG_PCS_ENA, PCS1G_CFG); + + /* No aneg on SGMII */ + ocelot_port_writel(ocelot_port, 0, PCS1G_ANEG_CFG); + + /* No loopback */ + ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); +} + +static const struct ocelot_ops ocelot_ops = { + .pcs_init = ocelot_port_pcs_init, +}; + static int mscc_ocelot_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -315,7 +342,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot->targets[HSIO] = hsio; - err = ocelot_chip_init(ocelot); + err = ocelot_chip_init(ocelot, &ocelot_ops); if (err) return err; diff --git a/drivers/net/ethernet/mscc/ocelot_regs.c b/drivers/net/ethernet/mscc/ocelot_regs.c index e59977d20400..b88b5899b227 100644 --- a/drivers/net/ethernet/mscc/ocelot_regs.c +++ b/drivers/net/ethernet/mscc/ocelot_regs.c @@ -423,7 +423,7 @@ static void ocelot_pll5_init(struct ocelot *ocelot) HSIO_PLL5G_CFG2_AMPC_SEL(0x10)); } -int ocelot_chip_init(struct ocelot *ocelot) +int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops) { int ret; @@ -431,6 +431,7 @@ int ocelot_chip_init(struct ocelot *ocelot) ocelot->stats_layout = ocelot_stats_layout; ocelot->num_stats = ARRAY_SIZE(ocelot_stats_layout); ocelot->shared_queue_sz = 224 * 1024; + ocelot->ops = ops; ret = ocelot_regfields_init(ocelot, ocelot_regfields); if (ret) -- cgit v1.2.3-59-g8ed1b From 5bc9d2e6e7d546548ae1a7cd3de37672db4075ce Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:22 +0200 Subject: net: mscc: ocelot: move invariant configs out of adjust_link It doesn't make sense to rewrite all these registers every time the PHY library notifies us about a link state change. In a future patch we will customize the MTU for the CPU port, and since the MTU was previously configured from adjust_link, if we don't make this change, its value would have got overridden. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 85 +++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 42 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 2b6792ab0eda..4558c09e2e8a 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -408,7 +408,7 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, struct phy_device *phydev) { struct ocelot_port *ocelot_port = ocelot->ports[port]; - int speed, atop_wm, mode = 0; + int speed, mode = 0; switch (phydev->speed) { case SPEED_10: @@ -440,32 +440,9 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, ocelot_port_writel(ocelot_port, DEV_MAC_MODE_CFG_FDX_ENA | mode, DEV_MAC_MODE_CFG); - /* Set MAC IFG Gaps - * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0 - * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5 - */ - ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5), - DEV_MAC_IFG_CFG); - - /* Load seed (0) and set MAC HDX late collision */ - ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) | - DEV_MAC_HDX_CFG_SEED_LOAD, - DEV_MAC_HDX_CFG); - mdelay(1); - ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), - DEV_MAC_HDX_CFG); - if (ocelot->ops->pcs_init) ocelot->ops->pcs_init(ocelot, port); - /* Set Max Length and maximum tags allowed */ - ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN, - DEV_MAC_MAXLEN_CFG); - ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | - DEV_MAC_TAGS_CFG_VLAN_AWR_ENA | - DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, - DEV_MAC_TAGS_CFG); - /* Enable MAC module */ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); @@ -475,22 +452,10 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(speed), DEV_CLOCK_CFG); - /* Set SMAC of Pause frame (00:00:00:00:00:00) */ - ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); - ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); - /* No PFC */ ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(speed), ANA_PFC_PFC_CFG, port); - /* Set Pause WM hysteresis - * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ - * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ - */ - ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | - SYS_PAUSE_CFG_PAUSE_STOP(101) | - SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); - /* Core: Enable port for frame transfer */ ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | @@ -505,12 +470,6 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, SYS_MAC_FC_CFG_FC_LINK_SPEED(speed), SYS_MAC_FC_CFG, port); ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); - - /* Tail dropping watermark */ - atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ; - ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN), - SYS_ATOP, port); - ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); } static void ocelot_port_adjust_link(struct net_device *dev) @@ -2141,11 +2100,53 @@ static int ocelot_init_timestamp(struct ocelot *ocelot) static void ocelot_init_port(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; + int atop_wm; INIT_LIST_HEAD(&ocelot_port->skbs); /* Basic L2 initialization */ + /* Set MAC IFG Gaps + * FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 0 + * !FDX: TX_IFG = 5, RX_IFG1 = RX_IFG2 = 5 + */ + ocelot_port_writel(ocelot_port, DEV_MAC_IFG_CFG_TX_IFG(5), + DEV_MAC_IFG_CFG); + + /* Load seed (0) and set MAC HDX late collision */ + ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67) | + DEV_MAC_HDX_CFG_SEED_LOAD, + DEV_MAC_HDX_CFG); + mdelay(1); + ocelot_port_writel(ocelot_port, DEV_MAC_HDX_CFG_LATE_COL_POS(67), + DEV_MAC_HDX_CFG); + + /* Set Max Length and maximum tags allowed */ + ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN, + DEV_MAC_MAXLEN_CFG); + ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | + DEV_MAC_TAGS_CFG_VLAN_AWR_ENA | + DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, + DEV_MAC_TAGS_CFG); + + /* Set SMAC of Pause frame (00:00:00:00:00:00) */ + ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); + ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); + + /* Set Pause WM hysteresis + * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ + * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ + */ + ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | + SYS_PAUSE_CFG_PAUSE_STOP(101) | + SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); + + /* Tail dropping watermark */ + atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ; + ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN), + SYS_ATOP, port); + ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); + /* Drop frames with multicast source address */ ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, -- cgit v1.2.3-59-g8ed1b From fa914e9c4d9485f06b3676791a74587d2642fca3 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:23 +0200 Subject: net: mscc: ocelot: create a helper for changing the port MTU Since in an NPI/DSA setup, not all ports will have the same MTU, we need to make sure the watermarks for pause frames and/or tail dropping logic that existed in the driver is still coherent for the new MTU values. We need to do this because the NPI (aka external CPU) port needs an increased MTU for the DSA tag. This will be done in a future patch. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 40 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 4558c09e2e8a..8ede8ad902c9 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2097,11 +2097,32 @@ static int ocelot_init_timestamp(struct ocelot *ocelot) return 0; } -static void ocelot_init_port(struct ocelot *ocelot, int port) +static void ocelot_port_set_mtu(struct ocelot *ocelot, int port, size_t mtu) { struct ocelot_port *ocelot_port = ocelot->ports[port]; int atop_wm; + ocelot_port_writel(ocelot_port, mtu, DEV_MAC_MAXLEN_CFG); + + /* Set Pause WM hysteresis + * 152 = 6 * mtu / OCELOT_BUFFER_CELL_SZ + * 101 = 4 * mtu / OCELOT_BUFFER_CELL_SZ + */ + ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | + SYS_PAUSE_CFG_PAUSE_STOP(101) | + SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); + + /* Tail dropping watermark */ + atop_wm = (ocelot->shared_queue_sz - 9 * mtu) / OCELOT_BUFFER_CELL_SZ; + ocelot_write_rix(ocelot, ocelot_wm_enc(9 * mtu), + SYS_ATOP, port); + ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); +} + +static void ocelot_init_port(struct ocelot *ocelot, int port) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + INIT_LIST_HEAD(&ocelot_port->skbs); /* Basic L2 initialization */ @@ -2122,8 +2143,7 @@ static void ocelot_init_port(struct ocelot *ocelot, int port) DEV_MAC_HDX_CFG); /* Set Max Length and maximum tags allowed */ - ocelot_port_writel(ocelot_port, VLAN_ETH_FRAME_LEN, - DEV_MAC_MAXLEN_CFG); + ocelot_port_set_mtu(ocelot, port, VLAN_ETH_FRAME_LEN); ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) | DEV_MAC_TAGS_CFG_VLAN_AWR_ENA | DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, @@ -2133,20 +2153,6 @@ static void ocelot_init_port(struct ocelot *ocelot, int port) ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_HIGH_CFG); ocelot_port_writel(ocelot_port, 0, DEV_MAC_FC_MAC_LOW_CFG); - /* Set Pause WM hysteresis - * 152 = 6 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ - * 101 = 4 * VLAN_ETH_FRAME_LEN / OCELOT_BUFFER_CELL_SZ - */ - ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA | - SYS_PAUSE_CFG_PAUSE_STOP(101) | - SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port); - - /* Tail dropping watermark */ - atop_wm = (ocelot->shared_queue_sz - 9 * VLAN_ETH_FRAME_LEN) / OCELOT_BUFFER_CELL_SZ; - ocelot_write_rix(ocelot, ocelot_wm_enc(9 * VLAN_ETH_FRAME_LEN), - SYS_ATOP, port); - ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); - /* Drop frames with multicast source address */ ocelot_rmw_gix(ocelot, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, ANA_PORT_DROP_CFG_DROP_MC_SMAC_ENA, -- cgit v1.2.3-59-g8ed1b From f24711fddc36aa7286af724393ef7334b92c5702 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:24 +0200 Subject: net: mscc: ocelot: export a constant for the tag length in bytes This constant will be used in a future patch to increase the MTU on NPI ports, and will also be used in the tagger driver for Felix. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 4 ++-- drivers/net/ethernet/mscc/ocelot.h | 4 ++-- drivers/net/ethernet/mscc/ocelot_board.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 8ede8ad902c9..8b73d760dfa5 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -576,11 +576,11 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) struct skb_shared_info *shinfo = skb_shinfo(skb); struct ocelot_port *ocelot_port = &priv->port; struct ocelot *ocelot = ocelot_port->ocelot; + u32 val, ifh[OCELOT_TAG_LEN / 4]; struct frame_info info = {}; u8 grp = 0; /* Send everything on CPU group 0 */ unsigned int i, count, last; int port = priv->chip_port; - u32 val, ifh[IFH_LEN]; val = ocelot_read(ocelot, QS_INJ_STATUS); if (!(val & QS_INJ_STATUS_FIFO_RDY(BIT(grp))) || @@ -603,7 +603,7 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) ocelot_gen_ifh(ifh, &info); - for (i = 0; i < IFH_LEN; i++) + for (i = 0; i < OCELOT_TAG_LEN / 4; i++) ocelot_write_rix(ocelot, (__force u32)cpu_to_be32(ifh[i]), QS_INJ_WR, grp); diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 7e28434c22c1..9159b0adf1e7 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -43,8 +43,6 @@ #define OCELOT_PTP_QUEUE_SZ 128 -#define IFH_LEN 4 - struct frame_info { u32 len; u16 port; @@ -66,6 +64,8 @@ struct frame_info { #define IFH_REW_OP_TWO_STEP_PTP 0x3 #define IFH_REW_OP_ORIGIN_PTP 0x5 +#define OCELOT_TAG_LEN 16 + #define OCELOT_SPEED_2500 0 #define OCELOT_SPEED_1000 1 #define OCELOT_SPEED_100 2 diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index de2da6d33d43..32aafd951483 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -105,7 +105,7 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) int sz, len, buf_len; struct sk_buff *skb; - for (i = 0; i < IFH_LEN; i++) { + for (i = 0; i < OCELOT_TAG_LEN / 4; i++) { err = ocelot_rx_frame_word(ocelot, grp, true, &ifh[i]); if (err != 4) break; -- cgit v1.2.3-59-g8ed1b From ba551bc3bc22f3a9f16a31cd856b823e76489009 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:25 +0200 Subject: net: mscc: ocelot: adjust MTU on the CPU port in NPI mode When using the NPI port, the DSA tag is passed through Ethernet, so the switch's MAC needs to accept it as it comes from the DSA master. Increase the MTU on the external CPU port to account for the length of the injection header. Without this patch, MTU-sized frames are dropped by the switch's CPU port on xmit, which is especially obvious in TCP sessions. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 9 +++++++++ drivers/net/ethernet/mscc/ocelot.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 8b73d760dfa5..42da193a8240 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2230,9 +2230,18 @@ void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, * Only one port can be an NPI at the same time. */ if (cpu < ocelot->num_phys_ports) { + int mtu = VLAN_ETH_FRAME_LEN + OCELOT_TAG_LEN; + ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M | QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu), QSYS_EXT_CPU_CFG); + + if (injection == OCELOT_TAG_PREFIX_SHORT) + mtu += OCELOT_SHORT_PREFIX_LEN; + else if (injection == OCELOT_TAG_PREFIX_LONG) + mtu += OCELOT_LONG_PREFIX_LEN; + + ocelot_port_set_mtu(ocelot, cpu, mtu); } /* CPU port Injection/Extraction configuration */ diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 9159b0adf1e7..bdc9b1d34b81 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -65,6 +65,8 @@ struct frame_info { #define IFH_REW_OP_ORIGIN_PTP 0x5 #define OCELOT_TAG_LEN 16 +#define OCELOT_SHORT_PREFIX_LEN 4 +#define OCELOT_LONG_PREFIX_LEN 16 #define OCELOT_SPEED_2500 0 #define OCELOT_SPEED_1000 1 -- cgit v1.2.3-59-g8ed1b From 3a77b5933fdb2ea4a9c7cdd9bd9b65b6fd23626e Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:26 +0200 Subject: net: mscc: ocelot: separate the implementation of switch reset The Felix switch has a different reset procedure, so a function pointer needs to be created and added to the ocelot_ops structure. The reset procedure has been moved into ocelot_init. Signed-off-by: Vladimir Oltean Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 8 +++++++ drivers/net/ethernet/mscc/ocelot.h | 1 + drivers/net/ethernet/mscc/ocelot_board.c | 37 +++++++++++++++++++++----------- 3 files changed, 33 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 42da193a8240..961f9a7c01e3 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -2269,6 +2269,14 @@ int ocelot_init(struct ocelot *ocelot) int i, ret; u32 port; + if (ocelot->ops->reset) { + ret = ocelot->ops->reset(ocelot); + if (ret) { + dev_err(ocelot->dev, "Switch reset failed\n"); + return ret; + } + } + ocelot->lags = devm_kcalloc(ocelot->dev, ocelot->num_phys_ports, sizeof(u32), GFP_KERNEL); if (!ocelot->lags) diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index bdc9b1d34b81..199ca2d6ea32 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -446,6 +446,7 @@ struct ocelot_stat_layout { struct ocelot_ops { void (*pcs_init)(struct ocelot *ocelot, int port); + int (*reset)(struct ocelot *ocelot); }; struct ocelot { diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 32aafd951483..5581b3b0165c 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -277,8 +277,32 @@ static void ocelot_port_pcs_init(struct ocelot *ocelot, int port) ocelot_port_writel(ocelot_port, 0, PCS1G_LB_CFG); } +static int ocelot_reset(struct ocelot *ocelot) +{ + int retries = 100; + u32 val; + + regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); + regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); + + do { + msleep(1); + regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], + &val); + } while (val && --retries); + + if (!retries) + return -ETIMEDOUT; + + regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); + regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); + + return 0; +} + static const struct ocelot_ops ocelot_ops = { .pcs_init = ocelot_port_pcs_init, + .reset = ocelot_reset, }; static int mscc_ocelot_probe(struct platform_device *pdev) @@ -289,7 +313,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev) struct ocelot *ocelot; struct regmap *hsio; unsigned int i; - u32 val; struct { enum ocelot_target id; @@ -369,18 +392,6 @@ static int mscc_ocelot_probe(struct platform_device *pdev) ocelot->ptp = 1; } - regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); - regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); - - do { - msleep(1); - regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], - &val); - } while (val); - - regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); - regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); - ocelot->num_cpu_ports = 1; /* 1 port on the switch, two groups */ ports = of_get_child_by_name(np, "ethernet-ports"); -- cgit v1.2.3-59-g8ed1b From 5e2563650232a4d998a60b10d3679f65dd4c02fb Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:27 +0200 Subject: net: mscc: ocelot: publish structure definitions to include/soc/mscc/ocelot.h We will be registering another switch driver based on ocelot, which lives under drivers/net/dsa. Make sure the Felix DSA front-end has the necessary abstractions to implement a new Ocelot driver instantiation. This includes the function prototypes for implementing DSA callbacks. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 78 +++--- drivers/net/ethernet/mscc/ocelot.h | 482 +-------------------------------- include/soc/mscc/ocelot.h | 539 +++++++++++++++++++++++++++++++++++++ 3 files changed, 588 insertions(+), 511 deletions(-) create mode 100644 include/soc/mscc/ocelot.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 961f9a7c01e3..90c46ba763d7 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "ocelot.h" #include "ocelot_ace.h" @@ -184,8 +183,8 @@ static void ocelot_vlan_mode(struct ocelot *ocelot, int port, ocelot_write(ocelot, val, ANA_VLANMASK); } -static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, - bool vlan_aware) +void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + bool vlan_aware) { struct ocelot_port *ocelot_port = ocelot->ports[port]; u32 val; @@ -230,6 +229,7 @@ static void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, REW_TAG_CFG_TAG_CFG_M, REW_TAG_CFG, port); } +EXPORT_SYMBOL(ocelot_port_vlan_filtering); static int ocelot_port_set_native_vlan(struct ocelot *ocelot, int port, u16 vid) @@ -267,8 +267,8 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port, u16 pvid) ocelot_port->pvid = pvid; } -static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, - bool untagged) +int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + bool untagged) { int ret; @@ -291,6 +291,7 @@ static int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, return 0; } +EXPORT_SYMBOL(ocelot_vlan_add); static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, bool untagged) @@ -312,7 +313,7 @@ static int ocelot_vlan_vid_add(struct net_device *dev, u16 vid, bool pvid, return 0; } -static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) +int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) { struct ocelot_port *ocelot_port = ocelot->ports[port]; int ret; @@ -333,6 +334,7 @@ static int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid) return 0; } +EXPORT_SYMBOL(ocelot_vlan_del); static int ocelot_vlan_vid_del(struct net_device *dev, u16 vid) { @@ -404,8 +406,8 @@ static u16 ocelot_wm_enc(u16 value) return value; } -static void ocelot_adjust_link(struct ocelot *ocelot, int port, - struct phy_device *phydev) +void ocelot_adjust_link(struct ocelot *ocelot, int port, + struct phy_device *phydev) { struct ocelot_port *ocelot_port = ocelot->ports[port]; int speed, mode = 0; @@ -471,6 +473,7 @@ static void ocelot_adjust_link(struct ocelot *ocelot, int port, SYS_MAC_FC_CFG, port); ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); } +EXPORT_SYMBOL(ocelot_adjust_link); static void ocelot_port_adjust_link(struct net_device *dev) { @@ -481,8 +484,8 @@ static void ocelot_port_adjust_link(struct net_device *dev) ocelot_adjust_link(ocelot, port, dev->phydev); } -static void ocelot_port_enable(struct ocelot *ocelot, int port, - struct phy_device *phy) +void ocelot_port_enable(struct ocelot *ocelot, int port, + struct phy_device *phy) { /* Enable receiving frames on the port, and activate auto-learning of * MAC addresses. @@ -492,6 +495,7 @@ static void ocelot_port_enable(struct ocelot *ocelot, int port, ANA_PORT_PORT_CFG_PORTID_VAL(port), ANA_PORT_PORT_CFG, port); } +EXPORT_SYMBOL(ocelot_port_enable); static int ocelot_port_open(struct net_device *dev) { @@ -526,7 +530,7 @@ static int ocelot_port_open(struct net_device *dev) return 0; } -static void ocelot_port_disable(struct ocelot *ocelot, int port) +void ocelot_port_disable(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -534,6 +538,7 @@ static void ocelot_port_disable(struct ocelot *ocelot, int port) ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, QSYS_SWITCH_PORT_MODE, port); } +EXPORT_SYMBOL(ocelot_port_disable); static int ocelot_port_stop(struct net_device *dev) { @@ -790,9 +795,8 @@ static void ocelot_get_stats64(struct net_device *dev, stats->collisions = ocelot_read(ocelot, SYS_COUNT_TX_COLLISION); } -static int ocelot_fdb_add(struct ocelot *ocelot, int port, - const unsigned char *addr, u16 vid, - bool vlan_aware) +int ocelot_fdb_add(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid, bool vlan_aware) { struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -812,6 +816,7 @@ static int ocelot_fdb_add(struct ocelot *ocelot, int port, return ocelot_mact_learn(ocelot, port, addr, vid, ENTRYTYPE_LOCKED); } +EXPORT_SYMBOL(ocelot_fdb_add); static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, @@ -826,11 +831,12 @@ static int ocelot_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return ocelot_fdb_add(ocelot, port, addr, vid, priv->vlan_aware); } -static int ocelot_fdb_del(struct ocelot *ocelot, int port, - const unsigned char *addr, u16 vid) +int ocelot_fdb_del(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid) { return ocelot_mact_forget(ocelot, addr, vid); } +EXPORT_SYMBOL(ocelot_fdb_del); static int ocelot_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, @@ -940,8 +946,8 @@ static int ocelot_mact_read(struct ocelot *ocelot, int port, int row, int col, return 0; } -static int ocelot_fdb_dump(struct ocelot *ocelot, int port, - dsa_fdb_dump_cb_t *cb, void *data) +int ocelot_fdb_dump(struct ocelot *ocelot, int port, + dsa_fdb_dump_cb_t *cb, void *data) { int i, j; @@ -973,6 +979,7 @@ static int ocelot_fdb_dump(struct ocelot *ocelot, int port, return 0; } +EXPORT_SYMBOL(ocelot_fdb_dump); static int ocelot_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, @@ -1153,8 +1160,7 @@ static const struct net_device_ops ocelot_port_netdev_ops = { .ndo_do_ioctl = ocelot_ioctl, }; -static void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, - u8 *data) +void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data) { int i; @@ -1165,6 +1171,7 @@ static void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, memcpy(data + i * ETH_GSTRING_LEN, ocelot->stats_layout[i].name, ETH_GSTRING_LEN); } +EXPORT_SYMBOL(ocelot_get_strings); static void ocelot_port_get_strings(struct net_device *netdev, u32 sset, u8 *data) @@ -1216,7 +1223,7 @@ static void ocelot_check_stats_work(struct work_struct *work) OCELOT_STATS_CHECK_DELAY); } -static void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) +void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) { int i; @@ -1227,6 +1234,7 @@ static void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data) for (i = 0; i < ocelot->num_stats; i++) *data++ = ocelot->stats[port * ocelot->num_stats + i]; } +EXPORT_SYMBOL(ocelot_get_ethtool_stats); static void ocelot_port_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, @@ -1239,13 +1247,14 @@ static void ocelot_port_get_ethtool_stats(struct net_device *dev, ocelot_get_ethtool_stats(ocelot, port, data); } -static int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset) +int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset) { if (sset != ETH_SS_STATS) return -EOPNOTSUPP; return ocelot->num_stats; } +EXPORT_SYMBOL(ocelot_get_sset_count); static int ocelot_port_get_sset_count(struct net_device *dev, int sset) { @@ -1256,8 +1265,8 @@ static int ocelot_port_get_sset_count(struct net_device *dev, int sset) return ocelot_get_sset_count(ocelot, port, sset); } -static int ocelot_get_ts_info(struct ocelot *ocelot, int port, - struct ethtool_ts_info *info) +int ocelot_get_ts_info(struct ocelot *ocelot, int port, + struct ethtool_ts_info *info) { info->phc_index = ocelot->ptp_clock ? ptp_clock_index(ocelot->ptp_clock) : -1; @@ -1273,6 +1282,7 @@ static int ocelot_get_ts_info(struct ocelot *ocelot, int port, return 0; } +EXPORT_SYMBOL(ocelot_get_ts_info); static int ocelot_port_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) @@ -1296,8 +1306,7 @@ static const struct ethtool_ops ocelot_ethtool_ops = { .get_ts_info = ocelot_port_get_ts_info, }; -static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, - u8 state) +void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) { u32 port_cfg; int p, i; @@ -1358,6 +1367,7 @@ static void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, } } } +EXPORT_SYMBOL(ocelot_bridge_stp_state_set); static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port, struct switchdev_trans *trans, @@ -1369,11 +1379,12 @@ static void ocelot_port_attr_stp_state_set(struct ocelot *ocelot, int port, ocelot_bridge_stp_state_set(ocelot, port, state); } -static void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs) +void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs) { ocelot_write(ocelot, ANA_AUTOAGE_AGE_PERIOD(msecs / 2), ANA_AUTOAGE); } +EXPORT_SYMBOL(ocelot_set_ageing_time); static void ocelot_port_attr_ageing_set(struct ocelot *ocelot, int port, unsigned long ageing_clock_t) @@ -1604,8 +1615,8 @@ static int ocelot_port_obj_del(struct net_device *dev, return ret; } -static int ocelot_port_bridge_join(struct ocelot *ocelot, int port, - struct net_device *bridge) +int ocelot_port_bridge_join(struct ocelot *ocelot, int port, + struct net_device *bridge) { if (!ocelot->bridge_mask) { ocelot->hw_bridge_dev = bridge; @@ -1620,9 +1631,10 @@ static int ocelot_port_bridge_join(struct ocelot *ocelot, int port, return 0; } +EXPORT_SYMBOL(ocelot_port_bridge_join); -static int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, - struct net_device *bridge) +int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, + struct net_device *bridge) { ocelot->bridge_mask &= ~BIT(port); @@ -1633,6 +1645,7 @@ static int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, ocelot_port_set_pvid(ocelot, port, 0); return ocelot_port_set_native_vlan(ocelot, port, 0); } +EXPORT_SYMBOL(ocelot_port_bridge_leave); static void ocelot_set_aggr_pgids(struct ocelot *ocelot) { @@ -2119,7 +2132,7 @@ static void ocelot_port_set_mtu(struct ocelot *ocelot, int port, size_t mtu) ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG); } -static void ocelot_init_port(struct ocelot *ocelot, int port) +void ocelot_init_port(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -2166,6 +2179,7 @@ static void ocelot_init_port(struct ocelot *ocelot, int port) /* Enable vcap lookups */ ocelot_vcap_enable(ocelot, port); } +EXPORT_SYMBOL(ocelot_init_port); int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 199ca2d6ea32..325afea3e846 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -18,6 +18,7 @@ #include #include +#include #include "ocelot_ana.h" #include "ocelot_dev.h" #include "ocelot_qsys.h" @@ -52,376 +53,6 @@ struct frame_info { u32 timestamp; /* rew_val */ }; -#define IFH_INJ_BYPASS BIT(31) -#define IFH_INJ_POP_CNT_DISABLE (3 << 28) - -#define IFH_TAG_TYPE_C 0 -#define IFH_TAG_TYPE_S 1 - -#define IFH_REW_OP_NOOP 0x0 -#define IFH_REW_OP_DSCP 0x1 -#define IFH_REW_OP_ONE_STEP_PTP 0x2 -#define IFH_REW_OP_TWO_STEP_PTP 0x3 -#define IFH_REW_OP_ORIGIN_PTP 0x5 - -#define OCELOT_TAG_LEN 16 -#define OCELOT_SHORT_PREFIX_LEN 4 -#define OCELOT_LONG_PREFIX_LEN 16 - -#define OCELOT_SPEED_2500 0 -#define OCELOT_SPEED_1000 1 -#define OCELOT_SPEED_100 2 -#define OCELOT_SPEED_10 3 - -#define TARGET_OFFSET 24 -#define REG_MASK GENMASK(TARGET_OFFSET - 1, 0) -#define REG(reg, offset) [reg & REG_MASK] = offset - -enum ocelot_target { - ANA = 1, - QS, - QSYS, - REW, - SYS, - S2, - HSIO, - PTP, - TARGET_MAX, -}; - -enum ocelot_reg { - ANA_ADVLEARN = ANA << TARGET_OFFSET, - ANA_VLANMASK, - ANA_PORT_B_DOMAIN, - ANA_ANAGEFIL, - ANA_ANEVENTS, - ANA_STORMLIMIT_BURST, - ANA_STORMLIMIT_CFG, - ANA_ISOLATED_PORTS, - ANA_COMMUNITY_PORTS, - ANA_AUTOAGE, - ANA_MACTOPTIONS, - ANA_LEARNDISC, - ANA_AGENCTRL, - ANA_MIRRORPORTS, - ANA_EMIRRORPORTS, - ANA_FLOODING, - ANA_FLOODING_IPMC, - ANA_SFLOW_CFG, - ANA_PORT_MODE, - ANA_CUT_THRU_CFG, - ANA_PGID_PGID, - ANA_TABLES_ANMOVED, - ANA_TABLES_MACHDATA, - ANA_TABLES_MACLDATA, - ANA_TABLES_STREAMDATA, - ANA_TABLES_MACACCESS, - ANA_TABLES_MACTINDX, - ANA_TABLES_VLANACCESS, - ANA_TABLES_VLANTIDX, - ANA_TABLES_ISDXACCESS, - ANA_TABLES_ISDXTIDX, - ANA_TABLES_ENTRYLIM, - ANA_TABLES_PTP_ID_HIGH, - ANA_TABLES_PTP_ID_LOW, - ANA_TABLES_STREAMACCESS, - ANA_TABLES_STREAMTIDX, - ANA_TABLES_SEQ_HISTORY, - ANA_TABLES_SEQ_MASK, - ANA_TABLES_SFID_MASK, - ANA_TABLES_SFIDACCESS, - ANA_TABLES_SFIDTIDX, - ANA_MSTI_STATE, - ANA_OAM_UPM_LM_CNT, - ANA_SG_ACCESS_CTRL, - ANA_SG_CONFIG_REG_1, - ANA_SG_CONFIG_REG_2, - ANA_SG_CONFIG_REG_3, - ANA_SG_CONFIG_REG_4, - ANA_SG_CONFIG_REG_5, - ANA_SG_GCL_GS_CONFIG, - ANA_SG_GCL_TI_CONFIG, - ANA_SG_STATUS_REG_1, - ANA_SG_STATUS_REG_2, - ANA_SG_STATUS_REG_3, - ANA_PORT_VLAN_CFG, - ANA_PORT_DROP_CFG, - ANA_PORT_QOS_CFG, - ANA_PORT_VCAP_CFG, - ANA_PORT_VCAP_S1_KEY_CFG, - ANA_PORT_VCAP_S2_CFG, - ANA_PORT_PCP_DEI_MAP, - ANA_PORT_CPU_FWD_CFG, - ANA_PORT_CPU_FWD_BPDU_CFG, - ANA_PORT_CPU_FWD_GARP_CFG, - ANA_PORT_CPU_FWD_CCM_CFG, - ANA_PORT_PORT_CFG, - ANA_PORT_POL_CFG, - ANA_PORT_PTP_CFG, - ANA_PORT_PTP_DLY1_CFG, - ANA_PORT_PTP_DLY2_CFG, - ANA_PORT_SFID_CFG, - ANA_PFC_PFC_CFG, - ANA_PFC_PFC_TIMER, - ANA_IPT_OAM_MEP_CFG, - ANA_IPT_IPT, - ANA_PPT_PPT, - ANA_FID_MAP_FID_MAP, - ANA_AGGR_CFG, - ANA_CPUQ_CFG, - ANA_CPUQ_CFG2, - ANA_CPUQ_8021_CFG, - ANA_DSCP_CFG, - ANA_DSCP_REWR_CFG, - ANA_VCAP_RNG_TYPE_CFG, - ANA_VCAP_RNG_VAL_CFG, - ANA_VRAP_CFG, - ANA_VRAP_HDR_DATA, - ANA_VRAP_HDR_MASK, - ANA_DISCARD_CFG, - ANA_FID_CFG, - ANA_POL_PIR_CFG, - ANA_POL_CIR_CFG, - ANA_POL_MODE_CFG, - ANA_POL_PIR_STATE, - ANA_POL_CIR_STATE, - ANA_POL_STATE, - ANA_POL_FLOWC, - ANA_POL_HYST, - ANA_POL_MISC_CFG, - QS_XTR_GRP_CFG = QS << TARGET_OFFSET, - QS_XTR_RD, - QS_XTR_FRM_PRUNING, - QS_XTR_FLUSH, - QS_XTR_DATA_PRESENT, - QS_XTR_CFG, - QS_INJ_GRP_CFG, - QS_INJ_WR, - QS_INJ_CTRL, - QS_INJ_STATUS, - QS_INJ_ERR, - QS_INH_DBG, - QSYS_PORT_MODE = QSYS << TARGET_OFFSET, - QSYS_SWITCH_PORT_MODE, - QSYS_STAT_CNT_CFG, - QSYS_EEE_CFG, - QSYS_EEE_THRES, - QSYS_IGR_NO_SHARING, - QSYS_EGR_NO_SHARING, - QSYS_SW_STATUS, - QSYS_EXT_CPU_CFG, - QSYS_PAD_CFG, - QSYS_CPU_GROUP_MAP, - QSYS_QMAP, - QSYS_ISDX_SGRP, - QSYS_TIMED_FRAME_ENTRY, - QSYS_TFRM_MISC, - QSYS_TFRM_PORT_DLY, - QSYS_TFRM_TIMER_CFG_1, - QSYS_TFRM_TIMER_CFG_2, - QSYS_TFRM_TIMER_CFG_3, - QSYS_TFRM_TIMER_CFG_4, - QSYS_TFRM_TIMER_CFG_5, - QSYS_TFRM_TIMER_CFG_6, - QSYS_TFRM_TIMER_CFG_7, - QSYS_TFRM_TIMER_CFG_8, - QSYS_RED_PROFILE, - QSYS_RES_QOS_MODE, - QSYS_RES_CFG, - QSYS_RES_STAT, - QSYS_EGR_DROP_MODE, - QSYS_EQ_CTRL, - QSYS_EVENTS_CORE, - QSYS_QMAXSDU_CFG_0, - QSYS_QMAXSDU_CFG_1, - QSYS_QMAXSDU_CFG_2, - QSYS_QMAXSDU_CFG_3, - QSYS_QMAXSDU_CFG_4, - QSYS_QMAXSDU_CFG_5, - QSYS_QMAXSDU_CFG_6, - QSYS_QMAXSDU_CFG_7, - QSYS_PREEMPTION_CFG, - QSYS_CIR_CFG, - QSYS_EIR_CFG, - QSYS_SE_CFG, - QSYS_SE_DWRR_CFG, - QSYS_SE_CONNECT, - QSYS_SE_DLB_SENSE, - QSYS_CIR_STATE, - QSYS_EIR_STATE, - QSYS_SE_STATE, - QSYS_HSCH_MISC_CFG, - QSYS_TAG_CONFIG, - QSYS_TAS_PARAM_CFG_CTRL, - QSYS_PORT_MAX_SDU, - QSYS_PARAM_CFG_REG_1, - QSYS_PARAM_CFG_REG_2, - QSYS_PARAM_CFG_REG_3, - QSYS_PARAM_CFG_REG_4, - QSYS_PARAM_CFG_REG_5, - QSYS_GCL_CFG_REG_1, - QSYS_GCL_CFG_REG_2, - QSYS_PARAM_STATUS_REG_1, - QSYS_PARAM_STATUS_REG_2, - QSYS_PARAM_STATUS_REG_3, - QSYS_PARAM_STATUS_REG_4, - QSYS_PARAM_STATUS_REG_5, - QSYS_PARAM_STATUS_REG_6, - QSYS_PARAM_STATUS_REG_7, - QSYS_PARAM_STATUS_REG_8, - QSYS_PARAM_STATUS_REG_9, - QSYS_GCL_STATUS_REG_1, - QSYS_GCL_STATUS_REG_2, - REW_PORT_VLAN_CFG = REW << TARGET_OFFSET, - REW_TAG_CFG, - REW_PORT_CFG, - REW_DSCP_CFG, - REW_PCP_DEI_QOS_MAP_CFG, - REW_PTP_CFG, - REW_PTP_DLY1_CFG, - REW_RED_TAG_CFG, - REW_DSCP_REMAP_DP1_CFG, - REW_DSCP_REMAP_CFG, - REW_STAT_CFG, - REW_REW_STICKY, - REW_PPT, - SYS_COUNT_RX_OCTETS = SYS << TARGET_OFFSET, - SYS_COUNT_RX_UNICAST, - SYS_COUNT_RX_MULTICAST, - SYS_COUNT_RX_BROADCAST, - SYS_COUNT_RX_SHORTS, - SYS_COUNT_RX_FRAGMENTS, - SYS_COUNT_RX_JABBERS, - SYS_COUNT_RX_CRC_ALIGN_ERRS, - SYS_COUNT_RX_SYM_ERRS, - SYS_COUNT_RX_64, - SYS_COUNT_RX_65_127, - SYS_COUNT_RX_128_255, - SYS_COUNT_RX_256_1023, - SYS_COUNT_RX_1024_1526, - SYS_COUNT_RX_1527_MAX, - SYS_COUNT_RX_PAUSE, - SYS_COUNT_RX_CONTROL, - SYS_COUNT_RX_LONGS, - SYS_COUNT_RX_CLASSIFIED_DROPS, - SYS_COUNT_TX_OCTETS, - SYS_COUNT_TX_UNICAST, - SYS_COUNT_TX_MULTICAST, - SYS_COUNT_TX_BROADCAST, - SYS_COUNT_TX_COLLISION, - SYS_COUNT_TX_DROPS, - SYS_COUNT_TX_PAUSE, - SYS_COUNT_TX_64, - SYS_COUNT_TX_65_127, - SYS_COUNT_TX_128_511, - SYS_COUNT_TX_512_1023, - SYS_COUNT_TX_1024_1526, - SYS_COUNT_TX_1527_MAX, - SYS_COUNT_TX_AGING, - SYS_RESET_CFG, - SYS_SR_ETYPE_CFG, - SYS_VLAN_ETYPE_CFG, - SYS_PORT_MODE, - SYS_FRONT_PORT_MODE, - SYS_FRM_AGING, - SYS_STAT_CFG, - SYS_SW_STATUS, - SYS_MISC_CFG, - SYS_REW_MAC_HIGH_CFG, - SYS_REW_MAC_LOW_CFG, - SYS_TIMESTAMP_OFFSET, - SYS_CMID, - SYS_PAUSE_CFG, - SYS_PAUSE_TOT_CFG, - SYS_ATOP, - SYS_ATOP_TOT_CFG, - SYS_MAC_FC_CFG, - SYS_MMGT, - SYS_MMGT_FAST, - SYS_EVENTS_DIF, - SYS_EVENTS_CORE, - SYS_CNT, - SYS_PTP_STATUS, - SYS_PTP_TXSTAMP, - SYS_PTP_NXT, - SYS_PTP_CFG, - SYS_RAM_INIT, - SYS_CM_ADDR, - SYS_CM_DATA_WR, - SYS_CM_DATA_RD, - SYS_CM_OP, - SYS_CM_DATA, - S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET, - S2_CORE_MV_CFG, - S2_CACHE_ENTRY_DAT, - S2_CACHE_MASK_DAT, - S2_CACHE_ACTION_DAT, - S2_CACHE_CNT_DAT, - S2_CACHE_TG_DAT, - PTP_PIN_CFG = PTP << TARGET_OFFSET, - PTP_PIN_TOD_SEC_MSB, - PTP_PIN_TOD_SEC_LSB, - PTP_PIN_TOD_NSEC, - PTP_CFG_MISC, - PTP_CLK_CFG_ADJ_CFG, - PTP_CLK_CFG_ADJ_FREQ, -}; - -enum ocelot_regfield { - ANA_ADVLEARN_VLAN_CHK, - ANA_ADVLEARN_LEARN_MIRROR, - ANA_ANEVENTS_FLOOD_DISCARD, - ANA_ANEVENTS_MSTI_DROP, - ANA_ANEVENTS_ACLKILL, - ANA_ANEVENTS_ACLUSED, - ANA_ANEVENTS_AUTOAGE, - ANA_ANEVENTS_VS2TTL1, - ANA_ANEVENTS_STORM_DROP, - ANA_ANEVENTS_LEARN_DROP, - ANA_ANEVENTS_AGED_ENTRY, - ANA_ANEVENTS_CPU_LEARN_FAILED, - ANA_ANEVENTS_AUTO_LEARN_FAILED, - ANA_ANEVENTS_LEARN_REMOVE, - ANA_ANEVENTS_AUTO_LEARNED, - ANA_ANEVENTS_AUTO_MOVED, - ANA_ANEVENTS_DROPPED, - ANA_ANEVENTS_CLASSIFIED_DROP, - ANA_ANEVENTS_CLASSIFIED_COPY, - ANA_ANEVENTS_VLAN_DISCARD, - ANA_ANEVENTS_FWD_DISCARD, - ANA_ANEVENTS_MULTICAST_FLOOD, - ANA_ANEVENTS_UNICAST_FLOOD, - ANA_ANEVENTS_DEST_KNOWN, - ANA_ANEVENTS_BUCKET3_MATCH, - ANA_ANEVENTS_BUCKET2_MATCH, - ANA_ANEVENTS_BUCKET1_MATCH, - ANA_ANEVENTS_BUCKET0_MATCH, - ANA_ANEVENTS_CPU_OPERATION, - ANA_ANEVENTS_DMAC_LOOKUP, - ANA_ANEVENTS_SMAC_LOOKUP, - ANA_ANEVENTS_SEQ_GEN_ERR_0, - ANA_ANEVENTS_SEQ_GEN_ERR_1, - ANA_TABLES_MACACCESS_B_DOM, - ANA_TABLES_MACTINDX_BUCKET, - ANA_TABLES_MACTINDX_M_INDEX, - QSYS_TIMED_FRAME_ENTRY_TFRM_VLD, - QSYS_TIMED_FRAME_ENTRY_TFRM_FP, - QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO, - QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL, - QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T, - SYS_RESET_CFG_CORE_ENA, - SYS_RESET_CFG_MEM_ENA, - SYS_RESET_CFG_MEM_INIT, - REGFIELD_MAX -}; - -enum ocelot_clk_pins { - ALT_PPS_PIN = 1, - EXT_CLK_PIN, - ALT_LDST_PIN, - TOD_ACC_PIN -}; - struct ocelot_multicast { struct list_head list; unsigned char addr[ETH_ALEN]; @@ -429,88 +60,6 @@ struct ocelot_multicast { u16 ports; }; -enum ocelot_tag_prefix { - OCELOT_TAG_PREFIX_DISABLED = 0, - OCELOT_TAG_PREFIX_NONE, - OCELOT_TAG_PREFIX_SHORT, - OCELOT_TAG_PREFIX_LONG, -}; - -struct ocelot_port; -struct ocelot; - -struct ocelot_stat_layout { - u32 offset; - char name[ETH_GSTRING_LEN]; -}; - -struct ocelot_ops { - void (*pcs_init)(struct ocelot *ocelot, int port); - int (*reset)(struct ocelot *ocelot); -}; - -struct ocelot { - const struct ocelot_ops *ops; - struct device *dev; - - struct regmap *targets[TARGET_MAX]; - struct regmap_field *regfields[REGFIELD_MAX]; - const u32 *const *map; - const struct ocelot_stat_layout *stats_layout; - unsigned int num_stats; - - u8 base_mac[ETH_ALEN]; - - struct net_device *hw_bridge_dev; - u16 bridge_mask; - u16 bridge_fwd_mask; - - struct workqueue_struct *ocelot_owq; - - int shared_queue_sz; - - u8 num_phys_ports; - u8 num_cpu_ports; - u8 cpu; - struct ocelot_port **ports; - - u32 *lags; - - /* Keep track of the vlan port masks */ - u32 vlan_mask[VLAN_N_VID]; - - struct list_head multicast; - - /* Workqueue to check statistics for overflow with its lock */ - struct mutex stats_lock; - u64 *stats; - struct delayed_work stats_work; - struct workqueue_struct *stats_queue; - - u8 ptp:1; - struct ptp_clock *ptp_clock; - struct ptp_clock_info ptp_info; - struct hwtstamp_config hwtstamp_config; - struct mutex ptp_lock; /* Protects the PTP interface state */ - spinlock_t ptp_clock_lock; /* Protects the PTP clock */ -}; - -struct ocelot_port { - struct ocelot *ocelot; - - void __iomem *regs; - - /* Ingress default VLAN (pvid) */ - u16 pvid; - - /* Egress default VLAN (vid) */ - u16 vid; - - u8 ptp_cmd; - struct list_head skbs; - u8 ts_id; -}; - struct ocelot_port_private { struct ocelot_port port; struct net_device *dev; @@ -531,37 +80,12 @@ struct ocelot_skb { u8 id; }; -u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset); -#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) -#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi)) -#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri)) -#define ocelot_read(ocelot, reg) __ocelot_read_ix(ocelot, reg, 0) - -void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset); -#define ocelot_write_ix(ocelot, val, reg, gi, ri) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) -#define ocelot_write_gix(ocelot, val, reg, gi) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi)) -#define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri)) -#define ocelot_write(ocelot, val, reg) __ocelot_write_ix(ocelot, val, reg, 0) - -void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg, - u32 offset); -#define ocelot_rmw_ix(ocelot, val, m, reg, gi, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) -#define ocelot_rmw_gix(ocelot, val, m, reg, gi) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi)) -#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri)) -#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0) - u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); -int ocelot_regfields_init(struct ocelot *ocelot, - const struct reg_field *const regfields); -struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res); - #define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val)) #define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val)) -int ocelot_init(struct ocelot *ocelot); -void ocelot_deinit(struct ocelot *ocelot); int ocelot_chip_init(struct ocelot *ocelot, const struct ocelot_ops *ops); int ocelot_probe_port(struct ocelot *ocelot, u8 port, void __iomem *regs, @@ -575,7 +99,7 @@ extern struct notifier_block ocelot_netdevice_nb; extern struct notifier_block ocelot_switchdev_nb; extern struct notifier_block ocelot_switchdev_blocking_nb; -int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); -void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts); +#define ocelot_field_write(ocelot, reg, val) regmap_field_write((ocelot)->regfields[(reg)], (val)) +#define ocelot_field_read(ocelot, reg, val) regmap_field_read((ocelot)->regfields[(reg)], (val)) #endif diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h new file mode 100644 index 000000000000..a836afe8f68e --- /dev/null +++ b/include/soc/mscc/ocelot.h @@ -0,0 +1,539 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* Copyright (c) 2017 Microsemi Corporation + */ + +#ifndef _SOC_MSCC_OCELOT_H +#define _SOC_MSCC_OCELOT_H + +#include +#include +#include +#include +#include + +#define IFH_INJ_BYPASS BIT(31) +#define IFH_INJ_POP_CNT_DISABLE (3 << 28) + +#define IFH_TAG_TYPE_C 0 +#define IFH_TAG_TYPE_S 1 + +#define IFH_REW_OP_NOOP 0x0 +#define IFH_REW_OP_DSCP 0x1 +#define IFH_REW_OP_ONE_STEP_PTP 0x2 +#define IFH_REW_OP_TWO_STEP_PTP 0x3 +#define IFH_REW_OP_ORIGIN_PTP 0x5 + +#define OCELOT_TAG_LEN 16 +#define OCELOT_SHORT_PREFIX_LEN 4 +#define OCELOT_LONG_PREFIX_LEN 16 + +#define OCELOT_SPEED_2500 0 +#define OCELOT_SPEED_1000 1 +#define OCELOT_SPEED_100 2 +#define OCELOT_SPEED_10 3 + +#define TARGET_OFFSET 24 +#define REG_MASK GENMASK(TARGET_OFFSET - 1, 0) +#define REG(reg, offset) [reg & REG_MASK] = offset + +#define REG_RESERVED_ADDR 0xffffffff +#define REG_RESERVED(reg) REG(reg, REG_RESERVED_ADDR) + +enum ocelot_target { + ANA = 1, + QS, + QSYS, + REW, + SYS, + S2, + HSIO, + PTP, + GCB, + TARGET_MAX, +}; + +enum ocelot_reg { + ANA_ADVLEARN = ANA << TARGET_OFFSET, + ANA_VLANMASK, + ANA_PORT_B_DOMAIN, + ANA_ANAGEFIL, + ANA_ANEVENTS, + ANA_STORMLIMIT_BURST, + ANA_STORMLIMIT_CFG, + ANA_ISOLATED_PORTS, + ANA_COMMUNITY_PORTS, + ANA_AUTOAGE, + ANA_MACTOPTIONS, + ANA_LEARNDISC, + ANA_AGENCTRL, + ANA_MIRRORPORTS, + ANA_EMIRRORPORTS, + ANA_FLOODING, + ANA_FLOODING_IPMC, + ANA_SFLOW_CFG, + ANA_PORT_MODE, + ANA_CUT_THRU_CFG, + ANA_PGID_PGID, + ANA_TABLES_ANMOVED, + ANA_TABLES_MACHDATA, + ANA_TABLES_MACLDATA, + ANA_TABLES_STREAMDATA, + ANA_TABLES_MACACCESS, + ANA_TABLES_MACTINDX, + ANA_TABLES_VLANACCESS, + ANA_TABLES_VLANTIDX, + ANA_TABLES_ISDXACCESS, + ANA_TABLES_ISDXTIDX, + ANA_TABLES_ENTRYLIM, + ANA_TABLES_PTP_ID_HIGH, + ANA_TABLES_PTP_ID_LOW, + ANA_TABLES_STREAMACCESS, + ANA_TABLES_STREAMTIDX, + ANA_TABLES_SEQ_HISTORY, + ANA_TABLES_SEQ_MASK, + ANA_TABLES_SFID_MASK, + ANA_TABLES_SFIDACCESS, + ANA_TABLES_SFIDTIDX, + ANA_MSTI_STATE, + ANA_OAM_UPM_LM_CNT, + ANA_SG_ACCESS_CTRL, + ANA_SG_CONFIG_REG_1, + ANA_SG_CONFIG_REG_2, + ANA_SG_CONFIG_REG_3, + ANA_SG_CONFIG_REG_4, + ANA_SG_CONFIG_REG_5, + ANA_SG_GCL_GS_CONFIG, + ANA_SG_GCL_TI_CONFIG, + ANA_SG_STATUS_REG_1, + ANA_SG_STATUS_REG_2, + ANA_SG_STATUS_REG_3, + ANA_PORT_VLAN_CFG, + ANA_PORT_DROP_CFG, + ANA_PORT_QOS_CFG, + ANA_PORT_VCAP_CFG, + ANA_PORT_VCAP_S1_KEY_CFG, + ANA_PORT_VCAP_S2_CFG, + ANA_PORT_PCP_DEI_MAP, + ANA_PORT_CPU_FWD_CFG, + ANA_PORT_CPU_FWD_BPDU_CFG, + ANA_PORT_CPU_FWD_GARP_CFG, + ANA_PORT_CPU_FWD_CCM_CFG, + ANA_PORT_PORT_CFG, + ANA_PORT_POL_CFG, + ANA_PORT_PTP_CFG, + ANA_PORT_PTP_DLY1_CFG, + ANA_PORT_PTP_DLY2_CFG, + ANA_PORT_SFID_CFG, + ANA_PFC_PFC_CFG, + ANA_PFC_PFC_TIMER, + ANA_IPT_OAM_MEP_CFG, + ANA_IPT_IPT, + ANA_PPT_PPT, + ANA_FID_MAP_FID_MAP, + ANA_AGGR_CFG, + ANA_CPUQ_CFG, + ANA_CPUQ_CFG2, + ANA_CPUQ_8021_CFG, + ANA_DSCP_CFG, + ANA_DSCP_REWR_CFG, + ANA_VCAP_RNG_TYPE_CFG, + ANA_VCAP_RNG_VAL_CFG, + ANA_VRAP_CFG, + ANA_VRAP_HDR_DATA, + ANA_VRAP_HDR_MASK, + ANA_DISCARD_CFG, + ANA_FID_CFG, + ANA_POL_PIR_CFG, + ANA_POL_CIR_CFG, + ANA_POL_MODE_CFG, + ANA_POL_PIR_STATE, + ANA_POL_CIR_STATE, + ANA_POL_STATE, + ANA_POL_FLOWC, + ANA_POL_HYST, + ANA_POL_MISC_CFG, + QS_XTR_GRP_CFG = QS << TARGET_OFFSET, + QS_XTR_RD, + QS_XTR_FRM_PRUNING, + QS_XTR_FLUSH, + QS_XTR_DATA_PRESENT, + QS_XTR_CFG, + QS_INJ_GRP_CFG, + QS_INJ_WR, + QS_INJ_CTRL, + QS_INJ_STATUS, + QS_INJ_ERR, + QS_INH_DBG, + QSYS_PORT_MODE = QSYS << TARGET_OFFSET, + QSYS_SWITCH_PORT_MODE, + QSYS_STAT_CNT_CFG, + QSYS_EEE_CFG, + QSYS_EEE_THRES, + QSYS_IGR_NO_SHARING, + QSYS_EGR_NO_SHARING, + QSYS_SW_STATUS, + QSYS_EXT_CPU_CFG, + QSYS_PAD_CFG, + QSYS_CPU_GROUP_MAP, + QSYS_QMAP, + QSYS_ISDX_SGRP, + QSYS_TIMED_FRAME_ENTRY, + QSYS_TFRM_MISC, + QSYS_TFRM_PORT_DLY, + QSYS_TFRM_TIMER_CFG_1, + QSYS_TFRM_TIMER_CFG_2, + QSYS_TFRM_TIMER_CFG_3, + QSYS_TFRM_TIMER_CFG_4, + QSYS_TFRM_TIMER_CFG_5, + QSYS_TFRM_TIMER_CFG_6, + QSYS_TFRM_TIMER_CFG_7, + QSYS_TFRM_TIMER_CFG_8, + QSYS_RED_PROFILE, + QSYS_RES_QOS_MODE, + QSYS_RES_CFG, + QSYS_RES_STAT, + QSYS_EGR_DROP_MODE, + QSYS_EQ_CTRL, + QSYS_EVENTS_CORE, + QSYS_QMAXSDU_CFG_0, + QSYS_QMAXSDU_CFG_1, + QSYS_QMAXSDU_CFG_2, + QSYS_QMAXSDU_CFG_3, + QSYS_QMAXSDU_CFG_4, + QSYS_QMAXSDU_CFG_5, + QSYS_QMAXSDU_CFG_6, + QSYS_QMAXSDU_CFG_7, + QSYS_PREEMPTION_CFG, + QSYS_CIR_CFG, + QSYS_EIR_CFG, + QSYS_SE_CFG, + QSYS_SE_DWRR_CFG, + QSYS_SE_CONNECT, + QSYS_SE_DLB_SENSE, + QSYS_CIR_STATE, + QSYS_EIR_STATE, + QSYS_SE_STATE, + QSYS_HSCH_MISC_CFG, + QSYS_TAG_CONFIG, + QSYS_TAS_PARAM_CFG_CTRL, + QSYS_PORT_MAX_SDU, + QSYS_PARAM_CFG_REG_1, + QSYS_PARAM_CFG_REG_2, + QSYS_PARAM_CFG_REG_3, + QSYS_PARAM_CFG_REG_4, + QSYS_PARAM_CFG_REG_5, + QSYS_GCL_CFG_REG_1, + QSYS_GCL_CFG_REG_2, + QSYS_PARAM_STATUS_REG_1, + QSYS_PARAM_STATUS_REG_2, + QSYS_PARAM_STATUS_REG_3, + QSYS_PARAM_STATUS_REG_4, + QSYS_PARAM_STATUS_REG_5, + QSYS_PARAM_STATUS_REG_6, + QSYS_PARAM_STATUS_REG_7, + QSYS_PARAM_STATUS_REG_8, + QSYS_PARAM_STATUS_REG_9, + QSYS_GCL_STATUS_REG_1, + QSYS_GCL_STATUS_REG_2, + REW_PORT_VLAN_CFG = REW << TARGET_OFFSET, + REW_TAG_CFG, + REW_PORT_CFG, + REW_DSCP_CFG, + REW_PCP_DEI_QOS_MAP_CFG, + REW_PTP_CFG, + REW_PTP_DLY1_CFG, + REW_RED_TAG_CFG, + REW_DSCP_REMAP_DP1_CFG, + REW_DSCP_REMAP_CFG, + REW_STAT_CFG, + REW_REW_STICKY, + REW_PPT, + SYS_COUNT_RX_OCTETS = SYS << TARGET_OFFSET, + SYS_COUNT_RX_UNICAST, + SYS_COUNT_RX_MULTICAST, + SYS_COUNT_RX_BROADCAST, + SYS_COUNT_RX_SHORTS, + SYS_COUNT_RX_FRAGMENTS, + SYS_COUNT_RX_JABBERS, + SYS_COUNT_RX_CRC_ALIGN_ERRS, + SYS_COUNT_RX_SYM_ERRS, + SYS_COUNT_RX_64, + SYS_COUNT_RX_65_127, + SYS_COUNT_RX_128_255, + SYS_COUNT_RX_256_1023, + SYS_COUNT_RX_1024_1526, + SYS_COUNT_RX_1527_MAX, + SYS_COUNT_RX_PAUSE, + SYS_COUNT_RX_CONTROL, + SYS_COUNT_RX_LONGS, + SYS_COUNT_RX_CLASSIFIED_DROPS, + SYS_COUNT_TX_OCTETS, + SYS_COUNT_TX_UNICAST, + SYS_COUNT_TX_MULTICAST, + SYS_COUNT_TX_BROADCAST, + SYS_COUNT_TX_COLLISION, + SYS_COUNT_TX_DROPS, + SYS_COUNT_TX_PAUSE, + SYS_COUNT_TX_64, + SYS_COUNT_TX_65_127, + SYS_COUNT_TX_128_511, + SYS_COUNT_TX_512_1023, + SYS_COUNT_TX_1024_1526, + SYS_COUNT_TX_1527_MAX, + SYS_COUNT_TX_AGING, + SYS_RESET_CFG, + SYS_SR_ETYPE_CFG, + SYS_VLAN_ETYPE_CFG, + SYS_PORT_MODE, + SYS_FRONT_PORT_MODE, + SYS_FRM_AGING, + SYS_STAT_CFG, + SYS_SW_STATUS, + SYS_MISC_CFG, + SYS_REW_MAC_HIGH_CFG, + SYS_REW_MAC_LOW_CFG, + SYS_TIMESTAMP_OFFSET, + SYS_CMID, + SYS_PAUSE_CFG, + SYS_PAUSE_TOT_CFG, + SYS_ATOP, + SYS_ATOP_TOT_CFG, + SYS_MAC_FC_CFG, + SYS_MMGT, + SYS_MMGT_FAST, + SYS_EVENTS_DIF, + SYS_EVENTS_CORE, + SYS_CNT, + SYS_PTP_STATUS, + SYS_PTP_TXSTAMP, + SYS_PTP_NXT, + SYS_PTP_CFG, + SYS_RAM_INIT, + SYS_CM_ADDR, + SYS_CM_DATA_WR, + SYS_CM_DATA_RD, + SYS_CM_OP, + SYS_CM_DATA, + S2_CORE_UPDATE_CTRL = S2 << TARGET_OFFSET, + S2_CORE_MV_CFG, + S2_CACHE_ENTRY_DAT, + S2_CACHE_MASK_DAT, + S2_CACHE_ACTION_DAT, + S2_CACHE_CNT_DAT, + S2_CACHE_TG_DAT, + PTP_PIN_CFG = PTP << TARGET_OFFSET, + PTP_PIN_TOD_SEC_MSB, + PTP_PIN_TOD_SEC_LSB, + PTP_PIN_TOD_NSEC, + PTP_CFG_MISC, + PTP_CLK_CFG_ADJ_CFG, + PTP_CLK_CFG_ADJ_FREQ, + GCB_SOFT_RST = GCB << TARGET_OFFSET, +}; + +enum ocelot_regfield { + ANA_ADVLEARN_VLAN_CHK, + ANA_ADVLEARN_LEARN_MIRROR, + ANA_ANEVENTS_FLOOD_DISCARD, + ANA_ANEVENTS_MSTI_DROP, + ANA_ANEVENTS_ACLKILL, + ANA_ANEVENTS_ACLUSED, + ANA_ANEVENTS_AUTOAGE, + ANA_ANEVENTS_VS2TTL1, + ANA_ANEVENTS_STORM_DROP, + ANA_ANEVENTS_LEARN_DROP, + ANA_ANEVENTS_AGED_ENTRY, + ANA_ANEVENTS_CPU_LEARN_FAILED, + ANA_ANEVENTS_AUTO_LEARN_FAILED, + ANA_ANEVENTS_LEARN_REMOVE, + ANA_ANEVENTS_AUTO_LEARNED, + ANA_ANEVENTS_AUTO_MOVED, + ANA_ANEVENTS_DROPPED, + ANA_ANEVENTS_CLASSIFIED_DROP, + ANA_ANEVENTS_CLASSIFIED_COPY, + ANA_ANEVENTS_VLAN_DISCARD, + ANA_ANEVENTS_FWD_DISCARD, + ANA_ANEVENTS_MULTICAST_FLOOD, + ANA_ANEVENTS_UNICAST_FLOOD, + ANA_ANEVENTS_DEST_KNOWN, + ANA_ANEVENTS_BUCKET3_MATCH, + ANA_ANEVENTS_BUCKET2_MATCH, + ANA_ANEVENTS_BUCKET1_MATCH, + ANA_ANEVENTS_BUCKET0_MATCH, + ANA_ANEVENTS_CPU_OPERATION, + ANA_ANEVENTS_DMAC_LOOKUP, + ANA_ANEVENTS_SMAC_LOOKUP, + ANA_ANEVENTS_SEQ_GEN_ERR_0, + ANA_ANEVENTS_SEQ_GEN_ERR_1, + ANA_TABLES_MACACCESS_B_DOM, + ANA_TABLES_MACTINDX_BUCKET, + ANA_TABLES_MACTINDX_M_INDEX, + QSYS_TIMED_FRAME_ENTRY_TFRM_VLD, + QSYS_TIMED_FRAME_ENTRY_TFRM_FP, + QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO, + QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL, + QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T, + SYS_RESET_CFG_CORE_ENA, + SYS_RESET_CFG_MEM_ENA, + SYS_RESET_CFG_MEM_INIT, + GCB_SOFT_RST_SWC_RST, + REGFIELD_MAX +}; + +enum ocelot_clk_pins { + ALT_PPS_PIN = 1, + EXT_CLK_PIN, + ALT_LDST_PIN, + TOD_ACC_PIN +}; + +struct ocelot_stat_layout { + u32 offset; + char name[ETH_GSTRING_LEN]; +}; + +enum ocelot_tag_prefix { + OCELOT_TAG_PREFIX_DISABLED = 0, + OCELOT_TAG_PREFIX_NONE, + OCELOT_TAG_PREFIX_SHORT, + OCELOT_TAG_PREFIX_LONG, +}; + +struct ocelot; + +struct ocelot_ops { + void (*pcs_init)(struct ocelot *ocelot, int port); + int (*reset)(struct ocelot *ocelot); +}; + +struct ocelot_port { + struct ocelot *ocelot; + + void __iomem *regs; + + /* Ingress default VLAN (pvid) */ + u16 pvid; + + /* Egress default VLAN (vid) */ + u16 vid; + + u8 ptp_cmd; + struct list_head skbs; + u8 ts_id; +}; + +struct ocelot { + struct device *dev; + + const struct ocelot_ops *ops; + struct regmap *targets[TARGET_MAX]; + struct regmap_field *regfields[REGFIELD_MAX]; + const u32 *const *map; + const struct ocelot_stat_layout *stats_layout; + unsigned int num_stats; + + int shared_queue_sz; + + struct net_device *hw_bridge_dev; + u16 bridge_mask; + u16 bridge_fwd_mask; + + struct ocelot_port **ports; + + u8 base_mac[ETH_ALEN]; + + /* Keep track of the vlan port masks */ + u32 vlan_mask[VLAN_N_VID]; + + u8 num_phys_ports; + u8 num_cpu_ports; + u8 cpu; + + u32 *lags; + + struct list_head multicast; + + /* Workqueue to check statistics for overflow with its lock */ + struct mutex stats_lock; + u64 *stats; + struct delayed_work stats_work; + struct workqueue_struct *stats_queue; + + u8 ptp:1; + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_info; + struct hwtstamp_config hwtstamp_config; + /* Protects the PTP interface state */ + struct mutex ptp_lock; + /* Protects the PTP clock */ + spinlock_t ptp_clock_lock; + + void (*port_pcs_init)(struct ocelot_port *port); +}; + +#define ocelot_read_ix(ocelot, reg, gi, ri) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) +#define ocelot_read_gix(ocelot, reg, gi) __ocelot_read_ix(ocelot, reg, reg##_GSZ * (gi)) +#define ocelot_read_rix(ocelot, reg, ri) __ocelot_read_ix(ocelot, reg, reg##_RSZ * (ri)) +#define ocelot_read(ocelot, reg) __ocelot_read_ix(ocelot, reg, 0) + +#define ocelot_write_ix(ocelot, val, reg, gi, ri) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) +#define ocelot_write_gix(ocelot, val, reg, gi) __ocelot_write_ix(ocelot, val, reg, reg##_GSZ * (gi)) +#define ocelot_write_rix(ocelot, val, reg, ri) __ocelot_write_ix(ocelot, val, reg, reg##_RSZ * (ri)) +#define ocelot_write(ocelot, val, reg) __ocelot_write_ix(ocelot, val, reg, 0) + +#define ocelot_rmw_ix(ocelot, val, m, reg, gi, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi) + reg##_RSZ * (ri)) +#define ocelot_rmw_gix(ocelot, val, m, reg, gi) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_GSZ * (gi)) +#define ocelot_rmw_rix(ocelot, val, m, reg, ri) __ocelot_rmw_ix(ocelot, val, m, reg, reg##_RSZ * (ri)) +#define ocelot_rmw(ocelot, val, m, reg) __ocelot_rmw_ix(ocelot, val, m, reg, 0) + +/* I/O */ +u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); +void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); +u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset); +void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset); +void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg, + u32 offset); + +/* Hardware initialization */ +int ocelot_regfields_init(struct ocelot *ocelot, + const struct reg_field *const regfields); +struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res); +void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu, + enum ocelot_tag_prefix injection, + enum ocelot_tag_prefix extraction); +int ocelot_init(struct ocelot *ocelot); +void ocelot_deinit(struct ocelot *ocelot); +void ocelot_init_port(struct ocelot *ocelot, int port); + +/* DSA callbacks */ +void ocelot_port_enable(struct ocelot *ocelot, int port, + struct phy_device *phy); +void ocelot_port_disable(struct ocelot *ocelot, int port); +void ocelot_get_strings(struct ocelot *ocelot, int port, u32 sset, u8 *data); +void ocelot_get_ethtool_stats(struct ocelot *ocelot, int port, u64 *data); +int ocelot_get_sset_count(struct ocelot *ocelot, int port, int sset); +int ocelot_get_ts_info(struct ocelot *ocelot, int port, + struct ethtool_ts_info *info); +void ocelot_set_ageing_time(struct ocelot *ocelot, unsigned int msecs); +void ocelot_adjust_link(struct ocelot *ocelot, int port, + struct phy_device *phydev); +void ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, + bool vlan_aware); +void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); +int ocelot_port_bridge_join(struct ocelot *ocelot, int port, + struct net_device *bridge); +int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, + struct net_device *bridge); +int ocelot_fdb_dump(struct ocelot *ocelot, int port, + dsa_fdb_dump_cb_t *cb, void *data); +int ocelot_fdb_add(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid, bool vlan_aware); +int ocelot_fdb_del(struct ocelot *ocelot, int port, + const unsigned char *addr, u16 vid); +int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, + bool untagged); +int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); +int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); +void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts); + +#endif -- cgit v1.2.3-59-g8ed1b From a030dfe1947310a2140b9e371dc9ebfab72c914f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:28 +0200 Subject: net: mscc: ocelot: publish ocelot_sys.h to include/soc/mscc The Felix DSA driver needs to write to SYS_RAM_INIT_RAM_INIT for its own chip initialization process. Also update the MAINTAINERS file such that the headers exported by the ocelot driver are under the same maintainers' umbrella as the driver itself. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- MAINTAINERS | 1 + drivers/net/ethernet/mscc/ocelot.h | 2 +- drivers/net/ethernet/mscc/ocelot_sys.h | 144 --------------------------------- include/soc/mscc/ocelot_sys.h | 144 +++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 145 deletions(-) delete mode 100644 drivers/net/ethernet/mscc/ocelot_sys.h create mode 100644 include/soc/mscc/ocelot_sys.h (limited to 'drivers/net') diff --git a/MAINTAINERS b/MAINTAINERS index 3e57fc1d9962..d09a3205da37 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10834,6 +10834,7 @@ M: Microchip Linux Driver Support L: netdev@vger.kernel.org S: Supported F: drivers/net/ethernet/mscc/ +F: include/soc/mscc/ocelot* MICROSOFT SURFACE PRO 3 BUTTON DRIVER M: Chen Yu diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 325afea3e846..32fef4f495aa 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -18,12 +18,12 @@ #include #include +#include #include #include "ocelot_ana.h" #include "ocelot_dev.h" #include "ocelot_qsys.h" #include "ocelot_rew.h" -#include "ocelot_sys.h" #include "ocelot_qs.h" #include "ocelot_tc.h" #include "ocelot_ptp.h" diff --git a/drivers/net/ethernet/mscc/ocelot_sys.h b/drivers/net/ethernet/mscc/ocelot_sys.h deleted file mode 100644 index 16f91e172bcb..000000000000 --- a/drivers/net/ethernet/mscc/ocelot_sys.h +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ -/* - * Microsemi Ocelot Switch driver - * - * Copyright (c) 2017 Microsemi Corporation - */ - -#ifndef _MSCC_OCELOT_SYS_H_ -#define _MSCC_OCELOT_SYS_H_ - -#define SYS_COUNT_RX_OCTETS_RSZ 0x4 - -#define SYS_COUNT_TX_OCTETS_RSZ 0x4 - -#define SYS_PORT_MODE_RSZ 0x4 - -#define SYS_PORT_MODE_DATA_WO_TS(x) (((x) << 5) & GENMASK(6, 5)) -#define SYS_PORT_MODE_DATA_WO_TS_M GENMASK(6, 5) -#define SYS_PORT_MODE_DATA_WO_TS_X(x) (((x) & GENMASK(6, 5)) >> 5) -#define SYS_PORT_MODE_INCL_INJ_HDR(x) (((x) << 3) & GENMASK(4, 3)) -#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3) -#define SYS_PORT_MODE_INCL_INJ_HDR_X(x) (((x) & GENMASK(4, 3)) >> 3) -#define SYS_PORT_MODE_INCL_XTR_HDR(x) (((x) << 1) & GENMASK(2, 1)) -#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1) -#define SYS_PORT_MODE_INCL_XTR_HDR_X(x) (((x) & GENMASK(2, 1)) >> 1) -#define SYS_PORT_MODE_INJ_HDR_ERR BIT(0) - -#define SYS_FRONT_PORT_MODE_RSZ 0x4 - -#define SYS_FRONT_PORT_MODE_HDX_MODE BIT(0) - -#define SYS_FRM_AGING_AGE_TX_ENA BIT(20) -#define SYS_FRM_AGING_MAX_AGE(x) ((x) & GENMASK(19, 0)) -#define SYS_FRM_AGING_MAX_AGE_M GENMASK(19, 0) - -#define SYS_STAT_CFG_STAT_CLEAR_SHOT(x) (((x) << 10) & GENMASK(16, 10)) -#define SYS_STAT_CFG_STAT_CLEAR_SHOT_M GENMASK(16, 10) -#define SYS_STAT_CFG_STAT_CLEAR_SHOT_X(x) (((x) & GENMASK(16, 10)) >> 10) -#define SYS_STAT_CFG_STAT_VIEW(x) ((x) & GENMASK(9, 0)) -#define SYS_STAT_CFG_STAT_VIEW_M GENMASK(9, 0) - -#define SYS_SW_STATUS_RSZ 0x4 - -#define SYS_SW_STATUS_PORT_RX_PAUSED BIT(0) - -#define SYS_MISC_CFG_PTP_RSRV_CLR BIT(1) -#define SYS_MISC_CFG_PTP_DIS_NEG_RO BIT(0) - -#define SYS_REW_MAC_HIGH_CFG_RSZ 0x4 - -#define SYS_REW_MAC_LOW_CFG_RSZ 0x4 - -#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG(x) (((x) << 6) & GENMASK(21, 6)) -#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_M GENMASK(21, 6) -#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_X(x) (((x) & GENMASK(21, 6)) >> 6) -#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x) ((x) & GENMASK(5, 0)) -#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M GENMASK(5, 0) - -#define SYS_PAUSE_CFG_RSZ 0x4 - -#define SYS_PAUSE_CFG_PAUSE_START(x) (((x) << 10) & GENMASK(18, 10)) -#define SYS_PAUSE_CFG_PAUSE_START_M GENMASK(18, 10) -#define SYS_PAUSE_CFG_PAUSE_START_X(x) (((x) & GENMASK(18, 10)) >> 10) -#define SYS_PAUSE_CFG_PAUSE_STOP(x) (((x) << 1) & GENMASK(9, 1)) -#define SYS_PAUSE_CFG_PAUSE_STOP_M GENMASK(9, 1) -#define SYS_PAUSE_CFG_PAUSE_STOP_X(x) (((x) & GENMASK(9, 1)) >> 1) -#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0) - -#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x) (((x) << 9) & GENMASK(17, 9)) -#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M GENMASK(17, 9) -#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x) (((x) & GENMASK(17, 9)) >> 9) -#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP(x) ((x) & GENMASK(8, 0)) -#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP_M GENMASK(8, 0) - -#define SYS_ATOP_RSZ 0x4 - -#define SYS_MAC_FC_CFG_RSZ 0x4 - -#define SYS_MAC_FC_CFG_FC_LINK_SPEED(x) (((x) << 26) & GENMASK(27, 26)) -#define SYS_MAC_FC_CFG_FC_LINK_SPEED_M GENMASK(27, 26) -#define SYS_MAC_FC_CFG_FC_LINK_SPEED_X(x) (((x) & GENMASK(27, 26)) >> 26) -#define SYS_MAC_FC_CFG_FC_LATENCY_CFG(x) (((x) << 20) & GENMASK(25, 20)) -#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_M GENMASK(25, 20) -#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_X(x) (((x) & GENMASK(25, 20)) >> 20) -#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA BIT(18) -#define SYS_MAC_FC_CFG_TX_FC_ENA BIT(17) -#define SYS_MAC_FC_CFG_RX_FC_ENA BIT(16) -#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG(x) ((x) & GENMASK(15, 0)) -#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_M GENMASK(15, 0) - -#define SYS_MMGT_RELCNT(x) (((x) << 16) & GENMASK(31, 16)) -#define SYS_MMGT_RELCNT_M GENMASK(31, 16) -#define SYS_MMGT_RELCNT_X(x) (((x) & GENMASK(31, 16)) >> 16) -#define SYS_MMGT_FREECNT(x) ((x) & GENMASK(15, 0)) -#define SYS_MMGT_FREECNT_M GENMASK(15, 0) - -#define SYS_MMGT_FAST_FREEVLD(x) (((x) << 4) & GENMASK(7, 4)) -#define SYS_MMGT_FAST_FREEVLD_M GENMASK(7, 4) -#define SYS_MMGT_FAST_FREEVLD_X(x) (((x) & GENMASK(7, 4)) >> 4) -#define SYS_MMGT_FAST_RELVLD(x) ((x) & GENMASK(3, 0)) -#define SYS_MMGT_FAST_RELVLD_M GENMASK(3, 0) - -#define SYS_EVENTS_DIF_RSZ 0x4 - -#define SYS_EVENTS_DIF_EV_DRX(x) (((x) << 6) & GENMASK(8, 6)) -#define SYS_EVENTS_DIF_EV_DRX_M GENMASK(8, 6) -#define SYS_EVENTS_DIF_EV_DRX_X(x) (((x) & GENMASK(8, 6)) >> 6) -#define SYS_EVENTS_DIF_EV_DTX(x) ((x) & GENMASK(5, 0)) -#define SYS_EVENTS_DIF_EV_DTX_M GENMASK(5, 0) - -#define SYS_EVENTS_CORE_EV_FWR BIT(2) -#define SYS_EVENTS_CORE_EV_ANA(x) ((x) & GENMASK(1, 0)) -#define SYS_EVENTS_CORE_EV_ANA_M GENMASK(1, 0) - -#define SYS_CNT_GSZ 0x4 - -#define SYS_PTP_STATUS_PTP_TXSTAMP_OAM BIT(29) -#define SYS_PTP_STATUS_PTP_OVFL BIT(28) -#define SYS_PTP_STATUS_PTP_MESS_VLD BIT(27) -#define SYS_PTP_STATUS_PTP_MESS_ID(x) (((x) << 21) & GENMASK(26, 21)) -#define SYS_PTP_STATUS_PTP_MESS_ID_M GENMASK(26, 21) -#define SYS_PTP_STATUS_PTP_MESS_ID_X(x) (((x) & GENMASK(26, 21)) >> 21) -#define SYS_PTP_STATUS_PTP_MESS_TXPORT(x) (((x) << 16) & GENMASK(20, 16)) -#define SYS_PTP_STATUS_PTP_MESS_TXPORT_M GENMASK(20, 16) -#define SYS_PTP_STATUS_PTP_MESS_TXPORT_X(x) (((x) & GENMASK(20, 16)) >> 16) -#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID(x) ((x) & GENMASK(15, 0)) -#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID_M GENMASK(15, 0) - -#define SYS_PTP_TXSTAMP_PTP_TXSTAMP(x) ((x) & GENMASK(29, 0)) -#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_M GENMASK(29, 0) -#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC BIT(31) - -#define SYS_PTP_NXT_PTP_NXT BIT(0) - -#define SYS_PTP_CFG_PTP_STAMP_WID(x) (((x) << 2) & GENMASK(7, 2)) -#define SYS_PTP_CFG_PTP_STAMP_WID_M GENMASK(7, 2) -#define SYS_PTP_CFG_PTP_STAMP_WID_X(x) (((x) & GENMASK(7, 2)) >> 2) -#define SYS_PTP_CFG_PTP_CF_ROLL_MODE(x) ((x) & GENMASK(1, 0)) -#define SYS_PTP_CFG_PTP_CF_ROLL_MODE_M GENMASK(1, 0) - -#define SYS_RAM_INIT_RAM_INIT BIT(1) -#define SYS_RAM_INIT_RAM_CFG_HOOK BIT(0) - -#endif diff --git a/include/soc/mscc/ocelot_sys.h b/include/soc/mscc/ocelot_sys.h new file mode 100644 index 000000000000..16f91e172bcb --- /dev/null +++ b/include/soc/mscc/ocelot_sys.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Microsemi Ocelot Switch driver + * + * Copyright (c) 2017 Microsemi Corporation + */ + +#ifndef _MSCC_OCELOT_SYS_H_ +#define _MSCC_OCELOT_SYS_H_ + +#define SYS_COUNT_RX_OCTETS_RSZ 0x4 + +#define SYS_COUNT_TX_OCTETS_RSZ 0x4 + +#define SYS_PORT_MODE_RSZ 0x4 + +#define SYS_PORT_MODE_DATA_WO_TS(x) (((x) << 5) & GENMASK(6, 5)) +#define SYS_PORT_MODE_DATA_WO_TS_M GENMASK(6, 5) +#define SYS_PORT_MODE_DATA_WO_TS_X(x) (((x) & GENMASK(6, 5)) >> 5) +#define SYS_PORT_MODE_INCL_INJ_HDR(x) (((x) << 3) & GENMASK(4, 3)) +#define SYS_PORT_MODE_INCL_INJ_HDR_M GENMASK(4, 3) +#define SYS_PORT_MODE_INCL_INJ_HDR_X(x) (((x) & GENMASK(4, 3)) >> 3) +#define SYS_PORT_MODE_INCL_XTR_HDR(x) (((x) << 1) & GENMASK(2, 1)) +#define SYS_PORT_MODE_INCL_XTR_HDR_M GENMASK(2, 1) +#define SYS_PORT_MODE_INCL_XTR_HDR_X(x) (((x) & GENMASK(2, 1)) >> 1) +#define SYS_PORT_MODE_INJ_HDR_ERR BIT(0) + +#define SYS_FRONT_PORT_MODE_RSZ 0x4 + +#define SYS_FRONT_PORT_MODE_HDX_MODE BIT(0) + +#define SYS_FRM_AGING_AGE_TX_ENA BIT(20) +#define SYS_FRM_AGING_MAX_AGE(x) ((x) & GENMASK(19, 0)) +#define SYS_FRM_AGING_MAX_AGE_M GENMASK(19, 0) + +#define SYS_STAT_CFG_STAT_CLEAR_SHOT(x) (((x) << 10) & GENMASK(16, 10)) +#define SYS_STAT_CFG_STAT_CLEAR_SHOT_M GENMASK(16, 10) +#define SYS_STAT_CFG_STAT_CLEAR_SHOT_X(x) (((x) & GENMASK(16, 10)) >> 10) +#define SYS_STAT_CFG_STAT_VIEW(x) ((x) & GENMASK(9, 0)) +#define SYS_STAT_CFG_STAT_VIEW_M GENMASK(9, 0) + +#define SYS_SW_STATUS_RSZ 0x4 + +#define SYS_SW_STATUS_PORT_RX_PAUSED BIT(0) + +#define SYS_MISC_CFG_PTP_RSRV_CLR BIT(1) +#define SYS_MISC_CFG_PTP_DIS_NEG_RO BIT(0) + +#define SYS_REW_MAC_HIGH_CFG_RSZ 0x4 + +#define SYS_REW_MAC_LOW_CFG_RSZ 0x4 + +#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG(x) (((x) << 6) & GENMASK(21, 6)) +#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_M GENMASK(21, 6) +#define SYS_TIMESTAMP_OFFSET_ETH_TYPE_CFG_X(x) (((x) & GENMASK(21, 6)) >> 6) +#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET(x) ((x) & GENMASK(5, 0)) +#define SYS_TIMESTAMP_OFFSET_TIMESTAMP_OFFSET_M GENMASK(5, 0) + +#define SYS_PAUSE_CFG_RSZ 0x4 + +#define SYS_PAUSE_CFG_PAUSE_START(x) (((x) << 10) & GENMASK(18, 10)) +#define SYS_PAUSE_CFG_PAUSE_START_M GENMASK(18, 10) +#define SYS_PAUSE_CFG_PAUSE_START_X(x) (((x) & GENMASK(18, 10)) >> 10) +#define SYS_PAUSE_CFG_PAUSE_STOP(x) (((x) << 1) & GENMASK(9, 1)) +#define SYS_PAUSE_CFG_PAUSE_STOP_M GENMASK(9, 1) +#define SYS_PAUSE_CFG_PAUSE_STOP_X(x) (((x) & GENMASK(9, 1)) >> 1) +#define SYS_PAUSE_CFG_PAUSE_ENA BIT(0) + +#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START(x) (((x) << 9) & GENMASK(17, 9)) +#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_M GENMASK(17, 9) +#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_START_X(x) (((x) & GENMASK(17, 9)) >> 9) +#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP(x) ((x) & GENMASK(8, 0)) +#define SYS_PAUSE_TOT_CFG_PAUSE_TOT_STOP_M GENMASK(8, 0) + +#define SYS_ATOP_RSZ 0x4 + +#define SYS_MAC_FC_CFG_RSZ 0x4 + +#define SYS_MAC_FC_CFG_FC_LINK_SPEED(x) (((x) << 26) & GENMASK(27, 26)) +#define SYS_MAC_FC_CFG_FC_LINK_SPEED_M GENMASK(27, 26) +#define SYS_MAC_FC_CFG_FC_LINK_SPEED_X(x) (((x) & GENMASK(27, 26)) >> 26) +#define SYS_MAC_FC_CFG_FC_LATENCY_CFG(x) (((x) << 20) & GENMASK(25, 20)) +#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_M GENMASK(25, 20) +#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_X(x) (((x) & GENMASK(25, 20)) >> 20) +#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA BIT(18) +#define SYS_MAC_FC_CFG_TX_FC_ENA BIT(17) +#define SYS_MAC_FC_CFG_RX_FC_ENA BIT(16) +#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG(x) ((x) & GENMASK(15, 0)) +#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_M GENMASK(15, 0) + +#define SYS_MMGT_RELCNT(x) (((x) << 16) & GENMASK(31, 16)) +#define SYS_MMGT_RELCNT_M GENMASK(31, 16) +#define SYS_MMGT_RELCNT_X(x) (((x) & GENMASK(31, 16)) >> 16) +#define SYS_MMGT_FREECNT(x) ((x) & GENMASK(15, 0)) +#define SYS_MMGT_FREECNT_M GENMASK(15, 0) + +#define SYS_MMGT_FAST_FREEVLD(x) (((x) << 4) & GENMASK(7, 4)) +#define SYS_MMGT_FAST_FREEVLD_M GENMASK(7, 4) +#define SYS_MMGT_FAST_FREEVLD_X(x) (((x) & GENMASK(7, 4)) >> 4) +#define SYS_MMGT_FAST_RELVLD(x) ((x) & GENMASK(3, 0)) +#define SYS_MMGT_FAST_RELVLD_M GENMASK(3, 0) + +#define SYS_EVENTS_DIF_RSZ 0x4 + +#define SYS_EVENTS_DIF_EV_DRX(x) (((x) << 6) & GENMASK(8, 6)) +#define SYS_EVENTS_DIF_EV_DRX_M GENMASK(8, 6) +#define SYS_EVENTS_DIF_EV_DRX_X(x) (((x) & GENMASK(8, 6)) >> 6) +#define SYS_EVENTS_DIF_EV_DTX(x) ((x) & GENMASK(5, 0)) +#define SYS_EVENTS_DIF_EV_DTX_M GENMASK(5, 0) + +#define SYS_EVENTS_CORE_EV_FWR BIT(2) +#define SYS_EVENTS_CORE_EV_ANA(x) ((x) & GENMASK(1, 0)) +#define SYS_EVENTS_CORE_EV_ANA_M GENMASK(1, 0) + +#define SYS_CNT_GSZ 0x4 + +#define SYS_PTP_STATUS_PTP_TXSTAMP_OAM BIT(29) +#define SYS_PTP_STATUS_PTP_OVFL BIT(28) +#define SYS_PTP_STATUS_PTP_MESS_VLD BIT(27) +#define SYS_PTP_STATUS_PTP_MESS_ID(x) (((x) << 21) & GENMASK(26, 21)) +#define SYS_PTP_STATUS_PTP_MESS_ID_M GENMASK(26, 21) +#define SYS_PTP_STATUS_PTP_MESS_ID_X(x) (((x) & GENMASK(26, 21)) >> 21) +#define SYS_PTP_STATUS_PTP_MESS_TXPORT(x) (((x) << 16) & GENMASK(20, 16)) +#define SYS_PTP_STATUS_PTP_MESS_TXPORT_M GENMASK(20, 16) +#define SYS_PTP_STATUS_PTP_MESS_TXPORT_X(x) (((x) & GENMASK(20, 16)) >> 16) +#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID(x) ((x) & GENMASK(15, 0)) +#define SYS_PTP_STATUS_PTP_MESS_SEQ_ID_M GENMASK(15, 0) + +#define SYS_PTP_TXSTAMP_PTP_TXSTAMP(x) ((x) & GENMASK(29, 0)) +#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_M GENMASK(29, 0) +#define SYS_PTP_TXSTAMP_PTP_TXSTAMP_SEC BIT(31) + +#define SYS_PTP_NXT_PTP_NXT BIT(0) + +#define SYS_PTP_CFG_PTP_STAMP_WID(x) (((x) << 2) & GENMASK(7, 2)) +#define SYS_PTP_CFG_PTP_STAMP_WID_M GENMASK(7, 2) +#define SYS_PTP_CFG_PTP_STAMP_WID_X(x) (((x) & GENMASK(7, 2)) >> 2) +#define SYS_PTP_CFG_PTP_CF_ROLL_MODE(x) ((x) & GENMASK(1, 0)) +#define SYS_PTP_CFG_PTP_CF_ROLL_MODE_M GENMASK(1, 0) + +#define SYS_RAM_INIT_RAM_INIT BIT(1) +#define SYS_RAM_INIT_RAM_CFG_HOOK BIT(0) + +#endif -- cgit v1.2.3-59-g8ed1b From 56051948773eeb4224fbda88102e891d1ad5cefd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Thu, 14 Nov 2019 17:03:30 +0200 Subject: net: dsa: ocelot: add driver for Felix switch family This supports an Ethernet switching core from Vitesse / Microsemi / Microchip (VSC9959) which is part of the Ocelot family (a brand name), and whose code name is Felix. The switch can be (and is) integrated on different SoCs as a PCIe endpoint device. The functionality is provided by the core of the Ocelot switch driver (drivers/net/ethernet/mscc). In this regard, the current driver is an instance of Microsemi's Ocelot core driver, with a DSA front-end. It inherits its name from VSC9959's code name, to distinguish itself from the switchdev ocelot driver. The patch adds the logic for probing a PCI device and defines the register map for the VSC9959 switch core, since it has some differences in register addresses and bitfield mappings compared to the other Ocelot switches (VSC7511, VSC7512, VSC7513, VSC7514). The Felix driver declares the register map as part of the "instance table". Currently the VSC9959 inside NXP LS1028A is the only instance, but presumably it can support other switches in the Ocelot family, when used in DSA mode (Linux running on the external CPU, and not on the embedded MIPS). In a few cases, some h/w operations have to be done differently on VSC9959 due to missing bitfields. This is the case for the switch core reset and init. Because for this operation Ocelot uses some bits that are not present on Felix, the latter has to use a register from the global registers block (GCB) instead. Although it is a PCI driver, it relies on DT bindings for compatibility with DSA (CPU port link, PHY library). It does not have any custom device tree bindings, since we would like to minimize its dependency on device tree though. Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- MAINTAINERS | 1 + drivers/net/dsa/Kconfig | 2 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/ocelot/Kconfig | 11 + drivers/net/dsa/ocelot/Makefile | 6 + drivers/net/dsa/ocelot/felix.c | 441 +++++++++++++++++++++++++ drivers/net/dsa/ocelot/felix.h | 37 +++ drivers/net/dsa/ocelot/felix_vsc9959.c | 567 +++++++++++++++++++++++++++++++++ 8 files changed, 1066 insertions(+) create mode 100644 drivers/net/dsa/ocelot/Kconfig create mode 100644 drivers/net/dsa/ocelot/Makefile create mode 100644 drivers/net/dsa/ocelot/felix.c create mode 100644 drivers/net/dsa/ocelot/felix.h create mode 100644 drivers/net/dsa/ocelot/felix_vsc9959.c (limited to 'drivers/net') diff --git a/MAINTAINERS b/MAINTAINERS index 112befcb712a..39681b34f8e3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17365,6 +17365,7 @@ M: Vladimir Oltean M: Claudiu Manoil L: netdev@vger.kernel.org S: Maintained +F: drivers/net/dsa/ocelot/* F: net/dsa/tag_ocelot.c VIVID VIRTUAL VIDEO DRIVER diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 685e12b05a7c..c7667645f04a 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -52,6 +52,8 @@ source "drivers/net/dsa/microchip/Kconfig" source "drivers/net/dsa/mv88e6xxx/Kconfig" +source "drivers/net/dsa/ocelot/Kconfig" + source "drivers/net/dsa/sja1105/Kconfig" config NET_DSA_QCA8K diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index ae70b79628d6..9d384a32b3a2 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -20,4 +20,5 @@ obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o obj-y += b53/ obj-y += microchip/ obj-y += mv88e6xxx/ +obj-y += ocelot/ obj-y += sja1105/ diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig new file mode 100644 index 000000000000..0031ca814346 --- /dev/null +++ b/drivers/net/dsa/ocelot/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +config NET_DSA_MSCC_FELIX + tristate "Ocelot / Felix Ethernet switch support" + depends on NET_DSA && PCI + select MSCC_OCELOT_SWITCH + select NET_DSA_TAG_OCELOT + help + This driver supports the VSC9959 network switch, which is a member of + the Vitesse / Microsemi / Microchip Ocelot family of switching cores. + It is embedded as a PCIe function of the NXP LS1028A ENETC integrated + endpoint. diff --git a/drivers/net/dsa/ocelot/Makefile b/drivers/net/dsa/ocelot/Makefile new file mode 100644 index 000000000000..37ad403e0b2a --- /dev/null +++ b/drivers/net/dsa/ocelot/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o + +mscc_felix-objs := \ + felix.o \ + felix_vsc9959.o diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c new file mode 100644 index 000000000000..05e3f2898bf6 --- /dev/null +++ b/drivers/net/dsa/ocelot/felix.c @@ -0,0 +1,441 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2019 NXP Semiconductors + */ +#include +#include +#include +#include +#include +#include +#include "felix.h" + +static enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds, + int port) +{ + return DSA_TAG_PROTO_OCELOT; +} + +static int felix_set_ageing_time(struct dsa_switch *ds, + unsigned int ageing_time) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_set_ageing_time(ocelot, ageing_time); + + return 0; +} + +static void felix_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_adjust_link(ocelot, port, phydev); +} + +static int felix_fdb_dump(struct dsa_switch *ds, int port, + dsa_fdb_dump_cb_t *cb, void *data) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_fdb_dump(ocelot, port, cb, data); +} + +static int felix_fdb_add(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct ocelot *ocelot = ds->priv; + bool vlan_aware; + + vlan_aware = dsa_port_is_vlan_filtering(dsa_to_port(ds, port)); + + return ocelot_fdb_add(ocelot, port, addr, vid, vlan_aware); +} + +static int felix_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_fdb_del(ocelot, port, addr, vid); +} + +static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, + u8 state) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_bridge_stp_state_set(ocelot, port, state); +} + +static int felix_bridge_join(struct dsa_switch *ds, int port, + struct net_device *br) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_port_bridge_join(ocelot, port, br); +} + +static void felix_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *br) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_bridge_leave(ocelot, port, br); +} + +/* This callback needs to be present */ +static int felix_vlan_prepare(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + return 0; +} + +static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_vlan_filtering(ocelot, port, enabled); + + return 0; +} + +static void felix_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ocelot *ocelot = ds->priv; + u16 vid; + int err; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + err = ocelot_vlan_add(ocelot, port, vid, + vlan->flags & BRIDGE_VLAN_INFO_PVID, + vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); + if (err) { + dev_err(ds->dev, "Failed to add VLAN %d to port %d: %d\n", + vid, port, err); + return; + } + } +} + +static int felix_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan) +{ + struct ocelot *ocelot = ds->priv; + u16 vid; + int err; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + err = ocelot_vlan_del(ocelot, port, vid); + if (err) { + dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n", + vid, port, err); + return err; + } + } + return 0; +} + +static int felix_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_enable(ocelot, port, phy); + + return 0; +} + +static void felix_port_disable(struct dsa_switch *ds, int port) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_port_disable(ocelot, port); +} + +static void felix_get_strings(struct dsa_switch *ds, int port, + u32 stringset, u8 *data) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_get_strings(ocelot, port, stringset, data); +} + +static void felix_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_get_ethtool_stats(ocelot, port, data); +} + +static int felix_get_sset_count(struct dsa_switch *ds, int port, int sset) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_get_sset_count(ocelot, port, sset); +} + +static int felix_get_ts_info(struct dsa_switch *ds, int port, + struct ethtool_ts_info *info) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_get_ts_info(ocelot, port, info); +} + +static int felix_init_structs(struct felix *felix, int num_phys_ports) +{ + struct ocelot *ocelot = &felix->ocelot; + resource_size_t base; + int port, i, err; + + ocelot->num_phys_ports = num_phys_ports; + ocelot->ports = devm_kcalloc(ocelot->dev, num_phys_ports, + sizeof(struct ocelot_port *), GFP_KERNEL); + if (!ocelot->ports) + return -ENOMEM; + + ocelot->map = felix->info->map; + ocelot->stats_layout = felix->info->stats_layout; + ocelot->num_stats = felix->info->num_stats; + ocelot->shared_queue_sz = felix->info->shared_queue_sz; + ocelot->ops = felix->info->ops; + + base = pci_resource_start(felix->pdev, felix->info->pci_bar); + + for (i = 0; i < TARGET_MAX; i++) { + struct regmap *target; + struct resource *res; + + if (!felix->info->target_io_res[i].name) + continue; + + res = &felix->info->target_io_res[i]; + res->flags = IORESOURCE_MEM; + res->start += base; + res->end += base; + + target = ocelot_regmap_init(ocelot, res); + if (IS_ERR(target)) { + dev_err(ocelot->dev, + "Failed to map device memory space\n"); + return PTR_ERR(target); + } + + ocelot->targets[i] = target; + } + + err = ocelot_regfields_init(ocelot, felix->info->regfields); + if (err) { + dev_err(ocelot->dev, "failed to init reg fields map\n"); + return err; + } + + for (port = 0; port < num_phys_ports; port++) { + struct ocelot_port *ocelot_port; + void __iomem *port_regs; + struct resource *res; + + ocelot_port = devm_kzalloc(ocelot->dev, + sizeof(struct ocelot_port), + GFP_KERNEL); + if (!ocelot_port) { + dev_err(ocelot->dev, + "failed to allocate port memory\n"); + return -ENOMEM; + } + + res = &felix->info->port_io_res[port]; + res->flags = IORESOURCE_MEM; + res->start += base; + res->end += base; + + port_regs = devm_ioremap_resource(ocelot->dev, res); + if (IS_ERR(port_regs)) { + dev_err(ocelot->dev, + "failed to map registers for port %d\n", port); + return PTR_ERR(port_regs); + } + + ocelot_port->ocelot = ocelot; + ocelot_port->regs = port_regs; + ocelot->ports[port] = ocelot_port; + } + + return 0; +} + +/* Hardware initialization done here so that we can allocate structures with + * devm without fear of dsa_register_switch returning -EPROBE_DEFER and causing + * us to allocate structures twice (leak memory) and map PCI memory twice + * (which will not work). + */ +static int felix_setup(struct dsa_switch *ds) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + int port, err; + + err = felix_init_structs(felix, ds->num_ports); + if (err) + return err; + + ocelot_init(ocelot); + + for (port = 0; port < ds->num_ports; port++) { + ocelot_init_port(ocelot, port); + + if (port == dsa_upstream_port(ds, port)) + ocelot_set_cpu_port(ocelot, port, + OCELOT_TAG_PREFIX_NONE, + OCELOT_TAG_PREFIX_LONG); + } + + return 0; +} + +static void felix_teardown(struct dsa_switch *ds) +{ + struct ocelot *ocelot = ds->priv; + + /* stop workqueue thread */ + ocelot_deinit(ocelot); +} + +static const struct dsa_switch_ops felix_switch_ops = { + .get_tag_protocol = felix_get_tag_protocol, + .setup = felix_setup, + .teardown = felix_teardown, + .set_ageing_time = felix_set_ageing_time, + .get_strings = felix_get_strings, + .get_ethtool_stats = felix_get_ethtool_stats, + .get_sset_count = felix_get_sset_count, + .get_ts_info = felix_get_ts_info, + .adjust_link = felix_adjust_link, + .port_enable = felix_port_enable, + .port_disable = felix_port_disable, + .port_fdb_dump = felix_fdb_dump, + .port_fdb_add = felix_fdb_add, + .port_fdb_del = felix_fdb_del, + .port_bridge_join = felix_bridge_join, + .port_bridge_leave = felix_bridge_leave, + .port_stp_state_set = felix_bridge_stp_state_set, + .port_vlan_prepare = felix_vlan_prepare, + .port_vlan_filtering = felix_vlan_filtering, + .port_vlan_add = felix_vlan_add, + .port_vlan_del = felix_vlan_del, +}; + +static struct felix_info *felix_instance_tbl[] = { + [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959, +}; + +static int felix_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + enum felix_instance instance = id->driver_data; + struct dsa_switch *ds; + struct ocelot *ocelot; + struct felix *felix; + int err; + + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, "device enable failed\n"); + goto err_pci_enable; + } + + /* set up for high or low dma */ + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) { + dev_err(&pdev->dev, + "DMA configuration failed: 0x%x\n", err); + goto err_dma; + } + } + + felix = kzalloc(sizeof(struct felix), GFP_KERNEL); + if (!felix) { + err = -ENOMEM; + dev_err(&pdev->dev, "Failed to allocate driver memory\n"); + goto err_alloc_felix; + } + + pci_set_drvdata(pdev, felix); + ocelot = &felix->ocelot; + ocelot->dev = &pdev->dev; + felix->pdev = pdev; + felix->info = felix_instance_tbl[instance]; + + pci_set_master(pdev); + + ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); + if (!ds) { + err = -ENOMEM; + dev_err(&pdev->dev, "Failed to allocate DSA switch\n"); + goto err_alloc_ds; + } + + ds->dev = &pdev->dev; + ds->num_ports = felix->info->num_ports; + ds->ops = &felix_switch_ops; + ds->priv = ocelot; + felix->ds = ds; + + err = dsa_register_switch(ds); + if (err) { + dev_err(&pdev->dev, "Failed to register DSA switch: %d\n", err); + goto err_register_ds; + } + + return 0; + +err_register_ds: + kfree(ds); +err_alloc_ds: +err_alloc_felix: + kfree(felix); +err_dma: + pci_disable_device(pdev); +err_pci_enable: + return err; +} + +static void felix_pci_remove(struct pci_dev *pdev) +{ + struct felix *felix; + + felix = pci_get_drvdata(pdev); + + dsa_unregister_switch(felix->ds); + + kfree(felix->ds); + kfree(felix); + + pci_disable_device(pdev); +} + +static struct pci_device_id felix_ids[] = { + { + /* NXP LS1028A */ + PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0xEEF0), + .driver_data = FELIX_INSTANCE_VSC9959, + }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, felix_ids); + +static struct pci_driver felix_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = felix_ids, + .probe = felix_pci_probe, + .remove = felix_pci_remove, +}; + +module_pci_driver(felix_pci_driver); + +MODULE_DESCRIPTION("Felix Switch driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h new file mode 100644 index 000000000000..204296e51d0c --- /dev/null +++ b/drivers/net/dsa/ocelot/felix.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright 2019 NXP Semiconductors + */ +#ifndef _MSCC_FELIX_H +#define _MSCC_FELIX_H + +#define ocelot_to_felix(o) container_of((o), struct felix, ocelot) + +/* Platform-specific information */ +struct felix_info { + struct resource *target_io_res; + struct resource *port_io_res; + const struct reg_field *regfields; + const u32 *const *map; + const struct ocelot_ops *ops; + int shared_queue_sz; + const struct ocelot_stat_layout *stats_layout; + unsigned int num_stats; + int num_ports; + int pci_bar; +}; + +extern struct felix_info felix_info_vsc9959; + +enum felix_instance { + FELIX_INSTANCE_VSC9959 = 0, +}; + +/* DSA glue / front-end for struct ocelot */ +struct felix { + struct dsa_switch *ds; + struct pci_dev *pdev; + struct felix_info *info; + struct ocelot ocelot; +}; + +#endif diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c new file mode 100644 index 000000000000..d67bd14a48e0 --- /dev/null +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -0,0 +1,567 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* Copyright 2017 Microsemi Corporation + * Copyright 2018-2019 NXP Semiconductors + */ +#include +#include +#include +#include +#include "felix.h" + +static const u32 vsc9959_ana_regmap[] = { + REG(ANA_ADVLEARN, 0x0089a0), + REG(ANA_VLANMASK, 0x0089a4), + REG_RESERVED(ANA_PORT_B_DOMAIN), + REG(ANA_ANAGEFIL, 0x0089ac), + REG(ANA_ANEVENTS, 0x0089b0), + REG(ANA_STORMLIMIT_BURST, 0x0089b4), + REG(ANA_STORMLIMIT_CFG, 0x0089b8), + REG(ANA_ISOLATED_PORTS, 0x0089c8), + REG(ANA_COMMUNITY_PORTS, 0x0089cc), + REG(ANA_AUTOAGE, 0x0089d0), + REG(ANA_MACTOPTIONS, 0x0089d4), + REG(ANA_LEARNDISC, 0x0089d8), + REG(ANA_AGENCTRL, 0x0089dc), + REG(ANA_MIRRORPORTS, 0x0089e0), + REG(ANA_EMIRRORPORTS, 0x0089e4), + REG(ANA_FLOODING, 0x0089e8), + REG(ANA_FLOODING_IPMC, 0x008a08), + REG(ANA_SFLOW_CFG, 0x008a0c), + REG(ANA_PORT_MODE, 0x008a28), + REG(ANA_CUT_THRU_CFG, 0x008a48), + REG(ANA_PGID_PGID, 0x008400), + REG(ANA_TABLES_ANMOVED, 0x007f1c), + REG(ANA_TABLES_MACHDATA, 0x007f20), + REG(ANA_TABLES_MACLDATA, 0x007f24), + REG(ANA_TABLES_STREAMDATA, 0x007f28), + REG(ANA_TABLES_MACACCESS, 0x007f2c), + REG(ANA_TABLES_MACTINDX, 0x007f30), + REG(ANA_TABLES_VLANACCESS, 0x007f34), + REG(ANA_TABLES_VLANTIDX, 0x007f38), + REG(ANA_TABLES_ISDXACCESS, 0x007f3c), + REG(ANA_TABLES_ISDXTIDX, 0x007f40), + REG(ANA_TABLES_ENTRYLIM, 0x007f00), + REG(ANA_TABLES_PTP_ID_HIGH, 0x007f44), + REG(ANA_TABLES_PTP_ID_LOW, 0x007f48), + REG(ANA_TABLES_STREAMACCESS, 0x007f4c), + REG(ANA_TABLES_STREAMTIDX, 0x007f50), + REG(ANA_TABLES_SEQ_HISTORY, 0x007f54), + REG(ANA_TABLES_SEQ_MASK, 0x007f58), + REG(ANA_TABLES_SFID_MASK, 0x007f5c), + REG(ANA_TABLES_SFIDACCESS, 0x007f60), + REG(ANA_TABLES_SFIDTIDX, 0x007f64), + REG(ANA_MSTI_STATE, 0x008600), + REG(ANA_OAM_UPM_LM_CNT, 0x008000), + REG(ANA_SG_ACCESS_CTRL, 0x008a64), + REG(ANA_SG_CONFIG_REG_1, 0x007fb0), + REG(ANA_SG_CONFIG_REG_2, 0x007fb4), + REG(ANA_SG_CONFIG_REG_3, 0x007fb8), + REG(ANA_SG_CONFIG_REG_4, 0x007fbc), + REG(ANA_SG_CONFIG_REG_5, 0x007fc0), + REG(ANA_SG_GCL_GS_CONFIG, 0x007f80), + REG(ANA_SG_GCL_TI_CONFIG, 0x007f90), + REG(ANA_SG_STATUS_REG_1, 0x008980), + REG(ANA_SG_STATUS_REG_2, 0x008984), + REG(ANA_SG_STATUS_REG_3, 0x008988), + REG(ANA_PORT_VLAN_CFG, 0x007800), + REG(ANA_PORT_DROP_CFG, 0x007804), + REG(ANA_PORT_QOS_CFG, 0x007808), + REG(ANA_PORT_VCAP_CFG, 0x00780c), + REG(ANA_PORT_VCAP_S1_KEY_CFG, 0x007810), + REG(ANA_PORT_VCAP_S2_CFG, 0x00781c), + REG(ANA_PORT_PCP_DEI_MAP, 0x007820), + REG(ANA_PORT_CPU_FWD_CFG, 0x007860), + REG(ANA_PORT_CPU_FWD_BPDU_CFG, 0x007864), + REG(ANA_PORT_CPU_FWD_GARP_CFG, 0x007868), + REG(ANA_PORT_CPU_FWD_CCM_CFG, 0x00786c), + REG(ANA_PORT_PORT_CFG, 0x007870), + REG(ANA_PORT_POL_CFG, 0x007874), + REG(ANA_PORT_PTP_CFG, 0x007878), + REG(ANA_PORT_PTP_DLY1_CFG, 0x00787c), + REG(ANA_PORT_PTP_DLY2_CFG, 0x007880), + REG(ANA_PORT_SFID_CFG, 0x007884), + REG(ANA_PFC_PFC_CFG, 0x008800), + REG_RESERVED(ANA_PFC_PFC_TIMER), + REG_RESERVED(ANA_IPT_OAM_MEP_CFG), + REG_RESERVED(ANA_IPT_IPT), + REG_RESERVED(ANA_PPT_PPT), + REG_RESERVED(ANA_FID_MAP_FID_MAP), + REG(ANA_AGGR_CFG, 0x008a68), + REG(ANA_CPUQ_CFG, 0x008a6c), + REG_RESERVED(ANA_CPUQ_CFG2), + REG(ANA_CPUQ_8021_CFG, 0x008a74), + REG(ANA_DSCP_CFG, 0x008ab4), + REG(ANA_DSCP_REWR_CFG, 0x008bb4), + REG(ANA_VCAP_RNG_TYPE_CFG, 0x008bf4), + REG(ANA_VCAP_RNG_VAL_CFG, 0x008c14), + REG_RESERVED(ANA_VRAP_CFG), + REG_RESERVED(ANA_VRAP_HDR_DATA), + REG_RESERVED(ANA_VRAP_HDR_MASK), + REG(ANA_DISCARD_CFG, 0x008c40), + REG(ANA_FID_CFG, 0x008c44), + REG(ANA_POL_PIR_CFG, 0x004000), + REG(ANA_POL_CIR_CFG, 0x004004), + REG(ANA_POL_MODE_CFG, 0x004008), + REG(ANA_POL_PIR_STATE, 0x00400c), + REG(ANA_POL_CIR_STATE, 0x004010), + REG_RESERVED(ANA_POL_STATE), + REG(ANA_POL_FLOWC, 0x008c48), + REG(ANA_POL_HYST, 0x008cb4), + REG_RESERVED(ANA_POL_MISC_CFG), +}; + +static const u32 vsc9959_qs_regmap[] = { + REG(QS_XTR_GRP_CFG, 0x000000), + REG(QS_XTR_RD, 0x000008), + REG(QS_XTR_FRM_PRUNING, 0x000010), + REG(QS_XTR_FLUSH, 0x000018), + REG(QS_XTR_DATA_PRESENT, 0x00001c), + REG(QS_XTR_CFG, 0x000020), + REG(QS_INJ_GRP_CFG, 0x000024), + REG(QS_INJ_WR, 0x00002c), + REG(QS_INJ_CTRL, 0x000034), + REG(QS_INJ_STATUS, 0x00003c), + REG(QS_INJ_ERR, 0x000040), + REG_RESERVED(QS_INH_DBG), +}; + +static const u32 vsc9959_s2_regmap[] = { + REG(S2_CORE_UPDATE_CTRL, 0x000000), + REG(S2_CORE_MV_CFG, 0x000004), + REG(S2_CACHE_ENTRY_DAT, 0x000008), + REG(S2_CACHE_MASK_DAT, 0x000108), + REG(S2_CACHE_ACTION_DAT, 0x000208), + REG(S2_CACHE_CNT_DAT, 0x000308), + REG(S2_CACHE_TG_DAT, 0x000388), +}; + +static const u32 vsc9959_qsys_regmap[] = { + REG(QSYS_PORT_MODE, 0x00f460), + REG(QSYS_SWITCH_PORT_MODE, 0x00f480), + REG(QSYS_STAT_CNT_CFG, 0x00f49c), + REG(QSYS_EEE_CFG, 0x00f4a0), + REG(QSYS_EEE_THRES, 0x00f4b8), + REG(QSYS_IGR_NO_SHARING, 0x00f4bc), + REG(QSYS_EGR_NO_SHARING, 0x00f4c0), + REG(QSYS_SW_STATUS, 0x00f4c4), + REG(QSYS_EXT_CPU_CFG, 0x00f4e0), + REG_RESERVED(QSYS_PAD_CFG), + REG(QSYS_CPU_GROUP_MAP, 0x00f4e8), + REG_RESERVED(QSYS_QMAP), + REG_RESERVED(QSYS_ISDX_SGRP), + REG_RESERVED(QSYS_TIMED_FRAME_ENTRY), + REG(QSYS_TFRM_MISC, 0x00f50c), + REG(QSYS_TFRM_PORT_DLY, 0x00f510), + REG(QSYS_TFRM_TIMER_CFG_1, 0x00f514), + REG(QSYS_TFRM_TIMER_CFG_2, 0x00f518), + REG(QSYS_TFRM_TIMER_CFG_3, 0x00f51c), + REG(QSYS_TFRM_TIMER_CFG_4, 0x00f520), + REG(QSYS_TFRM_TIMER_CFG_5, 0x00f524), + REG(QSYS_TFRM_TIMER_CFG_6, 0x00f528), + REG(QSYS_TFRM_TIMER_CFG_7, 0x00f52c), + REG(QSYS_TFRM_TIMER_CFG_8, 0x00f530), + REG(QSYS_RED_PROFILE, 0x00f534), + REG(QSYS_RES_QOS_MODE, 0x00f574), + REG(QSYS_RES_CFG, 0x00c000), + REG(QSYS_RES_STAT, 0x00c004), + REG(QSYS_EGR_DROP_MODE, 0x00f578), + REG(QSYS_EQ_CTRL, 0x00f57c), + REG_RESERVED(QSYS_EVENTS_CORE), + REG(QSYS_QMAXSDU_CFG_0, 0x00f584), + REG(QSYS_QMAXSDU_CFG_1, 0x00f5a0), + REG(QSYS_QMAXSDU_CFG_2, 0x00f5bc), + REG(QSYS_QMAXSDU_CFG_3, 0x00f5d8), + REG(QSYS_QMAXSDU_CFG_4, 0x00f5f4), + REG(QSYS_QMAXSDU_CFG_5, 0x00f610), + REG(QSYS_QMAXSDU_CFG_6, 0x00f62c), + REG(QSYS_QMAXSDU_CFG_7, 0x00f648), + REG(QSYS_PREEMPTION_CFG, 0x00f664), + REG_RESERVED(QSYS_CIR_CFG), + REG(QSYS_EIR_CFG, 0x000004), + REG(QSYS_SE_CFG, 0x000008), + REG(QSYS_SE_DWRR_CFG, 0x00000c), + REG_RESERVED(QSYS_SE_CONNECT), + REG(QSYS_SE_DLB_SENSE, 0x000040), + REG(QSYS_CIR_STATE, 0x000044), + REG(QSYS_EIR_STATE, 0x000048), + REG_RESERVED(QSYS_SE_STATE), + REG(QSYS_HSCH_MISC_CFG, 0x00f67c), + REG(QSYS_TAG_CONFIG, 0x00f680), + REG(QSYS_TAS_PARAM_CFG_CTRL, 0x00f698), + REG(QSYS_PORT_MAX_SDU, 0x00f69c), + REG(QSYS_PARAM_CFG_REG_1, 0x00f440), + REG(QSYS_PARAM_CFG_REG_2, 0x00f444), + REG(QSYS_PARAM_CFG_REG_3, 0x00f448), + REG(QSYS_PARAM_CFG_REG_4, 0x00f44c), + REG(QSYS_PARAM_CFG_REG_5, 0x00f450), + REG(QSYS_GCL_CFG_REG_1, 0x00f454), + REG(QSYS_GCL_CFG_REG_2, 0x00f458), + REG(QSYS_PARAM_STATUS_REG_1, 0x00f400), + REG(QSYS_PARAM_STATUS_REG_2, 0x00f404), + REG(QSYS_PARAM_STATUS_REG_3, 0x00f408), + REG(QSYS_PARAM_STATUS_REG_4, 0x00f40c), + REG(QSYS_PARAM_STATUS_REG_5, 0x00f410), + REG(QSYS_PARAM_STATUS_REG_6, 0x00f414), + REG(QSYS_PARAM_STATUS_REG_7, 0x00f418), + REG(QSYS_PARAM_STATUS_REG_8, 0x00f41c), + REG(QSYS_PARAM_STATUS_REG_9, 0x00f420), + REG(QSYS_GCL_STATUS_REG_1, 0x00f424), + REG(QSYS_GCL_STATUS_REG_2, 0x00f428), +}; + +static const u32 vsc9959_rew_regmap[] = { + REG(REW_PORT_VLAN_CFG, 0x000000), + REG(REW_TAG_CFG, 0x000004), + REG(REW_PORT_CFG, 0x000008), + REG(REW_DSCP_CFG, 0x00000c), + REG(REW_PCP_DEI_QOS_MAP_CFG, 0x000010), + REG(REW_PTP_CFG, 0x000050), + REG(REW_PTP_DLY1_CFG, 0x000054), + REG(REW_RED_TAG_CFG, 0x000058), + REG(REW_DSCP_REMAP_DP1_CFG, 0x000410), + REG(REW_DSCP_REMAP_CFG, 0x000510), + REG_RESERVED(REW_STAT_CFG), + REG_RESERVED(REW_REW_STICKY), + REG_RESERVED(REW_PPT), +}; + +static const u32 vsc9959_sys_regmap[] = { + REG(SYS_COUNT_RX_OCTETS, 0x000000), + REG(SYS_COUNT_RX_MULTICAST, 0x000008), + REG(SYS_COUNT_RX_SHORTS, 0x000010), + REG(SYS_COUNT_RX_FRAGMENTS, 0x000014), + REG(SYS_COUNT_RX_JABBERS, 0x000018), + REG(SYS_COUNT_RX_64, 0x000024), + REG(SYS_COUNT_RX_65_127, 0x000028), + REG(SYS_COUNT_RX_128_255, 0x00002c), + REG(SYS_COUNT_RX_256_1023, 0x000030), + REG(SYS_COUNT_RX_1024_1526, 0x000034), + REG(SYS_COUNT_RX_1527_MAX, 0x000038), + REG(SYS_COUNT_RX_LONGS, 0x000044), + REG(SYS_COUNT_TX_OCTETS, 0x000200), + REG(SYS_COUNT_TX_COLLISION, 0x000210), + REG(SYS_COUNT_TX_DROPS, 0x000214), + REG(SYS_COUNT_TX_64, 0x00021c), + REG(SYS_COUNT_TX_65_127, 0x000220), + REG(SYS_COUNT_TX_128_511, 0x000224), + REG(SYS_COUNT_TX_512_1023, 0x000228), + REG(SYS_COUNT_TX_1024_1526, 0x00022c), + REG(SYS_COUNT_TX_1527_MAX, 0x000230), + REG(SYS_COUNT_TX_AGING, 0x000278), + REG(SYS_RESET_CFG, 0x000e00), + REG(SYS_SR_ETYPE_CFG, 0x000e04), + REG(SYS_VLAN_ETYPE_CFG, 0x000e08), + REG(SYS_PORT_MODE, 0x000e0c), + REG(SYS_FRONT_PORT_MODE, 0x000e2c), + REG(SYS_FRM_AGING, 0x000e44), + REG(SYS_STAT_CFG, 0x000e48), + REG(SYS_SW_STATUS, 0x000e4c), + REG_RESERVED(SYS_MISC_CFG), + REG(SYS_REW_MAC_HIGH_CFG, 0x000e6c), + REG(SYS_REW_MAC_LOW_CFG, 0x000e84), + REG(SYS_TIMESTAMP_OFFSET, 0x000e9c), + REG(SYS_PAUSE_CFG, 0x000ea0), + REG(SYS_PAUSE_TOT_CFG, 0x000ebc), + REG(SYS_ATOP, 0x000ec0), + REG(SYS_ATOP_TOT_CFG, 0x000edc), + REG(SYS_MAC_FC_CFG, 0x000ee0), + REG(SYS_MMGT, 0x000ef8), + REG_RESERVED(SYS_MMGT_FAST), + REG_RESERVED(SYS_EVENTS_DIF), + REG_RESERVED(SYS_EVENTS_CORE), + REG_RESERVED(SYS_CNT), + REG(SYS_PTP_STATUS, 0x000f14), + REG(SYS_PTP_TXSTAMP, 0x000f18), + REG(SYS_PTP_NXT, 0x000f1c), + REG(SYS_PTP_CFG, 0x000f20), + REG(SYS_RAM_INIT, 0x000f24), + REG_RESERVED(SYS_CM_ADDR), + REG_RESERVED(SYS_CM_DATA_WR), + REG_RESERVED(SYS_CM_DATA_RD), + REG_RESERVED(SYS_CM_OP), + REG_RESERVED(SYS_CM_DATA), +}; + +static const u32 vsc9959_gcb_regmap[] = { + REG(GCB_SOFT_RST, 0x000004), +}; + +static const u32 *vsc9959_regmap[] = { + [ANA] = vsc9959_ana_regmap, + [QS] = vsc9959_qs_regmap, + [QSYS] = vsc9959_qsys_regmap, + [REW] = vsc9959_rew_regmap, + [SYS] = vsc9959_sys_regmap, + [S2] = vsc9959_s2_regmap, + [GCB] = vsc9959_gcb_regmap, +}; + +/* Addresses are relative to the PCI device's base address and + * will be fixed up at ioremap time. + */ +static struct resource vsc9959_target_io_res[] = { + [ANA] = { + .start = 0x0280000, + .end = 0x028ffff, + .name = "ana", + }, + [QS] = { + .start = 0x0080000, + .end = 0x00800ff, + .name = "qs", + }, + [QSYS] = { + .start = 0x0200000, + .end = 0x021ffff, + .name = "qsys", + }, + [REW] = { + .start = 0x0030000, + .end = 0x003ffff, + .name = "rew", + }, + [SYS] = { + .start = 0x0010000, + .end = 0x001ffff, + .name = "sys", + }, + [S2] = { + .start = 0x0060000, + .end = 0x00603ff, + .name = "s2", + }, + [GCB] = { + .start = 0x0070000, + .end = 0x00701ff, + .name = "devcpu_gcb", + }, +}; + +static struct resource vsc9959_port_io_res[] = { + { + .start = 0x0100000, + .end = 0x010ffff, + .name = "port0", + }, + { + .start = 0x0110000, + .end = 0x011ffff, + .name = "port1", + }, + { + .start = 0x0120000, + .end = 0x012ffff, + .name = "port2", + }, + { + .start = 0x0130000, + .end = 0x013ffff, + .name = "port3", + }, + { + .start = 0x0140000, + .end = 0x014ffff, + .name = "port4", + }, + { + .start = 0x0150000, + .end = 0x015ffff, + .name = "port5", + }, +}; + +static const struct reg_field vsc9959_regfields[] = { + [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), + [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), + [ANA_ANEVENTS_FLOOD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 30, 30), + [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 26, 26), + [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 24, 24), + [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 23, 23), + [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 22, 22), + [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 21, 21), + [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 20, 20), + [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 19, 19), + [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 18, 18), + [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 17, 17), + [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 15, 15), + [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 14, 14), + [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 13, 13), + [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 12, 12), + [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 11, 11), + [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 10, 10), + [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 9, 9), + [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 8, 8), + [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 7, 7), + [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), + [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), + [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 4, 4), + [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 3, 3), + [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 2, 2), + [ANA_ANEVENTS_SEQ_GEN_ERR_0] = REG_FIELD(ANA_ANEVENTS, 1, 1), + [ANA_ANEVENTS_SEQ_GEN_ERR_1] = REG_FIELD(ANA_ANEVENTS, 0, 0), + [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 16, 16), + [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 11, 12), + [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 10), + [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 0, 0), + [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 0, 0), +}; + +static const struct ocelot_stat_layout vsc9959_stats_layout[] = { + { .offset = 0x00, .name = "rx_octets", }, + { .offset = 0x01, .name = "rx_unicast", }, + { .offset = 0x02, .name = "rx_multicast", }, + { .offset = 0x03, .name = "rx_broadcast", }, + { .offset = 0x04, .name = "rx_shorts", }, + { .offset = 0x05, .name = "rx_fragments", }, + { .offset = 0x06, .name = "rx_jabbers", }, + { .offset = 0x07, .name = "rx_crc_align_errs", }, + { .offset = 0x08, .name = "rx_sym_errs", }, + { .offset = 0x09, .name = "rx_frames_below_65_octets", }, + { .offset = 0x0A, .name = "rx_frames_65_to_127_octets", }, + { .offset = 0x0B, .name = "rx_frames_128_to_255_octets", }, + { .offset = 0x0C, .name = "rx_frames_256_to_511_octets", }, + { .offset = 0x0D, .name = "rx_frames_512_to_1023_octets", }, + { .offset = 0x0E, .name = "rx_frames_1024_to_1526_octets", }, + { .offset = 0x0F, .name = "rx_frames_over_1526_octets", }, + { .offset = 0x10, .name = "rx_pause", }, + { .offset = 0x11, .name = "rx_control", }, + { .offset = 0x12, .name = "rx_longs", }, + { .offset = 0x13, .name = "rx_classified_drops", }, + { .offset = 0x14, .name = "rx_red_prio_0", }, + { .offset = 0x15, .name = "rx_red_prio_1", }, + { .offset = 0x16, .name = "rx_red_prio_2", }, + { .offset = 0x17, .name = "rx_red_prio_3", }, + { .offset = 0x18, .name = "rx_red_prio_4", }, + { .offset = 0x19, .name = "rx_red_prio_5", }, + { .offset = 0x1A, .name = "rx_red_prio_6", }, + { .offset = 0x1B, .name = "rx_red_prio_7", }, + { .offset = 0x1C, .name = "rx_yellow_prio_0", }, + { .offset = 0x1D, .name = "rx_yellow_prio_1", }, + { .offset = 0x1E, .name = "rx_yellow_prio_2", }, + { .offset = 0x1F, .name = "rx_yellow_prio_3", }, + { .offset = 0x20, .name = "rx_yellow_prio_4", }, + { .offset = 0x21, .name = "rx_yellow_prio_5", }, + { .offset = 0x22, .name = "rx_yellow_prio_6", }, + { .offset = 0x23, .name = "rx_yellow_prio_7", }, + { .offset = 0x24, .name = "rx_green_prio_0", }, + { .offset = 0x25, .name = "rx_green_prio_1", }, + { .offset = 0x26, .name = "rx_green_prio_2", }, + { .offset = 0x27, .name = "rx_green_prio_3", }, + { .offset = 0x28, .name = "rx_green_prio_4", }, + { .offset = 0x29, .name = "rx_green_prio_5", }, + { .offset = 0x2A, .name = "rx_green_prio_6", }, + { .offset = 0x2B, .name = "rx_green_prio_7", }, + { .offset = 0x80, .name = "tx_octets", }, + { .offset = 0x81, .name = "tx_unicast", }, + { .offset = 0x82, .name = "tx_multicast", }, + { .offset = 0x83, .name = "tx_broadcast", }, + { .offset = 0x84, .name = "tx_collision", }, + { .offset = 0x85, .name = "tx_drops", }, + { .offset = 0x86, .name = "tx_pause", }, + { .offset = 0x87, .name = "tx_frames_below_65_octets", }, + { .offset = 0x88, .name = "tx_frames_65_to_127_octets", }, + { .offset = 0x89, .name = "tx_frames_128_255_octets", }, + { .offset = 0x8B, .name = "tx_frames_256_511_octets", }, + { .offset = 0x8C, .name = "tx_frames_1024_1526_octets", }, + { .offset = 0x8D, .name = "tx_frames_over_1526_octets", }, + { .offset = 0x8E, .name = "tx_yellow_prio_0", }, + { .offset = 0x8F, .name = "tx_yellow_prio_1", }, + { .offset = 0x90, .name = "tx_yellow_prio_2", }, + { .offset = 0x91, .name = "tx_yellow_prio_3", }, + { .offset = 0x92, .name = "tx_yellow_prio_4", }, + { .offset = 0x93, .name = "tx_yellow_prio_5", }, + { .offset = 0x94, .name = "tx_yellow_prio_6", }, + { .offset = 0x95, .name = "tx_yellow_prio_7", }, + { .offset = 0x96, .name = "tx_green_prio_0", }, + { .offset = 0x97, .name = "tx_green_prio_1", }, + { .offset = 0x98, .name = "tx_green_prio_2", }, + { .offset = 0x99, .name = "tx_green_prio_3", }, + { .offset = 0x9A, .name = "tx_green_prio_4", }, + { .offset = 0x9B, .name = "tx_green_prio_5", }, + { .offset = 0x9C, .name = "tx_green_prio_6", }, + { .offset = 0x9D, .name = "tx_green_prio_7", }, + { .offset = 0x9E, .name = "tx_aged", }, + { .offset = 0x100, .name = "drop_local", }, + { .offset = 0x101, .name = "drop_tail", }, + { .offset = 0x102, .name = "drop_yellow_prio_0", }, + { .offset = 0x103, .name = "drop_yellow_prio_1", }, + { .offset = 0x104, .name = "drop_yellow_prio_2", }, + { .offset = 0x105, .name = "drop_yellow_prio_3", }, + { .offset = 0x106, .name = "drop_yellow_prio_4", }, + { .offset = 0x107, .name = "drop_yellow_prio_5", }, + { .offset = 0x108, .name = "drop_yellow_prio_6", }, + { .offset = 0x109, .name = "drop_yellow_prio_7", }, + { .offset = 0x10A, .name = "drop_green_prio_0", }, + { .offset = 0x10B, .name = "drop_green_prio_1", }, + { .offset = 0x10C, .name = "drop_green_prio_2", }, + { .offset = 0x10D, .name = "drop_green_prio_3", }, + { .offset = 0x10E, .name = "drop_green_prio_4", }, + { .offset = 0x10F, .name = "drop_green_prio_5", }, + { .offset = 0x110, .name = "drop_green_prio_6", }, + { .offset = 0x111, .name = "drop_green_prio_7", }, +}; + +#define VSC9959_INIT_TIMEOUT 50000 +#define VSC9959_GCB_RST_SLEEP 100 +#define VSC9959_SYS_RAMINIT_SLEEP 80 + +static int vsc9959_gcb_soft_rst_status(struct ocelot *ocelot) +{ + int val; + + regmap_field_read(ocelot->regfields[GCB_SOFT_RST_SWC_RST], &val); + + return val; +} + +static int vsc9959_sys_ram_init_status(struct ocelot *ocelot) +{ + return ocelot_read(ocelot, SYS_RAM_INIT); +} + +static int vsc9959_reset(struct ocelot *ocelot) +{ + int val, err; + + /* soft-reset the switch core */ + regmap_field_write(ocelot->regfields[GCB_SOFT_RST_SWC_RST], 1); + + err = readx_poll_timeout(vsc9959_gcb_soft_rst_status, ocelot, val, !val, + VSC9959_GCB_RST_SLEEP, VSC9959_INIT_TIMEOUT); + if (err) { + dev_err(ocelot->dev, "timeout: switch core reset\n"); + return err; + } + + /* initialize switch mem ~40us */ + ocelot_write(ocelot, SYS_RAM_INIT_RAM_INIT, SYS_RAM_INIT); + err = readx_poll_timeout(vsc9959_sys_ram_init_status, ocelot, val, !val, + VSC9959_SYS_RAMINIT_SLEEP, + VSC9959_INIT_TIMEOUT); + if (err) { + dev_err(ocelot->dev, "timeout: switch sram init\n"); + return err; + } + + /* enable switch core */ + regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); + + return 0; +} + +static const struct ocelot_ops vsc9959_ops = { + .reset = vsc9959_reset, +}; + +struct felix_info felix_info_vsc9959 = { + .target_io_res = vsc9959_target_io_res, + .port_io_res = vsc9959_port_io_res, + .regfields = vsc9959_regfields, + .map = vsc9959_regmap, + .ops = &vsc9959_ops, + .stats_layout = vsc9959_stats_layout, + .num_stats = ARRAY_SIZE(vsc9959_stats_layout), + .shared_queue_sz = 128 * 1024, + .num_ports = 6, + .pci_bar = 4, +}; -- cgit v1.2.3-59-g8ed1b From c39e342a050a4425348e6fe7f75827c0a1a7ebc5 Mon Sep 17 00:00:00 2001 From: Petar Penkov Date: Thu, 14 Nov 2019 09:52:09 -0800 Subject: tun: fix data-race in gro_normal_list() There is a race in the TUN driver between napi_busy_loop and napi_gro_frags. This commit resolves the race by adding the NAPI struct via netif_tx_napi_add, instead of netif_napi_add, which disables polling for the NAPI struct. KCSAN reported: BUG: KCSAN: data-race in gro_normal_list.part.0 / napi_busy_loop write to 0xffff8880b5d474b0 of 4 bytes by task 11205 on cpu 0: gro_normal_list.part.0+0x77/0xb0 net/core/dev.c:5682 gro_normal_list net/core/dev.c:5678 [inline] gro_normal_one net/core/dev.c:5692 [inline] napi_frags_finish net/core/dev.c:5705 [inline] napi_gro_frags+0x625/0x770 net/core/dev.c:5778 tun_get_user+0x2150/0x26a0 drivers/net/tun.c:1976 tun_chr_write_iter+0x79/0xd0 drivers/net/tun.c:2022 call_write_iter include/linux/fs.h:1895 [inline] do_iter_readv_writev+0x487/0x5b0 fs/read_write.c:693 do_iter_write fs/read_write.c:970 [inline] do_iter_write+0x13b/0x3c0 fs/read_write.c:951 vfs_writev+0x118/0x1c0 fs/read_write.c:1015 do_writev+0xe3/0x250 fs/read_write.c:1058 __do_sys_writev fs/read_write.c:1131 [inline] __se_sys_writev fs/read_write.c:1128 [inline] __x64_sys_writev+0x4e/0x60 fs/read_write.c:1128 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x44/0xa9 read to 0xffff8880b5d474b0 of 4 bytes by task 11168 on cpu 1: gro_normal_list net/core/dev.c:5678 [inline] napi_busy_loop+0xda/0x4f0 net/core/dev.c:6126 sk_busy_loop include/net/busy_poll.h:108 [inline] __skb_recv_udp+0x4ad/0x560 net/ipv4/udp.c:1689 udpv6_recvmsg+0x29e/0xe90 net/ipv6/udp.c:288 inet6_recvmsg+0xbb/0x240 net/ipv6/af_inet6.c:592 sock_recvmsg_nosec net/socket.c:871 [inline] sock_recvmsg net/socket.c:889 [inline] sock_recvmsg+0x92/0xb0 net/socket.c:885 sock_read_iter+0x15f/0x1e0 net/socket.c:967 call_read_iter include/linux/fs.h:1889 [inline] new_sync_read+0x389/0x4f0 fs/read_write.c:414 __vfs_read+0xb1/0xc0 fs/read_write.c:427 vfs_read fs/read_write.c:461 [inline] vfs_read+0x143/0x2c0 fs/read_write.c:446 ksys_read+0xd5/0x1b0 fs/read_write.c:587 __do_sys_read fs/read_write.c:597 [inline] __se_sys_read fs/read_write.c:595 [inline] __x64_sys_read+0x4c/0x60 fs/read_write.c:595 do_syscall_64+0xcc/0x370 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x44/0xa9 Reported by Kernel Concurrency Sanitizer on: CPU: 1 PID: 11168 Comm: syz-executor.0 Not tainted 5.4.0-rc6+ #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Fixes: 943170998b20 ("tun: enable NAPI for TUN/TAP driver") Signed-off-by: Petar Penkov Reported-by: syzbot Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/tun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dcb63f1f9110..683d371e6e82 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -313,8 +313,8 @@ static void tun_napi_init(struct tun_struct *tun, struct tun_file *tfile, tfile->napi_enabled = napi_en; tfile->napi_frags_enabled = napi_en && napi_frags; if (napi_en) { - netif_napi_add(tun->dev, &tfile->napi, tun_napi_poll, - NAPI_POLL_WEIGHT); + netif_tx_napi_add(tun->dev, &tfile->napi, tun_napi_poll, + NAPI_POLL_WEIGHT); napi_enable(&tfile->napi); } } -- cgit v1.2.3-59-g8ed1b From c3f812cea0d7006469d1cf33a4a9f0a12bb4b3a3 Mon Sep 17 00:00:00 2001 From: Jonathan Lemon Date: Thu, 14 Nov 2019 14:13:00 -0800 Subject: page_pool: do not release pool until inflight == 0. The page pool keeps track of the number of pages in flight, and it isn't safe to remove the pool until all pages are returned. Disallow removing the pool until all pages are back, so the pool is always available for page producers. Make the page pool responsible for its own delayed destruction instead of relying on XDP, so the page pool can be used without the xdp memory model. When all pages are returned, free the pool and notify xdp if the pool is registered with the xdp memory system. Have the callback perform a table walk since some drivers (cpsw) may share the pool among multiple xdp_rxq_info. Note that the increment of pages_state_release_cnt may result in inflight == 0, resulting in the pool being released. Fixes: d956a048cd3f ("xdp: force mem allocator removal and periodic warning") Signed-off-by: Jonathan Lemon Acked-by: Jesper Dangaard Brouer Acked-by: Ilias Apalodimas Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +- include/net/page_pool.h | 52 +++------ include/net/xdp_priv.h | 4 - include/trace/events/xdp.h | 19 +--- net/core/page_pool.c | 122 ++++++++++++++-------- net/core/xdp.c | 121 ++++++++------------- 6 files changed, 139 insertions(+), 183 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 4ba250a9008f..8cc4cd0cc515 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1503,10 +1503,8 @@ static void free_dma_rx_desc_resources(struct stmmac_priv *priv) rx_q->dma_erx, rx_q->dma_rx_phy); kfree(rx_q->buf_pool); - if (rx_q->page_pool) { - page_pool_request_shutdown(rx_q->page_pool); + if (rx_q->page_pool) page_pool_destroy(rx_q->page_pool); - } } } diff --git a/include/net/page_pool.h b/include/net/page_pool.h index 2cbcdbdec254..1121faa99c12 100644 --- a/include/net/page_pool.h +++ b/include/net/page_pool.h @@ -70,7 +70,12 @@ struct page_pool_params { struct page_pool { struct page_pool_params p; - u32 pages_state_hold_cnt; + struct delayed_work release_dw; + void (*disconnect)(void *); + unsigned long defer_start; + unsigned long defer_warn; + + u32 pages_state_hold_cnt; /* * Data structure for allocation side @@ -129,25 +134,19 @@ inline enum dma_data_direction page_pool_get_dma_dir(struct page_pool *pool) struct page_pool *page_pool_create(const struct page_pool_params *params); -void __page_pool_free(struct page_pool *pool); -static inline void page_pool_free(struct page_pool *pool) -{ - /* When page_pool isn't compiled-in, net/core/xdp.c doesn't - * allow registering MEM_TYPE_PAGE_POOL, but shield linker. - */ #ifdef CONFIG_PAGE_POOL - __page_pool_free(pool); -#endif -} - -/* Drivers use this instead of page_pool_free */ +void page_pool_destroy(struct page_pool *pool); +void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *)); +#else static inline void page_pool_destroy(struct page_pool *pool) { - if (!pool) - return; +} - page_pool_free(pool); +static inline void page_pool_use_xdp_mem(struct page_pool *pool, + void (*disconnect)(void *)) +{ } +#endif /* Never call this directly, use helpers below */ void __page_pool_put_page(struct page_pool *pool, @@ -170,24 +169,6 @@ static inline void page_pool_recycle_direct(struct page_pool *pool, __page_pool_put_page(pool, page, true); } -/* API user MUST have disconnected alloc-side (not allowed to call - * page_pool_alloc_pages()) before calling this. The free-side can - * still run concurrently, to handle in-flight packet-pages. - * - * A request to shutdown can fail (with false) if there are still - * in-flight packet-pages. - */ -bool __page_pool_request_shutdown(struct page_pool *pool); -static inline bool page_pool_request_shutdown(struct page_pool *pool) -{ - bool safe_to_remove = false; - -#ifdef CONFIG_PAGE_POOL - safe_to_remove = __page_pool_request_shutdown(pool); -#endif - return safe_to_remove; -} - /* Disconnects a page (from a page_pool). API users can have a need * to disconnect a page (from a page_pool), to allow it to be used as * a regular page (that will eventually be returned to the normal @@ -216,11 +197,6 @@ static inline bool is_page_pool_compiled_in(void) #endif } -static inline void page_pool_get(struct page_pool *pool) -{ - refcount_inc(&pool->user_cnt); -} - static inline bool page_pool_put(struct page_pool *pool) { return refcount_dec_and_test(&pool->user_cnt); diff --git a/include/net/xdp_priv.h b/include/net/xdp_priv.h index 6a8cba6ea79a..a9d5b7603b89 100644 --- a/include/net/xdp_priv.h +++ b/include/net/xdp_priv.h @@ -12,12 +12,8 @@ struct xdp_mem_allocator { struct page_pool *page_pool; struct zero_copy_allocator *zc_alloc; }; - int disconnect_cnt; - unsigned long defer_start; struct rhash_head node; struct rcu_head rcu; - struct delayed_work defer_wq; - unsigned long defer_warn; }; #endif /* __LINUX_NET_XDP_PRIV_H__ */ diff --git a/include/trace/events/xdp.h b/include/trace/events/xdp.h index c7e3c9c5bad3..a7378bcd9928 100644 --- a/include/trace/events/xdp.h +++ b/include/trace/events/xdp.h @@ -317,19 +317,15 @@ __MEM_TYPE_MAP(__MEM_TYPE_TP_FN) TRACE_EVENT(mem_disconnect, - TP_PROTO(const struct xdp_mem_allocator *xa, - bool safe_to_remove, bool force), + TP_PROTO(const struct xdp_mem_allocator *xa), - TP_ARGS(xa, safe_to_remove, force), + TP_ARGS(xa), TP_STRUCT__entry( __field(const struct xdp_mem_allocator *, xa) __field(u32, mem_id) __field(u32, mem_type) __field(const void *, allocator) - __field(bool, safe_to_remove) - __field(bool, force) - __field(int, disconnect_cnt) ), TP_fast_assign( @@ -337,19 +333,12 @@ TRACE_EVENT(mem_disconnect, __entry->mem_id = xa->mem.id; __entry->mem_type = xa->mem.type; __entry->allocator = xa->allocator; - __entry->safe_to_remove = safe_to_remove; - __entry->force = force; - __entry->disconnect_cnt = xa->disconnect_cnt; ), - TP_printk("mem_id=%d mem_type=%s allocator=%p" - " safe_to_remove=%s force=%s disconnect_cnt=%d", + TP_printk("mem_id=%d mem_type=%s allocator=%p", __entry->mem_id, __print_symbolic(__entry->mem_type, __MEM_TYPE_SYM_TAB), - __entry->allocator, - __entry->safe_to_remove ? "true" : "false", - __entry->force ? "true" : "false", - __entry->disconnect_cnt + __entry->allocator ) ); diff --git a/net/core/page_pool.c b/net/core/page_pool.c index 5bc65587f1c4..dfc2501c35d9 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -18,6 +18,9 @@ #include +#define DEFER_TIME (msecs_to_jiffies(1000)) +#define DEFER_WARN_INTERVAL (60 * HZ) + static int page_pool_init(struct page_pool *pool, const struct page_pool_params *params) { @@ -193,22 +196,14 @@ static s32 page_pool_inflight(struct page_pool *pool) { u32 release_cnt = atomic_read(&pool->pages_state_release_cnt); u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt); - s32 distance; - - distance = _distance(hold_cnt, release_cnt); - - trace_page_pool_inflight(pool, distance, hold_cnt, release_cnt); - return distance; -} + s32 inflight; -static bool __page_pool_safe_to_destroy(struct page_pool *pool) -{ - s32 inflight = page_pool_inflight(pool); + inflight = _distance(hold_cnt, release_cnt); - /* The distance should not be able to become negative */ + trace_page_pool_inflight(pool, inflight, hold_cnt, release_cnt); WARN(inflight < 0, "Negative(%d) inflight packet-pages", inflight); - return (inflight == 0); + return inflight; } /* Cleanup page_pool state from page */ @@ -216,6 +211,7 @@ static void __page_pool_clean_page(struct page_pool *pool, struct page *page) { dma_addr_t dma; + int count; if (!(pool->p.flags & PP_FLAG_DMA_MAP)) goto skip_dma_unmap; @@ -227,9 +223,11 @@ static void __page_pool_clean_page(struct page_pool *pool, DMA_ATTR_SKIP_CPU_SYNC); page->dma_addr = 0; skip_dma_unmap: - atomic_inc(&pool->pages_state_release_cnt); - trace_page_pool_state_release(pool, page, - atomic_read(&pool->pages_state_release_cnt)); + /* This may be the last page returned, releasing the pool, so + * it is not safe to reference pool afterwards. + */ + count = atomic_inc_return(&pool->pages_state_release_cnt); + trace_page_pool_state_release(pool, page, count); } /* unmap the page and clean our state */ @@ -338,31 +336,10 @@ static void __page_pool_empty_ring(struct page_pool *pool) } } -static void __warn_in_flight(struct page_pool *pool) +static void page_pool_free(struct page_pool *pool) { - u32 release_cnt = atomic_read(&pool->pages_state_release_cnt); - u32 hold_cnt = READ_ONCE(pool->pages_state_hold_cnt); - s32 distance; - - distance = _distance(hold_cnt, release_cnt); - - /* Drivers should fix this, but only problematic when DMA is used */ - WARN(1, "Still in-flight pages:%d hold:%u released:%u", - distance, hold_cnt, release_cnt); -} - -void __page_pool_free(struct page_pool *pool) -{ - /* Only last user actually free/release resources */ - if (!page_pool_put(pool)) - return; - - WARN(pool->alloc.count, "API usage violation"); - WARN(!ptr_ring_empty(&pool->ring), "ptr_ring is not empty"); - - /* Can happen due to forced shutdown */ - if (!__page_pool_safe_to_destroy(pool)) - __warn_in_flight(pool); + if (pool->disconnect) + pool->disconnect(pool); ptr_ring_cleanup(&pool->ring, NULL); @@ -371,12 +348,8 @@ void __page_pool_free(struct page_pool *pool) kfree(pool); } -EXPORT_SYMBOL(__page_pool_free); -/* Request to shutdown: release pages cached by page_pool, and check - * for in-flight pages - */ -bool __page_pool_request_shutdown(struct page_pool *pool) +static void page_pool_scrub(struct page_pool *pool) { struct page *page; @@ -393,7 +366,64 @@ bool __page_pool_request_shutdown(struct page_pool *pool) * be in-flight. */ __page_pool_empty_ring(pool); +} + +static int page_pool_release(struct page_pool *pool) +{ + int inflight; + + page_pool_scrub(pool); + inflight = page_pool_inflight(pool); + if (!inflight) + page_pool_free(pool); + + return inflight; +} + +static void page_pool_release_retry(struct work_struct *wq) +{ + struct delayed_work *dwq = to_delayed_work(wq); + struct page_pool *pool = container_of(dwq, typeof(*pool), release_dw); + int inflight; + + inflight = page_pool_release(pool); + if (!inflight) + return; + + /* Periodic warning */ + if (time_after_eq(jiffies, pool->defer_warn)) { + int sec = (s32)((u32)jiffies - (u32)pool->defer_start) / HZ; + + pr_warn("%s() stalled pool shutdown %d inflight %d sec\n", + __func__, inflight, sec); + pool->defer_warn = jiffies + DEFER_WARN_INTERVAL; + } + + /* Still not ready to be disconnected, retry later */ + schedule_delayed_work(&pool->release_dw, DEFER_TIME); +} + +void page_pool_use_xdp_mem(struct page_pool *pool, void (*disconnect)(void *)) +{ + refcount_inc(&pool->user_cnt); + pool->disconnect = disconnect; +} + +void page_pool_destroy(struct page_pool *pool) +{ + if (!pool) + return; + + if (!page_pool_put(pool)) + return; + + if (!page_pool_release(pool)) + return; + + pool->defer_start = jiffies; + pool->defer_warn = jiffies + DEFER_WARN_INTERVAL; - return __page_pool_safe_to_destroy(pool); + INIT_DELAYED_WORK(&pool->release_dw, page_pool_release_retry); + schedule_delayed_work(&pool->release_dw, DEFER_TIME); } -EXPORT_SYMBOL(__page_pool_request_shutdown); +EXPORT_SYMBOL(page_pool_destroy); diff --git a/net/core/xdp.c b/net/core/xdp.c index 20781ad5f9c3..8e405abaf05a 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -70,10 +70,6 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head *rcu) xa = container_of(rcu, struct xdp_mem_allocator, rcu); - /* Allocator have indicated safe to remove before this is called */ - if (xa->mem.type == MEM_TYPE_PAGE_POOL) - page_pool_free(xa->page_pool); - /* Allow this ID to be reused */ ida_simple_remove(&mem_id_pool, xa->mem.id); @@ -85,62 +81,57 @@ static void __xdp_mem_allocator_rcu_free(struct rcu_head *rcu) kfree(xa); } -static bool __mem_id_disconnect(int id, bool force) +static void mem_xa_remove(struct xdp_mem_allocator *xa) { - struct xdp_mem_allocator *xa; - bool safe_to_remove = true; + trace_mem_disconnect(xa); mutex_lock(&mem_id_lock); - xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params); - if (!xa) { - mutex_unlock(&mem_id_lock); - WARN(1, "Request remove non-existing id(%d), driver bug?", id); - return true; - } - xa->disconnect_cnt++; - - /* Detects in-flight packet-pages for page_pool */ - if (xa->mem.type == MEM_TYPE_PAGE_POOL) - safe_to_remove = page_pool_request_shutdown(xa->page_pool); - - trace_mem_disconnect(xa, safe_to_remove, force); - - if ((safe_to_remove || force) && - !rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params)) + if (!rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params)) call_rcu(&xa->rcu, __xdp_mem_allocator_rcu_free); mutex_unlock(&mem_id_lock); - return (safe_to_remove|force); } -#define DEFER_TIME (msecs_to_jiffies(1000)) -#define DEFER_WARN_INTERVAL (30 * HZ) -#define DEFER_MAX_RETRIES 120 +static void mem_allocator_disconnect(void *allocator) +{ + struct xdp_mem_allocator *xa; + struct rhashtable_iter iter; + + rhashtable_walk_enter(mem_id_ht, &iter); + do { + rhashtable_walk_start(&iter); + + while ((xa = rhashtable_walk_next(&iter)) && !IS_ERR(xa)) { + if (xa->allocator == allocator) + mem_xa_remove(xa); + } + + rhashtable_walk_stop(&iter); -static void mem_id_disconnect_defer_retry(struct work_struct *wq) + } while (xa == ERR_PTR(-EAGAIN)); + rhashtable_walk_exit(&iter); +} + +static void mem_id_disconnect(int id) { - struct delayed_work *dwq = to_delayed_work(wq); - struct xdp_mem_allocator *xa = container_of(dwq, typeof(*xa), defer_wq); - bool force = false; + struct xdp_mem_allocator *xa; - if (xa->disconnect_cnt > DEFER_MAX_RETRIES) - force = true; + mutex_lock(&mem_id_lock); - if (__mem_id_disconnect(xa->mem.id, force)) + xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params); + if (!xa) { + mutex_unlock(&mem_id_lock); + WARN(1, "Request remove non-existing id(%d), driver bug?", id); return; + } - /* Periodic warning */ - if (time_after_eq(jiffies, xa->defer_warn)) { - int sec = (s32)((u32)jiffies - (u32)xa->defer_start) / HZ; + trace_mem_disconnect(xa); - pr_warn("%s() stalled mem.id=%u shutdown %d attempts %d sec\n", - __func__, xa->mem.id, xa->disconnect_cnt, sec); - xa->defer_warn = jiffies + DEFER_WARN_INTERVAL; - } + if (!rhashtable_remove_fast(mem_id_ht, &xa->node, mem_id_rht_params)) + call_rcu(&xa->rcu, __xdp_mem_allocator_rcu_free); - /* Still not ready to be disconnected, retry later */ - schedule_delayed_work(&xa->defer_wq, DEFER_TIME); + mutex_unlock(&mem_id_lock); } void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) @@ -153,38 +144,21 @@ void xdp_rxq_info_unreg_mem_model(struct xdp_rxq_info *xdp_rxq) return; } - if (xdp_rxq->mem.type != MEM_TYPE_PAGE_POOL && - xdp_rxq->mem.type != MEM_TYPE_ZERO_COPY) { - return; - } - if (id == 0) return; - if (__mem_id_disconnect(id, false)) - return; - - /* Could not disconnect, defer new disconnect attempt to later */ - mutex_lock(&mem_id_lock); + if (xdp_rxq->mem.type == MEM_TYPE_ZERO_COPY) + return mem_id_disconnect(id); - xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params); - if (!xa) { - mutex_unlock(&mem_id_lock); - return; + if (xdp_rxq->mem.type == MEM_TYPE_PAGE_POOL) { + rcu_read_lock(); + xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params); + page_pool_destroy(xa->page_pool); + rcu_read_unlock(); } - xa->defer_start = jiffies; - xa->defer_warn = jiffies + DEFER_WARN_INTERVAL; - - INIT_DELAYED_WORK(&xa->defer_wq, mem_id_disconnect_defer_retry); - mutex_unlock(&mem_id_lock); - schedule_delayed_work(&xa->defer_wq, DEFER_TIME); } EXPORT_SYMBOL_GPL(xdp_rxq_info_unreg_mem_model); -/* This unregister operation will also cleanup and destroy the - * allocator. The page_pool_free() operation is first called when it's - * safe to remove, possibly deferred to a workqueue. - */ void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq) { /* Simplify driver cleanup code paths, allow unreg "unused" */ @@ -371,7 +345,7 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq, } if (type == MEM_TYPE_PAGE_POOL) - page_pool_get(xdp_alloc->page_pool); + page_pool_use_xdp_mem(allocator, mem_allocator_disconnect); mutex_unlock(&mem_id_lock); @@ -402,15 +376,8 @@ static void __xdp_return(void *data, struct xdp_mem_info *mem, bool napi_direct, /* mem->id is valid, checked in xdp_rxq_info_reg_mem_model() */ xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params); page = virt_to_head_page(data); - if (likely(xa)) { - napi_direct &= !xdp_return_frame_no_direct(); - page_pool_put_page(xa->page_pool, page, napi_direct); - } else { - /* Hopefully stack show who to blame for late return */ - WARN_ONCE(1, "page_pool gone mem.id=%d", mem->id); - trace_mem_return_failed(mem, page); - put_page(page); - } + napi_direct &= !xdp_return_frame_no_direct(); + page_pool_put_page(xa->page_pool, page, napi_direct); rcu_read_unlock(); break; case MEM_TYPE_PAGE_SHARED: -- cgit v1.2.3-59-g8ed1b From 34c6adf1977b611fca3b824ad12a2a415e1e420e Mon Sep 17 00:00:00 2001 From: Po Liu Date: Fri, 15 Nov 2019 03:33:33 +0000 Subject: enetc: Configure the Time-Aware Scheduler via tc-taprio offload ENETC supports in hardware for time-based egress shaping according to IEEE 802.1Qbv. This patch implement the Qbv enablement by the hardware offload method qdisc tc-taprio method. Also update cbdr writeback to up level since control bd ring may writeback data to control bd ring. Signed-off-by: Po Liu Signed-off-by: Vladimir Oltean Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/Kconfig | 10 ++ drivers/net/ethernet/freescale/enetc/Makefile | 2 + drivers/net/ethernet/freescale/enetc/enetc.c | 19 ++- drivers/net/ethernet/freescale/enetc/enetc.h | 7 ++ drivers/net/ethernet/freescale/enetc/enetc_cbdr.c | 5 +- drivers/net/ethernet/freescale/enetc/enetc_hw.h | 84 ++++++++++--- drivers/net/ethernet/freescale/enetc/enetc_qos.c | 138 ++++++++++++++++++++++ 7 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 drivers/net/ethernet/freescale/enetc/enetc_qos.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index c219587bd334..491659fe3e35 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -50,3 +50,13 @@ config FSL_ENETC_HW_TIMESTAMPING allocation has not been supported and it is too expensive to use extended RX BDs if timestamping is not used, this option enables extended RX BDs in order to support hardware timestamping. + +config FSL_ENETC_QOS + bool "ENETC hardware Time-sensitive Network support" + depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO + help + There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci + /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set + enable/disable from user space via Qos commands(tc). In the kernel + side, it can be loaded by Qos driver. Currently, it is only support + taprio(802.1Qbv). diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile index d200c27c3bf6..d0db33e5b6b7 100644 --- a/drivers/net/ethernet/freescale/enetc/Makefile +++ b/drivers/net/ethernet/freescale/enetc/Makefile @@ -5,9 +5,11 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs) fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o +fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o obj-$(CONFIG_FSL_ENETC_VF) += fsl-enetc-vf.o fsl-enetc-vf-y := enetc_vf.o $(common-objs) +fsl-enetc-vf-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o obj-$(CONFIG_FSL_ENETC_MDIO) += fsl-enetc-mdio.o fsl-enetc-mdio-y := enetc_pci_mdio.o enetc_mdio.o diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 3e8f9819f08c..d58dbc2c4270 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1427,8 +1427,7 @@ int enetc_close(struct net_device *ndev) return 0; } -int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, - void *type_data) +int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) { struct enetc_ndev_priv *priv = netdev_priv(ndev); struct tc_mqprio_qopt *mqprio = type_data; @@ -1436,9 +1435,6 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, u8 num_tc; int i; - if (type != TC_SETUP_QDISC_MQPRIO) - return -EOPNOTSUPP; - mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; num_tc = mqprio->num_tc; @@ -1483,6 +1479,19 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, return 0; } +int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_SETUP_QDISC_MQPRIO: + return enetc_setup_tc_mqprio(ndev, type_data); + case TC_SETUP_QDISC_TAPRIO: + return enetc_setup_tc_taprio(ndev, type_data); + default: + return -EOPNOTSUPP; + } +} + struct net_device_stats *enetc_get_stats(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index 541b4e2073fe..8ca2f97050c8 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -244,3 +244,10 @@ int enetc_set_fs_entry(struct enetc_si *si, struct enetc_cmd_rfse *rfse, void enetc_set_rss_key(struct enetc_hw *hw, const u8 *bytes); int enetc_get_rss_table(struct enetc_si *si, u32 *table, int count); int enetc_set_rss_table(struct enetc_si *si, const u32 *table, int count); +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd); + +#ifdef CONFIG_FSL_ENETC_QOS +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data); +#else +#define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP +#endif diff --git a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c index de466b71bf8f..201cbc362e33 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_cbdr.c @@ -32,7 +32,7 @@ static int enetc_cbd_unused(struct enetc_cbdr *r) r->bd_count; } -static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd) +int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd) { struct enetc_cbdr *ring = &si->cbd_ring; int timeout = ENETC_CBDR_TIMEOUT; @@ -66,6 +66,9 @@ static int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd) if (!timeout) return -EBUSY; + /* CBD may writeback data, feedback up level */ + *cbd = *dest_cbd; + enetc_clean_cbdr(si); return 0; diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 88276299f447..df6b35dc3534 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -18,6 +18,7 @@ #define ENETC_SICTR0 0x18 #define ENETC_SICTR1 0x1c #define ENETC_SIPCAPR0 0x20 +#define ENETC_SIPCAPR0_QBV BIT(4) #define ENETC_SIPCAPR0_RSS BIT(8) #define ENETC_SIPCAPR1 0x24 #define ENETC_SITGTGR 0x30 @@ -440,22 +441,6 @@ union enetc_rx_bd { #define EMETC_MAC_ADDR_FILT_RES 3 /* # of reserved entries at the beginning */ #define ENETC_MAX_NUM_VFS 2 -struct enetc_cbd { - union { - struct { - __le32 addr[2]; - __le32 opt[4]; - }; - __le32 data[6]; - }; - __le16 index; - __le16 length; - u8 cmd; - u8 cls; - u8 _res; - u8 status_flags; -}; - #define ENETC_CBD_FLAGS_SF BIT(7) /* short format */ #define ENETC_CBD_STATUS_MASK 0xf @@ -554,3 +539,70 @@ static inline void enetc_set_bdr_prio(struct enetc_hw *hw, int bdr_idx, val |= ENETC_TBMR_SET_PRIO(prio); enetc_txbdr_wr(hw, bdr_idx, ENETC_TBMR, val); } + +enum bdcr_cmd_class { + BDCR_CMD_UNSPEC = 0, + BDCR_CMD_MAC_FILTER, + BDCR_CMD_VLAN_FILTER, + BDCR_CMD_RSS, + BDCR_CMD_RFS, + BDCR_CMD_PORT_GCL, + BDCR_CMD_RECV_CLASSIFIER, + __BDCR_CMD_MAX_LEN, + BDCR_CMD_MAX_LEN = __BDCR_CMD_MAX_LEN - 1, +}; + +/* class 5, command 0 */ +struct tgs_gcl_conf { + u8 atc; /* init gate value */ + u8 res[7]; + struct { + u8 res1[4]; + __le16 acl_len; + u8 res2[2]; + }; +}; + +/* gate control list entry */ +struct gce { + __le32 period; + u8 gate; + u8 res[3]; +}; + +/* tgs_gcl_conf address point to this data space */ +struct tgs_gcl_data { + __le32 btl; + __le32 bth; + __le32 ct; + __le32 cte; + struct gce entry[0]; +}; + +struct enetc_cbd { + union{ + struct { + __le32 addr[2]; + union { + __le32 opt[4]; + struct tgs_gcl_conf gcl_conf; + }; + }; /* Long format */ + __le32 data[6]; + }; + __le16 index; + __le16 length; + u8 cmd; + u8 cls; + u8 _res; + u8 status_flags; +}; + +/* port time gating control register */ +#define ENETC_QBV_PTGCR_OFFSET 0x11a00 +#define ENETC_QBV_TGE BIT(31) +#define ENETC_QBV_TGPE BIT(30) + +/* Port time gating capability register */ +#define ENETC_QBV_PTGCAPR_OFFSET 0x11a08 +#define ENETC_QBV_MAX_GCL_LEN_MASK GENMASK(15, 0) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c new file mode 100644 index 000000000000..84c2ab98fae9 --- /dev/null +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2019 NXP */ + +#include "enetc.h" + +#include + +static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) +{ + return enetc_rd(hw, ENETC_QBV_PTGCAPR_OFFSET) + & ENETC_QBV_MAX_GCL_LEN_MASK; +} + +static int enetc_setup_taprio(struct net_device *ndev, + struct tc_taprio_qopt_offload *admin_conf) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_cbd cbd = {.cmd = 0}; + struct tgs_gcl_conf *gcl_config; + struct tgs_gcl_data *gcl_data; + struct gce *gce; + dma_addr_t dma; + u16 data_size; + u16 gcl_len; + u32 tge; + int err; + int i; + + if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw)) + return -EINVAL; + gcl_len = admin_conf->num_entries; + + tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET); + if (!admin_conf->enable) { + enetc_wr(&priv->si->hw, + ENETC_QBV_PTGCR_OFFSET, + tge & (~ENETC_QBV_TGE)); + return 0; + } + + if (admin_conf->cycle_time > U32_MAX || + admin_conf->cycle_time_extension > U32_MAX) + return -EINVAL; + + /* Configure the (administrative) gate control list using the + * control BD descriptor. + */ + gcl_config = &cbd.gcl_conf; + + data_size = struct_size(gcl_data, entry, gcl_len); + gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL); + if (!gcl_data) + return -ENOMEM; + + gce = (struct gce *)(gcl_data + 1); + + /* Set all gates open as default */ + gcl_config->atc = 0xff; + gcl_config->acl_len = cpu_to_le16(gcl_len); + + if (!admin_conf->base_time) { + gcl_data->btl = + cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR0)); + gcl_data->bth = + cpu_to_le32(enetc_rd(&priv->si->hw, ENETC_SICTR1)); + } else { + gcl_data->btl = + cpu_to_le32(lower_32_bits(admin_conf->base_time)); + gcl_data->bth = + cpu_to_le32(upper_32_bits(admin_conf->base_time)); + } + + gcl_data->ct = cpu_to_le32(admin_conf->cycle_time); + gcl_data->cte = cpu_to_le32(admin_conf->cycle_time_extension); + + for (i = 0; i < gcl_len; i++) { + struct tc_taprio_sched_entry *temp_entry; + struct gce *temp_gce = gce + i; + + temp_entry = &admin_conf->entries[i]; + + temp_gce->gate = (u8)temp_entry->gate_mask; + temp_gce->period = cpu_to_le32(temp_entry->interval); + } + + cbd.length = cpu_to_le16(data_size); + cbd.status_flags = 0; + + dma = dma_map_single(&priv->si->pdev->dev, gcl_data, + data_size, DMA_TO_DEVICE); + if (dma_mapping_error(&priv->si->pdev->dev, dma)) { + netdev_err(priv->si->ndev, "DMA mapping failed!\n"); + kfree(gcl_data); + return -ENOMEM; + } + + cbd.addr[0] = lower_32_bits(dma); + cbd.addr[1] = upper_32_bits(dma); + cbd.cls = BDCR_CMD_PORT_GCL; + cbd.status_flags = 0; + + enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET, + tge | ENETC_QBV_TGE); + + err = enetc_send_cmd(priv->si, &cbd); + if (err) + enetc_wr(&priv->si->hw, + ENETC_QBV_PTGCR_OFFSET, + tge & (~ENETC_QBV_TGE)); + + dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE); + kfree(gcl_data); + + return err; +} + +int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) +{ + struct tc_taprio_qopt_offload *taprio = type_data; + struct enetc_ndev_priv *priv = netdev_priv(ndev); + int err; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) + enetc_set_bdr_prio(&priv->si->hw, + priv->tx_ring[i]->index, + taprio->enable ? i : 0); + + err = enetc_setup_taprio(ndev, taprio); + + if (err) + for (i = 0; i < priv->num_tx_rings; i++) + enetc_set_bdr_prio(&priv->si->hw, + priv->tx_ring[i]->index, + taprio->enable ? 0 : i); + + return err; +} -- cgit v1.2.3-59-g8ed1b From 2e47cb415f0a0ec6555d71598361e90f8c144fb2 Mon Sep 17 00:00:00 2001 From: Po Liu Date: Fri, 15 Nov 2019 03:33:41 +0000 Subject: enetc: update TSN Qbv PSPEED set according to adjust link speed ENETC has a register PSPEED to indicate the link speed of hardware. It is need to update accordingly. PSPEED field needs to be updated with the port speed for QBV scheduling purposes. Or else there is chance for gate slot not free by frame taking the MAC if PSPEED and phy speed not match. So update PSPEED when link adjust. This is implement by the adjust_link. Signed-off-by: Po Liu Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc.c | 13 +++++++-- drivers/net/ethernet/freescale/enetc/enetc.h | 8 ++++++ drivers/net/ethernet/freescale/enetc/enetc_hw.h | 5 ++++ drivers/net/ethernet/freescale/enetc/enetc_pf.c | 3 +++ drivers/net/ethernet/freescale/enetc/enetc_qos.c | 34 ++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index d58dbc2c4270..f6b00c68451b 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -742,9 +742,14 @@ void enetc_get_si_caps(struct enetc_si *si) si->num_rss = 0; val = enetc_rd(hw, ENETC_SIPCAPR0); if (val & ENETC_SIPCAPR0_RSS) { - val = enetc_rd(hw, ENETC_SIRSSCAPR); - si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(val); + u32 rss; + + rss = enetc_rd(hw, ENETC_SIRSSCAPR); + si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss); } + + if (val & ENETC_SIPCAPR0_QBV) + si->hw_features |= ENETC_SI_F_QBV; } static int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size) @@ -1314,8 +1319,12 @@ static void enetc_disable_interrupts(struct enetc_ndev_priv *priv) static void adjust_link(struct net_device *ndev) { + struct enetc_ndev_priv *priv = netdev_priv(ndev); struct phy_device *phydev = ndev->phydev; + if (priv->active_offloads & ENETC_F_QBV) + enetc_sched_speed_set(ndev); + phy_print_status(phydev); } diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index 8ca2f97050c8..89f23156f330 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -118,6 +118,8 @@ enum enetc_errata { ENETC_ERR_UCMCSWP = BIT(2), }; +#define ENETC_SI_F_QBV BIT(0) + /* PCI IEP device data */ struct enetc_si { struct pci_dev *pdev; @@ -133,6 +135,7 @@ struct enetc_si { int num_fs_entries; int num_rss; /* number of RSS buckets */ unsigned short pad; + int hw_features; }; #define ENETC_SI_ALIGN 32 @@ -173,6 +176,7 @@ struct enetc_cls_rule { enum enetc_active_offloads { ENETC_F_RX_TSTAMP = BIT(0), ENETC_F_TX_TSTAMP = BIT(1), + ENETC_F_QBV = BIT(2), }; struct enetc_ndev_priv { @@ -188,6 +192,8 @@ struct enetc_ndev_priv { u16 msg_enable; int active_offloads; + u32 speed; /* store speed for compare update pspeed */ + struct enetc_bdr *tx_ring[16]; struct enetc_bdr *rx_ring[16]; @@ -248,6 +254,8 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd); #ifdef CONFIG_FSL_ENETC_QOS int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data); +void enetc_sched_speed_set(struct net_device *ndev); #else #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP +#define enetc_sched_speed_set(ndev) (void)0 #endif diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index df6b35dc3534..924ddb6d358a 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -149,6 +149,11 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PORT_BASE 0x10000 #define ENETC_PMR 0x0000 #define ENETC_PMR_EN GENMASK(18, 16) +#define ENETC_PMR_PSPEED_MASK GENMASK(11, 8) +#define ENETC_PMR_PSPEED_10M 0 +#define ENETC_PMR_PSPEED_100M BIT(8) +#define ENETC_PMR_PSPEED_1000M BIT(9) +#define ENETC_PMR_PSPEED_2500M BIT(10) #define ENETC_PSR 0x0004 /* RO */ #define ENETC_PSIPMR 0x0018 #define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */ diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index 7da79b816416..e7482d483b28 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -742,6 +742,9 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, ndev->priv_flags |= IFF_UNICAST_FLT; + if (si->hw_features & ENETC_SI_F_QBV) + priv->active_offloads |= ENETC_F_QBV; + /* pick up primary MAC address from SI */ enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr); } diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 84c2ab98fae9..66a3da61ca16 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -11,6 +11,40 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) & ENETC_QBV_MAX_GCL_LEN_MASK; } +void enetc_sched_speed_set(struct net_device *ndev) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct phy_device *phydev = ndev->phydev; + u32 old_speed = priv->speed; + u32 speed, pspeed; + + if (phydev->speed == old_speed) + return; + + speed = phydev->speed; + switch (speed) { + case SPEED_1000: + pspeed = ENETC_PMR_PSPEED_1000M; + break; + case SPEED_2500: + pspeed = ENETC_PMR_PSPEED_2500M; + break; + case SPEED_100: + pspeed = ENETC_PMR_PSPEED_100M; + break; + case SPEED_10: + default: + pspeed = ENETC_PMR_PSPEED_10M; + netdev_err(ndev, "Qbv PSPEED set speed link down.\n"); + } + + priv->speed = speed; + enetc_port_wr(&priv->si->hw, ENETC_PMR, + (enetc_port_rd(&priv->si->hw, ENETC_PMR) + & (~ENETC_PMR_PSPEED_MASK)) + | pspeed); +} + static int enetc_setup_taprio(struct net_device *ndev, struct tc_taprio_qopt_offload *admin_conf) { -- cgit v1.2.3-59-g8ed1b From 86c1fe8857afb379522fd8dabce9d348672c31c1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 14 Nov 2019 21:07:11 -0800 Subject: bnx2x: Drop redundant callback function casts NULL is already "void *" so it will auto-cast in assignments and initializers. Additionally, all the callbacks for .link_reset, .config_loopback, .set_link_led, and .phy_specific_func are already correct. No casting is needed for these, so remove them. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 160 +++++++++++------------ 1 file changed, 80 insertions(+), 80 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index d581d0ae6584..decde193c5b3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -11636,14 +11636,14 @@ static const struct bnx2x_phy phy_null = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)NULL, - .read_status = (read_status_t)NULL, - .link_reset = (link_reset_t)NULL, - .config_loopback = (config_loopback_t)NULL, - .format_fw_ver = (format_fw_ver_t)NULL, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .config_init = NULL, + .read_status = NULL, + .link_reset = NULL, + .config_loopback = NULL, + .format_fw_ver = NULL, + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_serdes = { @@ -11673,12 +11673,12 @@ static const struct bnx2x_phy phy_serdes = { .rsrv = 0, .config_init = (config_init_t)bnx2x_xgxs_config_init, .read_status = (read_status_t)bnx2x_link_settings_status, - .link_reset = (link_reset_t)bnx2x_int_link_reset, - .config_loopback = (config_loopback_t)NULL, - .format_fw_ver = (format_fw_ver_t)NULL, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .link_reset = bnx2x_int_link_reset, + .config_loopback = NULL, + .format_fw_ver = NULL, + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_xgxs = { @@ -11709,12 +11709,12 @@ static const struct bnx2x_phy phy_xgxs = { .rsrv = 0, .config_init = (config_init_t)bnx2x_xgxs_config_init, .read_status = (read_status_t)bnx2x_link_settings_status, - .link_reset = (link_reset_t)bnx2x_int_link_reset, - .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback, - .format_fw_ver = (format_fw_ver_t)NULL, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)bnx2x_xgxs_specific_func + .link_reset = bnx2x_int_link_reset, + .config_loopback = bnx2x_set_xgxs_loopback, + .format_fw_ver = NULL, + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = bnx2x_xgxs_specific_func }; static const struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, @@ -11747,12 +11747,12 @@ static const struct bnx2x_phy phy_warpcore = { /* rsrv = */0, .config_init = (config_init_t)bnx2x_warpcore_config_init, .read_status = (read_status_t)bnx2x_warpcore_read_status, - .link_reset = (link_reset_t)bnx2x_warpcore_link_reset, - .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback, - .format_fw_ver = (format_fw_ver_t)NULL, + .link_reset = bnx2x_warpcore_link_reset, + .config_loopback = bnx2x_set_warpcore_loopback, + .format_fw_ver = NULL, .hw_reset = (hw_reset_t)bnx2x_warpcore_hw_reset, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .set_link_led = NULL, + .phy_specific_func = NULL }; @@ -11778,12 +11778,12 @@ static const struct bnx2x_phy phy_7101 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_7101_config_init, .read_status = (read_status_t)bnx2x_7101_read_status, - .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, - .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback, + .link_reset = bnx2x_common_ext_link_reset, + .config_loopback = bnx2x_7101_config_loopback, .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, - .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led, - .phy_specific_func = (phy_specific_func_t)NULL + .set_link_led = bnx2x_7101_set_link_led, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_8073 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, @@ -11809,12 +11809,12 @@ static const struct bnx2x_phy phy_8073 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8073_config_init, .read_status = (read_status_t)bnx2x_8073_read_status, - .link_reset = (link_reset_t)bnx2x_8073_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_8073_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)bnx2x_8073_specific_func + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = bnx2x_8073_specific_func }; static const struct bnx2x_phy phy_8705 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705, @@ -11837,12 +11837,12 @@ static const struct bnx2x_phy phy_8705 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8705_config_init, .read_status = (read_status_t)bnx2x_8705_read_status, - .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_common_ext_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, @@ -11866,12 +11866,12 @@ static const struct bnx2x_phy phy_8706 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8706_config_init, .read_status = (read_status_t)bnx2x_8706_read_status, - .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_common_ext_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_8726 = { @@ -11898,12 +11898,12 @@ static const struct bnx2x_phy phy_8726 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8726_config_init, .read_status = (read_status_t)bnx2x_8726_read_status, - .link_reset = (link_reset_t)bnx2x_8726_link_reset, - .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback, + .link_reset = bnx2x_8726_link_reset, + .config_loopback = bnx2x_8726_config_loopback, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, - .phy_specific_func = (phy_specific_func_t)NULL + .hw_reset = NULL, + .set_link_led = NULL, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_8727 = { @@ -11929,12 +11929,12 @@ static const struct bnx2x_phy phy_8727 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8727_config_init, .read_status = (read_status_t)bnx2x_8727_read_status, - .link_reset = (link_reset_t)bnx2x_8727_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_8727_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, - .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func + .set_link_led = bnx2x_8727_set_link_led, + .phy_specific_func = bnx2x_8727_specific_func }; static const struct bnx2x_phy phy_8481 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, @@ -11964,12 +11964,12 @@ static const struct bnx2x_phy phy_8481 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_8481_config_init, .read_status = (read_status_t)bnx2x_848xx_read_status, - .link_reset = (link_reset_t)bnx2x_8481_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_8481_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, - .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, - .phy_specific_func = (phy_specific_func_t)NULL + .set_link_led = bnx2x_848xx_set_link_led, + .phy_specific_func = NULL }; static const struct bnx2x_phy phy_84823 = { @@ -12001,12 +12001,12 @@ static const struct bnx2x_phy phy_84823 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, .read_status = (read_status_t)bnx2x_848xx_read_status, - .link_reset = (link_reset_t)bnx2x_848x3_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_848x3_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func + .hw_reset = NULL, + .set_link_led = bnx2x_848xx_set_link_led, + .phy_specific_func = bnx2x_848xx_specific_func }; static const struct bnx2x_phy phy_84833 = { @@ -12036,12 +12036,12 @@ static const struct bnx2x_phy phy_84833 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, .read_status = (read_status_t)bnx2x_848xx_read_status, - .link_reset = (link_reset_t)bnx2x_848x3_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_848x3_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, - .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func + .set_link_led = bnx2x_848xx_set_link_led, + .phy_specific_func = bnx2x_848xx_specific_func }; static const struct bnx2x_phy phy_84834 = { @@ -12070,12 +12070,12 @@ static const struct bnx2x_phy phy_84834 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, .read_status = (read_status_t)bnx2x_848xx_read_status, - .link_reset = (link_reset_t)bnx2x_848x3_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_848x3_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, - .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func + .set_link_led = bnx2x_848xx_set_link_led, + .phy_specific_func = bnx2x_848xx_specific_func }; static const struct bnx2x_phy phy_84858 = { @@ -12104,12 +12104,12 @@ static const struct bnx2x_phy phy_84858 = { .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, .read_status = (read_status_t)bnx2x_848xx_read_status, - .link_reset = (link_reset_t)bnx2x_848x3_link_reset, - .config_loopback = (config_loopback_t)NULL, + .link_reset = bnx2x_848x3_link_reset, + .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_8485x_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, - .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func + .set_link_led = bnx2x_848xx_set_link_led, + .phy_specific_func = bnx2x_848xx_specific_func }; static const struct bnx2x_phy phy_54618se = { @@ -12138,12 +12138,12 @@ static const struct bnx2x_phy phy_54618se = { /* rsrv = */0, .config_init = (config_init_t)bnx2x_54618se_config_init, .read_status = (read_status_t)bnx2x_54618se_read_status, - .link_reset = (link_reset_t)bnx2x_54618se_link_reset, - .config_loopback = (config_loopback_t)bnx2x_54618se_config_loopback, - .format_fw_ver = (format_fw_ver_t)NULL, - .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)bnx2x_5461x_set_link_led, - .phy_specific_func = (phy_specific_func_t)bnx2x_54618se_specific_func + .link_reset = bnx2x_54618se_link_reset, + .config_loopback = bnx2x_54618se_config_loopback, + .format_fw_ver = NULL, + .hw_reset = NULL, + .set_link_led = bnx2x_5461x_set_link_led, + .phy_specific_func = bnx2x_54618se_specific_func }; /*****************************************************************/ /* */ -- cgit v1.2.3-59-g8ed1b From 2c855d73f2f6107f5b8ebc45f8b934bf7f4419e0 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 14 Nov 2019 21:07:12 -0800 Subject: bnx2x: Remove read_status_t function casts The function casts for .read_status callbacks end up casting some int return values to u8. This seems to be bug-prone (-EINVAL being returned into something that appears to be true/false), but fixing the function prototypes doesn't change the existing behavior. Fix the return values to remove the casts. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index decde193c5b3..a124f1e0819f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -5611,9 +5611,9 @@ static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, return 0; } -static int bnx2x_link_settings_status(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; @@ -5685,7 +5685,7 @@ static int bnx2x_link_settings_status(struct bnx2x_phy *phy, return rc; } -static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy, +static u8 bnx2x_warpcore_read_status(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars) { @@ -8993,9 +8993,9 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, return 0; } -static int bnx2x_8706_read_status(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { return bnx2x_8706_8726_read_status(phy, params, vars); } @@ -11672,7 +11672,7 @@ static const struct bnx2x_phy phy_serdes = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_xgxs_config_init, - .read_status = (read_status_t)bnx2x_link_settings_status, + .read_status = bnx2x_link_settings_status, .link_reset = bnx2x_int_link_reset, .config_loopback = NULL, .format_fw_ver = NULL, @@ -11708,7 +11708,7 @@ static const struct bnx2x_phy phy_xgxs = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_xgxs_config_init, - .read_status = (read_status_t)bnx2x_link_settings_status, + .read_status = bnx2x_link_settings_status, .link_reset = bnx2x_int_link_reset, .config_loopback = bnx2x_set_xgxs_loopback, .format_fw_ver = NULL, @@ -11746,7 +11746,7 @@ static const struct bnx2x_phy phy_warpcore = { /* req_duplex = */0, /* rsrv = */0, .config_init = (config_init_t)bnx2x_warpcore_config_init, - .read_status = (read_status_t)bnx2x_warpcore_read_status, + .read_status = bnx2x_warpcore_read_status, .link_reset = bnx2x_warpcore_link_reset, .config_loopback = bnx2x_set_warpcore_loopback, .format_fw_ver = NULL, @@ -11777,7 +11777,7 @@ static const struct bnx2x_phy phy_7101 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_7101_config_init, - .read_status = (read_status_t)bnx2x_7101_read_status, + .read_status = bnx2x_7101_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = bnx2x_7101_config_loopback, .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, @@ -11808,7 +11808,7 @@ static const struct bnx2x_phy phy_8073 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8073_config_init, - .read_status = (read_status_t)bnx2x_8073_read_status, + .read_status = bnx2x_8073_read_status, .link_reset = bnx2x_8073_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, @@ -11836,7 +11836,7 @@ static const struct bnx2x_phy phy_8705 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8705_config_init, - .read_status = (read_status_t)bnx2x_8705_read_status, + .read_status = bnx2x_8705_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, @@ -11865,7 +11865,7 @@ static const struct bnx2x_phy phy_8706 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8706_config_init, - .read_status = (read_status_t)bnx2x_8706_read_status, + .read_status = bnx2x_8706_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, @@ -11897,7 +11897,7 @@ static const struct bnx2x_phy phy_8726 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8726_config_init, - .read_status = (read_status_t)bnx2x_8726_read_status, + .read_status = bnx2x_8726_read_status, .link_reset = bnx2x_8726_link_reset, .config_loopback = bnx2x_8726_config_loopback, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, @@ -11928,7 +11928,7 @@ static const struct bnx2x_phy phy_8727 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8727_config_init, - .read_status = (read_status_t)bnx2x_8727_read_status, + .read_status = bnx2x_8727_read_status, .link_reset = bnx2x_8727_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, @@ -11963,7 +11963,7 @@ static const struct bnx2x_phy phy_8481 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_8481_config_init, - .read_status = (read_status_t)bnx2x_848xx_read_status, + .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_8481_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, @@ -12000,7 +12000,7 @@ static const struct bnx2x_phy phy_84823 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, - .read_status = (read_status_t)bnx2x_848xx_read_status, + .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, @@ -12035,7 +12035,7 @@ static const struct bnx2x_phy phy_84833 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, - .read_status = (read_status_t)bnx2x_848xx_read_status, + .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, @@ -12069,7 +12069,7 @@ static const struct bnx2x_phy phy_84834 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, - .read_status = (read_status_t)bnx2x_848xx_read_status, + .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, @@ -12103,7 +12103,7 @@ static const struct bnx2x_phy phy_84858 = { .req_duplex = 0, .rsrv = 0, .config_init = (config_init_t)bnx2x_848x3_config_init, - .read_status = (read_status_t)bnx2x_848xx_read_status, + .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = (format_fw_ver_t)bnx2x_8485x_format_ver, @@ -12137,7 +12137,7 @@ static const struct bnx2x_phy phy_54618se = { /* req_duplex = */0, /* rsrv = */0, .config_init = (config_init_t)bnx2x_54618se_config_init, - .read_status = (read_status_t)bnx2x_54618se_read_status, + .read_status = bnx2x_54618se_read_status, .link_reset = bnx2x_54618se_link_reset, .config_loopback = bnx2x_54618se_config_loopback, .format_fw_ver = NULL, -- cgit v1.2.3-59-g8ed1b From 3e19d1f2654ffd0e379c0f4ba30424bb57ed8acc Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 14 Nov 2019 21:07:13 -0800 Subject: bnx2x: Remove config_init_t function casts No callers of .config_init check return values. Remove the casting and change all callbacks to have the correct function prototype. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 105 ++++++++++------------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 4 +- 2 files changed, 48 insertions(+), 61 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index a124f1e0819f..2bc6408ce00d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -7364,9 +7364,9 @@ static void bnx2x_8073_specific_func(struct bnx2x_phy *phy, } } -static int bnx2x_8073_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8073_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 val = 0, tmp1; @@ -7427,7 +7427,7 @@ static int bnx2x_8073_config_init(struct bnx2x_phy *phy, if (params->loopback_mode == LOOPBACK_EXT) { bnx2x_807x_force_10G(bp, phy); DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n"); - return 0; + return; } else { bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002); @@ -7509,7 +7509,6 @@ static int bnx2x_8073_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200); DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n", ((val & (1<<5)) > 0), ((val & (1<<7)) > 0)); - return 0; } static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy, @@ -7676,9 +7675,9 @@ static void bnx2x_8073_link_reset(struct bnx2x_phy *phy, /******************************************************************/ /* BCM8705 PHY SECTION */ /******************************************************************/ -static int bnx2x_8705_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8705_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "init 8705\n"); @@ -7700,7 +7699,6 @@ static int bnx2x_8705_config_init(struct bnx2x_phy *phy, MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1); /* BCM8705 doesn't have microcode, hence the 0 */ bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0); - return 0; } static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy, @@ -8887,9 +8885,9 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, /******************************************************************/ /* BCM8706 PHY SECTION */ /******************************************************************/ -static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8706_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u32 tx_en_mode; u16 cnt, val, tmp1; @@ -8989,8 +8987,6 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1); } - - return 0; } static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy, @@ -9070,9 +9066,9 @@ static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy, } -static int bnx2x_8726_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8726_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); @@ -9150,9 +9146,6 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy, MDIO_PMA_REG_8726_TX_CTRL2, phy->tx_preemphasis[1]); } - - return 0; - } static void bnx2x_8726_link_reset(struct bnx2x_phy *phy, @@ -9288,9 +9281,9 @@ static void bnx2x_8727_config_speed(struct bnx2x_phy *phy, } } -static int bnx2x_8727_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8727_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u32 tx_en_mode; u16 tmp1, mod_abs, tmp2; @@ -9370,8 +9363,6 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, (tmp2 & 0x7fff)); } - - return 0; } static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, @@ -9946,9 +9937,9 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, return 0; } -static int bnx2x_8481_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_8481_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; /* Restore normal power mode*/ @@ -9960,7 +9951,7 @@ static int bnx2x_8481_config_init(struct bnx2x_phy *phy, bnx2x_wait_reset_complete(bp, phy, params); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); - return bnx2x_848xx_cmn_config_init(phy, params, vars); + bnx2x_848xx_cmn_config_init(phy, params, vars); } #define PHY848xx_CMDHDLR_WAIT 300 @@ -10283,9 +10274,9 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy, } #define PHY84833_CONSTANT_LATENCY 1193 -static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_848x3_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 port, initialize = 1; @@ -10430,7 +10421,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, if (rc) { DP(NETIF_MSG_LINK, "Failed to configure EEE timers\n"); bnx2x_8483x_disable_eee(phy, params, vars); - return rc; + return; } if ((phy->req_duplex == DUPLEX_FULL) && @@ -10442,7 +10433,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, rc = bnx2x_8483x_disable_eee(phy, params, vars); if (rc) { DP(NETIF_MSG_LINK, "Failed to set EEE advertisement\n"); - return rc; + return; } } else { vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK; @@ -10481,7 +10472,6 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, MDIO_84833_TOP_CFG_XGPHY_STRAP1, (u16)~MDIO_84833_SUPER_ISOLATE); } - return rc; } static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, @@ -11038,9 +11028,9 @@ static void bnx2x_54618se_specific_func(struct bnx2x_phy *phy, } } -static int bnx2x_54618se_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_54618se_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 port; @@ -11240,8 +11230,6 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy, bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, autoneg_val); - - return 0; } @@ -11465,9 +11453,9 @@ static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy, MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100); } -static int bnx2x_7101_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_7101_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u16 fw_ver1, fw_ver2, val; struct bnx2x *bp = params->bp; @@ -11502,7 +11490,6 @@ static int bnx2x_7101_config_init(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2); bnx2x_save_spirom_version(bp, params->port, (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr); - return 0; } static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy, @@ -11671,7 +11658,7 @@ static const struct bnx2x_phy phy_serdes = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_xgxs_config_init, + .config_init = bnx2x_xgxs_config_init, .read_status = bnx2x_link_settings_status, .link_reset = bnx2x_int_link_reset, .config_loopback = NULL, @@ -11707,7 +11694,7 @@ static const struct bnx2x_phy phy_xgxs = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_xgxs_config_init, + .config_init = bnx2x_xgxs_config_init, .read_status = bnx2x_link_settings_status, .link_reset = bnx2x_int_link_reset, .config_loopback = bnx2x_set_xgxs_loopback, @@ -11745,7 +11732,7 @@ static const struct bnx2x_phy phy_warpcore = { .speed_cap_mask = 0, /* req_duplex = */0, /* rsrv = */0, - .config_init = (config_init_t)bnx2x_warpcore_config_init, + .config_init = bnx2x_warpcore_config_init, .read_status = bnx2x_warpcore_read_status, .link_reset = bnx2x_warpcore_link_reset, .config_loopback = bnx2x_set_warpcore_loopback, @@ -11776,7 +11763,7 @@ static const struct bnx2x_phy phy_7101 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_7101_config_init, + .config_init = bnx2x_7101_config_init, .read_status = bnx2x_7101_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = bnx2x_7101_config_loopback, @@ -11807,7 +11794,7 @@ static const struct bnx2x_phy phy_8073 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8073_config_init, + .config_init = bnx2x_8073_config_init, .read_status = bnx2x_8073_read_status, .link_reset = bnx2x_8073_link_reset, .config_loopback = NULL, @@ -11835,7 +11822,7 @@ static const struct bnx2x_phy phy_8705 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8705_config_init, + .config_init = bnx2x_8705_config_init, .read_status = bnx2x_8705_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, @@ -11864,7 +11851,7 @@ static const struct bnx2x_phy phy_8706 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8706_config_init, + .config_init = bnx2x_8706_config_init, .read_status = bnx2x_8706_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, @@ -11896,7 +11883,7 @@ static const struct bnx2x_phy phy_8726 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8726_config_init, + .config_init = bnx2x_8726_config_init, .read_status = bnx2x_8726_read_status, .link_reset = bnx2x_8726_link_reset, .config_loopback = bnx2x_8726_config_loopback, @@ -11927,7 +11914,7 @@ static const struct bnx2x_phy phy_8727 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8727_config_init, + .config_init = bnx2x_8727_config_init, .read_status = bnx2x_8727_read_status, .link_reset = bnx2x_8727_link_reset, .config_loopback = NULL, @@ -11962,7 +11949,7 @@ static const struct bnx2x_phy phy_8481 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_8481_config_init, + .config_init = bnx2x_8481_config_init, .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_8481_link_reset, .config_loopback = NULL, @@ -11999,7 +11986,7 @@ static const struct bnx2x_phy phy_84823 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_848x3_config_init, + .config_init = bnx2x_848x3_config_init, .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, @@ -12034,7 +12021,7 @@ static const struct bnx2x_phy phy_84833 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_848x3_config_init, + .config_init = bnx2x_848x3_config_init, .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, @@ -12068,7 +12055,7 @@ static const struct bnx2x_phy phy_84834 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_848x3_config_init, + .config_init = bnx2x_848x3_config_init, .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, @@ -12102,7 +12089,7 @@ static const struct bnx2x_phy phy_84858 = { .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_848x3_config_init, + .config_init = bnx2x_848x3_config_init, .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, @@ -12136,7 +12123,7 @@ static const struct bnx2x_phy phy_54618se = { .speed_cap_mask = 0, /* req_duplex = */0, /* rsrv = */0, - .config_init = (config_init_t)bnx2x_54618se_config_init, + .config_init = bnx2x_54618se_config_init, .read_status = bnx2x_54618se_read_status, .link_reset = bnx2x_54618se_link_reset, .config_loopback = bnx2x_54618se_config_loopback, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index 7115f5025664..d31d15c78a17 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -127,8 +127,8 @@ struct link_vars; struct link_params; struct bnx2x_phy; -typedef u8 (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params, - struct link_vars *vars); +typedef void (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params, + struct link_vars *vars); typedef u8 (*read_status_t)(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars); typedef void (*link_reset_t)(struct bnx2x_phy *phy, -- cgit v1.2.3-59-g8ed1b From 26658f6bdb65ff192ff9b4b7ed9f3408d74ceeea Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 14 Nov 2019 21:07:14 -0800 Subject: bnx2x: Remove format_fw_ver_t function casts The return values for format_fw_ver_t callbacks are supposed to be "int", not "u8". Ultimately, the top-level caller doesn't actually check the return value at all, but just clean this all up anyway and fix the prototypes so that casts are no longer needed. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 22 +++++++++++----------- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 2bc6408ce00d..7dd35aa75925 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -11767,7 +11767,7 @@ static const struct bnx2x_phy phy_7101 = { .read_status = bnx2x_7101_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = bnx2x_7101_config_loopback, - .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, + .format_fw_ver = bnx2x_7101_format_ver, .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, .set_link_led = bnx2x_7101_set_link_led, .phy_specific_func = NULL @@ -11798,7 +11798,7 @@ static const struct bnx2x_phy phy_8073 = { .read_status = bnx2x_8073_read_status, .link_reset = bnx2x_8073_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .format_fw_ver = bnx2x_format_ver, .hw_reset = NULL, .set_link_led = NULL, .phy_specific_func = bnx2x_8073_specific_func @@ -11826,7 +11826,7 @@ static const struct bnx2x_phy phy_8705 = { .read_status = bnx2x_8705_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, + .format_fw_ver = bnx2x_null_format_ver, .hw_reset = NULL, .set_link_led = NULL, .phy_specific_func = NULL @@ -11855,7 +11855,7 @@ static const struct bnx2x_phy phy_8706 = { .read_status = bnx2x_8706_read_status, .link_reset = bnx2x_common_ext_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .format_fw_ver = bnx2x_format_ver, .hw_reset = NULL, .set_link_led = NULL, .phy_specific_func = NULL @@ -11887,7 +11887,7 @@ static const struct bnx2x_phy phy_8726 = { .read_status = bnx2x_8726_read_status, .link_reset = bnx2x_8726_link_reset, .config_loopback = bnx2x_8726_config_loopback, - .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .format_fw_ver = bnx2x_format_ver, .hw_reset = NULL, .set_link_led = NULL, .phy_specific_func = NULL @@ -11918,7 +11918,7 @@ static const struct bnx2x_phy phy_8727 = { .read_status = bnx2x_8727_read_status, .link_reset = bnx2x_8727_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .format_fw_ver = bnx2x_format_ver, .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, .set_link_led = bnx2x_8727_set_link_led, .phy_specific_func = bnx2x_8727_specific_func @@ -11953,7 +11953,7 @@ static const struct bnx2x_phy phy_8481 = { .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_8481_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .format_fw_ver = bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = NULL @@ -11990,7 +11990,7 @@ static const struct bnx2x_phy phy_84823 = { .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .format_fw_ver = bnx2x_848xx_format_ver, .hw_reset = NULL, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func @@ -12025,7 +12025,7 @@ static const struct bnx2x_phy phy_84833 = { .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .format_fw_ver = bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func @@ -12059,7 +12059,7 @@ static const struct bnx2x_phy phy_84834 = { .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .format_fw_ver = bnx2x_848xx_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func @@ -12093,7 +12093,7 @@ static const struct bnx2x_phy phy_84858 = { .read_status = bnx2x_848xx_read_status, .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, - .format_fw_ver = (format_fw_ver_t)bnx2x_8485x_format_ver, + .format_fw_ver = bnx2x_8485x_format_ver, .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index d31d15c78a17..cae03c89dc73 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -135,7 +135,7 @@ typedef void (*link_reset_t)(struct bnx2x_phy *phy, struct link_params *params); typedef void (*config_loopback_t)(struct bnx2x_phy *phy, struct link_params *params); -typedef u8 (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len); +typedef int (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len); typedef void (*hw_reset_t)(struct bnx2x_phy *phy, struct link_params *params); typedef void (*set_link_led_t)(struct bnx2x_phy *phy, struct link_params *params, u8 mode); -- cgit v1.2.3-59-g8ed1b From 548e5ffe2e11d10c54f8425019900c87788fd838 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 14 Nov 2019 21:07:15 -0800 Subject: bnx2x: Remove hw_reset_t function casts All .rw_reset callbacks except bnx2x_84833_hw_reset_phy() use a void return type. No callers of .hw_reset check a return value and bnx2x_84833_hw_reset_phy() unconditionally returns 0. Remove all hw_reset_t casts and fix the return type to void. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7dd35aa75925..9638d65d8261 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -10201,8 +10201,8 @@ static u8 bnx2x_84833_get_reset_gpios(struct bnx2x *bp, return reset_gpios; } -static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy, - struct link_params *params) +static void bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u8 reset_gpios; @@ -10230,8 +10230,6 @@ static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy, udelay(10); DP(NETIF_MSG_LINK, "84833 hw reset on pin values 0x%x\n", reset_gpios); - - return 0; } static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy, @@ -11737,7 +11735,7 @@ static const struct bnx2x_phy phy_warpcore = { .link_reset = bnx2x_warpcore_link_reset, .config_loopback = bnx2x_set_warpcore_loopback, .format_fw_ver = NULL, - .hw_reset = (hw_reset_t)bnx2x_warpcore_hw_reset, + .hw_reset = bnx2x_warpcore_hw_reset, .set_link_led = NULL, .phy_specific_func = NULL }; @@ -11768,7 +11766,7 @@ static const struct bnx2x_phy phy_7101 = { .link_reset = bnx2x_common_ext_link_reset, .config_loopback = bnx2x_7101_config_loopback, .format_fw_ver = bnx2x_7101_format_ver, - .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, + .hw_reset = bnx2x_7101_hw_reset, .set_link_led = bnx2x_7101_set_link_led, .phy_specific_func = NULL }; @@ -11919,7 +11917,7 @@ static const struct bnx2x_phy phy_8727 = { .link_reset = bnx2x_8727_link_reset, .config_loopback = NULL, .format_fw_ver = bnx2x_format_ver, - .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, + .hw_reset = bnx2x_8727_hw_reset, .set_link_led = bnx2x_8727_set_link_led, .phy_specific_func = bnx2x_8727_specific_func }; @@ -11954,7 +11952,7 @@ static const struct bnx2x_phy phy_8481 = { .link_reset = bnx2x_8481_link_reset, .config_loopback = NULL, .format_fw_ver = bnx2x_848xx_format_ver, - .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, + .hw_reset = bnx2x_8481_hw_reset, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = NULL }; @@ -12026,7 +12024,7 @@ static const struct bnx2x_phy phy_84833 = { .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = bnx2x_848xx_format_ver, - .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .hw_reset = bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func }; @@ -12060,7 +12058,7 @@ static const struct bnx2x_phy phy_84834 = { .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = bnx2x_848xx_format_ver, - .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .hw_reset = bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func }; @@ -12094,7 +12092,7 @@ static const struct bnx2x_phy phy_84858 = { .link_reset = bnx2x_848x3_link_reset, .config_loopback = NULL, .format_fw_ver = bnx2x_8485x_format_ver, - .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .hw_reset = bnx2x_84833_hw_reset_phy, .set_link_led = bnx2x_848xx_set_link_led, .phy_specific_func = bnx2x_848xx_specific_func }; -- cgit v1.2.3-59-g8ed1b From 4214fa1efffd4c6236231f1104eddc156b4e9104 Mon Sep 17 00:00:00 2001 From: Horatiu Vultur Date: Fri, 15 Nov 2019 11:11:15 +0100 Subject: net: mscc: ocelot: omit error check from of_get_phy_mode The commit 0c65b2b90d13c ("net: of_get_phy_mode: Change API to solve int/unit warnings") updated the function of_get_phy_mode declaration. Now it returns an error code and in case the node doesn't contain the property 'phy-mode' or 'phy-connection-type' it returns -EINVAL and would set the phy_interface_t to PHY_INTERFACE_MODE_NA. Ocelot VSC7514 has 4 internal phys which have the phy interface PHY_INTERFACE_MODE_NA. So because of_get_phy_mode would assign PHY_INTERFACE_MODE_NA to phy_mode when there is an error, there is no need to add the error check. Updates for v2: - drop error check because of_get_phy_mode already assigns phy_interface to PHY_INTERFACE_MODE in case of error. Signed-off-by: Horatiu Vultur Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot_board.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 5581b3b0165c..5541ec26f953 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -451,9 +451,7 @@ static int mscc_ocelot_probe(struct platform_device *pdev) priv = container_of(ocelot_port, struct ocelot_port_private, port); - err = of_get_phy_mode(portnp, &phy_mode); - if (err && err != -ENODEV) - goto out_put_ports; + of_get_phy_mode(portnp, &phy_mode); priv->phy_mode = phy_mode; -- cgit v1.2.3-59-g8ed1b From df98be06c94d23e2a8e12065bf2df5b186b81f0f Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Fri, 15 Nov 2019 12:10:37 +0100 Subject: bonding: symmetric ICMP transmit A bonding with layer2+3 or layer3+4 hashing uses the IP addresses and the ports to balance packets between slaves. With some network errors, we receive an ICMP error packet by the remote host or a router. If sent by a router, the source IP can differ from the remote host one. Additionally the ICMP protocol has no port numbers, so a layer3+4 bonding will get a different hash than the previous one. These two conditions could let the packet go through a different interface than the other packets of the same flow: # tcpdump -qltnni veth0 |sed 's/^/0: /' & # tcpdump -qltnni veth1 |sed 's/^/1: /' & # hping3 -2 192.168.0.2 -p 9 0: IP 192.168.0.1.2251 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 1: IP 192.168.0.1.2252 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 1: IP 192.168.0.1.2253 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 0: IP 192.168.0.1.2254 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 An ICMP error packet contains the header of the packet which caused the network error, so inspect it and match the flow against it, so we can send the ICMP via the same interface of the previous packet in the flow. Move the IP and port dissect code into a generic function bond_flow_ip() and if we are dissecting an ICMP error packet, call it again with the adjusted offset. # hping3 -2 192.168.0.2 -p 9 1: IP 192.168.0.1.1224 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 1: IP 192.168.0.1.1225 > 192.168.0.2.9: UDP, length 0 1: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 0: IP 192.168.0.1.1226 > 192.168.0.2.9: UDP, length 0 0: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 0: IP 192.168.0.1.1227 > 192.168.0.2.9: UDP, length 0 0: IP 192.168.0.2 > 192.168.0.1: ICMP 192.168.0.2 udp port 9 unreachable, length 36 Signed-off-by: Matteo Croce Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 83 ++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 08b2b0d855af..fcb7c2f7f001 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -3297,12 +3299,42 @@ static inline u32 bond_eth_hash(struct sk_buff *skb) return 0; } +static bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, + int *noff, int *proto, bool l34) +{ + const struct ipv6hdr *iph6; + const struct iphdr *iph; + + if (skb->protocol == htons(ETH_P_IP)) { + if (unlikely(!pskb_may_pull(skb, *noff + sizeof(*iph)))) + return false; + iph = (const struct iphdr *)(skb->data + *noff); + iph_to_flow_copy_v4addrs(fk, iph); + *noff += iph->ihl << 2; + if (!ip_is_fragment(iph)) + *proto = iph->protocol; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + if (unlikely(!pskb_may_pull(skb, *noff + sizeof(*iph6)))) + return false; + iph6 = (const struct ipv6hdr *)(skb->data + *noff); + iph_to_flow_copy_v6addrs(fk, iph6); + *noff += sizeof(*iph6); + *proto = iph6->nexthdr; + } else { + return false; + } + + if (l34 && *proto >= 0) + fk->ports.ports = skb_flow_get_ports(skb, *noff, *proto); + + return true; +} + /* Extract the appropriate headers based on bond's xmit policy */ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, struct flow_keys *fk) { - const struct ipv6hdr *iph6; - const struct iphdr *iph; + bool l34 = bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34; int noff, proto = -1; if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) { @@ -3314,31 +3346,30 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, fk->ports.ports = 0; memset(&fk->icmp, 0, sizeof(fk->icmp)); noff = skb_network_offset(skb); - if (skb->protocol == htons(ETH_P_IP)) { - if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) - return false; - iph = ip_hdr(skb); - iph_to_flow_copy_v4addrs(fk, iph); - noff += iph->ihl << 2; - if (!ip_is_fragment(iph)) - proto = iph->protocol; - } else if (skb->protocol == htons(ETH_P_IPV6)) { - if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6)))) - return false; - iph6 = ipv6_hdr(skb); - iph_to_flow_copy_v6addrs(fk, iph6); - noff += sizeof(*iph6); - proto = iph6->nexthdr; - } else { + if (!bond_flow_ip(skb, fk, &noff, &proto, l34)) return false; - } - if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34 && proto >= 0) { - if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) - skb_flow_get_icmp_tci(skb, &fk->icmp, skb->data, - skb_transport_offset(skb), - skb_headlen(skb)); - else - fk->ports.ports = skb_flow_get_ports(skb, noff, proto); + + /* ICMP error packets contains at least 8 bytes of the header + * of the packet which generated the error. Use this information + * to correlate ICMP error packets within the same flow which + * generated the error. + */ + if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) { + skb_flow_get_icmp_tci(skb, &fk->icmp, skb->data, + skb_transport_offset(skb), + skb_headlen(skb)); + if (proto == IPPROTO_ICMP) { + if (!icmp_is_err(fk->icmp.type)) + return true; + + noff += sizeof(struct icmphdr); + } else if (proto == IPPROTO_ICMPV6) { + if (!icmpv6_is_err(fk->icmp.type)) + return true; + + noff += sizeof(struct icmp6hdr); + } + return bond_flow_ip(skb, fk, &noff, &proto, l34); } return true; -- cgit v1.2.3-59-g8ed1b From 725ea4bff9ad6d594e2a633fcdc673dfcaf55d43 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 15 Nov 2019 20:05:45 +0000 Subject: net: phylink: update to use phy_support_asym_pause() Use phy_support_asym_pause() rather than open-coding it. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phylink.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index e3fbc8e93317..6ce2e6c63e75 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -713,11 +713,6 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy) __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); int ret; - memset(&config, 0, sizeof(config)); - linkmode_copy(supported, phy->supported); - linkmode_copy(config.advertising, phy->advertising); - config.interface = pl->link_config.interface; - /* * This is the new way of dealing with flow control for PHYs, * as described by Timur Tabi in commit 529ed1275263 ("net: phy: @@ -725,10 +720,12 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy) * using our validate call to the MAC, we rely upon the MAC * clearing the bits from both supported and advertising fields. */ - if (phylink_test(supported, Pause)) - phylink_set(config.advertising, Pause); - if (phylink_test(supported, Asym_Pause)) - phylink_set(config.advertising, Asym_Pause); + phy_support_asym_pause(phy); + + memset(&config, 0, sizeof(config)); + linkmode_copy(supported, phy->supported); + linkmode_copy(config.advertising, phy->advertising); + config.interface = pl->link_config.interface; ret = phylink_validate(pl, supported, &config); if (ret) -- cgit v1.2.3-59-g8ed1b From 718af5bc9709dbab643788719af32d4dfd9d9d35 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 15 Nov 2019 21:35:22 +0100 Subject: r8169: improve conditional firmware loading for RTL8168d Using constant MII_EXPANSION is misleading here because register 0x06 has a different meaning on page 0x0005. Here a proprietary PHY parameter is read by writing the parameter id to register 0x05 on page 0x0005, followed by reading the parameter value from register 0x06. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 39 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 81a0c426a9a1..cf13eb215352 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -2297,14 +2297,6 @@ static void rtl_apply_firmware(struct rtl8169_private *tp) rtl_fw_write_firmware(tp, tp->rtl_fw); } -static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) -{ - if (rtl_readphy(tp, reg) != val) - netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); - else - rtl_apply_firmware(tp); -} - static void rtl8168_config_eee_mac(struct rtl8169_private *tp) { /* Adjust EEE LED frequency */ @@ -2691,6 +2683,21 @@ static const struct phy_reg rtl8168d_1_phy_reg_init_1[] = { { 0x1f, 0x0002 } }; +static void rtl8168d_apply_firmware_cond(struct rtl8169_private *tp, u16 val) +{ + u16 reg_val; + + rtl_writephy(tp, 0x1f, 0x0005); + rtl_writephy(tp, 0x05, 0x001b); + reg_val = rtl_readphy(tp, 0x06); + rtl_writephy(tp, 0x1f, 0x0000); + + if (reg_val != val) + netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); + else + rtl_apply_firmware(tp); +} + static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) { rtl_writephy_batch(tp, rtl8168d_1_phy_reg_init_0); @@ -2737,13 +2744,9 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0002); rtl_w0w1_phy(tp, 0x02, 0x0100, 0x0600); rtl_w0w1_phy(tp, 0x03, 0x0000, 0xe000); - - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x001b); - - rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00); - rtl_writephy(tp, 0x1f, 0x0000); + + rtl8168d_apply_firmware_cond(tp, 0xbf00); } static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) @@ -2782,13 +2785,9 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) /* Switching regulator Slew rate */ rtl_writephy(tp, 0x1f, 0x0002); rtl_patchphy(tp, 0x0f, 0x0017); - - rtl_writephy(tp, 0x1f, 0x0005); - rtl_writephy(tp, 0x05, 0x001b); - - rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300); - rtl_writephy(tp, 0x1f, 0x0000); + + rtl8168d_apply_firmware_cond(tp, 0xb300); } static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp) -- cgit v1.2.3-59-g8ed1b From 229c1e0dfd3dfac23b33b7cd88bcb7a9e391b000 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 15 Nov 2019 22:38:25 +0100 Subject: r8169: load firmware for RTL8168fp/RTL8117 Load Realtek-provided firmware for RTL8168fp/RTL8117. Unlike the firmware for other chip versions which is for the PHY, firmware for RTL8168fp/RTL8117 is for the MAC. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index cf13eb215352..d8fcdb9db8d1 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -52,6 +52,7 @@ #define FIRMWARE_8168G_3 "rtl_nic/rtl8168g-3.fw" #define FIRMWARE_8168H_1 "rtl_nic/rtl8168h-1.fw" #define FIRMWARE_8168H_2 "rtl_nic/rtl8168h-2.fw" +#define FIRMWARE_8168FP_3 "rtl_nic/rtl8168fp-3.fw" #define FIRMWARE_8107E_1 "rtl_nic/rtl8107e-1.fw" #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" @@ -203,7 +204,7 @@ static const struct { [RTL_GIGA_MAC_VER_49] = {"RTL8168ep/8111ep" }, [RTL_GIGA_MAC_VER_50] = {"RTL8168ep/8111ep" }, [RTL_GIGA_MAC_VER_51] = {"RTL8168ep/8111ep" }, - [RTL_GIGA_MAC_VER_52] = {"RTL8117" }, + [RTL_GIGA_MAC_VER_52] = {"RTL8168fp/RTL8117", FIRMWARE_8168FP_3}, [RTL_GIGA_MAC_VER_60] = {"RTL8125" }, [RTL_GIGA_MAC_VER_61] = {"RTL8125", FIRMWARE_8125A_3}, }; @@ -715,6 +716,7 @@ MODULE_FIRMWARE(FIRMWARE_8168G_2); MODULE_FIRMWARE(FIRMWARE_8168G_3); MODULE_FIRMWARE(FIRMWARE_8168H_1); MODULE_FIRMWARE(FIRMWARE_8168H_2); +MODULE_FIRMWARE(FIRMWARE_8168FP_3); MODULE_FIRMWARE(FIRMWARE_8107E_1); MODULE_FIRMWARE(FIRMWARE_8107E_2); MODULE_FIRMWARE(FIRMWARE_8125A_3); @@ -4883,6 +4885,9 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp) r8168_mac_ocp_write(tp, 0xc094, 0x0000); r8168_mac_ocp_write(tp, 0xc09e, 0x0000); + /* firmware is for MAC only */ + rtl_apply_firmware(tp); + rtl_hw_aspm_clkreq_enable(tp, true); } -- cgit v1.2.3-59-g8ed1b From 1e8795b1b20d2721620165434cdcf427ecd2ba85 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sat, 16 Nov 2019 06:38:34 +0800 Subject: mscc.c: fix semicolon.cocci warnings drivers/net/phy/mscc.c:1683:3-4: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: 75a1ccfe6c72 ("mscc.c: Add support for additional VSC PHYs") CC: Bryan Whitehead Signed-off-by: kbuild test robot Signed-off-by: David S. Miller --- drivers/net/phy/mscc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index aadee8db0ff8..d5f8f351d9ef 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -1680,7 +1680,7 @@ static int vsc8584_config_init(struct phy_device *phydev) default: ret = -EINVAL; break; - }; + } if (ret) goto err; -- cgit v1.2.3-59-g8ed1b From 1e0bd5a091e5d9e0f1d5b0e6329b87bb1792f784 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 17 Nov 2019 09:28:02 -0800 Subject: bpf: Switch bpf_map ref counter to atomic64_t so bpf_map_inc() never fails 92117d8443bc ("bpf: fix refcnt overflow") turned refcounting of bpf_map into potentially failing operation, when refcount reaches BPF_MAX_REFCNT limit (32k). Due to using 32-bit counter, it's possible in practice to overflow refcounter and make it wrap around to 0, causing erroneous map free, while there are still references to it, causing use-after-free problems. But having a failing refcounting operations are problematic in some cases. One example is mmap() interface. After establishing initial memory-mapping, user is allowed to arbitrarily map/remap/unmap parts of mapped memory, arbitrarily splitting it into multiple non-contiguous regions. All this happening without any control from the users of mmap subsystem. Rather mmap subsystem sends notifications to original creator of memory mapping through open/close callbacks, which are optionally specified during initial memory mapping creation. These callbacks are used to maintain accurate refcount for bpf_map (see next patch in this series). The problem is that open() callback is not supposed to fail, because memory-mapped resource is set up and properly referenced. This is posing a problem for using memory-mapping with BPF maps. One solution to this is to maintain separate refcount for just memory-mappings and do single bpf_map_inc/bpf_map_put when it goes from/to zero, respectively. There are similar use cases in current work on tcp-bpf, necessitating extra counter as well. This seems like a rather unfortunate and ugly solution that doesn't scale well to various new use cases. Another approach to solve this is to use non-failing refcount_t type, which uses 32-bit counter internally, but, once reaching overflow state at UINT_MAX, stays there. This utlimately causes memory leak, but prevents use after free. But given refcounting is not the most performance-critical operation with BPF maps (it's not used from running BPF program code), we can also just switch to 64-bit counter that can't overflow in practice, potentially disadvantaging 32-bit platforms a tiny bit. This simplifies semantics and allows above described scenarios to not worry about failing refcount increment operation. In terms of struct bpf_map size, we are still good and use the same amount of space: BEFORE (3 cache lines, 8 bytes of padding at the end): struct bpf_map { const struct bpf_map_ops * ops __attribute__((__aligned__(64))); /* 0 8 */ struct bpf_map * inner_map_meta; /* 8 8 */ void * security; /* 16 8 */ enum bpf_map_type map_type; /* 24 4 */ u32 key_size; /* 28 4 */ u32 value_size; /* 32 4 */ u32 max_entries; /* 36 4 */ u32 map_flags; /* 40 4 */ int spin_lock_off; /* 44 4 */ u32 id; /* 48 4 */ int numa_node; /* 52 4 */ u32 btf_key_type_id; /* 56 4 */ u32 btf_value_type_id; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct btf * btf; /* 64 8 */ struct bpf_map_memory memory; /* 72 16 */ bool unpriv_array; /* 88 1 */ bool frozen; /* 89 1 */ /* XXX 38 bytes hole, try to pack */ /* --- cacheline 2 boundary (128 bytes) --- */ atomic_t refcnt __attribute__((__aligned__(64))); /* 128 4 */ atomic_t usercnt; /* 132 4 */ struct work_struct work; /* 136 32 */ char name[16]; /* 168 16 */ /* size: 192, cachelines: 3, members: 21 */ /* sum members: 146, holes: 1, sum holes: 38 */ /* padding: 8 */ /* forced alignments: 2, forced holes: 1, sum forced holes: 38 */ } __attribute__((__aligned__(64))); AFTER (same 3 cache lines, no extra padding now): struct bpf_map { const struct bpf_map_ops * ops __attribute__((__aligned__(64))); /* 0 8 */ struct bpf_map * inner_map_meta; /* 8 8 */ void * security; /* 16 8 */ enum bpf_map_type map_type; /* 24 4 */ u32 key_size; /* 28 4 */ u32 value_size; /* 32 4 */ u32 max_entries; /* 36 4 */ u32 map_flags; /* 40 4 */ int spin_lock_off; /* 44 4 */ u32 id; /* 48 4 */ int numa_node; /* 52 4 */ u32 btf_key_type_id; /* 56 4 */ u32 btf_value_type_id; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ struct btf * btf; /* 64 8 */ struct bpf_map_memory memory; /* 72 16 */ bool unpriv_array; /* 88 1 */ bool frozen; /* 89 1 */ /* XXX 38 bytes hole, try to pack */ /* --- cacheline 2 boundary (128 bytes) --- */ atomic64_t refcnt __attribute__((__aligned__(64))); /* 128 8 */ atomic64_t usercnt; /* 136 8 */ struct work_struct work; /* 144 32 */ char name[16]; /* 176 16 */ /* size: 192, cachelines: 3, members: 21 */ /* sum members: 154, holes: 1, sum holes: 38 */ /* forced alignments: 2, forced holes: 1, sum forced holes: 38 */ } __attribute__((__aligned__(64))); This patch, while modifying all users of bpf_map_inc, also cleans up its interface to match bpf_map_put with separate operations for bpf_map_inc and bpf_map_inc_with_uref (to match bpf_map_put and bpf_map_put_with_uref, respectively). Also, given there are no users of bpf_map_inc_not_zero specifying uref=true, remove uref flag and default to uref=false internally. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191117172806.2195367-2-andriin@fb.com --- drivers/net/ethernet/netronome/nfp/bpf/offload.c | 4 +- include/linux/bpf.h | 10 ++--- kernel/bpf/inode.c | 2 +- kernel/bpf/map_in_map.c | 2 +- kernel/bpf/syscall.c | 51 ++++++++++-------------- kernel/bpf/verifier.c | 6 +-- kernel/bpf/xskmap.c | 6 +-- net/core/bpf_sk_storage.c | 2 +- 8 files changed, 34 insertions(+), 49 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 88fab6a82acf..06927ba5a3ae 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -46,9 +46,7 @@ nfp_map_ptr_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog, /* Grab a single ref to the map for our record. The prog destroy ndo * happens after free_used_maps(). */ - map = bpf_map_inc(map, false); - if (IS_ERR(map)) - return PTR_ERR(map); + bpf_map_inc(map); record = kmalloc(sizeof(*record), GFP_KERNEL); if (!record) { diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 5b81cde47314..34a34445c009 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -103,8 +103,8 @@ struct bpf_map { /* The 3rd and 4th cacheline with misc members to avoid false sharing * particularly with refcounting. */ - atomic_t refcnt ____cacheline_aligned; - atomic_t usercnt; + atomic64_t refcnt ____cacheline_aligned; + atomic64_t usercnt; struct work_struct work; char name[BPF_OBJ_NAME_LEN]; }; @@ -783,9 +783,9 @@ void bpf_map_free_id(struct bpf_map *map, bool do_idr_lock); struct bpf_map *bpf_map_get_with_uref(u32 ufd); struct bpf_map *__bpf_map_get(struct fd f); -struct bpf_map * __must_check bpf_map_inc(struct bpf_map *map, bool uref); -struct bpf_map * __must_check bpf_map_inc_not_zero(struct bpf_map *map, - bool uref); +void bpf_map_inc(struct bpf_map *map); +void bpf_map_inc_with_uref(struct bpf_map *map); +struct bpf_map * __must_check bpf_map_inc_not_zero(struct bpf_map *map); void bpf_map_put_with_uref(struct bpf_map *map); void bpf_map_put(struct bpf_map *map); int bpf_map_charge_memlock(struct bpf_map *map, u32 pages); diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index a70f7209cda3..2f17f24258dc 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -34,7 +34,7 @@ static void *bpf_any_get(void *raw, enum bpf_type type) raw = bpf_prog_inc(raw); break; case BPF_TYPE_MAP: - raw = bpf_map_inc(raw, true); + bpf_map_inc_with_uref(raw); break; default: WARN_ON_ONCE(1); diff --git a/kernel/bpf/map_in_map.c b/kernel/bpf/map_in_map.c index fab4fb134547..4cbe987be35b 100644 --- a/kernel/bpf/map_in_map.c +++ b/kernel/bpf/map_in_map.c @@ -98,7 +98,7 @@ void *bpf_map_fd_get_ptr(struct bpf_map *map, return inner_map; if (bpf_map_meta_equal(map->inner_map_meta, inner_map)) - inner_map = bpf_map_inc(inner_map, false); + bpf_map_inc(inner_map); else inner_map = ERR_PTR(-EINVAL); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index c88c815c2154..20030751b7a2 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -311,7 +311,7 @@ static void bpf_map_free_deferred(struct work_struct *work) static void bpf_map_put_uref(struct bpf_map *map) { - if (atomic_dec_and_test(&map->usercnt)) { + if (atomic64_dec_and_test(&map->usercnt)) { if (map->ops->map_release_uref) map->ops->map_release_uref(map); } @@ -322,7 +322,7 @@ static void bpf_map_put_uref(struct bpf_map *map) */ static void __bpf_map_put(struct bpf_map *map, bool do_idr_lock) { - if (atomic_dec_and_test(&map->refcnt)) { + if (atomic64_dec_and_test(&map->refcnt)) { /* bpf_map_free_id() must be called first */ bpf_map_free_id(map, do_idr_lock); btf_put(map->btf); @@ -575,8 +575,8 @@ static int map_create(union bpf_attr *attr) if (err) goto free_map; - atomic_set(&map->refcnt, 1); - atomic_set(&map->usercnt, 1); + atomic64_set(&map->refcnt, 1); + atomic64_set(&map->usercnt, 1); if (attr->btf_key_type_id || attr->btf_value_type_id) { struct btf *btf; @@ -653,21 +653,19 @@ struct bpf_map *__bpf_map_get(struct fd f) return f.file->private_data; } -/* prog's and map's refcnt limit */ -#define BPF_MAX_REFCNT 32768 - -struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref) +void bpf_map_inc(struct bpf_map *map) { - if (atomic_inc_return(&map->refcnt) > BPF_MAX_REFCNT) { - atomic_dec(&map->refcnt); - return ERR_PTR(-EBUSY); - } - if (uref) - atomic_inc(&map->usercnt); - return map; + atomic64_inc(&map->refcnt); } EXPORT_SYMBOL_GPL(bpf_map_inc); +void bpf_map_inc_with_uref(struct bpf_map *map) +{ + atomic64_inc(&map->refcnt); + atomic64_inc(&map->usercnt); +} +EXPORT_SYMBOL_GPL(bpf_map_inc_with_uref); + struct bpf_map *bpf_map_get_with_uref(u32 ufd) { struct fd f = fdget(ufd); @@ -677,38 +675,30 @@ struct bpf_map *bpf_map_get_with_uref(u32 ufd) if (IS_ERR(map)) return map; - map = bpf_map_inc(map, true); + bpf_map_inc_with_uref(map); fdput(f); return map; } /* map_idr_lock should have been held */ -static struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, - bool uref) +static struct bpf_map *__bpf_map_inc_not_zero(struct bpf_map *map, bool uref) { int refold; - refold = atomic_fetch_add_unless(&map->refcnt, 1, 0); - - if (refold >= BPF_MAX_REFCNT) { - __bpf_map_put(map, false); - return ERR_PTR(-EBUSY); - } - + refold = atomic64_fetch_add_unless(&map->refcnt, 1, 0); if (!refold) return ERR_PTR(-ENOENT); - if (uref) - atomic_inc(&map->usercnt); + atomic64_inc(&map->usercnt); return map; } -struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map, bool uref) +struct bpf_map *bpf_map_inc_not_zero(struct bpf_map *map) { spin_lock_bh(&map_idr_lock); - map = __bpf_map_inc_not_zero(map, uref); + map = __bpf_map_inc_not_zero(map, false); spin_unlock_bh(&map_idr_lock); return map; @@ -1455,6 +1445,9 @@ static struct bpf_prog *____bpf_prog_get(struct fd f) return f.file->private_data; } +/* prog's refcnt limit */ +#define BPF_MAX_REFCNT 32768 + struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) { if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e9dc95a18d44..9f59f7a19dd0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8179,11 +8179,7 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env) * will be used by the valid program until it's unloaded * and all maps are released in free_used_maps() */ - map = bpf_map_inc(map, false); - if (IS_ERR(map)) { - fdput(f); - return PTR_ERR(map); - } + bpf_map_inc(map); aux->map_index = env->used_map_cnt; env->used_maps[env->used_map_cnt++] = map; diff --git a/kernel/bpf/xskmap.c b/kernel/bpf/xskmap.c index da16c30868f3..90c4fce1c981 100644 --- a/kernel/bpf/xskmap.c +++ b/kernel/bpf/xskmap.c @@ -11,10 +11,8 @@ int xsk_map_inc(struct xsk_map *map) { - struct bpf_map *m = &map->map; - - m = bpf_map_inc(m, false); - return PTR_ERR_OR_ZERO(m); + bpf_map_inc(&map->map); + return 0; } void xsk_map_put(struct xsk_map *map) diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c index da5639a5bd3b..458be6b3eda9 100644 --- a/net/core/bpf_sk_storage.c +++ b/net/core/bpf_sk_storage.c @@ -798,7 +798,7 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk) * Try to grab map refcnt to make sure that it's still * alive and prevent concurrent removal. */ - map = bpf_map_inc_not_zero(&smap->map, false); + map = bpf_map_inc_not_zero(&smap->map); if (IS_ERR(map)) continue; -- cgit v1.2.3-59-g8ed1b From 85192dbf4de08795afe2b88e52a36fc6abfc3dba Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 17 Nov 2019 09:28:03 -0800 Subject: bpf: Convert bpf_prog refcnt to atomic64_t Similarly to bpf_map's refcnt/usercnt, convert bpf_prog's refcnt to atomic64 and remove artificial 32k limit. This allows to make bpf_prog's refcounting non-failing, simplifying logic of users of bpf_prog_add/bpf_prog_inc. Validated compilation by running allyesconfig kernel build. Suggested-by: Daniel Borkmann Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191117172806.2195367-3-andriin@fb.com --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++----- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 9 ++----- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 7 ++---- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 24 +++++------------- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 18 ++++---------- drivers/net/ethernet/qlogic/qede/qede_main.c | 8 ++---- drivers/net/virtio_net.c | 7 ++---- include/linux/bpf.h | 13 ++++------ kernel/bpf/inode.c | 5 ++-- kernel/bpf/syscall.c | 30 +++++++---------------- kernel/events/core.c | 7 ++---- 11 files changed, 40 insertions(+), 97 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c07172429c70..9da4fbee3cf7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3171,13 +3171,8 @@ static int bnxt_init_one_rx_ring(struct bnxt *bp, int ring_nr) bnxt_init_rxbd_pages(ring, type); if (BNXT_RX_PAGE_MODE(bp) && bp->xdp_prog) { - rxr->xdp_prog = bpf_prog_add(bp->xdp_prog, 1); - if (IS_ERR(rxr->xdp_prog)) { - int rc = PTR_ERR(rxr->xdp_prog); - - rxr->xdp_prog = NULL; - return rc; - } + bpf_prog_add(bp->xdp_prog, 1); + rxr->xdp_prog = bp->xdp_prog; } prod = rxr->rx_prod; for (i = 0; i < bp->rx_ring_size; i++) { diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 40a44dcb3d9b..f28409279ea4 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1876,13 +1876,8 @@ static int nicvf_xdp_setup(struct nicvf *nic, struct bpf_prog *prog) if (nic->xdp_prog) { /* Attach BPF program */ - nic->xdp_prog = bpf_prog_add(nic->xdp_prog, nic->rx_queues - 1); - if (!IS_ERR(nic->xdp_prog)) { - bpf_attached = true; - } else { - ret = PTR_ERR(nic->xdp_prog); - nic->xdp_prog = NULL; - } + bpf_prog_add(nic->xdp_prog, nic->rx_queues - 1); + bpf_attached = true; } /* Calculate Tx queues needed for XDP and network stack */ diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index c26c0a7cbb6b..acc56606d3a5 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1807,11 +1807,8 @@ static int setup_xdp(struct net_device *dev, struct bpf_prog *prog) if (prog && !xdp_mtu_valid(priv, dev->mtu)) return -EINVAL; - if (prog) { - prog = bpf_prog_add(prog, priv->num_channels); - if (IS_ERR(prog)) - return PTR_ERR(prog); - } + if (prog) + bpf_prog_add(prog, priv->num_channels); up = netif_running(dev); need_update = (!!priv->xdp_prog != !!prog); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 40ec5acf79c0..d4697beeacc2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2286,11 +2286,7 @@ int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, lockdep_is_held(&priv->mdev->state_lock)); if (xdp_prog && carry_xdp_prog) { - xdp_prog = bpf_prog_add(xdp_prog, tmp->rx_ring_num); - if (IS_ERR(xdp_prog)) { - mlx4_en_free_resources(tmp); - return PTR_ERR(xdp_prog); - } + bpf_prog_add(xdp_prog, tmp->rx_ring_num); for (i = 0; i < tmp->rx_ring_num; i++) rcu_assign_pointer(tmp->rx_ring[i]->xdp_prog, xdp_prog); @@ -2782,11 +2778,9 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) * program for a new one. */ if (priv->tx_ring_num[TX_XDP] == xdp_ring_num) { - if (prog) { - prog = bpf_prog_add(prog, priv->rx_ring_num - 1); - if (IS_ERR(prog)) - return PTR_ERR(prog); - } + if (prog) + bpf_prog_add(prog, priv->rx_ring_num - 1); + mutex_lock(&mdev->state_lock); for (i = 0; i < priv->rx_ring_num; i++) { old_prog = rcu_dereference_protected( @@ -2807,13 +2801,8 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) if (!tmp) return -ENOMEM; - if (prog) { - prog = bpf_prog_add(prog, priv->rx_ring_num - 1); - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto out; - } - } + if (prog) + bpf_prog_add(prog, priv->rx_ring_num - 1); mutex_lock(&mdev->state_lock); memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); @@ -2862,7 +2851,6 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) unlock_out: mutex_unlock(&mdev->state_lock); -out: kfree(tmp); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 772bfdbdeb9c..1d4a66fb466a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -408,12 +408,9 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c, rq->stats = &c->priv->channel_stats[c->ix].rq; INIT_WORK(&rq->recover_work, mlx5e_rq_err_cqe_work); - rq->xdp_prog = params->xdp_prog ? bpf_prog_inc(params->xdp_prog) : NULL; - if (IS_ERR(rq->xdp_prog)) { - err = PTR_ERR(rq->xdp_prog); - rq->xdp_prog = NULL; - goto err_rq_wq_destroy; - } + if (params->xdp_prog) + bpf_prog_inc(params->xdp_prog); + rq->xdp_prog = params->xdp_prog; rq_xdp_ix = rq->ix; if (xsk) @@ -4406,16 +4403,11 @@ static int mlx5e_xdp_set(struct net_device *netdev, struct bpf_prog *prog) /* no need for full reset when exchanging programs */ reset = (!priv->channels.params.xdp_prog || !prog); - if (was_opened && !reset) { + if (was_opened && !reset) /* num_channels is invariant here, so we can take the * batched reference right upfront. */ - prog = bpf_prog_add(prog, priv->channels.num); - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto unlock; - } - } + bpf_prog_add(prog, priv->channels.num); if (was_opened && reset) { struct mlx5e_channels new_channels = {}; diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 8d1c208f778f..1e26964fe4e9 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -2107,12 +2107,8 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats) if (rc) goto out; - fp->rxq->xdp_prog = bpf_prog_add(edev->xdp_prog, 1); - if (IS_ERR(fp->rxq->xdp_prog)) { - rc = PTR_ERR(fp->rxq->xdp_prog); - fp->rxq->xdp_prog = NULL; - goto out; - } + bpf_prog_add(edev->xdp_prog, 1); + fp->rxq->xdp_prog = edev->xdp_prog; } if (fp->type & QEDE_FASTPATH_TX) { diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5a635f028bdc..4d7d5434cc5d 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -2445,11 +2445,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, if (!prog && !old_prog) return 0; - if (prog) { - prog = bpf_prog_add(prog, vi->max_queue_pairs - 1); - if (IS_ERR(prog)) - return PTR_ERR(prog); - } + if (prog) + bpf_prog_add(prog, vi->max_queue_pairs - 1); /* Make sure NAPI is not using any XDP TX queues for RX. */ if (netif_running(dev)) { diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 34a34445c009..fb606dc61a3a 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -485,7 +485,7 @@ struct bpf_func_info_aux { }; struct bpf_prog_aux { - atomic_t refcnt; + atomic64_t refcnt; u32 used_map_cnt; u32 max_ctx_offset; u32 max_pkt_offset; @@ -770,9 +770,9 @@ extern const struct bpf_verifier_ops xdp_analyzer_ops; struct bpf_prog *bpf_prog_get(u32 ufd); struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, enum bpf_prog_type type, bool attach_drv); -struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, int i); +void bpf_prog_add(struct bpf_prog *prog, int i); void bpf_prog_sub(struct bpf_prog *prog, int i); -struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog); +void bpf_prog_inc(struct bpf_prog *prog); struct bpf_prog * __must_check bpf_prog_inc_not_zero(struct bpf_prog *prog); void bpf_prog_put(struct bpf_prog *prog); int __bpf_prog_charge(struct user_struct *user, u32 pages); @@ -912,10 +912,8 @@ static inline struct bpf_prog *bpf_prog_get_type_dev(u32 ufd, return ERR_PTR(-EOPNOTSUPP); } -static inline struct bpf_prog * __must_check bpf_prog_add(struct bpf_prog *prog, - int i) +static inline void bpf_prog_add(struct bpf_prog *prog, int i) { - return ERR_PTR(-EOPNOTSUPP); } static inline void bpf_prog_sub(struct bpf_prog *prog, int i) @@ -926,9 +924,8 @@ static inline void bpf_prog_put(struct bpf_prog *prog) { } -static inline struct bpf_prog * __must_check bpf_prog_inc(struct bpf_prog *prog) +static inline void bpf_prog_inc(struct bpf_prog *prog) { - return ERR_PTR(-EOPNOTSUPP); } static inline struct bpf_prog *__must_check diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 2f17f24258dc..ecf42bec38c0 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -31,7 +31,7 @@ static void *bpf_any_get(void *raw, enum bpf_type type) { switch (type) { case BPF_TYPE_PROG: - raw = bpf_prog_inc(raw); + bpf_prog_inc(raw); break; case BPF_TYPE_MAP: bpf_map_inc_with_uref(raw); @@ -534,7 +534,8 @@ static struct bpf_prog *__get_prog_inode(struct inode *inode, enum bpf_prog_type if (!bpf_prog_get_ok(prog, &type, false)) return ERR_PTR(-EINVAL); - return bpf_prog_inc(prog); + bpf_prog_inc(prog); + return prog; } struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 20030751b7a2..52fe4bacb330 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1339,7 +1339,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred) static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) { - if (atomic_dec_and_test(&prog->aux->refcnt)) { + if (atomic64_dec_and_test(&prog->aux->refcnt)) { perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_UNLOAD, 0); /* bpf_prog_free_id() must be called first */ bpf_prog_free_id(prog, do_idr_lock); @@ -1445,16 +1445,9 @@ static struct bpf_prog *____bpf_prog_get(struct fd f) return f.file->private_data; } -/* prog's refcnt limit */ -#define BPF_MAX_REFCNT 32768 - -struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) +void bpf_prog_add(struct bpf_prog *prog, int i) { - if (atomic_add_return(i, &prog->aux->refcnt) > BPF_MAX_REFCNT) { - atomic_sub(i, &prog->aux->refcnt); - return ERR_PTR(-EBUSY); - } - return prog; + atomic64_add(i, &prog->aux->refcnt); } EXPORT_SYMBOL_GPL(bpf_prog_add); @@ -1465,13 +1458,13 @@ void bpf_prog_sub(struct bpf_prog *prog, int i) * path holds a reference to the program, thus atomic_sub() can * be safely used in such cases! */ - WARN_ON(atomic_sub_return(i, &prog->aux->refcnt) == 0); + WARN_ON(atomic64_sub_return(i, &prog->aux->refcnt) == 0); } EXPORT_SYMBOL_GPL(bpf_prog_sub); -struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) +void bpf_prog_inc(struct bpf_prog *prog) { - return bpf_prog_add(prog, 1); + atomic64_inc(&prog->aux->refcnt); } EXPORT_SYMBOL_GPL(bpf_prog_inc); @@ -1480,12 +1473,7 @@ struct bpf_prog *bpf_prog_inc_not_zero(struct bpf_prog *prog) { int refold; - refold = atomic_fetch_add_unless(&prog->aux->refcnt, 1, 0); - - if (refold >= BPF_MAX_REFCNT) { - __bpf_prog_put(prog, false); - return ERR_PTR(-EBUSY); - } + refold = atomic64_fetch_add_unless(&prog->aux->refcnt, 1, 0); if (!refold) return ERR_PTR(-ENOENT); @@ -1523,7 +1511,7 @@ static struct bpf_prog *__bpf_prog_get(u32 ufd, enum bpf_prog_type *attach_type, goto out; } - prog = bpf_prog_inc(prog); + bpf_prog_inc(prog); out: fdput(f); return prog; @@ -1714,7 +1702,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) prog->orig_prog = NULL; prog->jited = 0; - atomic_set(&prog->aux->refcnt, 1); + atomic64_set(&prog->aux->refcnt, 1); prog->gpl_compatible = is_gpl ? 1 : 0; if (bpf_prog_is_dev_bound(prog->aux)) { diff --git a/kernel/events/core.c b/kernel/events/core.c index aec8dba2bea4..73c616876597 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10477,12 +10477,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, context = parent_event->overflow_handler_context; #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_EVENT_TRACING) if (overflow_handler == bpf_overflow_handler) { - struct bpf_prog *prog = bpf_prog_inc(parent_event->prog); + struct bpf_prog *prog = parent_event->prog; - if (IS_ERR(prog)) { - err = PTR_ERR(prog); - goto err_ns; - } + bpf_prog_inc(prog); event->prog = prog; event->orig_overflow_handler = parent_event->orig_overflow_handler; -- cgit v1.2.3-59-g8ed1b From 298e54fa810e027f1b0800d789eb862592721f08 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 15 Nov 2019 19:56:51 +0000 Subject: net: phy: add core phylib sfp support Add core phylib help for supporting SFP sockets on PHYs. This provides a mechanism to inform the SFP layer about PHY up/down events, and also unregister the SFP bus when the PHY is going away. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 7 +++++ drivers/net/phy/phy_device.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/phy.h | 11 ++++++++ 3 files changed, 84 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 105d389b58e7..36d4ffe1cd3f 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -841,6 +842,9 @@ void phy_stop(struct phy_device *phydev) mutex_lock(&phydev->lock); + if (phydev->sfp_bus) + sfp_upstream_stop(phydev->sfp_bus); + phydev->state = PHY_HALTED; mutex_unlock(&phydev->lock); @@ -875,6 +879,9 @@ void phy_start(struct phy_device *phydev) goto out; } + if (phydev->sfp_bus) + sfp_upstream_start(phydev->sfp_bus); + /* if phy was suspended, bring the physical link up again */ __phy_resume(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index fa71998fea51..40f1942f1606 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1174,6 +1175,65 @@ phy_standalone_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(phy_standalone); +/** + * phy_sfp_attach - attach the SFP bus to the PHY upstream network device + * @upstream: pointer to the phy device + * @bus: sfp bus representing cage being attached + * + * This is used to fill in the sfp_upstream_ops .attach member. + */ +void phy_sfp_attach(void *upstream, struct sfp_bus *bus) +{ + struct phy_device *phydev = upstream; + + if (phydev->attached_dev) + phydev->attached_dev->sfp_bus = bus; + phydev->sfp_bus_attached = true; +} +EXPORT_SYMBOL(phy_sfp_attach); + +/** + * phy_sfp_detach - detach the SFP bus from the PHY upstream network device + * @upstream: pointer to the phy device + * @bus: sfp bus representing cage being attached + * + * This is used to fill in the sfp_upstream_ops .detach member. + */ +void phy_sfp_detach(void *upstream, struct sfp_bus *bus) +{ + struct phy_device *phydev = upstream; + + if (phydev->attached_dev) + phydev->attached_dev->sfp_bus = NULL; + phydev->sfp_bus_attached = false; +} +EXPORT_SYMBOL(phy_sfp_detach); + +/** + * phy_sfp_probe - probe for a SFP cage attached to this PHY device + * @phydev: Pointer to phy_device + * @ops: SFP's upstream operations + */ +int phy_sfp_probe(struct phy_device *phydev, + const struct sfp_upstream_ops *ops) +{ + struct sfp_bus *bus; + int ret; + + if (phydev->mdio.dev.fwnode) { + bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode); + if (IS_ERR(bus)) + return PTR_ERR(bus); + + phydev->sfp_bus = bus; + + ret = sfp_bus_add_upstream(bus, phydev, ops); + sfp_bus_put(bus); + } + return 0; +} +EXPORT_SYMBOL(phy_sfp_probe); + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1249,6 +1309,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, if (dev) { phydev->attached_dev = dev; dev->phydev = phydev; + + if (phydev->sfp_bus_attached) + dev->sfp_bus = phydev->sfp_bus; } /* Some Ethernet drivers try to connect to a PHY device before @@ -2418,6 +2481,9 @@ static int phy_remove(struct device *dev) phydev->state = PHY_DOWN; mutex_unlock(&phydev->lock); + sfp_bus_del_upstream(phydev->sfp_bus); + phydev->sfp_bus = NULL; + if (phydev->drv && phydev->drv->remove) { phydev->drv->remove(phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index 78436d58ce7c..124516fe2763 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_interface_t interface) struct device; struct phylink; +struct sfp_bus; +struct sfp_upstream_ops; struct sk_buff; /* @@ -342,6 +344,8 @@ struct phy_c45_device_ids { * dev_flags: Device-specific flags used by the PHY driver. * irq: IRQ number of the PHY's interrupt (-1 if none) * phy_timer: The timer for handling the state machine + * sfp_bus_attached: flag indicating whether the SFP bus has been attached + * sfp_bus: SFP bus attached to this PHY's fiber port * attached_dev: The attached enet driver's device instance ptr * adjust_link: Callback for the enet controller to respond to * changes in the link state. @@ -432,6 +436,9 @@ struct phy_device { struct mutex lock; + /* This may be modified under the rtnl lock */ + bool sfp_bus_attached; + struct sfp_bus *sfp_bus; struct phylink *phylink; struct net_device *attached_dev; @@ -1020,6 +1027,10 @@ int phy_suspend(struct phy_device *phydev); int phy_resume(struct phy_device *phydev); int __phy_resume(struct phy_device *phydev); int phy_loopback(struct phy_device *phydev, bool enable); +void phy_sfp_attach(void *upstream, struct sfp_bus *bus); +void phy_sfp_detach(void *upstream, struct sfp_bus *bus); +int phy_sfp_probe(struct phy_device *phydev, + const struct sfp_upstream_ops *ops); struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, phy_interface_t interface); struct phy_device *phy_find_first(struct mii_bus *bus); -- cgit v1.2.3-59-g8ed1b From 36023da1c704d56f2f264ccbfcfb7a15cdfd4d14 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 15 Nov 2019 19:56:56 +0000 Subject: net: phy: marvell10g: add SFP+ support Add support for SFP+ cages to the Marvell 10G PHY driver. This is slightly complicated by the way phylib works in that we need to use a multi-step process to attach the SFP bus, and we also need to track the phylink state machine to know when the module's transmit disable signal should change state. With appropriate DT changes, this allows the SFP+ canges on the Macchiatobin platform to be functional. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/marvell10g.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c index 3b99882692e3..1bf13017d288 100644 --- a/drivers/net/phy/marvell10g.c +++ b/drivers/net/phy/marvell10g.c @@ -26,6 +26,7 @@ #include #include #include +#include #define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe #define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa) @@ -206,6 +207,28 @@ static int mv3310_hwmon_probe(struct phy_device *phydev) } #endif +static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, }; + phy_interface_t iface; + + sfp_parse_support(phydev->sfp_bus, id, support); + iface = sfp_select_interface(phydev->sfp_bus, id, support); + + if (iface != PHY_INTERFACE_MODE_10GKR) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + return 0; +} + +static const struct sfp_upstream_ops mv3310_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = mv3310_sfp_insert, +}; + static int mv3310_probe(struct phy_device *phydev) { struct mv3310_priv *priv; @@ -236,7 +259,7 @@ static int mv3310_probe(struct phy_device *phydev) if (ret) return ret; - return 0; + return phy_sfp_probe(phydev, &mv3310_sfp_ops); } static int mv3310_suspend(struct phy_device *phydev) -- cgit v1.2.3-59-g8ed1b From b95e86d846b63b02ecdc94802ddbeaf9005fb6d9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 15 Nov 2019 20:08:37 +0000 Subject: net: phy: avoid matching all-ones clause 45 PHY IDs We currently match clause 45 PHYs using any ID read from a MMD marked as present in the "Devices in package" registers 5 and 6. However, this is incorrect. 45.2 says: "The definition of the term package is vendor specific and could be a chip, module, or other similar entity." so a package could be more or less than the whole PHY - a PHY could be made up of several modules instantiated onto a single chip such as the Marvell 88x3310, or some of the MMDs could be disabled according to chip configuration, such as the Broadcom 84881. In the case of Broadcom 84881, the "Devices in package" registers contain 0xc000009b, meaning that there is a PHYXS present in the package, but all registers in MMD 4 return 0xffff. This leads to our matching code incorrectly binding this PHY to one of our generic PHY drivers. This patch changes the way we determine whether to attempt to match a MMD identifier, or use it to request a module - if the identifier is all-ones, then we skip over it. When reading the identifiers, we initialise phydev->c45_ids.device_ids to all-ones, only reading the device ID if the "Devices in package" registers indicates we should. This avoids the generic drivers incorrectly matching on a PHY ID of 0xffffffff. Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 40f1942f1606..990f22eb6ce7 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -489,7 +489,7 @@ static int phy_bus_match(struct device *dev, struct device_driver *drv) if (phydev->is_c45) { for (i = 1; i < num_ids; i++) { - if (!(phydev->c45_ids.devices_in_package & (1 << i))) + if (phydev->c45_ids.device_ids[i] == 0xffffffff) continue; if ((phydrv->phy_id & phydrv->phy_id_mask) == @@ -633,7 +633,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, int i; for (i = 1; i < num_ids; i++) { - if (!(c45_ids->devices_in_package & (1 << i))) + if (c45_ids->device_ids[i] == 0xffffffff) continue; ret = phy_request_driver_module(dev, @@ -813,10 +813,13 @@ static int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id, */ struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45) { - struct phy_c45_device_ids c45_ids = {0}; + struct phy_c45_device_ids c45_ids; u32 phy_id = 0; int r; + c45_ids.devices_in_package = 0; + memset(c45_ids.device_ids, 0xff, sizeof(c45_ids.device_ids)); + r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids); if (r) return ERR_PTR(r); -- cgit v1.2.3-59-g8ed1b From 41136ab35888c4007c6aad2f86e35afb97003e69 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 18 Nov 2019 03:56:35 -0500 Subject: bnxt_en: Update firmware interface spec to 1.10.1.12. The aRFS ring table interface has changed for the 57500 chips. Updating it accordingly so it will work with the latest production firmware. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 20 +++--- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 6 +- drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h | 95 ++++++++++++++++++--------- 3 files changed, 77 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c07172429c70..81bb6ce0adbf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4601,21 +4601,21 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, struct hwrm_cfa_ntuple_filter_alloc_output *resp; struct flow_keys *keys = &fltr->fkeys; struct bnxt_vnic_info *vnic; - u32 dst_ena = 0; + u32 flags = 0; int rc = 0; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_NTUPLE_FILTER_ALLOC, -1, -1); req.l2_filter_id = bp->vnic_info[0].fw_l2_filter_id[fltr->l2_fltr_idx]; - if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX) { - dst_ena = CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_RFS_RING_TBL_IDX; - req.rfs_ring_tbl_idx = cpu_to_le16(fltr->rxq); - vnic = &bp->vnic_info[0]; + if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { + flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; + req.dst_id = cpu_to_le16(fltr->rxq); } else { vnic = &bp->vnic_info[fltr->rxq + 1]; + req.dst_id = cpu_to_le16(vnic->fw_vnic_id); } - req.dst_id = cpu_to_le16(vnic->fw_vnic_id); - req.enables = cpu_to_le32(BNXT_NTP_FLTR_FLAGS | dst_ena); + req.flags = cpu_to_le32(flags); + req.enables = cpu_to_le32(BNXT_NTP_FLTR_FLAGS); req.ethertype = htons(ETH_P_IP); memcpy(req.src_macaddr, fltr->src_mac_addr, ETH_ALEN); @@ -7042,8 +7042,8 @@ static int bnxt_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnxt *bp) flags = le32_to_cpu(resp->flags); if (flags & - CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_SUPPORTED) - bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX; + CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED) + bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2; hwrm_cfa_adv_qcaps_exit: mutex_unlock(&bp->hwrm_cmd_lock); @@ -9693,7 +9693,7 @@ static bool bnxt_can_reserve_rings(struct bnxt *bp) static bool bnxt_rfs_supported(struct bnxt *bp) { if (bp->flags & BNXT_FLAG_CHIP_P5) { - if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX) + if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) return true; return false; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a3545c846bfb..c260cbbffefa 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -12,11 +12,11 @@ #define BNXT_H #define DRV_MODULE_NAME "bnxt_en" -#define DRV_MODULE_VERSION "1.10.0" +#define DRV_MODULE_VERSION "1.10.1" #define DRV_VER_MAJ 1 #define DRV_VER_MIN 10 -#define DRV_VER_UPD 0 +#define DRV_VER_UPD 1 #include #include @@ -1666,7 +1666,7 @@ struct bnxt { #define BNXT_FW_CAP_ERROR_RECOVERY 0x00002000 #define BNXT_FW_CAP_PKG_VER 0x00004000 #define BNXT_FW_CAP_CFA_ADV_FLOW 0x00008000 - #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX 0x00010000 + #define BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2 0x00010000 #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000 #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h index 03b197eb793b..7cf27dffadb5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_hsi.h @@ -176,6 +176,9 @@ struct cmd_nums { #define HWRM_RESERVED6 0x65UL #define HWRM_VNIC_RSS_COS_LB_CTX_ALLOC 0x70UL #define HWRM_VNIC_RSS_COS_LB_CTX_FREE 0x71UL + #define HWRM_QUEUE_MPLS_QCAPS 0x80UL + #define HWRM_QUEUE_MPLSTC2PRI_QCFG 0x81UL + #define HWRM_QUEUE_MPLSTC2PRI_CFG 0x82UL #define HWRM_CFA_L2_FILTER_ALLOC 0x90UL #define HWRM_CFA_L2_FILTER_FREE 0x91UL #define HWRM_CFA_L2_FILTER_CFG 0x92UL @@ -208,7 +211,7 @@ struct cmd_nums { #define HWRM_FW_QSTATUS 0xc1UL #define HWRM_FW_HEALTH_CHECK 0xc2UL #define HWRM_FW_SYNC 0xc3UL - #define HWRM_FW_STATE_BUFFER_QCAPS 0xc4UL + #define HWRM_FW_STATE_QCAPS 0xc4UL #define HWRM_FW_STATE_QUIESCE 0xc5UL #define HWRM_FW_STATE_BACKUP 0xc6UL #define HWRM_FW_STATE_RESTORE 0xc7UL @@ -225,8 +228,11 @@ struct cmd_nums { #define HWRM_PORT_PRBS_TEST 0xd5UL #define HWRM_PORT_SFP_SIDEBAND_CFG 0xd6UL #define HWRM_PORT_SFP_SIDEBAND_QCFG 0xd7UL + #define HWRM_FW_STATE_UNQUIESCE 0xd8UL + #define HWRM_PORT_DSC_DUMP 0xd9UL #define HWRM_TEMP_MONITOR_QUERY 0xe0UL #define HWRM_REG_POWER_QUERY 0xe1UL + #define HWRM_CORE_FREQUENCY_QUERY 0xe2UL #define HWRM_WOL_FILTER_ALLOC 0xf0UL #define HWRM_WOL_FILTER_FREE 0xf1UL #define HWRM_WOL_FILTER_QCFG 0xf2UL @@ -308,6 +314,7 @@ struct cmd_nums { #define HWRM_ENGINE_STATS_CONFIG 0x155UL #define HWRM_ENGINE_STATS_CLEAR 0x156UL #define HWRM_ENGINE_STATS_QUERY 0x157UL + #define HWRM_ENGINE_STATS_QUERY_CONTINUOUS_ERROR 0x158UL #define HWRM_ENGINE_RQ_ALLOC 0x15eUL #define HWRM_ENGINE_RQ_FREE 0x15fUL #define HWRM_ENGINE_CQ_ALLOC 0x160UL @@ -390,6 +397,7 @@ struct ret_codes { #define HWRM_ERR_CODE_KEY_HASH_COLLISION 0xdUL #define HWRM_ERR_CODE_KEY_ALREADY_EXISTS 0xeUL #define HWRM_ERR_CODE_HWRM_ERROR 0xfUL + #define HWRM_ERR_CODE_BUSY 0x10UL #define HWRM_ERR_CODE_TLV_ENCAPSULATED_RESPONSE 0x8000UL #define HWRM_ERR_CODE_UNKNOWN_ERR 0xfffeUL #define HWRM_ERR_CODE_CMD_NOT_SUPPORTED 0xffffUL @@ -420,9 +428,9 @@ struct hwrm_err_output { #define HWRM_TARGET_ID_TOOLS 0xFFFD #define HWRM_VERSION_MAJOR 1 #define HWRM_VERSION_MINOR 10 -#define HWRM_VERSION_UPDATE 0 -#define HWRM_VERSION_RSVD 100 -#define HWRM_VERSION_STR "1.10.0.100" +#define HWRM_VERSION_UPDATE 1 +#define HWRM_VERSION_RSVD 12 +#define HWRM_VERSION_STR "1.10.1.12" /* hwrm_ver_get_input (size:192b/24B) */ struct hwrm_ver_get_input { @@ -637,6 +645,8 @@ struct hwrm_async_event_cmpl { #define ASYNC_EVENT_CMPL_EVENT_ID_EEM_CFG_CHANGE 0x3cUL #define ASYNC_EVENT_CMPL_EVENT_ID_TFLIB_DEFAULT_VNIC_CHANGE 0x3dUL #define ASYNC_EVENT_CMPL_EVENT_ID_TFLIB_LINK_STATUS_CHANGE 0x3eUL + #define ASYNC_EVENT_CMPL_EVENT_ID_QUIESCE_DONE 0x3fUL + #define ASYNC_EVENT_CMPL_EVENT_ID_DEFERRED_RESPONSE 0x40UL #define ASYNC_EVENT_CMPL_EVENT_ID_FW_TRACE_MSG 0xfeUL #define ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR 0xffUL #define ASYNC_EVENT_CMPL_EVENT_ID_LAST ASYNC_EVENT_CMPL_EVENT_ID_HWRM_ERROR @@ -1115,6 +1125,7 @@ struct hwrm_func_qcaps_output { #define FUNC_QCAPS_RESP_FLAGS_EXT_STATS_SUPPORTED 0x1000000UL #define FUNC_QCAPS_RESP_FLAGS_ERR_RECOVER_RELOAD 0x2000000UL #define FUNC_QCAPS_RESP_FLAGS_NOTIFY_VF_DEF_VNIC_CHNG_SUPPORTED 0x4000000UL + #define FUNC_QCAPS_RESP_FLAGS_VLAN_ACCELERATION_TX_DISABLED 0x8000000UL u8 mac_address[6]; __le16 max_rsscos_ctx; __le16 max_cmpl_rings; @@ -1255,7 +1266,8 @@ struct hwrm_func_qcfg_output { u8 unused_1; u8 always_1; __le32 reset_addr_poll; - u8 unused_2[3]; + __le16 legacy_l2_db_size_kb; + u8 unused_2[1]; u8 valid; }; @@ -1500,6 +1512,7 @@ struct hwrm_func_drv_rgtr_input { #define FUNC_DRV_RGTR_REQ_FLAGS_FLOW_HANDLE_64BIT_MODE 0x8UL #define FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT 0x10UL #define FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT 0x20UL + #define FUNC_DRV_RGTR_REQ_FLAGS_MASTER_SUPPORT 0x40UL __le32 enables; #define FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE 0x1UL #define FUNC_DRV_RGTR_REQ_ENABLES_VER 0x2UL @@ -1762,7 +1775,7 @@ struct hwrm_func_backing_store_qcaps_input { __le64 resp_addr; }; -/* hwrm_func_backing_store_qcaps_output (size:576b/72B) */ +/* hwrm_func_backing_store_qcaps_output (size:640b/80B) */ struct hwrm_func_backing_store_qcaps_output { __le16 error_code; __le16 req_type; @@ -1792,6 +1805,10 @@ struct hwrm_func_backing_store_qcaps_output { __le32 tim_max_entries; __le16 mrav_num_entries_units; u8 tqm_entries_multiple; + u8 ctx_kind_initializer; + __le32 rsvd; + __le16 rsvd1; + u8 rsvd2; u8 valid; }; @@ -2524,6 +2541,7 @@ struct hwrm_port_phy_qcfg_output { #define PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG 0x2UL #define PORT_PHY_QCFG_RESP_MODULE_STATUS_PWRDOWN 0x3UL #define PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTINSERTED 0x4UL + #define PORT_PHY_QCFG_RESP_MODULE_STATUS_CURRENTFAULT 0x5UL #define PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTAPPLICABLE 0xffUL #define PORT_PHY_QCFG_RESP_MODULE_STATUS_LAST PORT_PHY_QCFG_RESP_MODULE_STATUS_NOTAPPLICABLE __le32 preemphasis; @@ -2761,8 +2779,8 @@ struct hwrm_port_mac_ptp_qcfg_output { __le16 resp_len; u8 flags; #define PORT_MAC_PTP_QCFG_RESP_FLAGS_DIRECT_ACCESS 0x1UL - #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x2UL #define PORT_MAC_PTP_QCFG_RESP_FLAGS_ONE_STEP_TX_TS 0x4UL + #define PORT_MAC_PTP_QCFG_RESP_FLAGS_HWRM_ACCESS 0x8UL u8 unused_0[3]; __le32 rx_ts_reg_off_lower; __le32 rx_ts_reg_off_upper; @@ -3177,10 +3195,12 @@ struct hwrm_port_phy_qcaps_output { __le16 seq_id; __le16 resp_len; u8 flags; - #define PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED 0x1UL - #define PORT_PHY_QCAPS_RESP_FLAGS_EXTERNAL_LPBK_SUPPORTED 0x2UL - #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_MASK 0xfcUL - #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_SFT 2 + #define PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED 0x1UL + #define PORT_PHY_QCAPS_RESP_FLAGS_EXTERNAL_LPBK_SUPPORTED 0x2UL + #define PORT_PHY_QCAPS_RESP_FLAGS_AUTONEG_LPBK_SUPPORTED 0x4UL + #define PORT_PHY_QCAPS_RESP_FLAGS_SHARED_PHY_CFG_SUPPORTED 0x8UL + #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_MASK 0xf0UL + #define PORT_PHY_QCAPS_RESP_FLAGS_RSVD1_SFT 4 u8 port_cnt; #define PORT_PHY_QCAPS_RESP_PORT_CNT_UNKNOWN 0x0UL #define PORT_PHY_QCAPS_RESP_PORT_CNT_1 0x1UL @@ -4980,6 +5000,15 @@ struct hwrm_vnic_rss_cfg_output { u8 valid; }; +/* hwrm_vnic_rss_cfg_cmd_err (size:64b/8B) */ +struct hwrm_vnic_rss_cfg_cmd_err { + u8 code; + #define VNIC_RSS_CFG_CMD_ERR_CODE_UNKNOWN 0x0UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_INTERFACE_NOT_READY 0x1UL + #define VNIC_RSS_CFG_CMD_ERR_CODE_LAST VNIC_RSS_CFG_CMD_ERR_CODE_INTERFACE_NOT_READY + u8 unused_0[7]; +}; + /* hwrm_vnic_plcmodes_cfg_input (size:320b/40B) */ struct hwrm_vnic_plcmodes_cfg_input { __le16 req_type; @@ -5807,7 +5836,7 @@ struct hwrm_cfa_encap_record_free_output { u8 valid; }; -/* hwrm_cfa_ntuple_filter_alloc_input (size:1088b/136B) */ +/* hwrm_cfa_ntuple_filter_alloc_input (size:1024b/128B) */ struct hwrm_cfa_ntuple_filter_alloc_input { __le16 req_type; __le16 cmpl_ring; @@ -5815,10 +5844,12 @@ struct hwrm_cfa_ntuple_filter_alloc_input { __le16 target_id; __le64 resp_addr; __le32 flags; - #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x1UL - #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP 0x2UL - #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_METER 0x4UL - #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_FID 0x8UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_LOOPBACK 0x1UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP 0x2UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_METER 0x4UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_FID 0x8UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_ARP_REPLY 0x10UL + #define CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX 0x20UL __le32 enables; #define CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_L2_FILTER_ID 0x1UL #define CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_ETHERTYPE 0x2UL @@ -5887,8 +5918,6 @@ struct hwrm_cfa_ntuple_filter_alloc_input { __be16 dst_port; __be16 dst_port_mask; __le64 ntuple_filter_id_hint; - __le16 rfs_ring_tbl_idx; - u8 unused_0[6]; }; /* hwrm_cfa_ntuple_filter_alloc_output (size:192b/24B) */ @@ -5954,7 +5983,8 @@ struct hwrm_cfa_ntuple_filter_cfg_input { #define CFA_NTUPLE_FILTER_CFG_REQ_ENABLES_NEW_MIRROR_VNIC_ID 0x2UL #define CFA_NTUPLE_FILTER_CFG_REQ_ENABLES_NEW_METER_INSTANCE_ID 0x4UL __le32 flags; - #define CFA_NTUPLE_FILTER_CFG_REQ_FLAGS_DEST_FID 0x1UL + #define CFA_NTUPLE_FILTER_CFG_REQ_FLAGS_DEST_FID 0x1UL + #define CFA_NTUPLE_FILTER_CFG_REQ_FLAGS_DEST_RFS_RING_IDX 0x2UL __le64 ntuple_filter_id; __le32 new_dst_id; __le32 new_mirror_vnic_id; @@ -6534,18 +6564,21 @@ struct hwrm_cfa_adv_flow_mgnt_qcaps_output { __le16 seq_id; __le16 resp_len; __le32 flags; - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_HND_16BIT_SUPPORTED 0x1UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_HND_64BIT_SUPPORTED 0x2UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_BATCH_DELETE_SUPPORTED 0x4UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_RESET_ALL_SUPPORTED 0x8UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_DEST_FUNC_SUPPORTED 0x10UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_TX_EEM_FLOW_SUPPORTED 0x20UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RX_EEM_FLOW_SUPPORTED 0x40UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_COUNTER_ALLOC_SUPPORTED 0x80UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_SUPPORTED 0x100UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_UNTAGGED_VLAN_SUPPORTED 0x200UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_XDP_SUPPORTED 0x400UL - #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_L2_HEADER_SOURCE_FIELDS_SUPPORTED 0x800UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_HND_16BIT_SUPPORTED 0x1UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_HND_64BIT_SUPPORTED 0x2UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_BATCH_DELETE_SUPPORTED 0x4UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_RESET_ALL_SUPPORTED 0x8UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_DEST_FUNC_SUPPORTED 0x10UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_TX_EEM_FLOW_SUPPORTED 0x20UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RX_EEM_FLOW_SUPPORTED 0x40UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_FLOW_COUNTER_ALLOC_SUPPORTED 0x80UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_SUPPORTED 0x100UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_UNTAGGED_VLAN_SUPPORTED 0x200UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_XDP_SUPPORTED 0x400UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_L2_HEADER_SOURCE_FIELDS_SUPPORTED 0x800UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_ARP_SUPPORTED 0x1000UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED 0x2000UL + #define CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_ETHERTYPE_IP_SUPPORTED 0x4000UL u8 unused_0[3]; u8 valid; }; -- cgit v1.2.3-59-g8ed1b From 19b3751ffa713d04290effb26fe01009010f2206 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 18 Nov 2019 03:56:36 -0500 Subject: bnxt_en: Improve RX buffer error handling. When hardware reports RX buffer errors, the latest 57500 chips do not require reset. The packet is discarded by the hardware and the ring will continue to operate. Also, add an rx_buf_errors counter for this type of error. It can help the user to identify if the aggregation ring is too small. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 81bb6ce0adbf..0e5b5b853b2d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1767,8 +1767,12 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, rc = -EIO; if (rx_err & RX_CMPL_ERRORS_BUFFER_ERROR_MASK) { - netdev_warn(bp->dev, "RX buffer error %x\n", rx_err); - bnxt_sched_reset(bp, rxr); + bnapi->cp_ring.rx_buf_errors++; + if (!(bp->flags & BNXT_FLAG_CHIP_P5)) { + netdev_warn(bp->dev, "RX buffer error %x\n", + rx_err); + bnxt_sched_reset(bp, rxr); + } } goto next_rx_no_len; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c260cbbffefa..f2b5da702873 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -932,6 +932,7 @@ struct bnxt_cp_ring_info { dma_addr_t hw_stats_map; u32 hw_stats_ctx_id; u64 rx_l4_csum_errors; + u64 rx_buf_errors; u64 missed_irqs; struct bnxt_ring_struct cp_ring_struct; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index f2220b826d61..7a5f6bf1701c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -173,6 +173,7 @@ static const char * const bnxt_ring_tpa2_stats_str[] = { static const char * const bnxt_ring_sw_stats_str[] = { "rx_l4_csum_errors", + "rx_buf_errors", "missed_irqs", }; @@ -552,6 +553,7 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, for (k = 0; k < stat_fields; j++, k++) buf[j] = le64_to_cpu(hw_stats[k]); buf[j++] = cpr->rx_l4_csum_errors; + buf[j++] = cpr->rx_buf_errors; buf[j++] = cpr->missed_irqs; bnxt_sw_func_stats[RX_TOTAL_DISCARDS].counter += -- cgit v1.2.3-59-g8ed1b From 5b306bde2b46964d604924ec085d619ffc331e09 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:37 -0500 Subject: bnxt_en: Increase firmware response timeout for coredump commands. Use the larger HWRM_COREDUMP_TIMEOUT value for coredump related data response from the firmware. These commands take longer than normal commands. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 7a5f6bf1701c..c5cd8d802f02 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3040,7 +3040,8 @@ static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, int msg_len, mutex_lock(&bp->hwrm_cmd_lock); while (1) { *seq_ptr = cpu_to_le16(seq); - rc = _hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT); + rc = _hwrm_send_message(bp, msg, msg_len, + HWRM_COREDUMP_TIMEOUT); if (rc) break; -- cgit v1.2.3-59-g8ed1b From 0a3f4e4f342c070312d799f7998d2f916c502c6e Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:38 -0500 Subject: bnxt_en: Extend ETHTOOL_RESET to hot reset driver. If firmware supports hot reset, extend ETHTOOL_RESET to support hot reset driver which does not require a driver reload after ETHTOOL_RESET. The driver will go through the same coordinated reset sequence as a firmware initiated fatal/non-fatal reset. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 2 ++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 9 +++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0e5b5b853b2d..b081a555534b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -6947,6 +6947,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp) bp->flags |= BNXT_FLAG_ROCEV2_CAP; if (flags & FUNC_QCAPS_RESP_FLAGS_PCIE_STATS_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_PCIE_STATS_SUPPORTED; + if (flags & FUNC_QCAPS_RESP_FLAGS_HOT_RESET_CAPABLE) + bp->fw_cap |= BNXT_FW_CAP_HOT_RESET; if (flags & FUNC_QCAPS_RESP_FLAGS_EXT_STATS_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_EXT_STATS_SUPPORTED; if (flags & FUNC_QCAPS_RESP_FLAGS_ERROR_RECOVERY_CAPABLE) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index f2b5da702873..271085f7e481 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1671,6 +1671,7 @@ struct bnxt { #define BNXT_FW_CAP_PCIE_STATS_SUPPORTED 0x00020000 #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 + #define BNXT_FW_CAP_HOT_RESET 0x00200000 #define BNXT_NEW_RM(bp) ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM) u32 hwrm_spec_code; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index c5cd8d802f02..0641020b56d5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1787,6 +1787,8 @@ static int bnxt_firmware_reset(struct net_device *dev, case BNXT_FW_RESET_CHIP: req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_CHIP; req.selfrst_status = FW_RESET_REQ_SELFRST_STATUS_SELFRSTASAP; + if (bp->fw_cap & BNXT_FW_CAP_HOT_RESET) + req.flags = FW_RESET_REQ_FLAGS_RESET_GRACEFUL; break; case BNXT_FW_RESET_AP: req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_AP; @@ -2983,7 +2985,8 @@ static int bnxt_reset(struct net_device *dev, u32 *flags) return -EOPNOTSUPP; } - if (pci_vfs_assigned(bp->pdev)) { + if (pci_vfs_assigned(bp->pdev) && + !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) { netdev_err(dev, "Reset not allowed when VFs are assigned to VMs\n"); return -EBUSY; @@ -2996,7 +2999,9 @@ static int bnxt_reset(struct net_device *dev, u32 *flags) rc = bnxt_firmware_reset(dev, BNXT_FW_RESET_CHIP); if (!rc) { - netdev_info(dev, "Reset request successful. Reload driver to complete reset\n"); + netdev_info(dev, "Reset request successful.\n"); + if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) + netdev_info(dev, "Reload driver to complete reset\n"); *flags = 0; } } else if (*flags == ETH_RESET_AP) { -- cgit v1.2.3-59-g8ed1b From e633a32935a315b8e1f742622dcb254076a42352 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:39 -0500 Subject: bnxt_en: Set MASTER flag during driver registration. The Linux driver is capable of being the master function to handle resets, so we set the flag to let firmware know. Some other drivers, such as DPDK, is not capable and will not set the flag. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b081a555534b..178490cb4158 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4441,7 +4441,8 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp) flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE | FUNC_DRV_RGTR_REQ_FLAGS_HOT_RESET_SUPPORT; if (bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) - flags |= FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT; + flags |= FUNC_DRV_RGTR_REQ_FLAGS_ERROR_RECOVERY_SUPPORT | + FUNC_DRV_RGTR_REQ_FLAGS_MASTER_SUPPORT; req.flags = cpu_to_le32(flags); req.ver_maj_8b = DRV_VER_MAJ; req.ver_min_8b = DRV_VER_MIN; -- cgit v1.2.3-59-g8ed1b From e4e38237d7e39e84d4db4a5cf0aa1ce7fbfaa5d6 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:40 -0500 Subject: bnxt_en: Report health status update after reset is done Report health status update to devlink health reporter, once reset is completed. Cc: Jiri Pirko Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 21 +++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h | 1 + 4 files changed, 26 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 178490cb4158..a1683249e360 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10750,6 +10750,7 @@ static void bnxt_fw_reset_task(struct work_struct *work) smp_mb__before_atomic(); clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); bnxt_ulp_start(bp, rc); + bnxt_dl_health_status_update(bp, true); rtnl_unlock(); break; } @@ -10757,6 +10758,8 @@ static void bnxt_fw_reset_task(struct work_struct *work) fw_reset_abort: clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); + if (bp->fw_reset_state != BNXT_FW_RESET_STATE_POLL_VF) + bnxt_dl_health_status_update(bp, false); bp->fw_reset_state = 0; rtnl_lock(); dev_close(bp->dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 271085f7e481..37549cac3de6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1384,6 +1384,7 @@ struct bnxt_fw_health { u32 last_fw_reset_cnt; u8 enabled:1; u8 master:1; + u8 fatal:1; u8 tmr_multiplier; u8 tmr_counter; u8 fw_reset_seq_cnt; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index ae4ddf33fe5c..d85e439e9490 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -91,6 +91,7 @@ static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter, if (!priv_ctx) return -EOPNOTSUPP; + bp->fw_health->fatal = true; event = fw_reporter_ctx->sp_event; if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT) bnxt_fw_reset(bp); @@ -199,6 +200,26 @@ void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event) } } +void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy) +{ + struct bnxt_fw_health *health = bp->fw_health; + u8 state; + + if (healthy) + state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY; + else + state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; + + if (health->fatal) + devlink_health_reporter_state_update(health->fw_fatal_reporter, + state); + else + devlink_health_reporter_state_update(health->fw_reset_reporter, + state); + + health->fatal = false; +} + static const struct devlink_ops bnxt_dl_ops = { #ifdef CONFIG_BNXT_SRIOV .eswitch_mode_set = bnxt_dl_eswitch_mode_set, diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h index 2f4fd0a7d04b..665d4bdcd8c0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h @@ -57,6 +57,7 @@ struct bnxt_dl_nvm_param { }; void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event); +void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy); int bnxt_dl_register(struct bnxt *bp); void bnxt_dl_unregister(struct bnxt *bp); -- cgit v1.2.3-59-g8ed1b From 05069dd4c577f9b143dfd243d55834333c4470c5 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:41 -0500 Subject: bnxt_en: Return proper error code for non-existent NVM variable For NVM params that are not supported in the current NVM configuration, return the error as -EOPNOTSUPP. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index d85e439e9490..707827176231 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -335,10 +335,17 @@ static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, } else { rc = hwrm_send_message_silent(bp, msg, msg_len, HWRM_CMD_TIMEOUT); - if (!rc) + if (!rc) { bnxt_copy_from_nvm_data(val, data, nvm_param.nvm_num_bits, nvm_param.dl_num_bytes); + } else { + struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr; + + if (resp->cmd_err == + NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST) + rc = -EOPNOTSUPP; + } } dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr); if (rc == -EACCES) -- cgit v1.2.3-59-g8ed1b From a2b31e27f6269af8bbda4be2199c2af7c4dcb5a3 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 18 Nov 2019 03:56:42 -0500 Subject: bnxt_en: Add a warning message for driver initiated reset During loss of heartbeat, log this warning message. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a1683249e360..55e02a947765 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10122,6 +10122,7 @@ static void bnxt_force_fw_reset(struct bnxt *bp) void bnxt_fw_exception(struct bnxt *bp) { + netdev_warn(bp->dev, "Detected firmware fatal condition, initiating reset\n"); set_bit(BNXT_STATE_FW_FATAL_COND, &bp->state); bnxt_rtnl_lock_sp(bp); bnxt_force_fw_reset(bp); -- cgit v1.2.3-59-g8ed1b From 642aebdee4a1f53b713becb3b7df8896fbaeda33 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Mon, 18 Nov 2019 03:56:43 -0500 Subject: bnxt_en: Abort waiting for firmware response if there is no heartbeat. This is especially beneficial during the NVRAM related firmware commands that have longer timeouts. If the BNXT_STATE_FW_FATAL_COND flag gets set while waiting for firmware response, abort and return error. Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 55e02a947765..b20ab388e663 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4278,6 +4278,11 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, /* Wait until hwrm response cmpl interrupt is processed */ while (bp->hwrm_intr_seq_id != (u16)~seq_id && i++ < tmo_count) { + /* Abort the wait for completion if the FW health + * check has failed. + */ + if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) + return -EBUSY; /* on first few passes, just barely sleep */ if (i < HWRM_SHORT_TIMEOUT_COUNTER) usleep_range(HWRM_SHORT_MIN_TIMEOUT, @@ -4301,6 +4306,11 @@ static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len, /* Check if response len is updated */ for (i = 0; i < tmo_count; i++) { + /* Abort the wait for completion if the FW health + * check has failed. + */ + if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) + return -EBUSY; len = (le32_to_cpu(*resp_len) & HWRM_RESP_LEN_MASK) >> HWRM_RESP_LEN_SFT; if (len) -- cgit v1.2.3-59-g8ed1b From c21709e744b482baab544a893a3a1a9370d51850 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 18 Nov 2019 11:48:35 +0000 Subject: net: phy: dp83869: fix return of uninitialized variable ret In the case where the call to phy_interface_is_rgmii returns zero the variable ret is left uninitialized and this is returned at the end of the function dp83869_configure_rgmii. Fix this by returning 0 instead of the uninitialized value in ret. Addresses-Coverity: ("Uninitialized scalar variable") Fixes: 01db923e8377 ("net: phy: dp83869: Add TI dp83869 phy") Signed-off-by: Colin Ian King Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/dp83869.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index fcd418716c10..1c7a7c57dec3 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -239,7 +239,7 @@ static int dp83869_configure_rgmii(struct phy_device *phydev, dp83869->io_impedance & DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL); - return ret; + return 0; } static int dp83869_configure_mode(struct phy_device *phydev, -- cgit v1.2.3-59-g8ed1b From b8fc7177d8aef1cc9c83b98e29097861adc84b49 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 18 Nov 2019 20:16:57 +0200 Subject: net: dsa: felix: Fix CPU port assignment when not last port On the NXP LS1028A, there are 2 Ethernet links between the Felix switch and the ENETC: - eno2 <-> swp4, at 2.5G - eno3 <-> swp5, at 1G Only one of the above Ethernet port pairs can act as a DSA link for tagging. When adding initial support for the driver, it was tested only on the 1G eno3 <-> swp5 interface, due to the necessity of using PHYLIB initially (which treats fixed-link interfaces as emulated C22 PHYs, so it doesn't support fixed-link speeds higher than 1G). After making PHYLINK work, it appears that swp4 still can't act as CPU port. So it looks like ocelot_set_cpu_port was being called for swp4, but then it was called again for swp5, overwriting the CPU port assigned in the DT. It appears that when you call dsa_upstream_port for a port that is not defined in the device tree (such as swp5 when using swp4 as CPU port), its dp->cpu_dp pointer is not initialized by dsa_tree_setup_default_cpu, and this trips up the following condition in dsa_upstream_port: if (!cpu_dp) return port; So the moral of the story is: don't call dsa_upstream_port for a port that is not defined in the device tree, and therefore its dsa_port structure is not completely initialized (ds->num_ports is still 6). Fixes: 56051948773e ("net: dsa: ocelot: add driver for Felix switch family") Signed-off-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 05e3f2898bf6..ce3637b504dd 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -286,7 +286,7 @@ static int felix_setup(struct dsa_switch *ds) for (port = 0; port < ds->num_ports; port++) { ocelot_init_port(ocelot, port); - if (port == dsa_upstream_port(ds, port)) + if (dsa_is_cpu_port(ds, port)) ocelot_set_cpu_port(ocelot, port, OCELOT_TAG_PREFIX_NONE, OCELOT_TAG_PREFIX_LONG); -- cgit v1.2.3-59-g8ed1b From 272630feb4c0d274cc4f018c5dcc24bc94f685c7 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Tue, 19 Nov 2019 13:00:56 +0530 Subject: cxgb4: remove unneeded semicolon for switch block Semicolon is not required at the end of switch block. So, remove it. Addresses coccinelle warning: drivers/net/ethernet/chelsio/cxgb4/sge.c:2260:2-3: Unneeded semicolon Fixes: 4846d5330daf ("cxgb4: add Tx and Rx path for ETHOFLD traffic") Reported-by: kbuild test robot Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 09059adc3067..a0400b9a11e9 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2283,7 +2283,7 @@ static void ethofld_xmit(struct net_device *dev, struct sge_eosw_txq *eosw_txq) case CXGB4_EO_STATE_CLOSED: default: return; - }; + } while (pktcount--) { skb = eosw_txq_peek(eosw_txq); -- cgit v1.2.3-59-g8ed1b From 7af496b9eb0433bc4cb478c9a46f85509cdb5541 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Sat, 16 Nov 2019 15:22:47 +0800 Subject: brcmfmac: remove set but not used variable 'mpnum','nsp','nmp' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_get_regaddr: drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:790:5: warning: variable mpnum set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan: drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:10: warning: variable nsp set but not used [-Wunused-but-set-variable] drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan: drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:5: warning: variable nmp set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index dd586a96b57a..a795d781b4c5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -778,7 +778,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, { u8 desc; u32 val, szdesc; - u8 mpnum = 0; u8 stype, sztype, wraptype; *regbase = 0; @@ -786,7 +785,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); if (desc == DMP_DESC_MASTER_PORT) { - mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S; wraptype = DMP_SLAVE_TYPE_MWRAP; } else if (desc == DMP_DESC_ADDRESS) { /* revert erom address */ @@ -854,7 +852,7 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) u8 desc_type = 0; u32 val; u16 id; - u8 nmp, nsp, nmw, nsw, rev; + u8 nmw, nsw, rev; u32 base, wrap; int err; @@ -880,8 +878,6 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) return -EFAULT; /* only look at cores with master port(s) */ - nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S; - nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S; nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S; nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S; rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; -- cgit v1.2.3-59-g8ed1b From 805a57acd7b52e1ba0ad2649e33c585bba958633 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Sat, 16 Nov 2019 15:41:22 +0800 Subject: ipw2x00: remove set but not used variable 'reason' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/intel/ipw2x00/ipw2200.c: In function ipw_wx_set_mlme: drivers/net/wireless/intel/ipw2x00/ipw2200.c:6805:9: warning: variable reason set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/ipw2200.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index ed0f06532d5e..31e43fc1d12b 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -6788,9 +6788,6 @@ static int ipw_wx_set_mlme(struct net_device *dev, { struct ipw_priv *priv = libipw_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; - __le16 reason; - - reason = cpu_to_le16(mlme->reason_code); switch (mlme->cmd) { case IW_MLME_DEAUTH: -- cgit v1.2.3-59-g8ed1b From f89f1aefff5a53917579bbf8b85be09d7cc17daf Mon Sep 17 00:00:00 2001 From: zhengbin Date: Sat, 16 Nov 2019 15:41:23 +0800 Subject: ipw2x00: remove set but not used variable 'force_update' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/intel/ipw2x00/ipw2100.c: In function shim__set_security: drivers/net/wireless/intel/ipw2x00/ipw2100.c:5582:9: warning: variable force_update set but not used [-Wunused-but-set-variable] Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Kalle Valo --- drivers/net/wireless/intel/ipw2x00/ipw2100.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 8dfbaff2d1fe..c4c83ab60cbc 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -5565,7 +5565,7 @@ static void shim__set_security(struct net_device *dev, struct libipw_security *sec) { struct ipw2100_priv *priv = libipw_priv(dev); - int i, force_update = 0; + int i; mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) @@ -5605,7 +5605,6 @@ static void shim__set_security(struct net_device *dev, priv->ieee->sec.flags |= SEC_ENABLED; priv->ieee->sec.enabled = sec->enabled; priv->status |= STATUS_SECURITY_UPDATED; - force_update = 1; } if (sec->flags & SEC_ENCRYPT) -- cgit v1.2.3-59-g8ed1b From 92541dd9dda5ab474751e24cdb4253eb290b8b33 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 18 Nov 2019 11:14:54 +0800 Subject: rtlwifi: rf_lock use non-irqsave spin_lock rf_lock is used to protect RF register access, but they will not called from interrupt context, so *_irqsave version isn't necessary. Then, these delays don't affect IRQ services. The old code holds spin_lock_irqsave() that will be detected a long delay as below: kworker/-276 4d... 0us : _raw_spin_lock_irqsave kworker/-276 4d... 0us : rtl8723_phy_rf_serial_read <-rtl8723de_phy_set_rf_reg kworker/-276 4d... 1us : rtl8723_phy_query_bb_reg <-rtl8723_phy_rf_serial_read kworker/-276 4d... 3us : rtl8723_phy_set_bb_reg <-rtl8723_phy_rf_serial_read kworker/-276 4d... 4us : __const_udelay <-rtl8723_phy_rf_serial_read kworker/-276 4d... 4us!: delay_mwaitx <-rtl8723_phy_rf_serial_read kworker/-276 4d... 1004us : rtl8723_phy_set_bb_reg <-rtl8723_phy_rf_serial_read [...] Reported-by: Lucas Stach Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c | 10 ++++------ drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c | 10 ++++------ drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c | 10 ++++------ drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c | 10 ++++------ drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c | 10 ++++------ drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c | 10 ++++------ 6 files changed, 24 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c index 978e6a169654..01206651c7df 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c @@ -85,20 +85,19 @@ u32 rtl88e_phy_query_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl88e_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl88e_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", @@ -112,13 +111,12 @@ void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl88e_phy_rf_serial_read(hw, @@ -133,7 +131,7 @@ void rtl88e_phy_set_rf_reg(struct ieee80211_hw *hw, _rtl88e_phy_rf_serial_write(hw, rfpath, regaddr, data); - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c index 0ae6371b6318..4b672199c81d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c @@ -307,16 +307,15 @@ u32 rtl92d_phy_query_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl92d_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl92d_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", regaddr, rfpath, bitmask, original_value); @@ -329,14 +328,13 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath); if (bitmask == 0) return; - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (rtlphy->rf_mode != RF_OP_BY_FW) { if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl92d_phy_rf_serial_read(hw, @@ -347,7 +345,7 @@ void rtl92d_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, } _rtl92d_phy_rf_serial_write(hw, rfpath, regaddr, data); } - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index f03de8bdd2d1..75265b4fdf7e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -84,19 +84,18 @@ u32 rtl92ee_phy_query_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl92ee_phy_rf_serial_read(hw , rfpath, regaddr); bitshift = _rtl92ee_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x),rfpath(%#x),bitmask(%#x),original_value(%#x)\n", @@ -111,13 +110,12 @@ void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", addr, bitmask, data, rfpath); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (bitmask != RFREG_OFFSET_MASK) { original_value = _rtl92ee_phy_rf_serial_read(hw, rfpath, addr); @@ -127,7 +125,7 @@ void rtl92ee_phy_set_rf_reg(struct ieee80211_hw *hw, _rtl92ee_phy_rf_serial_write(hw, rfpath, addr, data); - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c index 1385e5a2e0b0..772aecedf0b4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c @@ -37,13 +37,12 @@ u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value = 0, readback_value, bitshift; struct rtl_phy *rtlphy = &rtlpriv->phy; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (rtlphy->rf_mode != RF_OP_BY_FW) { original_value = rtl8723_phy_rf_serial_read(hw, @@ -53,7 +52,7 @@ u32 rtl8723e_phy_query_rf_reg(struct ieee80211_hw *hw, bitshift = rtl8723_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", @@ -69,13 +68,12 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &rtlpriv->phy; u32 original_value = 0, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (rtlphy->rf_mode != RF_OP_BY_FW) { if (bitmask != RFREG_OFFSET_MASK) { @@ -99,7 +97,7 @@ void rtl8723e_phy_set_rf_reg(struct ieee80211_hw *hw, _rtl8723e_phy_fw_rf_serial_write(hw, rfpath, regaddr, data); } - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c index d48364460922..9528ac3f3b87 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/phy.c @@ -33,19 +33,18 @@ u32 rtl8723be_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = rtl8723_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = rtl8723_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", @@ -59,13 +58,12 @@ void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, path); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (bitmask != RFREG_OFFSET_MASK) { original_value = rtl8723_phy_rf_serial_read(hw, path, @@ -77,7 +75,7 @@ void rtl8723be_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path path, rtl8723_phy_rf_serial_write(hw, path, regaddr, data); - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c index c1a04efa69ea..b8a2b2326902 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c @@ -139,19 +139,18 @@ u32 rtl8821ae_phy_query_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n", regaddr, rfpath, bitmask); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); original_value = _rtl8821ae_phy_rf_serial_read(hw, rfpath, regaddr); bitshift = _rtl8821ae_phy_calculate_bit_shift(bitmask); readback_value = (original_value & bitmask) >> bitshift; - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n", @@ -166,13 +165,12 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw, { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, bitshift; - unsigned long flags; RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath); - spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags); + spin_lock(&rtlpriv->locks.rf_lock); if (bitmask != RFREG_OFFSET_MASK) { original_value = @@ -183,7 +181,7 @@ void rtl8821ae_phy_set_rf_reg(struct ieee80211_hw *hw, _rtl8821ae_phy_rf_serial_write(hw, rfpath, regaddr, data); - spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags); + spin_unlock(&rtlpriv->locks.rf_lock); RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n", -- cgit v1.2.3-59-g8ed1b From 4c8c0d8f709d16f418a5d1962b4eda86ff570151 Mon Sep 17 00:00:00 2001 From: Ping-Ke Shih Date: Mon, 18 Nov 2019 11:14:55 +0800 Subject: rtlwifi: set proper udelay within rf_serial_read Since read RF register is an indirect access that hardware needs time to accomplish read action, but there's no ready bit, so delay is required to guarantee the read value is correct. After investigating internal documents, these delays are reduced as proper values. Reported-by: Lucas Stach Signed-off-by: Ping-Ke Shih Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c | 4 ++-- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c | 3 +-- drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c | 4 +--- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c index 01206651c7df..5ca900f97d66 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c @@ -164,9 +164,9 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw, (newoffset << 23) | BLSSIREADEDGE; rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong & (~BLSSIREADEDGE)); - mdelay(1); + udelay(10); rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); - mdelay(2); + udelay(120); if (rfpath == RF90_PATH_A) rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c index 75265b4fdf7e..6dba576aa81e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c @@ -158,9 +158,8 @@ static u32 _rtl92ee_phy_rf_serial_read(struct ieee80211_hw *hw, (newoffset << 23) | BLSSIREADEDGE; rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong & (~BLSSIREADEDGE)); - mdelay(1); rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); - mdelay(2); + udelay(20); if (rfpath == RF90_PATH_A) rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c index aae14c68bf69..debecc623a01 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c @@ -89,12 +89,10 @@ u32 rtl8723_phy_rf_serial_read(struct ieee80211_hw *hw, (newoffset << 23) | BLSSIREADEDGE; rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong & (~BLSSIREADEDGE)); - mdelay(1); rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2); - mdelay(1); rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong | BLSSIREADEDGE); - mdelay(1); + udelay(120); if (rfpath == RF90_PATH_A) rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); -- cgit v1.2.3-59-g8ed1b From 45028223425dc37d3452da7e9bd01f7789024ee7 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 18 Nov 2019 08:23:04 +0000 Subject: qtnfmac: remove VIF in firmware in case of error Currently in case of error when registering network device with the kernel, we won't properly cleanup VIF state in firmware due to DEL_VIF command will not be send to wifi card. Make sure it does. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 8 +++----- drivers/net/wireless/quantenna/qtnfmac/core.c | 19 +++++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index aa0ed0f2b973..4f02159a69db 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -238,22 +238,20 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, pr_err("VIF%u.%u: FW reported bad MAC: %pM\n", mac->macid, vif->vifid, vif->mac_addr); ret = -EINVAL; - goto err_mac; + goto error_del_vif; } ret = qtnf_core_net_attach(mac, vif, name, name_assign_t); if (ret) { pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid, vif->vifid); - goto err_net; + goto error_del_vif; } vif->wdev.netdev = vif->netdev; return &vif->wdev; -err_net: - vif->netdev = NULL; -err_mac: +error_del_vif: qtnf_cmd_send_del_intf(vif); err_cmd: vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 8116b224c946..9ccc17ad1176 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -465,10 +465,8 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, dev = alloc_netdev_mqs(sizeof(struct qtnf_vif *), name, name_assign_type, ether_setup, 1, 1); - if (!dev) { - vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + if (!dev) return -ENOMEM; - } vif->netdev = dev; @@ -491,7 +489,7 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, ret = register_netdevice(dev); if (ret) { free_netdev(dev); - vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; + vif->netdev = NULL; } return ret; @@ -588,19 +586,19 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) ret = qtnf_cmd_send_get_phy_params(mac); if (ret) { pr_err("MAC%u: failed to get PHY settings\n", macid); - goto error; + goto error_del_vif; } ret = qtnf_mac_init_bands(mac); if (ret) { pr_err("MAC%u: failed to init bands\n", macid); - goto error; + goto error_del_vif; } ret = qtnf_wiphy_register(&bus->hw_info, mac); if (ret) { pr_err("MAC%u: wiphy registration failed\n", macid); - goto error; + goto error_del_vif; } mac->wiphy_registered = 1; @@ -612,15 +610,16 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) if (ret) { pr_err("MAC%u: failed to attach netdev\n", macid); - vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; - vif->netdev = NULL; - goto error; + goto error_del_vif; } pr_debug("MAC%u initialized\n", macid); return 0; +error_del_vif: + qtnf_cmd_send_del_intf(vif); + vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; error: qtnf_core_mac_detach(bus, macid); return ret; -- cgit v1.2.3-59-g8ed1b From decfc5c70d206fdfba5de8405eb9148de6d7897b Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 18 Nov 2019 08:23:06 +0000 Subject: qtnfmac: track broadcast domain of each interface If firmware reports that it supports hardware switch capabilities, driver needs to track and notify device whenever broadcast domain of a particular network device changes (ie. whenever it's upper master device changes). Firmware needs a unique ID to tell broadcast domains from each other which is an opaque number otherwise. For that purpose we can use netspace:ifidx pair to uniquely identify each broadcast domain: - if netdev is not part of a bridge, then use it's own ifidx as a broadcast domain ID - if netdev is part of a bridge, then use bridge netdev ifidx as broadcast domain ID Firmware makes sure that packets are only forwarded between interfaces marked with the same broadcast domain ID. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 1 + drivers/net/wireless/quantenna/qtnfmac/cfg80211.c | 9 ++++ drivers/net/wireless/quantenna/qtnfmac/commands.c | 32 ++++++++++++ drivers/net/wireless/quantenna/qtnfmac/commands.h | 1 + drivers/net/wireless/quantenna/qtnfmac/core.c | 64 +++++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/core.h | 1 + drivers/net/wireless/quantenna/qtnfmac/qlink.h | 41 +++++++++++++++ 7 files changed, 149 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 7cea08f71838..4c6eca344a09 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -54,6 +54,7 @@ struct qtnf_bus { struct work_struct event_work; struct mutex bus_lock; /* lock during command/event processing */ struct dentry *dbg_dir; + struct notifier_block netdev_nb; /* bus private data */ char bus_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 4f02159a69db..59d089e092f9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -248,6 +248,15 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy, goto error_del_vif; } + if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) { + ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex); + if (ret) { + unregister_netdevice(vif->netdev); + vif->netdev = NULL; + goto error_del_vif; + } + } + vif->wdev.netdev = vif->netdev; return &vif->wdev; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 61bda34e2ac2..cbc56464220e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -2756,3 +2756,35 @@ out: qtnf_bus_unlock(bus); return ret; } + +int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain) +{ + struct qtnf_bus *bus = vif->mac->bus; + struct sk_buff *cmd_skb; + struct qlink_cmd_ndev_changeupper *cmd; + int ret; + + cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, + QLINK_CMD_NDEV_EVENT, + sizeof(*cmd)); + if (!cmd_skb) + return -ENOMEM; + + pr_debug("[VIF%u.%u] set broadcast domain to %d\n", + vif->mac->macid, vif->vifid, br_domain); + + cmd = (struct qlink_cmd_ndev_changeupper *)cmd_skb->data; + cmd->nehdr.event = cpu_to_le16(QLINK_NDEV_EVENT_CHANGEUPPER); + cmd->upper_type = QLINK_NDEV_UPPER_TYPE_BRIDGE; + cmd->br_domain = cpu_to_le32(br_domain); + + qtnf_bus_lock(bus); + ret = qtnf_cmd_send(bus, cmd_skb); + qtnf_bus_unlock(bus); + + if (ret) + pr_err("[VIF%u.%u] failed to set broadcast domain\n", + vif->mac->macid, vif->vifid); + + return ret; +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.h b/drivers/net/wireless/quantenna/qtnfmac/commands.h index e0de65261213..761755bf9ede 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.h +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.h @@ -75,5 +75,6 @@ int qtnf_cmd_set_tx_power(const struct qtnf_vif *vif, enum nl80211_tx_power_setting type, int mbm); int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif, const struct cfg80211_wowlan *wowl); +int qtnf_cmd_netdev_changeupper(const struct qtnf_vif *vif, int br_domain); #endif /* QLINK_COMMANDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 9ccc17ad1176..3ba19a966c7f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -613,6 +613,12 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) goto error_del_vif; } + if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) { + ret = qtnf_cmd_netdev_changeupper(vif, vif->netdev->ifindex); + if (ret) + goto error; + } + pr_debug("MAC%u initialized\n", macid); return 0; @@ -625,6 +631,54 @@ error: return ret; } +bool qtnf_netdev_is_qtn(const struct net_device *ndev) +{ + return ndev->netdev_ops == &qtnf_netdev_ops; +} + +static int qtnf_core_netdevice_event(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + const struct netdev_notifier_changeupper_info *info; + struct qtnf_vif *vif; + int br_domain; + int ret = 0; + + if (!qtnf_netdev_is_qtn(ndev)) + return NOTIFY_DONE; + + if (!net_eq(dev_net(ndev), &init_net)) + return NOTIFY_OK; + + vif = qtnf_netdev_get_priv(ndev); + + switch (event) { + case NETDEV_CHANGEUPPER: + info = ptr; + + if (!netif_is_bridge_master(info->upper_dev)) + break; + + pr_debug("[VIF%u.%u] change bridge: %s %s\n", + vif->mac->macid, vif->vifid, + netdev_name(info->upper_dev), + info->linking ? "add" : "del"); + + if (info->linking) + br_domain = info->upper_dev->ifindex; + else + br_domain = ndev->ifindex; + + ret = qtnf_cmd_netdev_changeupper(vif, br_domain); + break; + default: + break; + } + + return notifier_from_errno(ret); +} + int qtnf_core_attach(struct qtnf_bus *bus) { unsigned int i; @@ -685,6 +739,15 @@ int qtnf_core_attach(struct qtnf_bus *bus) } } + if (bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) { + bus->netdev_nb.notifier_call = qtnf_core_netdevice_event; + ret = register_netdevice_notifier(&bus->netdev_nb); + if (ret) { + pr_err("failed to register netdev notifier: %d\n", ret); + goto error; + } + } + bus->fw_state = QTNF_FW_STATE_RUNNING; return 0; @@ -698,6 +761,7 @@ void qtnf_core_detach(struct qtnf_bus *bus) { unsigned int macid; + unregister_netdevice_notifier(&bus->netdev_nb); qtnf_bus_data_rx_stop(bus); for (macid = 0; macid < QTNF_MAX_MAC; macid++) diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index e3feea31191e..75b70f0c2b8e 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -153,6 +153,7 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev); void qtnf_netdev_updown(struct net_device *ndev, bool up); void qtnf_scan_done(struct qtnf_wmac *mac, bool aborted); struct dentry *qtnf_get_debugfs_dir(void); +bool qtnf_netdev_is_qtn(const struct net_device *ndev); static inline struct qtnf_vif *qtnf_netdev_get_priv(struct net_device *dev) { diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 59c69c0a6e06..18b2ddf39ef8 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -59,6 +59,7 @@ struct qlink_msg_header { * @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address * Randomization in probe requests. * @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning. + * @QLINK_HW_CAPAB_HW_BRIDGE: device has hardware switch capabilities. */ enum qlink_hw_capab { QLINK_HW_CAPAB_REG_UPDATE = BIT(0), @@ -69,6 +70,7 @@ enum qlink_hw_capab { QLINK_HW_CAPAB_OBSS_SCAN = BIT(5), QLINK_HW_CAPAB_SCAN_DWELL = BIT(6), QLINK_HW_CAPAB_SAE = BIT(8), + QLINK_HW_CAPAB_HW_BRIDGE = BIT(9), }; enum qlink_iface_type { @@ -219,6 +221,8 @@ struct qlink_sta_info_state { * @QLINK_CMD_START_CAC: start radar detection procedure on a specified channel. * @QLINK_CMD_TXPWR: get or set current channel transmit power for * the specified MAC. + * @QLINK_CMD_NDEV_EVENT: signalizes changes made with a corresponding network + * device. */ enum qlink_cmd_type { QLINK_CMD_FW_INIT = 0x0001, @@ -251,6 +255,7 @@ enum qlink_cmd_type { QLINK_CMD_DEL_STA = 0x0052, QLINK_CMD_SCAN = 0x0053, QLINK_CMD_CHAN_STATS = 0x0054, + QLINK_CMD_NDEV_EVENT = 0x0055, QLINK_CMD_CONNECT = 0x0060, QLINK_CMD_DISCONNECT = 0x0061, QLINK_CMD_PM_SET = 0x0062, @@ -771,6 +776,42 @@ struct qlink_cmd_wowlan_set { u8 data[0]; } __packed; +enum qlink_ndev_event_type { + QLINK_NDEV_EVENT_CHANGEUPPER, +}; + +/** + * struct qlink_cmd_ndev_event - data for QLINK_CMD_NDEV_EVENT command + * + * @event: type of event, one of &enum qlink_ndev_event_type + */ +struct qlink_cmd_ndev_event { + struct qlink_cmd chdr; + __le16 event; + u8 rsvd[2]; +} __packed; + +enum qlink_ndev_upper_type { + QLINK_NDEV_UPPER_TYPE_NONE, + QLINK_NDEV_UPPER_TYPE_BRIDGE, +}; + +/** + * struct qlink_cmd_ndev_changeupper - data for QLINK_NDEV_EVENT_CHANGEUPPER + * + * @br_domain: layer 2 broadcast domain ID that ndev is a member of + * @upper_type: type of upper device, one of &enum qlink_ndev_upper_type + */ +struct qlink_cmd_ndev_changeupper { + struct qlink_cmd_ndev_event nehdr; + __le64 flags; + __le32 br_domain; + __le32 netspace_id; + __le16 vlanid; + u8 upper_type; + u8 rsvd[1]; +} __packed; + /* QLINK Command Responses messages related definitions */ -- cgit v1.2.3-59-g8ed1b From 904628d3130b5aef0c9b06efa80e5a96f203e000 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 18 Nov 2019 08:23:08 +0000 Subject: qtnfmac: add interface ID to each packet Add interface ID information to the tail of each transmitted packet so that firmware can know to which interface the packet belongs to. This is only needed if device supports HW switch capability. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 21 ++++++++-- drivers/net/wireless/quantenna/qtnfmac/core.c | 19 ++++----- .../wireless/quantenna/qtnfmac/pcie/pearl_pcie.c | 47 ++++++++++++++++++++-- .../wireless/quantenna/qtnfmac/pcie/topaz_pcie.c | 5 ++- 4 files changed, 74 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 4c6eca344a09..49372d42e471 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -12,6 +12,16 @@ #define QTNF_MAX_MAC 3 +#define HBM_FRAME_META_MAGIC_PATTERN_S 0xAB +#define HBM_FRAME_META_MAGIC_PATTERN_E 0xBA + +struct qtnf_frame_meta_info { + u8 magic_s; + u8 ifidx; + u8 macid; + u8 magic_e; +} __packed; + enum qtnf_fw_state { QTNF_FW_STATE_DETACHED, QTNF_FW_STATE_BOOT_DONE, @@ -31,8 +41,10 @@ struct qtnf_bus_ops { int (*control_tx)(struct qtnf_bus *, struct sk_buff *); /* data xfer methods */ - int (*data_tx)(struct qtnf_bus *, struct sk_buff *); + int (*data_tx)(struct qtnf_bus *bus, struct sk_buff *skb, + unsigned int macid, unsigned int vifid); void (*data_tx_timeout)(struct qtnf_bus *, struct net_device *); + void (*data_tx_use_meta_set)(struct qtnf_bus *bus, bool use_meta); void (*data_rx_start)(struct qtnf_bus *); void (*data_rx_stop)(struct qtnf_bus *); }; @@ -42,7 +54,7 @@ struct qtnf_bus { enum qtnf_fw_state fw_state; u32 chip; u32 chiprev; - const struct qtnf_bus_ops *bus_ops; + struct qtnf_bus_ops *bus_ops; struct qtnf_wmac *mac[QTNF_MAX_MAC]; struct qtnf_qlink_transport trans; struct qtnf_hw_info hw_info; @@ -100,9 +112,10 @@ static inline void qtnf_bus_stop(struct qtnf_bus *bus) bus->bus_ops->stop(bus); } -static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +static inline int qtnf_bus_data_tx(struct qtnf_bus *bus, struct sk_buff *skb, + unsigned int macid, unsigned int vifid) { - return bus->bus_ops->data_tx(bus, skb); + return bus->bus_ops->data_tx(bus, skb, macid, vifid); } static inline void diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 3ba19a966c7f..7300ab407cd6 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -22,13 +22,6 @@ MODULE_PARM_DESC(slave_radar, "set 0 to disable radar detection in slave mode"); static struct dentry *qtnf_debugfs_dir; -struct qtnf_frame_meta_info { - u8 magic_s; - u8 ifidx; - u8 macid; - u8 magic_e; -} __packed; - struct qtnf_wmac *qtnf_core_get_mac(const struct qtnf_bus *bus, u8 macid) { struct qtnf_wmac *mac = NULL; @@ -121,7 +114,7 @@ qtnf_netdev_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) return NETDEV_TX_OK; } - return qtnf_bus_data_tx(mac->bus, skb); + return qtnf_bus_data_tx(mac->bus, skb, mac->macid, vif->vifid); } /* Netdev handler for getting stats. @@ -481,6 +474,9 @@ int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *vif, dev->tx_queue_len = 100; dev->ethtool_ops = &qtnf_ethtool_ops; + if (mac->bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) + dev->needed_tailroom = sizeof(struct qtnf_frame_meta_info); + qdev_vif = netdev_priv(dev); *((void **)qdev_vif) = vif; @@ -723,6 +719,10 @@ int qtnf_core_attach(struct qtnf_bus *bus) goto error; } + if ((bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE) && + bus->bus_ops->data_tx_use_meta_set) + bus->bus_ops->data_tx_use_meta_set(bus, true); + if (bus->hw_info.num_mac > QTNF_MAX_MAC) { pr_err("no support for number of MACs=%u\n", bus->hw_info.num_mac); @@ -790,7 +790,8 @@ EXPORT_SYMBOL_GPL(qtnf_core_detach); static inline int qtnf_is_frame_meta_magic_valid(struct qtnf_frame_meta_info *m) { - return m->magic_s == 0xAB && m->magic_e == 0xBA; + return m->magic_s == HBM_FRAME_META_MAGIC_PATTERN_S && + m->magic_e == HBM_FRAME_META_MAGIC_PATTERN_E; } struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb) diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c index a501a1fd5332..8e0d8018208a 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -532,7 +532,7 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps) return 1; } -static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +static int qtnf_pcie_skb_send(struct qtnf_bus *bus, struct sk_buff *skb) { struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; @@ -608,6 +608,38 @@ tx_done: return NETDEV_TX_OK; } +static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb, + unsigned int macid, unsigned int vifid) +{ + return qtnf_pcie_skb_send(bus, skb); +} + +static int qtnf_pcie_data_tx_meta(struct qtnf_bus *bus, struct sk_buff *skb, + unsigned int macid, unsigned int vifid) +{ + struct qtnf_frame_meta_info *meta; + int tail_need = sizeof(*meta) - skb_tailroom(skb); + int ret; + + if (tail_need > 0 && pskb_expand_head(skb, 0, tail_need, GFP_ATOMIC)) { + skb->dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + meta = skb_put(skb, sizeof(*meta)); + meta->magic_s = HBM_FRAME_META_MAGIC_PATTERN_S; + meta->magic_e = HBM_FRAME_META_MAGIC_PATTERN_E; + meta->macid = macid; + meta->ifidx = vifid; + + ret = qtnf_pcie_skb_send(bus, skb); + if (unlikely(ret == NETDEV_TX_BUSY)) + __skb_trim(skb, skb->len - sizeof(*meta)); + + return ret; +} + static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; @@ -796,13 +828,22 @@ static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) qtnf_disable_hdp_irqs(ps); } -static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = { +static void qtnf_pearl_tx_use_meta_info_set(struct qtnf_bus *bus, bool use_meta) +{ + if (use_meta) + bus->bus_ops->data_tx = qtnf_pcie_data_tx_meta; + else + bus->bus_ops->data_tx = qtnf_pcie_data_tx; +} + +static struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = { /* control path methods */ .control_tx = qtnf_pcie_control_tx, /* data path methods */ .data_tx = qtnf_pcie_data_tx, .data_tx_timeout = qtnf_pcie_data_tx_timeout, + .data_tx_use_meta_set = qtnf_pearl_tx_use_meta_info_set, .data_rx_start = qtnf_pcie_data_rx_start, .data_rx_stop = qtnf_pcie_data_rx_stop, }; @@ -905,7 +946,7 @@ static int qtnf_ep_fw_send(struct pci_dev *pdev, uint32_t size, memcpy(pdata, pblk, len); hdr->crc = cpu_to_le32(~crc32(0, pdata, len)); - ret = qtnf_pcie_data_tx(bus, skb); + ret = qtnf_pcie_skb_send(bus, skb); return (ret == NETDEV_TX_OK) ? len : 0; } diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c index a0587472736f..dbf3c5fd751f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/topaz_pcie.c @@ -497,7 +497,8 @@ static int qtnf_tx_queue_ready(struct qtnf_pcie_topaz_state *ts) return 1; } -static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb, + unsigned int macid, unsigned int vifid) { struct qtnf_pcie_topaz_state *ts = (void *)get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ts->base; @@ -740,7 +741,7 @@ static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) napi_disable(&bus->mux_napi); } -static const struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = { +static struct qtnf_bus_ops qtnf_pcie_topaz_bus_ops = { /* control path methods */ .control_tx = qtnf_pcie_control_tx, -- cgit v1.2.3-59-g8ed1b From 4e14e76cee382619766176095ac0c10651980b66 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 18 Nov 2019 08:23:10 +0000 Subject: qtnfmac: advertise netdev port parent ID Use MAC address of the first active radio as a unique device ID. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/bus.h | 1 + drivers/net/wireless/quantenna/qtnfmac/commands.c | 5 +---- drivers/net/wireless/quantenna/qtnfmac/core.c | 20 ++++++++++++++++++++ drivers/net/wireless/quantenna/qtnfmac/core.h | 1 - 4 files changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 49372d42e471..87d048df09d1 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -67,6 +67,7 @@ struct qtnf_bus { struct mutex bus_lock; /* lock during command/event processing */ struct dentry *dbg_dir; struct notifier_block netdev_nb; + u8 hw_id[ETH_ALEN]; /* bus private data */ char bus_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index cbc56464220e..1c1b377932cf 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -1242,10 +1242,7 @@ qtnf_cmd_resp_proc_mac_info(struct qtnf_wmac *mac, mac_info = &mac->macinfo; mac_info->bands_cap = resp_info->bands_cap; - memcpy(&mac_info->dev_mac, &resp_info->dev_mac, - sizeof(mac_info->dev_mac)); - - ether_addr_copy(mac->macaddr, mac_info->dev_mac); + ether_addr_copy(mac->macaddr, resp_info->dev_mac); vif = qtnf_mac_get_base_vif(mac); if (vif) diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 7300ab407cd6..a709e378928d 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -204,6 +204,21 @@ static int qtnf_netdev_set_mac_address(struct net_device *ndev, void *addr) return ret; } +static int qtnf_netdev_port_parent_id(struct net_device *ndev, + struct netdev_phys_item_id *ppid) +{ + const struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev); + const struct qtnf_bus *bus = vif->mac->bus; + + if (!(bus->hw_info.hw_capab & QLINK_HW_CAPAB_HW_BRIDGE)) + return -EOPNOTSUPP; + + ppid->id_len = sizeof(bus->hw_id); + memcpy(&ppid->id, bus->hw_id, ppid->id_len); + + return 0; +} + /* Network device ops handlers */ const struct net_device_ops qtnf_netdev_ops = { .ndo_open = qtnf_netdev_open, @@ -212,6 +227,7 @@ const struct net_device_ops qtnf_netdev_ops = { .ndo_tx_timeout = qtnf_netdev_tx_timeout, .ndo_get_stats64 = qtnf_netdev_get_stats64, .ndo_set_mac_address = qtnf_netdev_set_mac_address, + .ndo_get_port_parent_id = qtnf_netdev_port_parent_id, }; static int qtnf_mac_init_single_band(struct wiphy *wiphy, @@ -565,6 +581,10 @@ static int qtnf_core_mac_attach(struct qtnf_bus *bus, unsigned int macid) goto error; } + /* Use MAC address of the first active radio as a unique device ID */ + if (is_zero_ether_addr(mac->bus->hw_id)) + ether_addr_copy(mac->bus->hw_id, mac->macaddr); + vif = qtnf_mac_get_base_vif(mac); if (!vif) { pr_err("MAC%u: primary VIF is not ready\n", macid); diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index 75b70f0c2b8e..116ec16aa15b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -74,7 +74,6 @@ struct qtnf_vif { struct qtnf_mac_info { u8 bands_cap; - u8 dev_mac[ETH_ALEN]; u8 num_tx_chain; u8 num_rx_chain; u16 max_ap_assoc_sta; -- cgit v1.2.3-59-g8ed1b From 1db359946bd1602dd7a70ca461c7cfb3835ab270 Mon Sep 17 00:00:00 2001 From: Igor Mitsyanko Date: Mon, 18 Nov 2019 08:23:12 +0000 Subject: qtnfmac: signal that all packets coming from device are already flooded Firmware floods all packets that need to be flooded (multicast, broadcast, unknown unicast) as required. Tell kernel bridge subsystem it does not need to flood packet itself by marking each incoming frame with skb->offload_fwd_mark flag. Signed-off-by: Igor Mitsyanko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/core.c | 3 +++ drivers/net/wireless/quantenna/qtnfmac/switchdev.h | 24 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 drivers/net/wireless/quantenna/qtnfmac/switchdev.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index a709e378928d..f5aa2c547b94 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -12,6 +12,7 @@ #include "cfg80211.h" #include "event.h" #include "util.h" +#include "switchdev.h" #define QTNF_DMP_MAX_LEN 48 #define QTNF_PRIMARY_VIF_IDX 0 @@ -866,6 +867,8 @@ struct net_device *qtnf_classify_skb(struct qtnf_bus *bus, struct sk_buff *skb) } __skb_trim(skb, skb->len - sizeof(*meta)); + /* Firmware always handles packets that require flooding */ + qtnfmac_switch_mark_skb_flooded(skb); out: return ndev; diff --git a/drivers/net/wireless/quantenna/qtnfmac/switchdev.h b/drivers/net/wireless/quantenna/qtnfmac/switchdev.h new file mode 100644 index 000000000000..b962e670c4b0 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/switchdev.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2019 Quantenna Communications. All rights reserved. */ + +#ifndef QTNFMAC_SWITCHDEV_H_ +#define QTNFMAC_SWITCHDEV_H_ + +#include + +#ifdef CONFIG_NET_SWITCHDEV + +static inline void qtnfmac_switch_mark_skb_flooded(struct sk_buff *skb) +{ + skb->offload_fwd_mark = 1; +} + +#else + +static inline void qtnfmac_switch_mark_skb_flooded(struct sk_buff *skb) +{ +} + +#endif + +#endif /* QTNFMAC_SWITCHDEV_H_ */ -- cgit v1.2.3-59-g8ed1b From be4f00cf15925903138577263bfc2366183a0704 Mon Sep 17 00:00:00 2001 From: Mikhail Karpenko Date: Mon, 18 Nov 2019 08:23:14 +0000 Subject: qtnfmac: add TLV for extension IEs Extension information elements have additional field for ID. This commit adds TLV for such elements and a structure for interface HE capabilities communication with firmware. Signed-off-by: Mikhail Karpenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/qlink.h | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 18b2ddf39ef8..75527f1bb306 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -1269,6 +1269,7 @@ struct qlink_event_mic_failure { * @QTN_TLV_ID_SCAN_SAMPLE_DURATION: total duration of sampling a single channel * during a scan including off-channel dwell time and operating channel * time. + * @QTN_TLV_ID_IFTYPE_DATA: supported band data. */ enum qlink_tlv_id { QTN_TLV_ID_FRAG_THRESH = 0x0201, @@ -1304,6 +1305,7 @@ enum qlink_tlv_id { QTN_TLV_ID_SCAN_DWELL_ACTIVE = 0x0413, QTN_TLV_ID_SCAN_DWELL_PASSIVE = 0x0416, QTN_TLV_ID_SCAN_SAMPLE_DURATION = 0x0417, + QTN_TLV_ID_IFTYPE_DATA = 0x0418, }; struct qlink_tlv_hdr { @@ -1465,6 +1467,39 @@ struct qlink_tlv_ie_set { u8 ie_data[0]; } __packed; +/** + * struct qlink_tlv_ext_ie - extension IE + * + * @eid_ext: element ID extension, one of &enum ieee80211_eid_ext. + * @ie_data: IEs data. + */ +struct qlink_tlv_ext_ie { + struct qlink_tlv_hdr hdr; + u8 eid_ext; + u8 ie_data[0]; +} __packed; + +#define IEEE80211_HE_PPE_THRES_MAX_LEN 25 +struct qlink_sband_iftype_data { + __le16 types_mask; + struct ieee80211_he_cap_elem he_cap_elem; + struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp; + u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN]; +} __packed; + +/** + * struct qlink_tlv_iftype_data - data for QTN_TLV_ID_IFTYPE_DATA + * + * @n_iftype_data: number of entries in iftype_data. + * @iftype_data: interface type data entries. + */ +struct qlink_tlv_iftype_data { + struct qlink_tlv_hdr hdr; + u8 n_iftype_data; + u8 rsvd[3]; + struct qlink_sband_iftype_data iftype_data[0]; +} __packed; + struct qlink_chan_stats { __le32 chan_num; __le32 cca_tx; -- cgit v1.2.3-59-g8ed1b From df0af4c7bac47039c97682fbf2c1cbe6efb08950 Mon Sep 17 00:00:00 2001 From: Mikhail Karpenko Date: Mon, 18 Nov 2019 08:23:16 +0000 Subject: qtnfmac: process HE capabilities requests Pass HE interface type data requests between firmware and driver. Signed-off-by: Mikhail Karpenko Signed-off-by: Kalle Valo --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 90 ++++++++++++++++++++++- drivers/net/wireless/quantenna/qtnfmac/core.c | 3 + 2 files changed, 92 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 1c1b377932cf..548f6ff6d0f2 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -214,6 +214,20 @@ static bool qtnf_cmd_start_ap_can_fit(const struct qtnf_vif *vif, return true; } +static void qtnf_cmd_tlv_ie_ext_add(struct sk_buff *cmd_skb, u8 eid_ext, + const void *buf, size_t len) +{ + struct qlink_tlv_ext_ie *tlv; + + tlv = (struct qlink_tlv_ext_ie *)skb_put(cmd_skb, sizeof(*tlv) + len); + tlv->hdr.type = cpu_to_le16(WLAN_EID_EXTENSION); + tlv->hdr.len = cpu_to_le16(sizeof(*tlv) + len - sizeof(tlv->hdr)); + tlv->eid_ext = eid_ext; + + if (len && buf) + memcpy(tlv->ie_data, buf, len); +} + int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, const struct cfg80211_ap_settings *s) { @@ -309,6 +323,10 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, memcpy(tlv->val, s->vht_cap, sizeof(*s->vht_cap)); } + if (s->he_cap) + qtnf_cmd_tlv_ie_ext_add(cmd_skb, WLAN_EID_EXT_HE_CAPABILITY, + s->he_cap, sizeof(*s->he_cap)); + if (s->acl) { size_t acl_size = struct_size(s->acl, mac_addrs, s->acl->n_acl_entries); @@ -1292,6 +1310,69 @@ static void qtnf_cmd_resp_band_fill_vhtcap(const u8 *info, memcpy(&bcap->vht_mcs, &vht_cap->supp_mcs, sizeof(bcap->vht_mcs)); } +static void qtnf_cmd_conv_iftype(struct ieee80211_sband_iftype_data + *iftype_data, + const struct qlink_sband_iftype_data + *qlink_data) +{ + iftype_data->types_mask = le16_to_cpu(qlink_data->types_mask); + + iftype_data->he_cap.has_he = true; + memcpy(&iftype_data->he_cap.he_cap_elem, &qlink_data->he_cap_elem, + sizeof(qlink_data->he_cap_elem)); + memcpy(iftype_data->he_cap.ppe_thres, qlink_data->ppe_thres, + ARRAY_SIZE(qlink_data->ppe_thres)); + + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80 = + qlink_data->he_mcs_nss_supp.rx_mcs_80; + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 = + qlink_data->he_mcs_nss_supp.tx_mcs_80; + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_160 = + qlink_data->he_mcs_nss_supp.rx_mcs_160; + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 = + qlink_data->he_mcs_nss_supp.tx_mcs_160; + iftype_data->he_cap.he_mcs_nss_supp.rx_mcs_80p80 = + qlink_data->he_mcs_nss_supp.rx_mcs_80p80; + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 = + qlink_data->he_mcs_nss_supp.tx_mcs_80p80; +} + +static int qtnf_cmd_band_fill_iftype(const u8 *data, + struct ieee80211_supported_band *band) +{ + unsigned int i; + struct ieee80211_sband_iftype_data *iftype_data; + const struct qlink_tlv_iftype_data *tlv = + (const struct qlink_tlv_iftype_data *)data; + size_t payload_len = tlv->n_iftype_data * sizeof(*tlv->iftype_data) + + sizeof(*tlv) - + sizeof(struct qlink_tlv_hdr); + + if (tlv->hdr.len != cpu_to_le16(payload_len)) { + pr_err("bad IFTYPE_DATA TLV len %u\n", tlv->hdr.len); + return -EINVAL; + } + + kfree(band->iftype_data); + band->iftype_data = NULL; + band->n_iftype_data = tlv->n_iftype_data; + if (band->n_iftype_data == 0) + return 0; + + iftype_data = kcalloc(band->n_iftype_data, sizeof(*iftype_data), + GFP_KERNEL); + if (!iftype_data) { + band->n_iftype_data = 0; + return -ENOMEM; + } + band->iftype_data = iftype_data; + + for (i = 0; i < band->n_iftype_data; i++) + qtnf_cmd_conv_iftype(iftype_data++, &tlv->iftype_data[i]); + + return 0; +} + static int qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band, struct qlink_resp_band_info_get *resp, @@ -1305,6 +1386,7 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band, struct ieee80211_channel *chan; unsigned int chidx = 0; u32 qflags; + int ret = -EINVAL; memset(&band->ht_cap, 0, sizeof(band->ht_cap)); memset(&band->vht_cap, 0, sizeof(band->vht_cap)); @@ -1442,6 +1524,12 @@ qtnf_cmd_resp_fill_band_info(struct ieee80211_supported_band *band, qtnf_cmd_resp_band_fill_vhtcap(tlv->val, &band->vht_cap); break; + case QTN_TLV_ID_IFTYPE_DATA: + ret = qtnf_cmd_band_fill_iftype((const uint8_t *)tlv, + band); + if (ret) + goto error_ret; + break; default: pr_warn("unknown TLV type: %#x\n", tlv_type); break; @@ -1469,7 +1557,7 @@ error_ret: band->channels = NULL; band->n_channels = 0; - return -EINVAL; + return ret; } static int qtnf_cmd_resp_proc_phy_params(struct qtnf_wmac *mac, diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index f5aa2c547b94..5fb598389487 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -543,6 +543,9 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid) if (!wiphy->bands[band]) continue; + kfree(wiphy->bands[band]->iftype_data); + wiphy->bands[band]->n_iftype_data = 0; + kfree(wiphy->bands[band]->channels); wiphy->bands[band]->n_channels = 0; -- cgit v1.2.3-59-g8ed1b From 83a5a2d76f996ff47dc9fbf09d80bbff6bf85e71 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 18 Nov 2019 17:54:29 +0800 Subject: rtw88: pci: use macros to access PCI DBI/MDIO registers Add some register and bit macros to access DBI/MDIO register. This should not change the logic. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/pci.c | 21 ++++++++++----------- drivers/net/wireless/realtek/rtw88/pci.h | 10 ++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 17b9cdf9cb05..b158ef8ded17 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1060,14 +1060,15 @@ static void rtw_pci_io_unmapping(struct rtw_dev *rtwdev, static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data) { u16 write_addr; - u16 remainder = addr & 0x3; + u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK); u8 flag; - u8 cnt = 20; + u8 cnt = RTW_PCI_WR_RETRY_CNT; - write_addr = ((addr & 0x0ffc) | (BIT(0) << (remainder + 12))); + write_addr = addr & BITS_DBI_ADDR_MASK; + write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN); rtw_write8(rtwdev, REG_DBI_WDATA_V1 + remainder, data); rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr); - rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, 0x01); + rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16); flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2); while (flag && (cnt != 0)) { @@ -1083,19 +1084,17 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1) { u8 page; u8 wflag; - u8 cnt; + u8 cnt = RTW_PCI_WR_RETRY_CNT; rtw_write16(rtwdev, REG_MDIO_V1, data); - page = addr < 0x20 ? 0 : 1; - page += g1 ? 0 : 2; - rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & 0x1f); + page = addr < RTW_PCI_MDIO_PG_SZ ? 0 : 1; + page += g1 ? RTW_PCI_MDIO_PG_OFFS_G1 : RTW_PCI_MDIO_PG_OFFS_G2; + rtw_write8(rtwdev, REG_PCIE_MIX_CFG, addr & BITS_MDIO_ADDR_MASK); rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page); - rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1); - wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1); - cnt = 20; + wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1); while (wflag && (cnt != 0)) { udelay(10); wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 87824a4caba9..50aff49738d4 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -21,9 +21,19 @@ #define BIT_RX_TAG_EN BIT(15) #define REG_DBI_WDATA_V1 0x03E8 #define REG_DBI_FLAG_V1 0x03F0 +#define BIT_DBI_RFLAG BIT(17) +#define BIT_DBI_WFLAG BIT(16) +#define BITS_DBI_WREN GENMASK(15, 12) +#define BITS_DBI_ADDR_MASK GENMASK(11, 2) + #define REG_MDIO_V1 0x03F4 #define REG_PCIE_MIX_CFG 0x03F8 +#define BITS_MDIO_ADDR_MASK GENMASK(4, 0) #define BIT_MDIO_WFLAG_V1 BIT(5) +#define RTW_PCI_MDIO_PG_SZ BIT(5) +#define RTW_PCI_MDIO_PG_OFFS_G1 0 +#define RTW_PCI_MDIO_PG_OFFS_G2 2 +#define RTW_PCI_WR_RETRY_CNT 20 #define BIT_PCI_BCNQ_FLAG BIT(4) #define RTK_PCI_TXBD_DESA_BCNQ 0x308 -- cgit v1.2.3-59-g8ed1b From ff3297f62fff6fc90d35051eec48913dbd9cbb18 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 18 Nov 2019 17:54:30 +0800 Subject: rtw88: pci: use for loop instead of while loop for DBI/MDIO Use a for loop to polling DBI/MDIO read/write flags to avoid infinite loop happens Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/pci.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index b158ef8ded17..6d1aa6f41e84 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1062,7 +1062,7 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data) u16 write_addr; u16 remainder = addr & ~(BITS_DBI_WREN | BITS_DBI_ADDR_MASK); u8 flag; - u8 cnt = RTW_PCI_WR_RETRY_CNT; + u8 cnt; write_addr = addr & BITS_DBI_ADDR_MASK; write_addr |= u16_encode_bits(BIT(remainder), BITS_DBI_WREN); @@ -1070,21 +1070,22 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data) rtw_write16(rtwdev, REG_DBI_FLAG_V1, write_addr); rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_WFLAG >> 16); - flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2); - while (flag && (cnt != 0)) { - udelay(10); + for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) { flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2); - cnt--; + if (flag == 0) + return; + + udelay(10); } - WARN(flag, "DBI write fail\n"); + WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr); } static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1) { u8 page; u8 wflag; - u8 cnt = RTW_PCI_WR_RETRY_CNT; + u8 cnt; rtw_write16(rtwdev, REG_MDIO_V1, data); @@ -1094,15 +1095,16 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1) rtw_write8(rtwdev, REG_PCIE_MIX_CFG + 3, page); rtw_write32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1, 1); - wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1); - while (wflag && (cnt != 0)) { - udelay(10); + for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) { wflag = rtw_read32_mask(rtwdev, REG_PCIE_MIX_CFG, BIT_MDIO_WFLAG_V1); - cnt--; + if (wflag == 0) + return; + + udelay(10); } - WARN(wflag, "MDIO write fail\n"); + WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr); } static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) -- cgit v1.2.3-59-g8ed1b From d2e2c47e65af7310ad7d40ebf4cbb1d898719ec2 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 18 Nov 2019 17:54:31 +0800 Subject: rtw88: pci: enable CLKREQ function if host supports it By Realtek's design, there are two HW modules associated for CLKREQ, one is responsible to follow the PCIE host settings, and another is to actually working on it. But the module that is actually working on it is default disabled, and driver should enable that module if host and device have successfully sync'ed with each other. The module is default disabled because sometimes the host does not support it, and if there is any incorrect settings (ex. CLKREQ# is not Bi-Direction), device can be lost and disconnected to the host. So driver should first check after host and device are sync'ed, and the host does support the function and set it in configuration space, then driver can turn on the HW module to working on it. Signed-off-by: Yan-Hsuan Chuang Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/pci.c | 80 ++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/pci.h | 5 ++ 2 files changed, 85 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 6d1aa6f41e84..6e99aad39487 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1081,6 +1081,30 @@ static void rtw_dbi_write8(struct rtw_dev *rtwdev, u16 addr, u8 data) WARN(flag, "failed to write to DBI register, addr=0x%04x\n", addr); } +static int rtw_dbi_read8(struct rtw_dev *rtwdev, u16 addr, u8 *value) +{ + u16 read_addr = addr & BITS_DBI_ADDR_MASK; + u8 flag; + u8 cnt; + + rtw_write16(rtwdev, REG_DBI_FLAG_V1, read_addr); + rtw_write8(rtwdev, REG_DBI_FLAG_V1 + 2, BIT_DBI_RFLAG >> 16); + + for (cnt = 0; cnt < RTW_PCI_WR_RETRY_CNT; cnt++) { + flag = rtw_read8(rtwdev, REG_DBI_FLAG_V1 + 2); + if (flag == 0) { + read_addr = REG_DBI_RDATA_V1 + (addr & 3); + *value = rtw_read8(rtwdev, read_addr); + return 0; + } + + udelay(10); + } + + WARN(1, "failed to read DBI register, addr=0x%04x\n", addr); + return -EIO; +} + static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1) { u8 page; @@ -1107,6 +1131,60 @@ static void rtw_mdio_write(struct rtw_dev *rtwdev, u8 addr, u16 data, bool g1) WARN(wflag, "failed to write to MDIO register, addr=0x%02x\n", addr); } +static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable) +{ + u8 value; + int ret; + + ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value); + if (ret) { + rtw_err(rtwdev, "failed to read CLKREQ_L1, ret=%d", ret); + return; + } + + if (enable) + value |= BIT_CLKREQ_SW_EN; + else + value &= ~BIT_CLKREQ_SW_EN; + + rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); +} + +static void rtw_pci_link_cfg(struct rtw_dev *rtwdev) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + struct pci_dev *pdev = rtwpci->pdev; + u16 link_ctrl; + int ret; + + /* Though there is standard PCIE configuration space to set the + * link control register, but by Realtek's design, driver should + * check if host supports CLKREQ/ASPM to enable the HW module. + * + * These functions are implemented by two HW modules associated, + * one is responsible to access PCIE configuration space to + * follow the host settings, and another is in charge of doing + * CLKREQ/ASPM mechanisms, it is default disabled. Because sometimes + * the host does not support it, and due to some reasons or wrong + * settings (ex. CLKREQ# not Bi-Direction), it could lead to device + * loss if HW misbehaves on the link. + * + * Hence it's designed that driver should first check the PCIE + * configuration space is sync'ed and enabled, then driver can turn + * on the other module that is actually working on the mechanism. + */ + ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &link_ctrl); + if (ret) { + rtw_err(rtwdev, "failed to read PCI cap, ret=%d\n", ret); + return; + } + + if (link_ctrl & PCI_EXP_LNKCTL_CLKREQ_EN) + rtw_pci_clkreq_set(rtwdev, true); + + rtwpci->link_ctrl = link_ctrl; +} + static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) { struct rtw_chip_info *chip = rtwdev->chip; @@ -1145,6 +1223,8 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) else rtw_dbi_write8(rtwdev, offset, value); } + + rtw_pci_link_cfg(rtwdev); } static int rtw_pci_claim(struct rtw_dev *rtwdev, struct pci_dev *pdev) diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 50aff49738d4..90efb73c607e 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -20,6 +20,7 @@ #define BIT_RST_TRXDMA_INTF BIT(20) #define BIT_RX_TAG_EN BIT(15) #define REG_DBI_WDATA_V1 0x03E8 +#define REG_DBI_RDATA_V1 0x03EC #define REG_DBI_FLAG_V1 0x03F0 #define BIT_DBI_RFLAG BIT(17) #define BIT_DBI_WFLAG BIT(16) @@ -35,6 +36,9 @@ #define RTW_PCI_MDIO_PG_OFFS_G2 2 #define RTW_PCI_WR_RETRY_CNT 20 +#define RTK_PCIE_LINK_CFG 0x0719 +#define BIT_CLKREQ_SW_EN BIT(4) + #define BIT_PCI_BCNQ_FLAG BIT(4) #define RTK_PCI_TXBD_DESA_BCNQ 0x308 #define RTK_PCI_TXBD_DESA_H2CQ 0x1320 @@ -200,6 +204,7 @@ struct rtw_pci { u16 rx_tag; struct rtw_pci_tx_ring tx_rings[RTK_MAX_TX_QUEUE_NUM]; struct rtw_pci_rx_ring rx_rings[RTK_MAX_RX_QUEUE_NUM]; + u16 link_ctrl; void __iomem *mmap; }; -- cgit v1.2.3-59-g8ed1b From 3dff7c6e37499c87a7ba3f728b2ad1775cbbf725 Mon Sep 17 00:00:00 2001 From: Yan-Hsuan Chuang Date: Mon, 18 Nov 2019 17:54:32 +0800 Subject: rtw88: allows to enable/disable HCI link PS mechanism Different interfaces have its own link-related power save mechanism. Such as PCI can enter L1 state based on the traffic on the link, and sometimes driver needs to enable/disable it to avoid some issues, like throughput degrade when PCI trying to enter L1 state even if driver is having heavy traffic. For now, rtw88 only supports PCIE chips, and they just need to disable ASPM L1 when driver is not in power save mode, such as IPS and LPS. Signed-off-by: Yan-Hsuan Chuang Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtw88/hci.h | 6 +++++ drivers/net/wireless/realtek/rtw88/pci.c | 38 ++++++++++++++++++++++++++++++++ drivers/net/wireless/realtek/rtw88/pci.h | 1 + drivers/net/wireless/realtek/rtw88/ps.c | 6 +++++ 4 files changed, 51 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtw88/hci.h b/drivers/net/wireless/realtek/rtw88/hci.h index 4afbf0d163d1..3d91aea942c3 100644 --- a/drivers/net/wireless/realtek/rtw88/hci.h +++ b/drivers/net/wireless/realtek/rtw88/hci.h @@ -14,6 +14,7 @@ struct rtw_hci_ops { int (*start)(struct rtw_dev *rtwdev); void (*stop)(struct rtw_dev *rtwdev); void (*deep_ps)(struct rtw_dev *rtwdev, bool enter); + void (*link_ps)(struct rtw_dev *rtwdev, bool enter); int (*write_data_rsvd_page)(struct rtw_dev *rtwdev, u8 *buf, u32 size); int (*write_data_h2c)(struct rtw_dev *rtwdev, u8 *buf, u32 size); @@ -53,6 +54,11 @@ static inline void rtw_hci_deep_ps(struct rtw_dev *rtwdev, bool enter) rtwdev->hci.ops->deep_ps(rtwdev, enter); } +static inline void rtw_hci_link_ps(struct rtw_dev *rtwdev, bool enter) +{ + rtwdev->hci.ops->link_ps(rtwdev, enter); +} + static inline int rtw_hci_write_data_rsvd_page(struct rtw_dev *rtwdev, u8 *buf, u32 size) { diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 6e99aad39487..a58e8276a41a 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1150,6 +1150,43 @@ static void rtw_pci_clkreq_set(struct rtw_dev *rtwdev, bool enable) rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); } +static void rtw_pci_aspm_set(struct rtw_dev *rtwdev, bool enable) +{ + u8 value; + int ret; + + ret = rtw_dbi_read8(rtwdev, RTK_PCIE_LINK_CFG, &value); + if (ret) { + rtw_err(rtwdev, "failed to read ASPM, ret=%d", ret); + return; + } + + if (enable) + value |= BIT_L1_SW_EN; + else + value &= ~BIT_L1_SW_EN; + + rtw_dbi_write8(rtwdev, RTK_PCIE_LINK_CFG, value); +} + +static void rtw_pci_link_ps(struct rtw_dev *rtwdev, bool enter) +{ + struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; + + /* Like CLKREQ, ASPM is also implemented by two HW modules, and can + * only be enabled when host supports it. + * + * And ASPM mechanism should be enabled when driver/firmware enters + * power save mode, without having heavy traffic. Because we've + * experienced some inter-operability issues that the link tends + * to enter L1 state on the fly even when driver is having high + * throughput. This is probably because the ASPM behavior slightly + * varies from different SOC. + */ + if (rtwpci->link_ctrl & PCI_EXP_LNKCTL_ASPM_L1) + rtw_pci_aspm_set(rtwdev, enter); +} + static void rtw_pci_link_cfg(struct rtw_dev *rtwdev) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; @@ -1292,6 +1329,7 @@ static struct rtw_hci_ops rtw_pci_ops = { .start = rtw_pci_start, .stop = rtw_pci_stop, .deep_ps = rtw_pci_deep_ps, + .link_ps = rtw_pci_link_ps, .read8 = rtw_pci_read8, .read16 = rtw_pci_read16, diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 90efb73c607e..49bf29a92152 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -38,6 +38,7 @@ #define RTK_PCIE_LINK_CFG 0x0719 #define BIT_CLKREQ_SW_EN BIT(4) +#define BIT_L1_SW_EN BIT(3) #define BIT_PCI_BCNQ_FLAG BIT(4) #define RTK_PCI_TXBD_DESA_BCNQ 0x308 diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c index 2226e3e7d7f8..913e6f47130f 100644 --- a/drivers/net/wireless/realtek/rtw88/ps.c +++ b/drivers/net/wireless/realtek/rtw88/ps.c @@ -31,6 +31,7 @@ int rtw_enter_ips(struct rtw_dev *rtwdev) rtw_coex_ips_notify(rtwdev, COEX_IPS_ENTER); rtw_core_stop(rtwdev); + rtw_hci_link_ps(rtwdev, true); return 0; } @@ -49,6 +50,8 @@ int rtw_leave_ips(struct rtw_dev *rtwdev) { int ret; + rtw_hci_link_ps(rtwdev, false); + ret = rtw_ips_pwr_up(rtwdev); if (ret) { rtw_err(rtwdev, "failed to leave ips state\n"); @@ -150,6 +153,7 @@ static void rtw_leave_lps_core(struct rtw_dev *rtwdev) conf->rlbm = 0; conf->smart_ps = 0; + rtw_hci_link_ps(rtwdev, false); rtw_fw_set_pwr_mode(rtwdev); rtw_fw_leave_lps_state_check(rtwdev); @@ -187,6 +191,8 @@ static void rtw_enter_lps_core(struct rtw_dev *rtwdev) rtw_coex_lps_notify(rtwdev, COEX_LPS_ENABLE); rtw_fw_set_pwr_mode(rtwdev); + rtw_hci_link_ps(rtwdev, true); + set_bit(RTW_FLAG_LEISURE_PS, rtwdev->flags); } -- cgit v1.2.3-59-g8ed1b From 5d26a6a6150c486f51ea2aaab33af04db02f63b8 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 18 Nov 2019 12:53:08 +0100 Subject: brcmfmac: disable PCIe interrupts before bus reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keeping interrupts on could result in brcmfmac freeing some resources and then IRQ handlers trying to use them. That was obviously a straight path for crashing a kernel. Example: CPU0 CPU1 ---- ---- brcmf_pcie_reset brcmf_pcie_bus_console_read brcmf_detach ... brcmf_fweh_detach brcmf_proto_detach brcmf_pcie_isr_thread ... brcmf_proto_msgbuf_rx_trigger ... drvr->proto->pd brcmf_pcie_release_irq [ 363.789218] Unable to handle kernel NULL pointer dereference at virtual address 00000038 [ 363.797339] pgd = c0004000 [ 363.800050] [00000038] *pgd=00000000 [ 363.803635] Internal error: Oops: 17 [#1] SMP ARM (...) [ 364.029209] Backtrace: [ 364.031725] [] (brcmf_proto_msgbuf_rx_trigger [brcmfmac]) from [] (brcmf_pcie_isr_thread+0x228/0x274 [brcmfmac]) [ 364.043662] r7:00000001 r6:c8ca0000 r5:00010000 r4:c7b4f800 Fixes: 4684997d9eea ("brcmfmac: reset PCIe bus on a firmware crash") Cc: stable@vger.kernel.org # v5.2+ Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 3184dab41a5e..f64ce5074a55 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -1425,6 +1425,8 @@ static int brcmf_pcie_reset(struct device *dev) struct brcmf_fw_request *fwreq; int err; + brcmf_pcie_intr_disable(devinfo); + brcmf_pcie_bus_console_read(devinfo, true); brcmf_detach(dev); -- cgit v1.2.3-59-g8ed1b From 4f61563da075bc8faefddfd5f8fc0cc14c49650a Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 18 Nov 2019 13:38:55 +0100 Subject: brcmfmac: remove monitor interface when detaching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a minor WARNING in the cfg80211: [ 130.658034] ------------[ cut here ]------------ [ 130.662805] WARNING: CPU: 1 PID: 610 at net/wireless/core.c:954 wiphy_unregister+0xb4/0x198 [cfg80211] Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 406b367c284c..85cf96461dde 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -1350,6 +1350,11 @@ void brcmf_detach(struct device *dev) brcmf_fweh_detach(drvr); brcmf_proto_detach(drvr); + if (drvr->mon_if) { + brcmf_net_detach(drvr->mon_if->ndev, false); + drvr->mon_if = NULL; + } + /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS - 1; i > -1; i--) { if (drvr->iflist[i]) -- cgit v1.2.3-59-g8ed1b From eac08515d7bd665d306cefa2ae9f3de56e875d6d Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 19 Nov 2019 10:25:14 +0800 Subject: rtl8xxxu: Remove set but not used variable 'vif','dev','len' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c: In function rtl8xxxu_c2hcmd_callback: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5396:24: warning: variable vif set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c: In function rtl8xxxu_c2hcmd_callback: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5397:17: warning: variable dev set but not used [-Wunused-but-set-variable] drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c: In function rtl8xxxu_c2hcmd_callback: drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c:5400:6: warning: variable len set but not used [-Wunused-but-set-variable] They are introduced by commit e542e66b7c2e ("rtl8xxxu: add bluetooth co-existence support for single antenna"), but never used, so remove them. Reported-by: Hulk Robot Signed-off-by: zhengbin Reviewed-by: Chris Chiu Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 1d94cab6f71f..aa2bb2ae9809 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -5393,18 +5393,13 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) { struct rtl8xxxu_priv *priv; struct rtl8723bu_c2h *c2h; - struct ieee80211_vif *vif; - struct device *dev; struct sk_buff *skb = NULL; unsigned long flags; - int len; u8 bt_info = 0; struct rtl8xxxu_btcoex *btcoex; priv = container_of(work, struct rtl8xxxu_priv, c2hcmd_work); - vif = priv->vif; btcoex = &priv->bt_coex; - dev = &priv->udev->dev; if (priv->rf_paths > 1) goto out; @@ -5415,7 +5410,6 @@ static void rtl8xxxu_c2hcmd_callback(struct work_struct *work) spin_unlock_irqrestore(&priv->c2hcmd_lock, flags); c2h = (struct rtl8723bu_c2h *)skb->data; - len = skb->len - 2; switch (c2h->id) { case C2H_8723B_BT_INFO: -- cgit v1.2.3-59-g8ed1b From 4f4925a7b23428d5719af5a2816586b2a0e6fd19 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 1 Jun 2018 10:32:55 +0200 Subject: iwlwifi: pcie: fix support for transmitting SKBs with fraglist When the implementation of SKBs with fraglist was sent upstream, a merge-damage occurred and half the patch was not applied. This causes problems in high-throughput situations with AX200 devices, including low throughput and FW crashes. Introduce the part that was missing from the original patch. Fixes: 0044f1716c4d ("iwlwifi: pcie: support transmitting SKBs with fraglist") Cc: stable@vger.kernel.org # 4.20+ Signed-off-by: Johannes Berg [ This patch was created by me, but the original author of this code is Johannes, so his s-o-b is here and he's marked as the author of the patch. ] Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 8323fa7c0762..1ca9a7e48c1a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -468,6 +468,7 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, dma_addr_t tb_phys; int len, tb1_len, tb2_len; void *tb1_addr; + struct sk_buff *frag; tb_phys = iwl_pcie_get_first_tb_dma(txq, idx); @@ -516,6 +517,19 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta)) goto out_err; + skb_walk_frags(skb, frag) { + tb_phys = dma_map_single(trans->dev, frag->data, + skb_headlen(frag), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(trans->dev, tb_phys))) + goto out_err; + iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_headlen(frag)); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, + frag->data, + skb_headlen(frag)); + if (iwl_pcie_gen2_tx_add_frags(trans, frag, tfd, out_meta)) + goto out_err; + } + return tfd; out_err: -- cgit v1.2.3-59-g8ed1b From 17ffa21af93ad1558c12108701f6216ff1cc68c2 Mon Sep 17 00:00:00 2001 From: Tova Mussai Date: Sun, 15 Sep 2019 10:22:58 +0300 Subject: iwlwifi: scan: support scan req FW API ver 13 1. Modify channel config flags to be used for legacy bands channels as well, to indicate SSIDs elements from ssidIEsArray. 2. Add new general flag. 3. Remove ssidNum from probe params. Signed-off-by: Tova Mussai Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/fw/api/scan.h | 56 ++++++++++++++++++++++-- drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 54 +++++++++++++++++++++-- 2 files changed, 104 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 71883ca6a596..408798f351c6 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -664,6 +664,9 @@ enum iwl_umac_scan_general_flags2 { * @IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID: matching on multiple SSIDs * @IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE: all the channels scanned * as passive + * @IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN: at the end of 2.4GHz and + * 5.2Ghz bands scan, trigger scan on 6GHz band to discover + * the reported collocated APs */ enum iwl_umac_scan_general_flags_v2 { IWL_UMAC_SCAN_GEN_FLAGS_V2_PERIODIC = BIT(0), @@ -678,6 +681,7 @@ enum iwl_umac_scan_general_flags_v2 { IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START = BIT(9), IWL_UMAC_SCAN_GEN_FLAGS_V2_MULTI_SSID = BIT(10), IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE = BIT(11), + IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN = BIT(12), }; /** @@ -893,7 +897,27 @@ struct iwl_scan_probe_params_v3 { struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; -} __packed; +} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_3 */ + +/** + * struct iwl_scan_probe_params_v4 + * @preq: scan probe request params + * @short_ssid_num: number of valid short SSIDs in short ssid array + * @bssid_num: number of valid bssid in bssids array + * @reserved: reserved + * @direct_scan: list of ssids + * @short_ssid: array of short ssids + * @bssid_array: array of bssids + */ +struct iwl_scan_probe_params_v4 { + struct iwl_scan_probe_req preq; + u8 short_ssid_num; + u8 bssid_num; + __le16 reserved; + struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; + __le32 short_ssid[SCAN_SHORT_SSID_MAX_SIZE]; + u8 bssid_array[ETH_ALEN][SCAN_BSSID_MAX_SIZE]; +} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */ #define SCAN_MAX_NUM_CHANS_V3 67 @@ -932,8 +956,8 @@ struct iwl_scan_channel_params_v4 { u8 reserved; struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3]; u8 adwell_ch_override_bitmap[16]; -} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 */ - +} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_4 also + SCAN_CHANNEL_PARAMS_API_S_VER_5 */ /** * struct iwl_scan_general_params_v10 * @flags: &enum iwl_umac_scan_flags @@ -1014,6 +1038,20 @@ struct iwl_scan_req_params_v12 { struct iwl_scan_probe_params_v3 probe_params; } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ +/** + * struct iwl_scan_req_params_v13 + * @general_params: &struct iwl_scan_general_params_v10 + * @channel_params: &struct iwl_scan_channel_params_v4 + * @periodic_params: &struct iwl_scan_periodic_parms_v1 + * @probe_params: &struct iwl_scan_probe_params_v4 + */ +struct iwl_scan_req_params_v13 { + struct iwl_scan_general_params_v10 general_params; + struct iwl_scan_channel_params_v4 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_13 */ + /** * struct iwl_scan_req_umac_v11 * @uid: scan id, &enum iwl_umac_scan_uid_offsets @@ -1038,6 +1076,18 @@ struct iwl_scan_req_umac_v12 { struct iwl_scan_req_params_v12 scan_params; } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ +/** + * struct iwl_scan_req_umac_v13 + * @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_v13 { + __le32 uid; + __le32 ooc_priority; + struct iwl_scan_req_params_v13 scan_params; +} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_13 */ + /** * struct iwl_umac_scan_abort * @uid: scan id, &enum iwl_umac_scan_uid_offsets diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 60edba558c99..a046ac9fa852 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1897,6 +1897,15 @@ iwl_mvm_scan_umac_fill_probe_p_v3(struct iwl_mvm_scan_params *params, iwl_scan_build_ssids(params, pp->direct_scan, NULL); } +static void +iwl_mvm_scan_umac_fill_probe_p_v4(struct iwl_mvm_scan_params *params, + struct iwl_scan_probe_params_v4 *pp, + u32 *bitmap_ssid) +{ + pp->preq = params->preq; + iwl_scan_build_ssids(params, pp->direct_scan, bitmap_ssid); +} + static void iwl_mvm_scan_umac_fill_ch_p_v3(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, @@ -1915,14 +1924,17 @@ static void iwl_mvm_scan_umac_fill_ch_p_v4(struct iwl_mvm *mvm, struct iwl_mvm_scan_params *params, struct ieee80211_vif *vif, - struct iwl_scan_channel_params_v4 *cp) + struct iwl_scan_channel_params_v4 *cp, + u32 channel_cfg_flags) { cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif); cp->count = params->n_channels; cp->num_of_aps_override = IWL_SCAN_ADWELL_DEFAULT_N_APS_OVERRIDE; iwl_mvm_umac_scan_cfg_channels_v4(mvm, params->channels, cp, - params->n_channels, 0, vif->type); + params->n_channels, + channel_cfg_flags, + vif->type); } static int iwl_mvm_scan_umac_v11(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -1984,7 +1996,41 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_scan_umac_fill_probe_p_v3(params, &scan_p->probe_params); iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, - &scan_p->channel_params); + &scan_p->channel_params, 0); + + return 0; +} + +static int iwl_mvm_scan_umac_v13(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct iwl_mvm_scan_params *params, int type, + int uid) +{ + struct iwl_scan_req_umac_v13 *cmd = mvm->scan_cmd; + struct iwl_scan_req_params_v13 *scan_p = &cmd->scan_params; + int ret; + u16 gen_flags; + u32 bitmap_ssid = 0; + + mvm->scan_uid_status[uid] = type; + + cmd->ooc_priority = cpu_to_le32(iwl_mvm_scan_umac_ooc_priority(params)); + 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_v10(mvm, params, vif, + &scan_p->general_params, + gen_flags); + + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); + if (ret) + return ret; + + iwl_mvm_scan_umac_fill_probe_p_v4(params, &scan_p->probe_params, + &bitmap_ssid); + iwl_mvm_scan_umac_fill_ch_p_v4(mvm, params, vif, + &scan_p->channel_params, bitmap_ssid); return 0; } @@ -2104,6 +2150,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(13), IWL_SCAN_UMAC_HANDLER(12), IWL_SCAN_UMAC_HANDLER(11), }; @@ -2462,6 +2509,7 @@ static int iwl_mvm_scan_stop_wait(struct iwl_mvm *mvm, int type) static int iwl_scan_req_umac_get_size(u8 scan_ver) { switch (scan_ver) { + IWL_SCAN_REQ_UMAC_HANDLE_SIZE(13); IWL_SCAN_REQ_UMAC_HANDLE_SIZE(12); IWL_SCAN_REQ_UMAC_HANDLE_SIZE(11); } -- cgit v1.2.3-59-g8ed1b From ab393cb12d035be73d9064456dae86393713f392 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Sep 2019 12:54:14 +0200 Subject: iwlwifi: pcie: make some RX functions static These aren't used outside the rx.c file, so make them static. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/internal.h | 2 -- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h index 3da2c7e38ffa..a091690f6c79 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -646,7 +646,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); /***************************************************** * RX ******************************************************/ -int _iwl_pcie_rx_init(struct iwl_trans *trans); int iwl_pcie_rx_init(struct iwl_trans *trans); int iwl_pcie_gen2_rx_init(struct iwl_trans *trans); irqreturn_t iwl_pcie_msix_isr(int irq, void *data); @@ -660,7 +659,6 @@ void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq); int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget); void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority, struct iwl_rxq *rxq); -int iwl_pcie_rx_alloc(struct iwl_trans *trans); /***************************************************** * ICT - interrupt handling diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 4bba6b8a863c..7f9cc4c84c18 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -793,7 +793,7 @@ err: return -ENOMEM; } -int iwl_pcie_rx_alloc(struct iwl_trans *trans) +static int iwl_pcie_rx_alloc(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rb_allocator *rba = &trans_pcie->rba; @@ -1024,7 +1024,7 @@ int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget) return 0; } -int _iwl_pcie_rx_init(struct iwl_trans *trans) +static int _iwl_pcie_rx_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *def_rxq; -- cgit v1.2.3-59-g8ed1b From 49b7b35cf61f1b9f831dd3043c40c957a39d47aa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Sep 2019 10:42:38 +0200 Subject: iwlwifi: config: remove max_rx_agg_size This field isn't set by any configuration, remove it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/iwl-config.h | 2 -- drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 59bb960b460a..317eac066082 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -409,7 +409,6 @@ struct iwl_fw_mon_regs { * @mac_addr_from_csr: read HW address from CSR registers * @features: hw features, any combination of feature_whitelist * @pwr_tx_backoffs: translation table between power limits and backoffs - * @max_rx_agg_size: max RX aggregation size of the ADDBA request/response * @max_tx_agg_size: max TX aggregation size of the ADDBA request/response * @max_ht_ampdu_factor: the exponent of the max length of A-MPDU that the * station can receive in HT @@ -481,7 +480,6 @@ struct iwl_cfg { u8 valid_rx_ant; u8 non_shared_ant; u8 nvm_hw_section_num; - u8 max_rx_agg_size; u8 max_tx_agg_size; u8 max_ht_ampdu_exponent; u8 max_vht_ampdu_exponent; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 3b0637311e3c..1b07a8e8f069 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -664,10 +664,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, if (!hw) return NULL; - if (cfg->max_rx_agg_size) - hw->max_rx_aggregation_subframes = cfg->max_rx_agg_size; - else - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF; if (cfg->max_tx_agg_size) hw->max_tx_aggregation_subframes = cfg->max_tx_agg_size; -- cgit v1.2.3-59-g8ed1b From 924f838b6b368f81bab7778fa829def1e8552246 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Sep 2019 18:36:10 +0200 Subject: iwlwifi: mvm: remove left-over non-functional email alias This email alias (ilw@linux.intel.com) hasn't been functional for probably closer to a decade than not, remove it. It's not really clear to me how this ended up in new code though. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 75a7af5ad7b2..ef99c49247b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -23,7 +23,7 @@ * in the file called COPYING. * * Contact Information: - * Intel Linux Wireless + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE -- cgit v1.2.3-59-g8ed1b From 5661925a9b383f7cb348c196c6c69ab92f08102d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 27 Sep 2019 11:11:20 +0200 Subject: iwlwifi: pcie: rx: use rxq queue_size instead of constant This is a little less efficient now as it's known to be a multiqueue device in this function, but a future patch will have to use a variable here anyway, so use rxq->queue_size now instead to make it clearer. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/pcie/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 7f9cc4c84c18..a4d325fcf94a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -322,7 +322,7 @@ static void iwl_pcie_rxmq_restock(struct iwl_trans *trans, WARN_ON(rxb->page_dma & DMA_BIT_MASK(12)); /* Point to Rx buffer via next RBD in circular buffer */ iwl_pcie_restock_bd(trans, rxq, rxb); - rxq->write = (rxq->write + 1) & MQ_RX_TABLE_MASK; + rxq->write = (rxq->write + 1) & (rxq->queue_size - 1); rxq->free_count--; } spin_unlock(&rxq->lock); -- cgit v1.2.3-59-g8ed1b From e8503aeca3547d30087e8615156a7ba82a28b365 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 5 Sep 2019 14:28:01 -0700 Subject: iwlwifi: mvm: Report tx/rx antennas This makes it easier for user-space to know how many antennas the radio has. Seems to work with the AX200 radio, at least. Signed-off-by: Ben Greear Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 473d56552e26..32dc9d6f0fb6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -355,6 +355,15 @@ static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = { }, }; +static int +iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + *tx_ant = iwl_mvm_get_valid_tx_ant(mvm); + *rx_ant = iwl_mvm_get_valid_rx_ant(mvm); + return 0; +} + int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) { struct ieee80211_hw *hw = mvm->hw; @@ -734,6 +743,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + hw->wiphy->available_antennas_tx = iwl_mvm_get_valid_tx_ant(mvm); + hw->wiphy->available_antennas_rx = iwl_mvm_get_valid_rx_ant(mvm); + ret = ieee80211_register_hw(mvm->hw); if (ret) { iwl_mvm_leds_exit(mvm); @@ -5028,6 +5040,7 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, .ampdu_action = iwl_mvm_mac_ampdu_action, + .get_antenna = iwl_mvm_op_get_antenna, .start = iwl_mvm_mac_start, .reconfig_complete = iwl_mvm_mac_reconfig_complete, .stop = iwl_mvm_mac_stop, -- cgit v1.2.3-59-g8ed1b From e7babbe31fe28a812eb64dab16a0c4423c6ebadd Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Wed, 25 Sep 2019 23:49:35 +0300 Subject: iwlwifi: dvm: excessive if in rs_bt_update_lq() There is no need to check 'priv->bt_ant_couple_ok' twice in rs_bt_update_lq(). The second check is always true. Thus, the expression can be simplified. Signed-off-by: Denis Efremov Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/rs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index 74229fcb63a9..226165db7dfd 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -851,7 +851,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, * Is there a need to switch between * full concurrency and 3-wire? */ - if (priv->bt_ci_compliance && priv->bt_ant_couple_ok) + if (priv->bt_ci_compliance) full_concurrent = true; else full_concurrent = false; -- cgit v1.2.3-59-g8ed1b From 9b08ae2219b141a31de2935452e7fe20ea10a72d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Sep 2019 11:49:49 +0200 Subject: iwlwifi: pcie: trace IOVA for iwlwifi_dev_tx_tb We trace the whole TFD with all TBs when in iwlwifi_dev_tx, but sometimes we add TBs to it later and then we don't have any of this data. Trace the I/O virtual address (IOVA) (it can be the physical address, or as returned by the IOMMU) here to aid debugging the DMA flows. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- .../net/wireless/intel/iwlwifi/iwl-devtrace-data.h | 8 +++++--- drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c | 20 +++++++++----------- drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 14 ++++++-------- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h index 9e8643618578..1bc6ecc32140 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-data.h @@ -3,7 +3,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * Contact Information: * Intel Linux Wireless @@ -21,16 +21,18 @@ TRACE_EVENT(iwlwifi_dev_tx_tb, TP_PROTO(const struct device *dev, struct sk_buff *skb, - u8 *data_src, size_t data_len), - TP_ARGS(dev, skb, data_src, data_len), + u8 *data_src, dma_addr_t phys, size_t data_len), + TP_ARGS(dev, skb, data_src, phys, data_len), TP_STRUCT__entry( DEV_ENTRY + __field(u64, phys) __dynamic_array(u8, data, iwl_trace_data(skb) ? data_len : 0) ), TP_fast_assign( DEV_ASSIGN; + __entry->phys = phys; if (iwl_trace_data(skb)) memcpy(__get_dynamic_array(data), data_src, data_len); ), diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 1ca9a7e48c1a..8ca0250de99e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -333,7 +333,8 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); - trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, + tb_phys, tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); @@ -351,7 +352,7 @@ static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, - tb_len); + tb_phys, tb_len); data_left -= tb_len; tso_build_data(skb, &tso, tb_len); @@ -441,9 +442,8 @@ static int iwl_pcie_gen2_tx_add_frags(struct iwl_trans *trans, return -ENOMEM; tb_idx = iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_frag_size(frag)); - trace_iwlwifi_dev_tx_tb(trans->dev, skb, - skb_frag_address(frag), - skb_frag_size(frag)); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb_frag_address(frag), + tb_phys, skb_frag_size(frag)); if (tb_idx < 0) return tb_idx; @@ -509,9 +509,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb2_len); - trace_iwlwifi_dev_tx_tb(trans->dev, skb, - skb->data + hdr_len, - tb2_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb->data + hdr_len, + tb_phys, tb2_len); } if (iwl_pcie_gen2_tx_add_frags(trans, skb, tfd, out_meta)) @@ -523,9 +522,8 @@ iwl_tfh_tfd *iwl_pcie_gen2_build_tx(struct iwl_trans *trans, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) goto out_err; iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, skb_headlen(frag)); - trace_iwlwifi_dev_tx_tb(trans->dev, skb, - frag->data, - skb_headlen(frag)); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, frag->data, + tb_phys, skb_headlen(frag)); if (iwl_pcie_gen2_tx_add_frags(trans, frag, tfd, out_meta)) goto out_err; } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c index b710b8a25b54..f21f16ab2a97 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -2019,9 +2019,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, head_tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; - trace_iwlwifi_dev_tx_tb(trans->dev, skb, - skb->data + hdr_len, - head_tb_len); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb->data + hdr_len, + tb_phys, head_tb_len); iwl_pcie_txq_build_tfd(trans, txq, tb_phys, head_tb_len, false); } @@ -2039,9 +2038,8 @@ static int iwl_fill_data_tbs(struct iwl_trans *trans, struct sk_buff *skb, if (unlikely(dma_mapping_error(trans->dev, tb_phys))) return -EINVAL; - trace_iwlwifi_dev_tx_tb(trans->dev, skb, - skb_frag_address(frag), - skb_frag_size(frag)); + trace_iwlwifi_dev_tx_tb(trans->dev, skb, skb_frag_address(frag), + tb_phys, skb_frag_size(frag)); tb_idx = iwl_pcie_txq_build_tfd(trans, txq, tb_phys, skb_frag_size(frag), false); if (tb_idx < 0) @@ -2222,7 +2220,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_txq_build_tfd(trans, txq, hdr_tb_phys, hdr_tb_len, false); trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, - hdr_tb_len); + hdr_tb_phys, hdr_tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); @@ -2248,7 +2246,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, iwl_pcie_txq_build_tfd(trans, txq, tb_phys, size, false); trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, - size); + tb_phys, size); data_left -= size; tso_build_data(skb, &tso, size); -- cgit v1.2.3-59-g8ed1b From b646a883ad74387ec17266e94720c46d6aaa1be2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 30 Sep 2019 14:16:18 +0200 Subject: iwlwifi: mvm: remove outdated comment referring to wake lock There's no multicast wake lock in the driver, remove the comment that refers to it. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/mvm/power.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 22136e4832ea..25d7faea1c62 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -370,8 +370,6 @@ static void iwl_mvm_power_config_skip_dtim(struct iwl_mvm *mvm, if (dtimper >= 10) return; - /* TODO: check that multicast wake lock is off */ - if (host_awake) { if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_LP) return; -- cgit v1.2.3-59-g8ed1b From 5974fbb5e10b018fdbe3c3b81cb4cc54e1105ab9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Nov 2019 14:50:32 +0100 Subject: iwlwifi: check kasprintf() return value kasprintf() can fail, we should check the return value. Fixes: 5ed540aecc2a ("iwlwifi: use mac80211 throughput trigger") Fixes: 8ca151b568b6 ("iwlwifi: add the MVM driver") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/dvm/led.c | 3 +++ drivers/net/wireless/intel/iwlwifi/mvm/led.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c index dd387aba3317..e8a4d604b910 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c @@ -171,6 +171,9 @@ void iwl_leds_init(struct iwl_priv *priv) priv->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(priv->hw->wiphy)); + if (!priv->led.name) + return; + priv->led.brightness_set = iwl_led_brightness_set; priv->led.blink_set = iwl_led_blink_set; priv->led.max_brightness = 1; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index d104da9170ca..72c4b2b8399d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -129,6 +129,9 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) mvm->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(mvm->hw->wiphy)); + if (!mvm->led.name) + return -ENOMEM; + mvm->led.brightness_set = iwl_led_brightness_set; mvm->led.max_brightness = 1; -- cgit v1.2.3-59-g8ed1b From 54fae6e31bed393a17512c1c8d2559bc737943c9 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Wed, 10 Apr 2019 09:23:39 +0300 Subject: iwlwifi: bump FW API to 52 for 22000 series Start supporting API version 52 for 22000 series. Signed-off-by: Luca Coelho --- drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 8ad771dadae2..56dc335a788c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -57,7 +57,7 @@ #include "iwl-prph.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 51 +#define IWL_22000_UCODE_API_MAX 52 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 -- cgit v1.2.3-59-g8ed1b From b4124a5b1a00d461e40c00755adda8ae05810648 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 12 Sep 2019 16:42:53 +0200 Subject: mt76: mt7615: fix control frame rx in monitor mode Adjust filters and ensure frames don't get sent to MCU instead of host Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 13 ++++++++++++- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 10 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 1104e4c8aaa6..5de04f6e6046 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -20,7 +20,7 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_mac_init(struct mt7615_dev *dev) { - u32 val; + u32 val, mask, set; /* enable band 0/1 clk */ mt76_set(dev, MT_CFG_CCR, @@ -85,6 +85,17 @@ static void mt7615_mac_init(struct mt7615_dev *dev) MT_AGG_ARCR_RATE_DOWN_RATIO_EN | FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) | FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4))); + + mask = MT_DMA_RCFR0_MCU_RX_MGMT | + MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR | + MT_DMA_RCFR0_MCU_RX_CTL_BAR | + MT_DMA_RCFR0_MCU_RX_BYPASS | + MT_DMA_RCFR0_RX_DROPPED_UCAST | + MT_DMA_RCFR0_RX_DROPPED_MCAST; + set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) | + FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); + mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); + mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b6d78212306a..7252423a89fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -263,6 +263,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, u64 multicast) { struct mt7615_dev *dev = hw->priv; + u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | + MT_WF_RFCR1_DROP_BF_POLL | + MT_WF_RFCR1_DROP_BA | + MT_WF_RFCR1_DROP_CFEND | + MT_WF_RFCR1_DROP_CFACK; u32 flags = 0; #define MT76_FILTER(_flag, _hw) do { \ @@ -296,6 +301,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw, *total_flags = flags; mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter); + + if (*total_flags & FIF_CONTROL) + mt76_clear(dev, MT_WF_RFCR1, ctl_flags); + else + mt76_set(dev, MT_WF_RFCR1, ctl_flags); } static void mt7615_bss_info_changed(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index b193814d5cf8..8ecefcb19354 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -176,6 +176,13 @@ #define MT_WF_RFCR_DROP_NDPA BIT(20) #define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21) +#define MT_WF_RFCR1 MT_WF_RMAC(0x004) +#define MT_WF_RFCR1_DROP_ACK BIT(4) +#define MT_WF_RFCR1_DROP_BF_POLL BIT(5) +#define MT_WF_RFCR1_DROP_BA BIT(6) +#define MT_WF_RFCR1_DROP_CFEND BIT(7) +#define MT_WF_RFCR1_DROP_CFACK BIT(8) + #define MT_WF_DMA_BASE 0x21800 #define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) @@ -183,6 +190,15 @@ #define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 2) #define MT_DMA_DCR0_RX_VEC_DROP BIT(17) +#define MT_DMA_BN0RCFR0 MT_WF_DMA(0x070) +#define MT_DMA_BN1RCFR0 MT_WF_DMA(0x0b0) +#define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2) +#define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3) +#define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4) +#define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21) +#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24) +#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26) + #define MT_WTBL_BASE 0x30000 #define MT_WTBL_ENTRY_SIZE 256 -- cgit v1.2.3-59-g8ed1b From c7f647d9bdb062845592bd5fd56d726b554bb48b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Sep 2019 18:43:14 +0200 Subject: mt76: remove aggr_work field from struct mt76_wcid It is unused Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8aec7ccf2d79..09544a4efd12 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -191,8 +191,6 @@ DECLARE_EWMA(signal, 10, 8); struct mt76_wcid { struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS]; - struct work_struct aggr_work; - unsigned long flags; struct ewma_signal rssi; -- cgit v1.2.3-59-g8ed1b From b0b2373db7fe3624f2c378795e21d23d9e23b06f Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 15 Sep 2019 18:43:59 +0200 Subject: mt76: use cancel_delayed_work_sync in mt76_rx_aggr_shutdown The workqueue item needs to be fully shut down before the struct can be freed. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 8f3d36a15e17..2276fd4e9ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -257,7 +257,7 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; - cancel_delayed_work(&tid->reorder_work); + cancel_delayed_work_sync(&tid->reorder_work); spin_lock_bh(&tid->lock); -- cgit v1.2.3-59-g8ed1b From a670111131db75b53c6377f26b4ccf12fe3912c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 22 Aug 2019 11:49:10 +0200 Subject: mt76: remove empty flag in mt76_txq_schedule_list Remove empty flag in mt76_txq_schedule_list and mt76_txq_send_burst since we just need retry_q length to notify mac80211 to reschedule the current tx queue Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/tx.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index c22a05f06fd0..7ee91d946882 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -378,7 +378,7 @@ EXPORT_SYMBOL_GPL(mt76_release_buffered_frames); static int mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, - struct mt76_txq *mtxq, bool *empty) + struct mt76_txq *mtxq) { struct ieee80211_txq *txq = mtxq_to_txq(mtxq); enum mt76_txq_id qid = mt76_txq_get_qid(txq); @@ -392,16 +392,12 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, bool probe; int idx; - if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) { - *empty = true; + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) return 0; - } skb = mt76_txq_dequeue(dev, mtxq, false); - if (!skb) { - *empty = true; + if (!skb) return 0; - } info = IEEE80211_SKB_CB(skb); if (!(wcid->tx_info & MT_WCID_TX_INFO_SET)) @@ -431,10 +427,8 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, return -EBUSY; skb = mt76_txq_dequeue(dev, mtxq, false); - if (!skb) { - *empty = true; + if (!skb) break; - } info = IEEE80211_SKB_CB(skb); cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU; @@ -481,8 +475,6 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid) spin_lock_bh(&hwq->lock); while (1) { - bool empty = false; - if (sq->swq_queued >= 4) break; @@ -513,10 +505,9 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid) spin_lock_bh(&hwq->lock); } - ret += mt76_txq_send_burst(dev, sq, mtxq, &empty); - if (skb_queue_empty(&mtxq->retry_q)) - empty = true; - ieee80211_return_txq(dev->hw, txq, !empty); + ret += mt76_txq_send_burst(dev, sq, mtxq); + ieee80211_return_txq(dev->hw, txq, + !skb_queue_empty(&mtxq->retry_q)); } spin_unlock_bh(&hwq->lock); -- cgit v1.2.3-59-g8ed1b From af3076db14b1d143d53815bd37033a1b684ed6bc Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 5 Sep 2019 18:32:58 +0200 Subject: mt76: usb: add lockdep_assert_held in __mt76u_vendor_request Introduce lockdep_assert_held macro in __mt76u_vendor_request routine and remove comments regarding usb_ctrl_mtx lock Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/usb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index 20c6fe510e9d..cac058fc41ef 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -15,7 +15,6 @@ static bool disable_usb_sg; module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644); MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support"); -/* should be called with usb_ctrl_mtx locked */ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) @@ -24,6 +23,8 @@ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, unsigned int pipe; int i, ret; + lockdep_assert_held(&dev->usb.usb_ctrl_mtx); + pipe = (req_type & USB_DIR_IN) ? usb_rcvctrlpipe(udev, 0) : usb_sndctrlpipe(udev, 0); for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { @@ -60,7 +61,6 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req, } EXPORT_SYMBOL_GPL(mt76u_vendor_request); -/* should be called with usb_ctrl_mtx locked */ static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr) { struct mt76_usb *usb = &dev->usb; @@ -103,7 +103,6 @@ static u32 mt76u_rr(struct mt76_dev *dev, u32 addr) return ret; } -/* should be called with usb_ctrl_mtx locked */ static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) { struct mt76_usb *usb = &dev->usb; -- cgit v1.2.3-59-g8ed1b From 4482455409b044ed64b48e5e9c153469e2df7f86 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 13:19:26 +0100 Subject: mt76: mt76x0e: make array mt76x0_chan_map static const, makes object smaller Don't populate the array mt76x0_chan_map on the stack but instead make it static const. Makes the object code smaller by 80 bytes. Before: text data bss dec hex filename 7685 1192 0 8877 22ad mediatek/mt76/mt76x0/eeprom.o After: text data bss dec hex filename 7541 1256 0 8797 225d mediatek/mt76/mt76x0/eeprom.o (gcc version 9.2.1, amd64) Signed-off-by: Colin Ian King Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 9d4426f6905f..96368fac4228 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -212,7 +212,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev, void mt76x0_get_power_info(struct mt76x02_dev *dev, struct ieee80211_channel *chan, s8 *tp) { - struct mt76x0_chan_map { + static const struct mt76x0_chan_map { u8 chan; u8 offset; } chan_map[] = { -- cgit v1.2.3-59-g8ed1b From 45971b2385d6a30b7d377c2e24728d680eae7553 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 6 Sep 2019 17:29:04 +0200 Subject: mt76: mt7615: enable SCS by default Enable Smart Carrier Sense algorithm by default in order to improve performances in a noisy environment Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 5de04f6e6046..ad94a7ce2e10 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -50,7 +50,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev) MT_TMAC_CTCR0_INS_DDLMT_EN); mt7615_mcu_set_rts_thresh(dev, 0x92b); - mt7615_mac_set_scs(dev, false); + mt7615_mac_set_scs(dev, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, MT_AGG_SCR_NLNAV_MID_PTEC_DIS); -- cgit v1.2.3-59-g8ed1b From 7b37cce09d187fdc4a2e2a57adb1b2e170d1dfe6 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:35 +0200 Subject: mt76: mt76x02: move mac_reset_counter in mt76x02_lib module Unify mac_reset_counter routine and move it in mt76x02_lib module since it is shared by all mt76x02 drivers (pci/usb) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 12 +----------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 21 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../net/wireless/mediatek/mt76/mt76x2/pci_init.c | 10 +--------- drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c | 12 +----------- 5 files changed, 25 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index cf7fc307322b..541e81deba83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -150,16 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); } -static void mt76x0_reset_counters(struct mt76x02_dev *dev) -{ - mt76_rr(dev, MT_RX_STAT_0); - mt76_rr(dev, MT_RX_STAT_1); - mt76_rr(dev, MT_RX_STAT_2); - mt76_rr(dev, MT_TX_STA_0); - mt76_rr(dev, MT_TX_STA_1); - mt76_rr(dev, MT_TX_STA_2); -} - int mt76x0_mac_start(struct mt76x02_dev *dev) { mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); @@ -244,7 +234,7 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) for (i = 0; i < 256; i++) mt76x02_mac_wcid_setup(dev, i, 0, NULL); - mt76x0_reset_counters(dev); + mt76x02_mac_reset_counters(dev); ret = mt76x0_eeprom_init(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index abacb4ea7179..c681601f9114 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -7,6 +7,27 @@ #include "mt76x02.h" #include "mt76x02_trace.h" +void mt76x02_mac_reset_counters(struct mt76x02_dev *dev) +{ + int i; + + mt76_rr(dev, MT_RX_STAT_0); + mt76_rr(dev, MT_RX_STAT_1); + mt76_rr(dev, MT_RX_STAT_2); + mt76_rr(dev, MT_TX_STA_0); + mt76_rr(dev, MT_TX_STA_1); + mt76_rr(dev, MT_TX_STA_2); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + for (i = 0; i < 16; i++) + mt76_rr(dev, MT_TX_STAT_FIFO); + + memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters); + static enum mt76x02_cipher_type mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index efa4ef945e35..b687341236c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -161,6 +161,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev) return false; } +void mt76x02_mac_reset_counters(struct mt76x02_dev *dev); void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable); int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, u8 key_idx, struct ieee80211_key_conf *key); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 343127f2d621..114e4fa4f4f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -148,15 +148,7 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) int mt76x2_mac_start(struct mt76x02_dev *dev) { - int i; - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_AGG_CNT(i)); - - for (i = 0; i < 16; i++) - mt76_rr(dev, MT_TX_STAT_FIFO); - - memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + mt76x02_mac_reset_counters(dev); mt76x02_mac_start(dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index e7fea3a6f1fd..95eb85653bbd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -6,16 +6,6 @@ #include "mt76x2u.h" #include "eeprom.h" -static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev) -{ - mt76_rr(dev, MT_RX_STAT_0); - mt76_rr(dev, MT_RX_STAT_1); - mt76_rr(dev, MT_RX_STAT_2); - mt76_rr(dev, MT_TX_STA_0); - mt76_rr(dev, MT_TX_STA_1); - mt76_rr(dev, MT_TX_STA_2); -} - static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev) { s8 offset = 0; @@ -104,7 +94,7 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev) int mt76x2u_mac_start(struct mt76x02_dev *dev) { - mt76x2u_mac_reset_counters(dev); + mt76x02_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); mt76x02_wait_for_wpdma(&dev->mt76, 1000); -- cgit v1.2.3-59-g8ed1b From ad571c93169bbefd834b2359b782c5a94174c321 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:36 +0200 Subject: mt76: mt76x2: move mt76x02_mac_reset_counters in mt76x02_mac_start Move mt76x02_mac_reset_counters in mt76x02_mac_start and get rid of mt76x2_mac_start since it is just a wrapper for mt76x02_mac_start Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/mac.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 13 ++----------- drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 6 ++---- 4 files changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index dc773070481d..4e2371c926d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -343,6 +343,7 @@ EXPORT_SYMBOL_GPL(mt76x02_dma_disable); void mt76x02_mac_start(struct mt76x02_dev *dev) { + mt76x02_mac_reset_counters(dev); mt76x02_dma_enable(dev); mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); mt76_wr(dev, MT_MAC_SYS_CTRL, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index a1583021e1e9..d5c3d26b94c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -12,7 +12,6 @@ struct mt76x02_dev; struct mt76x2_sta; struct mt76x02_vif; -int mt76x2_mac_start(struct mt76x02_dev *dev); void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force); static inline void mt76x2_mac_resume(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 114e4fa4f4f6..3cf54963854a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -7,6 +7,7 @@ #include "mt76x2.h" #include "eeprom.h" #include "mcu.h" +#include "../mt76x02_mac.h" static void mt76x2_mac_pbf_init(struct mt76x02_dev *dev) @@ -146,14 +147,6 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) return 0; } -int mt76x2_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - mt76x02_mac_start(dev); - - return 0; -} - static void mt76x2_power_on_rf_patch(struct mt76x02_dev *dev) { @@ -256,9 +249,7 @@ static int mt76x2_init_hardware(struct mt76x02_dev *dev) return ret; set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - ret = mt76x2_mac_start(dev); - if (ret) - return ret; + mt76x02_mac_start(dev); ret = mt76x2_mcu_init(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 4971685aafe8..385960dca906 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -4,6 +4,7 @@ */ #include "mt76x2.h" +#include "../mt76x02_mac.h" static int mt76x2_start(struct ieee80211_hw *hw) @@ -11,10 +12,7 @@ mt76x2_start(struct ieee80211_hw *hw) struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x2_mac_start(dev); - if (ret) - return ret; - + mt76x02_mac_start(dev); ret = mt76x2_phy_start(dev); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From d5b3be417b015d4f401eba05943b5ca33137aecd Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:37 +0200 Subject: mt76: mt76x0u: reset counter starting the device Remove mt76x02_mac_reset_counters from mt76x0_init_hardware since it will be run starting the device Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index 541e81deba83..d7bac4961c7b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -152,6 +152,7 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) int mt76x0_mac_start(struct mt76x02_dev *dev) { + mt76x02_mac_reset_counters(dev); mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) @@ -234,8 +235,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev) for (i = 0; i < 256; i++) mt76x02_mac_wcid_setup(dev, i, 0, NULL); - mt76x02_mac_reset_counters(dev); - ret = mt76x0_eeprom_init(dev); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From fdb96b06040d0d410705f9b42851a75ec4106ae4 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 12 Sep 2019 11:06:38 +0200 Subject: mt76: mt76x02u: move mt76x02u_mac_start in mt76x02-usb module Unify mt76x02u_mac_start between mt76x2u and mt76x0u since the code is shared between both drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/init.c | 16 ---------------- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_usb.h | 1 + .../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 21 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h | 1 - drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c | 17 ----------------- .../net/wireless/mediatek/mt76/mt76x2/usb_main.c | 3 ++- 8 files changed, 25 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index d7bac4961c7b..388b54cded1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -150,22 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev) mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201); } -int mt76x0_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - - if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) - return -ETIMEDOUT; - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); - - return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0; -} -EXPORT_SYMBOL_GPL(mt76x0_mac_start); - void mt76x0_mac_stop(struct mt76x02_dev *dev) { int i = 200, ok = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 26517e062bdb..82f5b481b723 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -46,7 +46,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev); int mt76x0_register_device(struct mt76x02_dev *dev); void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); -int mt76x0_mac_start(struct mt76x02_dev *dev); void mt76x0_mac_stop(struct mt76x02_dev *dev); int mt76x0_config(struct ieee80211_hw *hw, u32 changed); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 00a445d27599..4c2b66b53533 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -103,7 +103,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw) struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x0_mac_start(dev); + ret = mt76x02u_mac_start(dev); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 98329debc033..a57dcc8820aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -8,6 +8,7 @@ #include "mt76x02.h" +int mt76x02u_mac_start(struct mt76x02_dev *dev); void mt76x02u_init_mcu(struct mt76_dev *dev); void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev); int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 78dfc1e7f27b..203420087ac4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -23,6 +23,27 @@ void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, } EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb); +int mt76x02u_mac_start(struct mt76x02_dev *dev) +{ + mt76x02_mac_reset_counters(dev); + + mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); + if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000)) + return -ETIMEDOUT; + + mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); + + mt76_wr(dev, MT_MAC_SYS_CTRL, + MT_MAC_SYS_CTRL_ENABLE_TX | + MT_MAC_SYS_CTRL_ENABLE_RX); + + if (!mt76x02_wait_for_wpdma(&dev->mt76, 50)) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(mt76x02u_mac_start); + int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags) { struct sk_buff *iter, *last = skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index c876bac43751..f9d37c6cf1f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -24,7 +24,6 @@ void mt76x2u_cleanup(struct mt76x02_dev *dev); void mt76x2u_stop_hw(struct mt76x02_dev *dev); int mt76x2u_mac_reset(struct mt76x02_dev *dev); -int mt76x2u_mac_start(struct mt76x02_dev *dev); int mt76x2u_mac_stop(struct mt76x02_dev *dev); int mt76x2u_phy_set_channel(struct mt76x02_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index 95eb85653bbd..59cbe826188a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -92,23 +92,6 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev) return 0; } -int mt76x2u_mac_start(struct mt76x02_dev *dev) -{ - mt76x02_mac_reset_counters(dev); - - mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); - mt76x02_wait_for_wpdma(&dev->mt76, 1000); - usleep_range(50, 100); - - mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); - - mt76_wr(dev, MT_MAC_SYS_CTRL, - MT_MAC_SYS_CTRL_ENABLE_TX | - MT_MAC_SYS_CTRL_ENABLE_RX); - - return 0; -} - int mt76x2u_mac_stop(struct mt76x02_dev *dev) { int i, count = 0, val; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index eb73cb856c81..1e6f78760dd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -4,13 +4,14 @@ */ #include "mt76x2u.h" +#include "../mt76x02_usb.h" static int mt76x2u_start(struct ieee80211_hw *hw) { struct mt76x02_dev *dev = hw->priv; int ret; - ret = mt76x2u_mac_start(dev); + ret = mt76x02u_mac_start(dev); if (ret) return ret; -- cgit v1.2.3-59-g8ed1b From 0b82a8e8024b34cf99094105a44ae959c21b7534 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:50 +0200 Subject: mt76: move queue debugfs entry to driver specific code Move queue debugfs entry to driver specific code since mt7615 devices rely on a different queue layout Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/debugfs.c | 5 ++--- drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index d95b73fd0d2b..d2202acb8dc6 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -25,8 +25,7 @@ mt76_reg_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); -static int -mt76_queues_read(struct seq_file *s, void *data) +int mt76_queues_read(struct seq_file *s, void *data) { struct mt76_dev *dev = dev_get_drvdata(s->private); int i; @@ -45,6 +44,7 @@ mt76_queues_read(struct seq_file *s, void *data) return 0; } +EXPORT_SYMBOL_GPL(mt76_queues_read); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) @@ -90,7 +90,6 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); - debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, mt76_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 09544a4efd12..888dfc58546d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -624,6 +624,7 @@ void mt76_unregister_device(struct mt76_dev *dev); void mt76_free_device(struct mt76_dev *dev); struct dentry *mt76_register_debugfs(struct mt76_dev *dev); +int mt76_queues_read(struct seq_file *s, void *data); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index 5942fe76c6e9..45eb24862240 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -77,6 +77,8 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) if (!dir) return; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test); debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 0cb2a7b35fe5..186838128c55 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -143,6 +143,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev) if (!dir) return; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt76_queues_read); debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); -- cgit v1.2.3-59-g8ed1b From 25990ed3816e0d47f56b5430bb9415d631e313a7 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:51 +0200 Subject: mt76: mt7615: add queue entry in debugfs Introduce mt7615_queues_read routine to dump hw queue related info. Add hw ac queues statistics in mt7615 debugfs Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 61 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 11 ++++ 2 files changed, 72 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 2428a4659a1c..1dc68d4aee57 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -61,6 +61,63 @@ static int mt7615_read_temperature(struct seq_file *s, void *data) return 0; } +static int +mt7615_queues_acq(struct seq_file *s, void *data) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + int i; + + for (i = 0; i < 16; i++) { + int j, acs = i / 4, index = i % 4; + u32 ctrl, val, qlen = 0; + + val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index)); + ctrl = BIT(31) | BIT(15) | (acs << 8); + + for (j = 0; j < 32; j++) { + if (val & BIT(j)) + continue; + + mt76_wr(dev, MT_PLE_FL_Q0_CTRL, + ctrl | (j + (index << 5))); + qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL, + GENMASK(11, 0)); + } + seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen); + } + + return 0; +} + +static int +mt7615_queues_read(struct seq_file *s, void *data) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + static const struct { + char *queue; + int id; + } queue_map[] = { + { "PDMA0", MT_TXQ_BE }, + { "MCUQ", MT_TXQ_MCU }, + { "MCUFWQ", MT_TXQ_FWDL }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(queue_map); i++) { + struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id]; + + if (!q->q) + continue; + + seq_printf(s, + "%s: queued=%d head=%d tail=%d\n", + queue_map[i].queue, q->q->queued, q->q->head, + q->q->tail); + } + + return 0; +} + int mt7615_init_debugfs(struct mt7615_dev *dev) { struct dentry *dir; @@ -69,6 +126,10 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) if (!dir) return -ENOMEM; + debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, + mt7615_queues_read); + debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, + mt7615_queues_acq); debugfs_create_file("scs", 0600, dir, dev, &fops_scs); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 8ecefcb19354..43676736a807 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -65,6 +65,17 @@ #define MT_WPDMA_ABT_CFG MT_HIF(0x530) #define MT_WPDMA_ABT_CFG1 MT_HIF(0x534) +#define MT_PLE_BASE 0x8000 +#define MT_PLE(ofs) (MT_PLE_BASE + (ofs)) + +#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0) +#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4) +#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8) +#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc) + +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \ + ((n) << 2)) + #define MT_WF_PHY_BASE 0x10000 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs)) -- cgit v1.2.3-59-g8ed1b From d7b47bbdd71cbd769501bf181d57e9ff12efc30b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:52 +0200 Subject: mt76: move aggr_stats array in mt76_dev Move aggr_stats array from mt76x02_dev to mt76_dev in order to be reused adding aggregation stats for mt7603/mt7615 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02.h | 2 -- drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 888dfc58546d..b3e776ef9469 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -461,6 +461,8 @@ struct mt76_dev { u32 rev; unsigned long state; + u32 aggr_stats[32]; + u8 antenna_mask; u16 chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index e858bba8c8ff..50b0131f85bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -92,8 +92,6 @@ struct mt76x02_dev { const struct mt76x02_beacon_ops *beacon_ops; - u32 aggr_stats[32]; - struct sk_buff *beacons[8]; u8 beacon_data_mask; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 186838128c55..68b40d63a46d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -19,7 +19,8 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data) seq_puts(file, "\n"); seq_puts(file, "Count: "); for (j = 0; j < 8; j++) - seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]); + seq_printf(file, "%8d | ", + dev->mt76.aggr_stats[i * 8 + j]); seq_puts(file, "\n"); seq_puts(file, "--------"); for (j = 0; j < 8; j++) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c681601f9114..0d000906b2e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -24,7 +24,7 @@ void mt76x02_mac_reset_counters(struct mt76x02_dev *dev) for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); - memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats)); + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); } EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters); @@ -1119,8 +1119,8 @@ void mt76x02_mac_work(struct work_struct *work) for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); - dev->aggr_stats[idx++] += val & 0xffff; - dev->aggr_stats[idx++] += val >> 16; + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; } if (!dev->mt76.beacon_mask) -- cgit v1.2.3-59-g8ed1b From 75601194a1c80f4d2a830ce36b9c3e3abfd8d006 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:53 +0200 Subject: mt76: mt7615: collect aggregation stats Introduce ampdu_stat entry in mt7615 debugfs in order to dump 802.11 aggr cumulative statistics Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7615/debugfs.c | 39 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 18 ++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 6 ++++ 5 files changed, 66 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 1dc68d4aee57..f6b75f832e6a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -36,6 +36,44 @@ mt7615_scs_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get, mt7615_scs_set, "%lld\n"); +static int +mt7615_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7615_dev *dev = file->private; + int bound[7], i, range; + + range = mt76_rr(dev, MT_AGG_ASRCR0); + for (i = 0; i < 4; i++) + bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; + range = mt76_rr(dev, MT_AGG_ASRCR1); + for (i = 0; i < 3; i++) + bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1; + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i], bound[i + 1]); + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + return 0; +} + +static int +mt7615_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7615_ampdu_stat_read, inode->i_private); +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt7615_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int mt7615_radio_read(struct seq_file *s, void *data) { @@ -130,6 +168,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev) mt7615_queues_read); debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir, mt7615_queues_acq); + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); debugfs_create_file("scs", 0600, dir, dev, &fops_scs); debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir, mt7615_radio_read); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index e07ce2c10013..237d15521e18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -41,6 +41,16 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev, return &sta->vif->sta.wcid; } +void mt7615_mac_reset_counters(struct mt7615_dev *dev) +{ + int i; + + for (i = 0; i < 4; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); +} + int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; @@ -1261,6 +1271,7 @@ void mt7615_update_channel(struct mt76_dev *mdev) void mt7615_mac_work(struct work_struct *work) { struct mt7615_dev *dev; + int i, idx; dev = (struct mt7615_dev *)container_of(work, struct mt76_dev, mac_work.work); @@ -1271,6 +1282,13 @@ void mt7615_mac_work(struct work_struct *work) mt7615_mac_scs_check(dev); dev->mac_work_count = 0; } + + for (i = 0, idx = 0; i < 4; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; + } mutex_unlock(&dev->mt76.mutex); mt76_tx_status_check(&dev->mt76, NULL, false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 7252423a89fa..6949cda9df0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -16,6 +16,8 @@ static int mt7615_start(struct ieee80211_hw *hw) { struct mt7615_dev *dev = hw->priv; + mt7615_mac_reset_counters(dev); + dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 7963e302d705..efb8be29c392 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -229,6 +229,7 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) } void mt7615_update_channel(struct mt76_dev *mdev); +void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 43676736a807..643b8bd17850 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -136,6 +136,10 @@ MT_AGG_ARxCR_LIMIT_SHIFT(_n), \ MT_AGG_ARxCR_LIMIT_SHIFT(_n)) +#define MT_AGG_ASRCR0 MT_WF_AGG(0x060) +#define MT_AGG_ASRCR1 MT_WF_AGG(0x064) +#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) + #define MT_AGG_ACR0 MT_WF_AGG(0x070) #define MT_AGG_ACR1 MT_WF_AGG(0x170) #define MT_AGG_ACR_NO_BA_RULE BIT(0) @@ -285,6 +289,8 @@ #define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) #define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2)) + #define MT_EFUSE_BASE 0x81070000 #define MT_EFUSE_BASE_CTRL 0x000 #define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) -- cgit v1.2.3-59-g8ed1b From 5a8d4678e02bb3ab89191336b505dd7a7212c4e3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 13 Sep 2019 09:05:54 +0200 Subject: mt76: mt7603: collect aggregation stats Introduce ampdu_stat entry in mt7603 debugfs in order to dump 802.11 aggr cumulative statistics Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- .../net/wireless/mediatek/mt76/mt7603/debugfs.c | 36 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 18 +++++++++++ drivers/net/wireless/mediatek/mt76/mt7603/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 1 + drivers/net/wireless/mediatek/mt76/mt7603/regs.h | 5 +++ 5 files changed, 61 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index 45eb24862240..47c85a9fac28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -69,6 +69,41 @@ mt7603_edcca_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get, mt7603_edcca_set, "%lld\n"); +static int +mt7603_ampdu_stat_read(struct seq_file *file, void *data) +{ + struct mt7603_dev *dev = file->private; + int bound[3], i, range; + + range = mt76_rr(dev, MT_AGG_ASRCR); + for (i = 0; i < ARRAY_SIZE(bound); i++) + bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1; + + seq_printf(file, "Length: %8d | ", bound[0]); + for (i = 0; i < ARRAY_SIZE(bound) - 1; i++) + seq_printf(file, "%3d -%3d | ", + bound[i], bound[i + 1]); + seq_puts(file, "\nCount: "); + for (i = 0; i < ARRAY_SIZE(bound); i++) + seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]); + seq_puts(file, "\n"); + + return 0; +} + +static int +mt7603_ampdu_stat_open(struct inode *inode, struct file *f) +{ + return single_open(f, mt7603_ampdu_stat_read, inode->i_private); +} + +static const struct file_operations fops_ampdu_stat = { + .open = mt7603_ampdu_stat_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + void mt7603_init_debugfs(struct mt7603_dev *dev) { struct dentry *dir; @@ -77,6 +112,7 @@ void mt7603_init_debugfs(struct mt7603_dev *dev) if (!dir) return; + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir, mt76_queues_read); debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index c328192307c4..c52c4bf5597e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -31,6 +31,16 @@ mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask) mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask)); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev) +{ + int i; + + for (i = 0; i < 2; i++) + mt76_rr(dev, MT_TX_AGG_CNT(i)); + + memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); +} + void mt7603_mac_set_timing(struct mt7603_dev *dev) { u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) | @@ -1677,6 +1687,7 @@ void mt7603_mac_work(struct work_struct *work) struct mt7603_dev *dev = container_of(work, struct mt7603_dev, mt76.mac_work.work); bool reset = false; + int i, idx; mt76_tx_status_check(&dev->mt76, NULL, false); @@ -1686,6 +1697,13 @@ void mt7603_mac_work(struct work_struct *work) mt7603_update_channel(&dev->mt76); mt7603_edcca_check(dev); + for (i = 0, idx = 0; i < 2; i++) { + u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); + + dev->mt76.aggr_stats[idx++] += val & 0xffff; + dev->mt76.aggr_stats[idx++] += val >> 16; + } + if (dev->mac_work_count == 10) mt7603_false_cca_check(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 4b3217b43a04..9c378f017877 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -13,6 +13,7 @@ mt7603_start(struct ieee80211_hw *hw) { struct mt7603_dev *dev = hw->priv; + mt7603_mac_reset_counters(dev); mt7603_mac_start(dev); dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 257300fec4f8..fb10adca17f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -191,6 +191,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } +void mt7603_mac_reset_counters(struct mt7603_dev *dev); void mt7603_mac_dma_start(struct mt7603_dev *dev); void mt7603_mac_start(struct mt7603_dev *dev); void mt7603_mac_stop(struct mt7603_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index eb9eefe8e125..6e23ed3dfdff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -212,6 +212,9 @@ #define MT_AGG_PCR_RTS_THR GENMASK(19, 0) #define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25) +#define MT_AGG_ASRCR MT_WF_AGG(0x060) +#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0)) + #define MT_AGG_CONTROL MT_WF_AGG(0x070) #define MT_AGG_CONTROL_NO_BA_RULE BIT(0) #define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1) @@ -555,6 +558,8 @@ enum { #define MT_MIB_STAT_PSCCA MT_MIB_STAT(16) #define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0) +#define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2)) + #define MT_MIB_STAT_ED MT_MIB_STAT(18) #define MT_MIB_STAT_ED_MASK GENMASK(23, 0) -- cgit v1.2.3-59-g8ed1b From 055da6cfd0dc5c87f8999f747cc9dce75b390419 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 Aug 2019 11:07:39 +0200 Subject: mt76: mt7603: remove q_rx field from struct mt7603_dev It is no longer used Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index fb10adca17f3..17176de4fb23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -118,8 +118,6 @@ struct mt7603_dev { ktime_t ed_time; - struct mt76_queue q_rx; - spinlock_t ps_lock; u8 mac_work_count; -- cgit v1.2.3-59-g8ed1b From d515fdca46e7290547547f7a5e1a30c608eeb0ac Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 28 Aug 2019 11:28:36 +0200 Subject: mt76: report rx a-mpdu subframe status This can be used in monitor mode to figure out which subframes were sent as part of which A-MPDU Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 14 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 14 ++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 15 +++++++++++++++ 7 files changed, 50 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 1a2c143b34d0..cc301216e527 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -502,6 +502,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) status->band = mstat.band; status->signal = mstat.signal; status->chains = mstat.chains; + status->ampdu_reference = mstat.ampdu_ref; BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(status->chain_signal) != diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index b3e776ef9469..187c3e8998d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -438,6 +438,7 @@ struct mt76_dev { spinlock_t rx_lock; struct napi_struct napi[__MT_RXQ_MAX]; struct sk_buff_head rx_skb[__MT_RXQ_MAX]; + u32 ampdu_ref; struct list_head txwi_cache; struct mt76_sw_queue q_tx[__MT_TXQ_MAX]; @@ -514,6 +515,8 @@ struct mt76_rx_status { unsigned long reorder_time; + u32 ampdu_ref; + u8 iv[6]; u8 aggr:1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index c52c4bf5597e..44d093943588 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -445,6 +445,20 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } + if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | + MT_RXD2_NORMAL_NON_AMPDU))) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (dev->rx_ampdu_ts != rxd[12]) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + dev->rx_ampdu_ts = rxd[12]; + + status->ampdu_ref = dev->mt76.ampdu_ref; + } + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 17176de4fb23..01b933538c25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -109,6 +109,7 @@ struct mt7603_dev { u32 false_cca_ofdm, false_cca_cck; unsigned long last_cca_adj; + __le32 rx_ampdu_ts; u8 rssi_offset[3]; u8 slottime; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 237d15521e18..88271524fb83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -93,6 +93,20 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED; } + if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB | + MT_RXD2_NORMAL_NON_AMPDU))) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + + /* all subframes of an A-MPDU have the same timestamp */ + if (dev->rx_ampdu_ts != rxd[12]) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + dev->rx_ampdu_ts = rxd[12]; + + status->ampdu_ref = dev->mt76.ampdu_ref; + } + remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET; if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index efb8be29c392..fa8f2f1ed040 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -81,6 +81,8 @@ struct mt7615_dev { u32 vif_mask; u32 omac_mask; + __le32 rx_ampdu_ts; + struct { u8 n_pulses; u32 period; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 0d000906b2e1..9d2795c1e943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -789,6 +789,21 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) status->aggr = true; + if (rxinfo & MT_RXINFO_AMPDU) { + status->flag |= RX_FLAG_AMPDU_DETAILS; + status->ampdu_ref = dev->mt76.ampdu_ref; + + /* + * When receiving an A-MPDU subframe and RSSI info is not valid, + * we can assume that more subframes belonging to the same A-MPDU + * are coming. The last one will have valid RSSI info + */ + if (!(rxinfo & MT_RXINFO_RSSI)) { + if (!++dev->mt76.ampdu_ref) + dev->mt76.ampdu_ref++; + } + } + if (WARN_ON_ONCE(len > skb->len)) return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 9ec0b821b815243d60235220c45250805398147b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 31 Aug 2019 12:41:59 +0200 Subject: mt76: rename mt76_driver_ops txwi_flags to drv_flags and include tx aligned4 This reduces the struct size and is useful for adding more flags later Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 8f69d00bd940..6442a45ba303 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -166,7 +166,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush) dev->drv->tx_complete_skb(dev, qid, &entry); if (entry.txwi) { - if (!(dev->drv->txwi_flags & MT_TXWI_NO_FREE)) + if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE)) mt76_put_txwi(dev, entry.txwi); wake = !flush; } @@ -301,7 +301,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; - if (dev->drv->tx_aligned4_skbs) + if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS) mt76_insert_hdr_pad(skb); len = skb_headlen(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 187c3e8998d6..daf2b640e4d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -280,11 +280,11 @@ struct mt76_hw_cap { bool has_5ghz; }; -#define MT_TXWI_NO_FREE BIT(0) +#define MT_DRV_TXWI_NO_FREE BIT(0) +#define MT_DRV_TX_ALIGNED4_SKBS BIT(1) struct mt76_driver_ops { - bool tx_aligned4_skbs; - u32 txwi_flags; + u32 drv_flags; u16 txwi_size; void (*update_survey)(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index e250607e0a80..73744563a573 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -72,7 +72,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev, static const struct mt76_driver_ops drv_ops = { /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp), - .txwi_flags = MT_TXWI_NO_FREE, + .drv_flags = MT_DRV_TXWI_NO_FREE, .tx_prepare_skb = mt7615_tx_prepare_skb, .tx_complete_skb = mt7615_tx_complete_skb, .rx_skb = mt7615_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 7705e55aa3d1..d20fd40418a7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -155,7 +155,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .tx_aligned4_skbs = true, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index cf611d1b817c..3d8408d11f0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -21,7 +21,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .tx_aligned4_skbs = true, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, -- cgit v1.2.3-59-g8ed1b From 0fd0eb54bfe09afc1c0fd5da2893338c215de276 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 16:58:08 +0200 Subject: mt76: store current channel survey_state in struct mt76_dev Move mt76_channel_state() from mt76.h to mac80211.c Preparation for updating channel state from more places in the drivers/core Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 24 +++++++++++++++++++----- drivers/net/wireless/mediatek/mt76/mt76.h | 16 +--------------- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 2 +- 5 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index cc301216e527..aefdd22d74ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -180,6 +180,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, sband->bitrates = rates; sband->n_bitrates = n_rates; dev->chandef.chan = &sband->channels[0]; + dev->chan_state = &msband->chan[0]; ht_cap = &sband->ht_cap; ht_cap->ht_supported = true; @@ -398,11 +399,25 @@ bool mt76_has_tx_pending(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); +static struct mt76_channel_state * +mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) +{ + struct mt76_sband *msband; + int idx; + + if (c->band == NL80211_BAND_2GHZ) + msband = &dev->sband_2g; + else + msband = &dev->sband_5g; + + idx = c - &msband->sband.channels[0]; + return &msband->chan[idx]; +} + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct cfg80211_chan_def *chandef = &hw->conf.chandef; - struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; int timeout = HZ / 5; @@ -412,14 +427,13 @@ void mt76_set_channel(struct mt76_dev *dev) dev->drv->update_survey(dev); dev->chandef = *chandef; + dev->chan_state = mt76_channel_state(dev, chandef->chan); if (!offchannel) dev->main_chan = chandef->chan; - if (chandef->chan != dev->main_chan) { - state = mt76_channel_state(dev, chandef->chan); - memset(state, 0, sizeof(*state)); - } + if (chandef->chan != dev->main_chan) + memset(dev->chan_state, 0, sizeof(*dev->chan_state)); } EXPORT_SYMBOL_GPL(mt76_set_channel); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index daf2b640e4d4..f26b51f94437 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -424,6 +424,7 @@ struct mt76_dev { struct cfg80211_chan_def chandef; struct ieee80211_channel *main_chan; + struct mt76_channel_state *chan_state; spinlock_t lock; spinlock_t cc_lock; @@ -605,21 +606,6 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) -static inline struct mt76_channel_state * -mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) -{ - struct mt76_sband *msband; - int idx; - - if (c->band == NL80211_BAND_2GHZ) - msband = &dev->sband_2g; - else - msband = &dev->sband_5g; - - idx = c - &msband->sband.channels[0]; - return &msband->chan[idx]; -} - struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size, const struct ieee80211_ops *ops, const struct mt76_driver_ops *drv_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 44d093943588..3d160230d929 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1491,7 +1491,7 @@ void mt7603_update_channel(struct mt76_dev *mdev) if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) return; - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + state = mdev->chan_state; busy = mt76_rr(dev, MT_MIB_STAT_PSCCA); spin_lock_bh(&dev->mt76.cc_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 88271524fb83..9189a86d7825 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1269,7 +1269,7 @@ void mt7615_update_channel(struct mt76_dev *mdev) if (!test_bit(MT76_STATE_RUNNING, &mdev->state)) return; - state = mt76_channel_state(mdev, mdev->chandef.chan); + state = mdev->chan_state; /* TODO: add DBDC support */ busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 9d2795c1e943..f73ec17e5f47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -986,7 +986,7 @@ void mt76x02_update_channel(struct mt76_dev *mdev) struct mt76_channel_state *state; u32 active, busy; - state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + state = mdev->chan_state; busy = mt76_rr(dev, MT_CH_BUSY); active = busy + mt76_rr(dev, MT_CH_IDLE); -- cgit v1.2.3-59-g8ed1b From 5ce09c1a79074f613326f626f4781d21fc557296 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 17:45:02 +0200 Subject: mt76: track rx airtime for airtime fairness and survey Report total rx airtime for valid stations as BSS rx time in survey mt7615 is left out for now, it will be supported later by reading hardware counters instead of calculating airtime in software Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/Makefile | 2 +- drivers/net/wireless/mediatek/mt76/airtime.c | 278 +++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mac80211.c | 110 ++++++++- drivers/net/wireless/mediatek/mt76/mt76.h | 64 ++++-- drivers/net/wireless/mediatek/mt76/mt7603/init.c | 1 + drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 4 +- drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 3 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 12 files changed, 434 insertions(+), 37 deletions(-) create mode 100644 drivers/net/wireless/mediatek/mt76/airtime.c (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d7a1ddc9e407..99bbc74acda8 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ - tx.o agg-rx.o mcu.o + tx.o agg-rx.o mcu.o airtime.o mt76-$(CONFIG_PCI) += pci.o diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c new file mode 100644 index 000000000000..d5bc4d713a88 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2019 Felix Fietkau + */ + +#include "mt76.h" + +#define AVG_PKT_SIZE 1024 + +/* Number of bits for an average sized packet */ +#define MCS_NBITS (AVG_PKT_SIZE << 3) + +/* Number of symbols for a packet with (bps) bits per symbol */ +#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) + +/* Transmission time (1024 usec) for a packet containing (syms) * symbols */ +#define MCS_SYMBOL_TIME(sgi, syms) \ + (sgi ? \ + ((syms) * 18 * 1024 + 4 * 1024) / 5 : /* syms * 3.6 us */ \ + ((syms) * 1024) << 2 /* syms * 4 us */ \ + ) + +/* Transmit duration for the raw data part of an average sized packet */ +#define MCS_DURATION(streams, sgi, bps) \ + MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) + +#define BW_20 0 +#define BW_40 1 +#define BW_80 2 + +/* + * Define group sort order: HT40 -> SGI -> #streams + */ +#define MT_MAX_STREAMS 4 +#define MT_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ +#define MT_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ + +#define MT_HT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_HT_STREAM_GROUPS) +#define MT_VHT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_VHT_STREAM_GROUPS) +#define MT_GROUPS_NB (MT_HT_GROUPS_NB + \ + MT_VHT_GROUPS_NB) + +#define MT_HT_GROUP_0 0 +#define MT_VHT_GROUP_0 (MT_HT_GROUP_0 + MT_HT_GROUPS_NB) + +#define MCS_GROUP_RATES 10 + +#define HT_GROUP_IDX(_streams, _sgi, _ht40) \ + MT_HT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * _ht40 + \ + MT_MAX_STREAMS * _sgi + \ + _streams - 1 + +#define _MAX(a, b) (((a)>(b))?(a):(b)) + +#define GROUP_SHIFT(duration) \ + _MAX(0, 16 - __builtin_clz(duration)) + +/* MCS rate information for an MCS group */ +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ + [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ + } \ +} + +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) + +#define MCS_GROUP(_streams, _sgi, _ht40) \ + __MCS_GROUP(_streams, _sgi, _ht40, \ + MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) + +#define VHT_GROUP_IDX(_streams, _sgi, _bw) \ + (MT_VHT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * (_bw) + \ + MT_MAX_STREAMS * (_sgi) + \ + (_streams) - 1) + +#define BW2VBPS(_bw, r3, r2, r1) \ + (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) + +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ + [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ + } \ +} + +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26))) + +#define VHT_GROUP(_streams, _sgi, _bw) \ + __VHT_GROUP(_streams, _sgi, _bw, \ + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) + +struct mcs_group { + u8 shift; + u16 duration[MCS_GROUP_RATES]; +}; + +static const struct mcs_group airtime_mcs_groups[] = { + MCS_GROUP(1, 0, BW_20), + MCS_GROUP(2, 0, BW_20), + MCS_GROUP(3, 0, BW_20), + MCS_GROUP(4, 0, BW_20), + + MCS_GROUP(1, 1, BW_20), + MCS_GROUP(2, 1, BW_20), + MCS_GROUP(3, 1, BW_20), + MCS_GROUP(4, 1, BW_20), + + MCS_GROUP(1, 0, BW_40), + MCS_GROUP(2, 0, BW_40), + MCS_GROUP(3, 0, BW_40), + MCS_GROUP(4, 0, BW_40), + + MCS_GROUP(1, 1, BW_40), + MCS_GROUP(2, 1, BW_40), + MCS_GROUP(3, 1, BW_40), + MCS_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_20), + VHT_GROUP(2, 0, BW_20), + VHT_GROUP(3, 0, BW_20), + VHT_GROUP(4, 0, BW_20), + + VHT_GROUP(1, 1, BW_20), + VHT_GROUP(2, 1, BW_20), + VHT_GROUP(3, 1, BW_20), + VHT_GROUP(4, 1, BW_20), + + VHT_GROUP(1, 0, BW_40), + VHT_GROUP(2, 0, BW_40), + VHT_GROUP(3, 0, BW_40), + VHT_GROUP(4, 0, BW_40), + + VHT_GROUP(1, 1, BW_40), + VHT_GROUP(2, 1, BW_40), + VHT_GROUP(3, 1, BW_40), + VHT_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_80), + VHT_GROUP(2, 0, BW_80), + VHT_GROUP(3, 0, BW_80), + VHT_GROUP(4, 0, BW_80), + + VHT_GROUP(1, 1, BW_80), + VHT_GROUP(2, 1, BW_80), + VHT_GROUP(3, 1, BW_80), + VHT_GROUP(4, 1, BW_80), +}; + +static u32 +mt76_calc_legacy_rate_duration(const struct ieee80211_rate *rate, bool short_pre, + int len) +{ + u32 duration; + + switch (rate->hw_value >> 8) { + case MT_PHY_TYPE_CCK: + duration = 144 + 48; /* preamble + PLCP */ + if (short_pre) + duration >>= 1; + + duration += 10; /* SIFS */ + break; + case MT_PHY_TYPE_OFDM: + duration = 20 + 16; /* premable + SIFS */ + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + len <<= 3; + duration += (len * 10) / rate->bitrate; + + return duration; +} + +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct ieee80211_supported_band *sband; + const struct ieee80211_rate *rate; + bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; + int bw, streams; + u32 duration; + int group, idx; + + switch (status->bw) { + case RATE_INFO_BW_20: + bw = BW_20; + break; + case RATE_INFO_BW_40: + bw = BW_40; + break; + case RATE_INFO_BW_80: + bw = BW_80; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + switch (status->encoding) { + case RX_ENC_LEGACY: + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) + return 0; + + sband = dev->hw->wiphy->bands[status->band]; + if (!sband || status->rate_idx > sband->n_bitrates) + return 0; + + rate = &sband->bitrates[status->rate_idx]; + + return mt76_calc_legacy_rate_duration(rate, sp, len); + case RX_ENC_VHT: + streams = status->nss; + idx = status->rate_idx; + group = VHT_GROUP_IDX(streams, sgi, bw); + break; + case RX_ENC_HT: + streams = ((status->rate_idx >> 3) & 3) + 1; + idx = status->rate_idx & 7; + group = HT_GROUP_IDX(streams, sgi, bw); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + if (WARN_ON_ONCE(streams > 4)) + return 0; + + duration = airtime_mcs_groups[group].duration[idx]; + duration <<= airtime_mcs_groups[group].shift; + duration *= len; + duration /= AVG_PKT_SIZE; + duration /= 1024; + + duration += 36 + (streams << 2); + + return duration; +} diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index aefdd22d74ef..c6076c66cd37 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -414,6 +414,25 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) return &msband->chan[idx]; } +void mt76_update_survey(struct mt76_dev *dev) +{ + struct mt76_channel_state *state; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { + state = mt76_channel_state(dev, dev->chandef.chan); + spin_lock_bh(&dev->rx_lock); + spin_lock(&dev->cc_lock); + state->cc_bss_rx += dev->cur_cc_bss_rx; + dev->cur_cc_bss_rx = 0; + spin_unlock(&dev->cc_lock); + spin_unlock_bh(&dev->rx_lock); + } +} +EXPORT_SYMBOL_GPL(mt76_update_survey); + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; @@ -422,9 +441,7 @@ void mt76_set_channel(struct mt76_dev *dev) int timeout = HZ / 5; wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); - - if (dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); dev->chandef = *chandef; dev->chan_state = mt76_channel_state(dev, chandef->chan); @@ -447,7 +464,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, int ret = 0; if (idx == 0 && dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); sband = &dev->sband_2g; if (idx >= sband->sband.n_channels) { @@ -464,12 +481,17 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; - if (chan == dev->main_chan) + if (chan == dev->main_chan) { survey->filled |= SURVEY_INFO_IN_USE; + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) + survey->filled |= SURVEY_INFO_TIME_BSS_RX; + } + spin_lock_bh(&dev->cc_lock); survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); + survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); spin_unlock_bh(&dev->cc_lock); return ret; @@ -566,6 +588,82 @@ mt76_check_ccmp_pn(struct sk_buff *skb) return 0; } +static void +mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct mt76_wcid *wcid = status->wcid; + struct ieee80211_sta *sta; + u32 airtime; + + airtime = mt76_calc_rx_airtime(dev, status, len); + dev->cur_cc_bss_rx += airtime; + + if (!wcid || !wcid->sta) + return; + + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); + ieee80211_sta_register_airtime(sta, status->tid, 0, airtime); +} + +static void +mt76_airtime_flush_ampdu(struct mt76_dev *dev) +{ + struct mt76_wcid *wcid; + int wcid_idx; + + if (!dev->rx_ampdu_len) + return; + + wcid_idx = dev->rx_ampdu_status.wcid_idx; + if (dev->rx_ampdu_status.wcid_idx != 0xff) + wcid = rcu_dereference(dev->wcid[wcid_idx]); + else + wcid = NULL; + dev->rx_ampdu_status.wcid = wcid; + + mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len); + + dev->rx_ampdu_len = 0; + dev->rx_ampdu_ref = 0; +} + +static void +mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct mt76_wcid *wcid = status->wcid; + + if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)) + return; + + if (!wcid || !wcid->sta) { + if (!ether_addr_equal(hdr->addr1, dev->macaddr)) + return; + + wcid = NULL; + } + + if (!(status->flag & RX_FLAG_AMPDU_DETAILS) || + status->ampdu_ref != dev->rx_ampdu_ref) + mt76_airtime_flush_ampdu(dev); + + if (status->flag & RX_FLAG_AMPDU_DETAILS) { + if (!dev->rx_ampdu_len || + status->ampdu_ref != dev->rx_ampdu_ref) { + dev->rx_ampdu_status = *status; + dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff; + dev->rx_ampdu_ref = status->ampdu_ref; + } + + dev->rx_ampdu_len += skb->len; + return; + } + + mt76_airtime_report(dev, status, skb->len); +} + static void mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) { @@ -582,6 +680,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; } + mt76_airtime_check(dev, skb); + if (!wcid || !wcid->sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f26b51f94437..048b7ebbc46d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -282,6 +282,7 @@ struct mt76_hw_cap { #define MT_DRV_TXWI_NO_FREE BIT(0) #define MT_DRV_TX_ALIGNED4_SKBS BIT(1) +#define MT_DRV_SW_RX_AIRTIME BIT(2) struct mt76_driver_ops { u32 drv_flags; @@ -320,6 +321,7 @@ struct mt76_driver_ops { struct mt76_channel_state { u64 cc_active; u64 cc_busy; + u64 cc_bss_rx; }; struct mt76_sband { @@ -419,6 +421,34 @@ struct mt76_mmio { u32 irqmask; }; +struct mt76_rx_status { + union { + struct mt76_wcid *wcid; + u8 wcid_idx; + }; + + unsigned long reorder_time; + + u32 ampdu_ref; + + u8 iv[6]; + + u8 aggr:1; + u8 tid; + u16 seqno; + + u16 freq; + u32 flag; + u8 enc_flags; + u8 encoding:2, bw:3; + u8 rate_idx; + u8 nss; + u8 band; + s8 signal; + u8 chains; + s8 chain_signal[IEEE80211_MAX_CHAINS]; +}; + struct mt76_dev { struct ieee80211_hw *hw; struct cfg80211_chan_def chandef; @@ -428,6 +458,12 @@ struct mt76_dev { spinlock_t lock; spinlock_t cc_lock; + u32 cur_cc_bss_rx; + + struct mt76_rx_status rx_ampdu_status; + u32 rx_ampdu_len; + u32 rx_ampdu_ref; + struct mutex mutex; const struct mt76_bus_ops *bus; @@ -511,31 +547,6 @@ enum mt76_phy_type { MT_PHY_TYPE_VHT, }; -struct mt76_rx_status { - struct mt76_wcid *wcid; - - unsigned long reorder_time; - - u32 ampdu_ref; - - u8 iv[6]; - - u8 aggr:1; - u8 tid; - u16 seqno; - - u16 freq; - u32 flag; - u8 enc_flags; - u8 encoding:2, bw:3; - u8 rate_idx; - u8 nss; - u8 band; - s8 signal; - u8 chains; - s8 chain_signal[IEEE80211_MAX_CHAINS]; -}; - #define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__) #define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__) #define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__) @@ -708,6 +719,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, bool more_data); bool mt76_has_tx_pending(struct mt76_dev *dev); void mt76_set_channel(struct mt76_dev *dev); +void mt76_update_survey(struct mt76_dev *dev); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); void mt76_set_stream_caps(struct mt76_dev *dev, bool vht); @@ -768,6 +780,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames, void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q, struct napi_struct *napi); void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames); +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index ad2ccdbe7258..a68533684b18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -7,6 +7,7 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, + .drv_flags = MT_DRV_SW_RX_AIRTIME, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 3d160230d929..0212384d0d56 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1708,7 +1708,7 @@ void mt7603_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); dev->mac_work_count++; - mt7603_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); mt7603_edcca_check(dev); for (i = 0, idx = 0; i < 2; i++) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 9189a86d7825..81f45c4ccc26 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1291,7 +1291,7 @@ void mt7615_mac_work(struct work_struct *work) mac_work.work); mutex_lock(&dev->mt76.mutex); - mt7615_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); if (++dev->mac_work_count == 5) { mt7615_mac_scs_check(dev); dev->mac_work_count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index d20fd40418a7..f42450b4319c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -155,7 +155,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | + MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 4c2b66b53533..54f9c0cc881f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -211,6 +211,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { + .drv_flags = MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index f73ec17e5f47..c987e57db0b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -798,7 +798,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, * we can assume that more subframes belonging to the same A-MPDU * are coming. The last one will have valid RSSI info */ - if (!(rxinfo & MT_RXINFO_RSSI)) { + if (rxinfo & MT_RXINFO_RSSI) { if (!++dev->mt76.ampdu_ref) dev->mt76.ampdu_ref++; } @@ -1130,7 +1130,7 @@ void mt76x02_mac_work(struct work_struct *work) mutex_lock(&dev->mt76.mutex); - mt76x02_update_channel(&dev->mt76); + mt76_update_survey(&dev->mt76); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 3d8408d11f0e..8f57ef50f35d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -21,7 +21,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x02_txwi), - .drv_flags = MT_DRV_TX_ALIGNED4_SKBS, + .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | + MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index da5e0f9a8bae..81be59c60155 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -25,6 +25,7 @@ static int mt76x2u_probe(struct usb_interface *intf, const struct usb_device_id *id) { static const struct mt76_driver_ops drv_ops = { + .drv_flags = MT_DRV_SW_RX_AIRTIME, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, -- cgit v1.2.3-59-g8ed1b From ea565833fd7848208eb63fc653d32a6ad3a86d87 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 20:50:14 +0200 Subject: mt76: mt7603: track tx airtime for airtime fairness and survey Poll per-station hardware counters after tx status events Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 + drivers/net/wireless/mediatek/mt76/mt76.h | 2 + drivers/net/wireless/mediatek/mt76/mt7603/dma.c | 2 + drivers/net/wireless/mediatek/mt76/mt7603/init.c | 3 + drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 86 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7603/main.c | 15 +++- drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h | 7 ++ 7 files changed, 116 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c6076c66cd37..38db311b3ca8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -481,6 +481,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; + survey->filled |= dev->drv->survey_flags; if (chan == dev->main_chan) { survey->filled |= SURVEY_INFO_IN_USE; @@ -492,6 +493,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); + survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 048b7ebbc46d..322595f4e84e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -286,6 +286,7 @@ struct mt76_hw_cap { struct mt76_driver_ops { u32 drv_flags; + u32 survey_flags; u16 txwi_size; void (*update_survey)(struct mt76_dev *dev); @@ -322,6 +323,7 @@ struct mt76_channel_state { u64 cc_active; u64 cc_busy; u64 cc_bss_rx; + u64 cc_tx; }; struct mt76_sband { diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 24d82a20d046..a6ab73060aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget) for (i = MT_TXQ_MCU; i >= 0; i--) mt76_queue_tx_cleanup(dev, i, false); + mt7603_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index a68533684b18..3a2927a524c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -8,6 +8,7 @@ const struct mt76_driver_ops mt7603_drv_ops = { .txwi_size = MT_TXD_SIZE, .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .tx_prepare_skb = mt7603_tx_prepare_skb, .tx_complete_skb = mt7603_tx_complete_skb, .rx_skb = mt7603_queue_rx_skb, @@ -525,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev) bus_ops->rmw = mt7603_rmw; dev->mt76.bus = bus_ops; + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); spin_lock_init(&dev->ps_lock); INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 0212384d0d56..caa1456adc50 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -160,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif, addr = mt7603_wtbl4_addr(idx); for (i = 0; i < MT_WTBL4_SIZE; i += 4) mt76_wr(dev, addr + i, 0); + + mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); } static void @@ -380,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val); } +void mt7603_mac_sta_poll(struct mt7603_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + struct ieee80211_sta *sta; + struct mt7603_sta *msta; + u32 total_airtime = 0; + u32 airtime[4]; + u32 addr; + int i; + + rcu_read_lock(); + + while (1) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + + msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta, + poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7603_wtbl4_addr(msta->wcid.idx); + for (i = 0; i < 4; i++) { + u32 airtime_last = msta->tx_airtime_ac[i]; + + msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8); + airtime[i] = msta->tx_airtime_ac[i] - airtime_last; + airtime[i] *= 32; + total_airtime += airtime[i]; + + if (msta->tx_airtime_ac[i] & BIT(22)) + clear = true; + } + + if (clear) { + mt7603_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->tx_airtime_ac, 0, + sizeof(msta->tx_airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + for (i = 0; i < 4; i++) { + struct mt76_queue *q = dev->mt76.q_tx[i].q; + u8 qidx = q->hw_idx; + u8 tid = ac_to_tid[i]; + u32 txtime = airtime[qidx]; + + if (!txtime) + continue; + + ieee80211_sta_register_airtime(sta, tid, txtime, 0); + } + } + + rcu_read_unlock(); + + if (!total_airtime) + return; + + spin_lock_bh(&dev->mt76.cc_lock); + dev->mt76.chan_state->cc_tx += total_airtime; + spin_unlock_bh(&dev->mt76.cc_lock); +} + static struct mt76_wcid * mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast) { @@ -1159,6 +1239,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data) msta = container_of(wcid, struct mt7603_sta, wcid); sta = wcid_to_sta(wcid); + if (list_empty(&msta->poll_list)) { + spin_lock_bh(&dev->sta_poll_lock); + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 9c378f017877..31cce1c005c6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -66,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) idx = MT7603_WTBL_RESERVED - 1 - mvif->idx; dev->vif_mask |= BIT(mvif->idx); + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; @@ -87,8 +88,9 @@ static void mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv; + struct mt7603_sta *msta = &mvif->sta; struct mt7603_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0); mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0); @@ -99,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) rcu_assign_pointer(dev->mt76.wcid[idx], NULL); mt76_txq_remove(&dev->mt76, vif->txq); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mutex_lock(&dev->mt76.mutex); dev->vif_mask &= ~BIT(mvif->idx); mutex_unlock(&dev->mt76.mutex); @@ -325,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); __skb_queue_head_init(&msta->psq); msta->ps = ~0; msta->smps = ~0; @@ -361,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, mt7603_filter_tx(dev, wcid->idx, true); spin_unlock_bh(&dev->ps_lock); + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + mt7603_wtbl_clear(dev, wcid->idx); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 01b933538c25..ab54b0612e98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -61,6 +61,9 @@ struct mt7603_sta { struct mt7603_vif *vif; + struct list_head poll_list; + u32 tx_airtime_ac[4]; + struct sk_buff_head psq; struct ieee80211_tx_rate rates[4]; @@ -103,6 +106,9 @@ struct mt7603_dev { u8 vif_mask; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct mt7603_sta global_sta; u32 agc0, agc3; @@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data); void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid); void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid, int ba_size); +void mt7603_mac_sta_poll(struct mt7603_dev *dev); void mt7603_pse_client_reset(struct mt7603_dev *dev); -- cgit v1.2.3-59-g8ed1b From dcff8d4dc301c0601625ccae0dffec1bbef83234 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 4 Sep 2019 21:12:10 +0200 Subject: mt76: mt7603: switch to a different counter for survey busy time MT_MIB_STAT_PSCCA only counts rx CCA busy time, which does not include tx time. MT_MIB_STAT_CCA counts full busy time, including Rx, Tx and NAV Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index caa1456adc50..8e6568d4505b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1578,7 +1578,7 @@ void mt7603_update_channel(struct mt76_dev *mdev) return; state = mdev->chan_state; - busy = mt76_rr(dev, MT_MIB_STAT_PSCCA); + busy = mt76_rr(dev, MT_MIB_STAT_CCA); spin_lock_bh(&dev->mt76.cc_lock); cur_time = ktime_get_boottime(); -- cgit v1.2.3-59-g8ed1b From aec65e484779c6326116be921cc1bf1aa8e85ecc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 18:29:13 +0200 Subject: mt76: unify channel survey update code Host time is used to calculate the channel active time on mt7603 and mt7615. Use the same on mt76x02 and move the lock to core code to get rid of some duplicated code. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 16 ++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 15 +-------------- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 18 +++--------------- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 20 +++++++++++--------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 5 +---- drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 5 +---- 8 files changed, 33 insertions(+), 52 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 38db311b3ca8..10d736967fbb 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -416,13 +416,25 @@ mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) void mt76_update_survey(struct mt76_dev *dev) { - struct mt76_channel_state *state; + struct mt76_channel_state *state = dev->chan_state; + ktime_t cur_time; + + if (!test_bit(MT76_STATE_RUNNING, &dev->state)) + return; + + spin_lock_bh(&dev->cc_lock); if (dev->drv->update_survey) dev->drv->update_survey(dev); + cur_time = ktime_get_boottime(); + state->cc_active += ktime_to_us(ktime_sub(cur_time, + dev->survey_time)); + dev->survey_time = cur_time; + + spin_unlock_bh(&dev->cc_lock); + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - state = mt76_channel_state(dev, dev->chandef.chan); spin_lock_bh(&dev->rx_lock); spin_lock(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 8e6568d4505b..1497d5ec649e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1571,22 +1571,9 @@ void mt7603_update_channel(struct mt76_dev *mdev) { struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76); struct mt76_channel_state *state; - ktime_t cur_time; - u32 busy; - - if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) - return; state = mdev->chan_state; - busy = mt76_rr(dev, MT_MIB_STAT_CCA); - - spin_lock_bh(&dev->mt76.cc_lock); - cur_time = ktime_get_boottime(); - state->cc_busy += busy; - state->cc_active += ktime_to_us(ktime_sub(cur_time, - dev->mt76.survey_time)); - dev->mt76.survey_time = cur_time; - spin_unlock_bh(&dev->mt76.cc_lock); + state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA); } void diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 81f45c4ccc26..271f36f4acb3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1263,23 +1263,11 @@ void mt7615_update_channel(struct mt76_dev *mdev) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt76_channel_state *state; - ktime_t cur_time; - u32 busy; - if (!test_bit(MT76_STATE_RUNNING, &mdev->state)) - return; - - state = mdev->chan_state; /* TODO: add DBDC support */ - busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); - - spin_lock_bh(&mdev->cc_lock); - cur_time = ktime_get_boottime(); - state->cc_busy += busy; - state->cc_active += ktime_to_us(ktime_sub(cur_time, - mdev->survey_time)); - mdev->survey_time = cur_time; - spin_unlock_bh(&mdev->cc_lock); + state = mdev->chan_state; + state->cc_busy += mt76_get_field(dev, MT_MIB_SDR16(0), + MT_MIB_BUSY_MASK); } void mt7615_mac_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index efb7ca93863d..f7682bd2e5a8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -19,10 +19,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76_set_channel(&dev->mt76); mt76x0_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x02_edcca_init(dev); if (mt76_is_mmio(dev)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index c987e57db0b4..e49d0136adbc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -984,17 +984,9 @@ void mt76x02_update_channel(struct mt76_dev *mdev) { struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); struct mt76_channel_state *state; - u32 active, busy; state = mdev->chan_state; - - busy = mt76_rr(dev, MT_CH_BUSY); - active = busy + mt76_rr(dev, MT_CH_IDLE); - - spin_lock_bh(&dev->mt76.cc_lock); - state->cc_busy += busy; - state->cc_active += active; - spin_unlock_bh(&dev->mt76.cc_lock); + state->cc_busy += mt76_rr(dev, MT_CH_BUSY); } EXPORT_SYMBOL_GPL(mt76x02_update_channel); @@ -1152,6 +1144,16 @@ void mt76x02_mac_work(struct work_struct *work) MT_MAC_WORK_INTERVAL); } +void mt76x02_mac_cc_reset(struct mt76x02_dev *dev) +{ + dev->mt76.survey_time = ktime_get_boottime(); + + /* channel cycle counters read-and-clear */ + mt76_rr(dev, MT_CH_BUSY); + mt76_rr(dev, MT_CH_IDLE); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset); + void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) { idx &= 7; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index b687341236c0..48de8eb82856 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -193,6 +193,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, void mt76x02_update_channel(struct mt76_dev *mdev); void mt76x02_mac_work(struct work_struct *work); +void mt76x02_mac_cc_reset(struct mt76x02_dev *dev); void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr); int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 385960dca906..1387f3172d7f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -52,10 +52,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76x2_mac_stop(dev, true); ret = mt76x2_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x02_dfs_init_params(dev); mt76x2_mac_resume(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 1e6f78760dd8..a76a40dcd261 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -49,10 +49,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev, err = mt76x2u_phy_set_channel(dev, chandef); - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); - + mt76x02_mac_cc_reset(dev); mt76x2_mac_resume(dev); clear_bit(MT76_RESET, &dev->mt76.state); -- cgit v1.2.3-59-g8ed1b From b02f42f4ed2ff5756780da024108866aa87aa528 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 5 Sep 2019 19:30:21 +0200 Subject: mt76: mt76x02: move MT_CH_TIME_CFG init to mt76x02_mac_cc_reset Reduces code duplication and adds missing bits for USB variants Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 9 +++++++++ drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c | 7 ------- 5 files changed, 9 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index f42450b4319c..9f224f0f7c00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -132,15 +132,6 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev) mt76_clear(dev, 0x110, BIT(9)); mt76_set(dev, MT_MAX_LEN_CFG, BIT(13)); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY | - MT_CH_CCA_RC_EN | - FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - err = mt76x0_register_device(dev); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 54f9c0cc881f..259bd2a55b23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -165,13 +165,6 @@ static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset) FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) | FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58)); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY); - return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index e49d0136adbc..d32efc0b100d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1148,6 +1148,15 @@ void mt76x02_mac_cc_reset(struct mt76x02_dev *dev) { dev->mt76.survey_time = ktime_get_boottime(); + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + MT_CH_CCA_RC_EN | + FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + /* channel cycle counters read-and-clear */ mt76_rr(dev, MT_CH_BUSY); mt76_rr(dev, MT_CH_IDLE); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 3cf54963854a..33fcec9179b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -133,15 +133,6 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard) for (i = 0; i < 16; i++) mt76_rr(dev, MT_TX_STAT_FIFO); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY | - MT_CH_CCA_RC_EN | - FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); - mt76x02_set_tx_ackto(dev); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index e305b374c904..2910068f4e79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -184,13 +184,6 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev) mt76x02_phy_set_rxpath(dev); mt76x02_phy_set_txdac(dev); - mt76_wr(dev, MT_CH_TIME_CFG, - MT_CH_TIME_CFG_TIMER_EN | - MT_CH_TIME_CFG_TX_AS_BUSY | - MT_CH_TIME_CFG_RX_AS_BUSY | - MT_CH_TIME_CFG_NAV_AS_BUSY | - MT_CH_TIME_CFG_EIFS_AS_BUSY); - return mt76x2u_mac_stop(dev); } -- cgit v1.2.3-59-g8ed1b From 355f8d00c597f944213708d296e86a06f7a9ade8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 6 Sep 2019 10:19:19 +0200 Subject: mt76: mt76x02: track approximate tx airtime for airtime fairness and survey Estimate by calculating duration for EWMA packet size + estimated A-MPDU length on tx status events Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/airtime.c | 48 +++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 2 + drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 49 ++++++++++++++++++---- drivers/net/wireless/mediatek/mt76/mt76x02_mac.h | 6 +++ drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c | 10 ++++- .../net/wireless/mediatek/mt76/mt76x02_usb_core.c | 4 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 1 + 12 files changed, 116 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c index d5bc4d713a88..55116f395f9a 100644 --- a/drivers/net/wireless/mediatek/mt76/airtime.c +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -276,3 +276,51 @@ u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, return duration; } + +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len) +{ + struct mt76_rx_status stat = { + .band = info->band, + }; + u32 duration = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { + struct ieee80211_tx_rate *rate = &info->status.rates[i]; + u32 cur_duration; + + if (rate->idx < 0 || !rate->count) + break; + + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_80; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_40; + else + stat.bw = RATE_INFO_BW_20; + + stat.enc_flags = 0; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; + + stat.rate_idx = rate->idx; + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + stat.encoding = RX_ENC_VHT; + stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); + stat.nss = ieee80211_rate_get_vht_nss(rate); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + stat.encoding = RX_ENC_HT; + } else { + stat.encoding = RX_ENC_LEGACY; + } + + cur_duration = mt76_calc_rx_airtime(dev, &stat, len); + duration += cur_duration * rate->count; + } + + return duration; +} +EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 322595f4e84e..8876231d8cdb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -772,6 +772,8 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len); /* internal */ void mt76_tx_free(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 9f224f0f7c00..9621e7b16eaf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -148,6 +148,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id) .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 259bd2a55b23..ade6312c7367 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -205,6 +205,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, { static const struct mt76_driver_ops drv_ops = { .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 50b0131f85bf..0ca0bbfe8769 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -81,6 +81,7 @@ struct mt76x02_dev { u8 txdone_seq; DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status); spinlock_t txstatus_fifo_lock; + u32 tx_airtime; struct sk_buff *rx_head; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index d32efc0b100d..38329ebca572 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -483,8 +483,8 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta, phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate); if (st->pktid & MT_PACKET_ID_HAS_RATE) { - first_rate = st->rate & ~MT_RXWI_RATE_INDEX; - first_rate |= st->pktid & MT_RXWI_RATE_INDEX; + first_rate = st->rate & ~MT_PKTID_RATE; + first_rate |= st->pktid & MT_PKTID_RATE; mt76x02_mac_process_tx_rate(&rate[0], first_rate, dev->mt76.chandef.chan->band); @@ -537,10 +537,20 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, struct ieee80211_tx_status status = { .info = &info }; + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; struct mt76_wcid *wcid = NULL; struct mt76x02_sta *msta = NULL; struct mt76_dev *mdev = &dev->mt76; struct sk_buff_head list; + u32 duration = 0; + u8 cur_pktid; + u32 ac = 0; + int len = 0; if (stat->pktid == MT_PACKET_ID_NO_ACK) return; @@ -570,10 +580,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) { mt76_tx_status_unlock(mdev, &list); - rcu_read_unlock(); - return; + goto out; } + if (msta && stat->aggr && !status.skb) { u32 stat_val, stat_cache; @@ -586,10 +596,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, stat->wcid == msta->status.wcid && msta->n_frames < 32) { msta->n_frames++; mt76_tx_status_unlock(mdev, &list); - rcu_read_unlock(); - return; + goto out; } + cur_pktid = msta->status.pktid; mt76x02_mac_fill_tx_status(dev, msta, status.info, &msta->status, msta->n_frames); @@ -597,16 +607,39 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev, msta->n_frames = 1; *update = 0; } else { + cur_pktid = stat->pktid; mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1); *update = 1; } - if (status.skb) + if (status.skb) { + info = *status.info; + len = status.skb->len; + ac = skb_get_queue_mapping(status.skb); mt76_tx_status_skb_done(mdev, status.skb, &list); + } else if (msta) { + len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen); + ac = FIELD_GET(MT_PKTID_AC, cur_pktid); + } + mt76_tx_status_unlock(mdev, &list); if (!status.skb) ieee80211_tx_status_ext(mt76_hw(dev), &status); + + if (!len) + goto out; + + duration = mt76_calc_tx_airtime(&dev->mt76, &info, len); + + spin_lock_bh(&dev->mt76.cc_lock); + dev->tx_airtime += duration; + spin_unlock_bh(&dev->mt76.cc_lock); + + if (msta) + ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0); + +out: rcu_read_unlock(); } @@ -987,6 +1020,8 @@ void mt76x02_update_channel(struct mt76_dev *mdev) state = mdev->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); + state->cc_tx += dev->tx_airtime; + dev->tx_airtime = 0; } EXPORT_SYMBOL_GPL(mt76x02_update_channel); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index 48de8eb82856..7d946aa77182 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -23,11 +23,16 @@ struct mt76x02_tx_status { #define MT_VIF_WCID(_n) (254 - ((_n) & 7)) #define MT_MAX_VIFS 8 +#define MT_PKTID_RATE GENMASK(4, 0) +#define MT_PKTID_AC GENMASK(6, 5) + struct mt76x02_vif { struct mt76_wcid group_wcid; /* must be first */ u8 idx; }; +DECLARE_EWMA(pktlen, 8, 8); + struct mt76x02_sta { struct mt76_wcid wcid; /* must be first */ @@ -35,6 +40,7 @@ struct mt76x02_sta { struct mt76x02_tx_status status; int n_frames; + struct ewma_pktlen pktlen; }; #define MT_RXINFO_BA BIT(0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index f27aade34c1e..13825f642087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -158,7 +158,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, /* encode packet rate for no-skb packet id to fix up status reporting */ if (pid == MT_PACKET_ID_NO_SKB) pid = MT_PACKET_ID_HAS_RATE | - (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX); + (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX) | + FIELD_PREP(MT_PKTID_AC, + skb_get_queue_mapping(tx_info->skb)); txwi->pktid = pid; @@ -171,6 +173,12 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) tx_info->info |= MT_TXD_INFO_WIV; + if (sta) { + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; + + ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); + } + return 0; } EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 203420087ac4..4294ffc0478b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -104,7 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, /* encode packet rate for no-skb packet id to fix up status reporting */ if (pid == MT_PACKET_ID_NO_SKB) pid = MT_PACKET_ID_HAS_RATE | - (le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX); + (le16_to_cpu(txwi->rate) & MT_PKTID_RATE) | + FIELD_PREP(MT_PKTID_AC, + skb_get_queue_mapping(tx_info->skb)); txwi->pktid = pid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 414b22399d93..23134bb8690b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -264,6 +264,7 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, msta->wcid.hw_key_idx = -1; mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr); mt76x02_mac_wcid_set_drop(dev, idx, false); + ewma_pktlen_init(&msta->pktlen); if (vif->type == NL80211_IFTYPE_AP) set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index 8f57ef50f35d..53ca0cedf026 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -23,6 +23,7 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) .txwi_size = sizeof(struct mt76x02_txwi), .drv_flags = MT_DRV_TX_ALIGNED4_SKBS | MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02_tx_prepare_skb, .tx_complete_skb = mt76x02_tx_complete_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 81be59c60155..e6d778456e5e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -26,6 +26,7 @@ static int mt76x2u_probe(struct usb_interface *intf, { static const struct mt76_driver_ops drv_ops = { .drv_flags = MT_DRV_SW_RX_AIRTIME, + .survey_flags = SURVEY_INFO_TIME_TX, .update_survey = mt76x02_update_channel, .tx_prepare_skb = mt76x02u_tx_prepare_skb, .tx_complete_skb = mt76x02u_tx_complete_skb, -- cgit v1.2.3-59-g8ed1b From 6bfa6e38266d234c845c37e976084e6b524743b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:02 +0200 Subject: mt76: mt7615: report tx_time, bss_rx and busy time to mac80211 Report tx time/rx time and obss time from hw mib counters to fill survey info requested by mac80211 Co-developed-by: Felix Fietkau Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 26 ++++++++++++++++++++++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt7615/pci.c | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 12 +++++++++++ 7 files changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 10d736967fbb..24b507fb06d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -505,6 +505,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); + survey->time_rx = div_u64(state->cc_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 8876231d8cdb..f50a12252158 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -322,6 +322,7 @@ struct mt76_driver_ops { struct mt76_channel_state { u64 cc_active; u64 cc_busy; + u64 cc_rx; u64 cc_bss_rx; u64 cc_tx; }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index ad94a7ce2e10..05a9e1154dd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -96,6 +96,8 @@ static void mt7615_mac_init(struct mt7615_dev *dev) FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2); mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); + + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN); } static int mt7615_init_hardware(struct mt7615_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 271f36f4acb3..9b113037c4f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -49,6 +49,14 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) mt76_rr(dev, MT_TX_AGG_CNT(i)); memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats)); + + /* TODO: add DBDC support */ + + /* reset airtime counters */ + mt76_rr(dev, MT_MIB_SDR16(0)); + mt76_rr(dev, MT_MIB_SDR36(0)); + mt76_rr(dev, MT_MIB_SDR37(0)); + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) @@ -1263,11 +1271,25 @@ void mt7615_update_channel(struct mt76_dev *mdev) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; /* TODO: add DBDC support */ + busy_time = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); + tx_time = mt76_get_field(dev, MT_MIB_SDR36(0), + MT_MIB_SDR36_TXTIME_MASK); + rx_time = mt76_get_field(dev, MT_MIB_SDR37(0), + MT_MIB_SDR37_RXTIME_MASK); + obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_TIME5, + MT_MIB_OBSSTIME_MASK); + state = mdev->chan_state; - state->cc_busy += mt76_get_field(dev, MT_MIB_SDR16(0), - MT_MIB_BUSY_MASK); + state->cc_busy += busy_time; + state->cc_tx += tx_time; + state->cc_rx += rx_time + obss_time; + state->cc_bss_rx += rx_time; + + /* reset obss airtime */ + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } void mt7615_mac_work(struct work_struct *work) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 6949cda9df0b..a4fc58fadffd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -153,8 +153,8 @@ static int mt7615_set_channel(struct mt7615_dev *dev) ret = mt7615_dfs_init_radar_detector(dev); mt7615_mac_cca_stats_reset(dev); dev->mt76.survey_time = ktime_get_boottime(); - /* TODO: add DBDC support */ - mt76_rr(dev, MT_MIB_SDR16(0)); + + mt7615_mac_reset_counters(dev); out: clear_bit(MT76_RESET, &dev->mt76.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 73744563a573..1eb1eb659c3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -73,6 +73,9 @@ static int mt7615_pci_probe(struct pci_dev *pdev, /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp), .drv_flags = MT_DRV_TXWI_NO_FREE, + .survey_flags = SURVEY_INFO_TIME_TX | + SURVEY_INFO_TIME_RX | + SURVEY_INFO_TIME_BSS_RX, .tx_prepare_skb = mt7615_tx_prepare_skb, .tx_complete_skb = mt7615_tx_complete_skb, .rx_skb = mt7615_queue_rx_skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 643b8bd17850..9a2ff1f3a68c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -198,6 +198,13 @@ #define MT_WF_RFCR1_DROP_CFEND BIT(7) #define MT_WF_RFCR1_DROP_CFACK BIT(8) +#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4) +#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) +#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) + +#define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8) +#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) + #define MT_WF_DMA_BASE 0x21800 #define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs)) @@ -289,6 +296,11 @@ #define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) #define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9)) +#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) +#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9)) +#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0) + #define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2)) #define MT_EFUSE_BASE 0x81070000 -- cgit v1.2.3-59-g8ed1b From 29ed2a79de000a7cf48a2aba74f25b59f1bbc36d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 26 Sep 2019 18:23:56 +0200 Subject: mt76: mt7615: fix survey channel busy time Like on mt7603, MIB status register 16 tracks CCA time, but does not include tx time. Switch to status register 9 to includ NAV and tx time as well. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 5 +++-- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 9b113037c4f2..f688390bfd3a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -53,7 +53,7 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) /* TODO: add DBDC support */ /* reset airtime counters */ - mt76_rr(dev, MT_MIB_SDR16(0)); + mt76_rr(dev, MT_MIB_SDR9(0)); mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); @@ -1274,7 +1274,8 @@ void mt7615_update_channel(struct mt76_dev *mdev) u64 busy_time, tx_time, rx_time, obss_time; /* TODO: add DBDC support */ - busy_time = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK); + busy_time = mt76_get_field(dev, MT_MIB_SDR9(0), + MT_MIB_SDR9_BUSY_MASK); tx_time = mt76_get_field(dev, MT_MIB_SDR36(0), MT_MIB_SDR36_TXTIME_MASK); rx_time = mt76_get_field(dev, MT_MIB_SDR37(0), diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 9a2ff1f3a68c..226b9ada89f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -293,8 +293,11 @@ #define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) #define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0) -#define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9)) -#define MT_MIB_BUSY_MASK GENMASK(23, 0) +#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9)) +#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0) + +#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9)) +#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0) #define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9)) #define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0) -- cgit v1.2.3-59-g8ed1b From 87d3cdeb28113703d4caac5a6926e5a60ccedbeb Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:03 +0200 Subject: mt76: mt7615: introduce mt7615_mac_wtbl_update routine Introduce mt7615_mac_wtbl_update utility routine in order to update WTBL update register Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 16 +++++++++++----- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index f688390bfd3a..2e36b3289fa6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -492,6 +492,15 @@ static u32 mt7615_mac_wtbl_addr(int wcid) return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE; } +bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) +{ + mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); + + return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + 0, 5000); +} + void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -724,11 +733,8 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, mt76_wr(dev, MT_WTBL_RICR0, w0); mt76_wr(dev, MT_WTBL_RICR1, w1); - mt76_wr(dev, MT_WTBL_UPDATE, - FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid->idx) | - MT_WTBL_UPDATE_RXINFO_UPDATE); - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + if (!mt7615_mac_wtbl_update(dev, wcid->idx, + MT_WTBL_UPDATE_RXINFO_UPDATE)) return -ETIMEDOUT; return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index fa8f2f1ed040..857279fda661 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -231,6 +231,7 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) } void mt7615_update_channel(struct mt76_dev *mdev); +bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); -- cgit v1.2.3-59-g8ed1b From b2c2f029683c4f42265c18dbb7e8ccbe06e6b01d Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 18 Sep 2019 12:58:05 +0200 Subject: mt76: mt7615: track tx/rx airtime for airtime fairness Poll per-station hardware counters available in WTBL after tx/rx status events in order to report tx/rx airtime to mac80211 layer Co-developed-by: Felix Fietkau Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/dma.c | 2 + drivers/net/wireless/mediatek/mt76/mt7615/init.c | 12 ++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 92 ++++++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 24 +++++- drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h | 7 ++ drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 3 + 6 files changed, 137 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index fe532cecbbdd..285d4f1d6178 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -110,6 +110,8 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget) for (i = 0; i < ARRAY_SIZE(queue_map); i++) mt76_queue_tx_cleanup(dev, queue_map[i], false); + mt7615_mac_sta_poll(dev); + tasklet_schedule(&dev->mt76.tx_tasklet); return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 05a9e1154dd5..1e7723aceee2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -21,6 +21,7 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_mac_init(struct mt7615_dev *dev) { u32 val, mask, set; + int i; /* enable band 0/1 clk */ mt76_set(dev, MT_CFG_CCR, @@ -97,7 +98,12 @@ static void mt7615_mac_init(struct mt7615_dev *dev) mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set); mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set); + for (i = 0; i < MT7615_WTBL_SIZE; i++) + mt7615_mac_wtbl_update(dev, i, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN); } static int mt7615_init_hardware(struct mt7615_dev *dev) @@ -262,12 +268,14 @@ int mt7615_register_device(struct mt7615_dev *dev) struct wiphy *wiphy = hw->wiphy; int ret; + INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); + INIT_LIST_HEAD(&dev->sta_poll_list); + spin_lock_init(&dev->sta_poll_lock); + ret = mt7615_init_hardware(dev); if (ret) return ret; - INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work); - hw->queues = 4; hw->max_rates = 3; hw->max_report_rates = 7; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 2e36b3289fa6..2b810ba359ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -57,6 +57,7 @@ void mt7615_mac_reset_counters(struct mt7615_dev *dev) mt76_rr(dev, MT_MIB_SDR36(0)); mt76_rr(dev, MT_MIB_SDR37(0)); mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR); + mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR); } int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) @@ -80,6 +81,16 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb) idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2); status->wcid = mt7615_rx_get_wcid(dev, idx, unicast); + if (status->wcid) { + struct mt7615_sta *msta; + + msta = container_of(status->wcid, struct mt7615_sta, wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + } + /* TODO: properly support DBDC */ status->freq = dev->mt76.chandef.chan->center_freq; status->band = dev->mt76.chandef.chan->band; @@ -501,6 +512,82 @@ bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask) 0, 5000); } +void mt7615_mac_sta_poll(struct mt7615_dev *dev) +{ + static const u8 ac_to_tid[4] = { + [IEEE80211_AC_BE] = 0, + [IEEE80211_AC_BK] = 1, + [IEEE80211_AC_VI] = 4, + [IEEE80211_AC_VO] = 6 + }; + static const u8 hw_queue_map[] = { + [IEEE80211_AC_BK] = 0, + [IEEE80211_AC_BE] = 1, + [IEEE80211_AC_VI] = 2, + [IEEE80211_AC_VO] = 3, + }; + struct ieee80211_sta *sta; + struct mt7615_sta *msta; + u32 addr, tx_time[4], rx_time[4]; + int i; + + rcu_read_lock(); + + while (true) { + bool clear = false; + + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&dev->sta_poll_list)) { + spin_unlock_bh(&dev->sta_poll_lock); + break; + } + msta = list_first_entry(&dev->sta_poll_list, + struct mt7615_sta, poll_list); + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + + addr = mt7615_mac_wtbl_addr(msta->wcid.idx) + 19 * 4; + + for (i = 0; i < 4; i++, addr += 8) { + u32 tx_last = msta->airtime_ac[i]; + u32 rx_last = msta->airtime_ac[i + 4]; + + msta->airtime_ac[i] = mt76_rr(dev, addr); + msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4); + tx_time[i] = msta->airtime_ac[i] - tx_last; + rx_time[i] = msta->airtime_ac[i + 4] - rx_last; + + if ((tx_last | rx_last) & BIT(30)) + clear = true; + } + + if (clear) { + mt7615_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac)); + } + + if (!msta->wcid.sta) + continue; + + sta = container_of((void *)msta, struct ieee80211_sta, + drv_priv); + for (i = 0; i < 4; i++) { + u32 tx_cur = tx_time[i]; + u32 rx_cur = rx_time[hw_queue_map[i]]; + u8 tid = ac_to_tid[i]; + + if (!tx_cur && !rx_cur) + continue; + + ieee80211_sta_register_airtime(sta, tid, tx_cur, + rx_cur); + } + } + + rcu_read_unlock(); +} + void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates) @@ -1064,6 +1151,11 @@ void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data) msta = container_of(wcid, struct mt7615_sta, wcid); sta = wcid_to_sta(wcid); + spin_lock_bh(&dev->sta_poll_lock); + if (list_empty(&msta->poll_list)) + list_add_tail(&msta->poll_list, &dev->sta_poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index a4fc58fadffd..602add1be029 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -99,8 +99,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, dev->vif_mask |= BIT(mvif->idx); dev->omac_mask |= BIT(mvif->omac_idx); idx = MT7615_WTBL_RESERVED - mvif->idx; + + INIT_LIST_HEAD(&mvif->sta.poll_list); mvif->sta.wcid.idx = idx; mvif->sta.wcid.hw_key_idx = -1; + mt7615_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); mtxq = (struct mt76_txq *)vif->txq->drv_priv; @@ -117,8 +121,9 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + struct mt7615_sta *msta = &mvif->sta; struct mt7615_dev *dev = hw->priv; - int idx = mvif->sta.wcid.idx; + int idx = msta->wcid.idx; /* TODO: disable beacon for the bss */ @@ -131,6 +136,11 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, dev->vif_mask &= ~BIT(mvif->idx); dev->omac_mask &= ~BIT(mvif->omac_idx); mutex_unlock(&dev->mt76.mutex); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); } static int mt7615_set_channel(struct mt7615_dev *dev) @@ -360,9 +370,12 @@ int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + INIT_LIST_HEAD(&msta->poll_list); msta->vif = mvif; msta->wcid.sta = 1; msta->wcid.idx = idx; + mt7615_mac_wtbl_update(dev, idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); mt7615_mcu_add_wtbl(dev, vif, sta); mt7615_mcu_set_sta_rec(dev, vif, sta, 1); @@ -383,9 +396,18 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; mt7615_mcu_set_sta_rec(dev, vif, sta, 0); mt7615_mcu_del_wtbl(dev, sta); + + mt7615_mac_wtbl_update(dev, msta->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&msta->poll_list)) + list_del_init(&msta->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); } static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index 857279fda661..21486831172c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -56,6 +56,9 @@ struct mt7615_sta { struct mt7615_vif *vif; + struct list_head poll_list; + u32 airtime_ac[8]; + struct ieee80211_tx_rate rates[4]; struct mt7615_rate_set rateset[2]; @@ -83,6 +86,9 @@ struct mt7615_dev { __le32 rx_ampdu_ts; + struct list_head sta_poll_list; + spinlock_t sta_poll_lock; + struct { u8 n_pulses; u32 period; @@ -235,6 +241,7 @@ bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask); void mt7615_mac_reset_counters(struct mt7615_dev *dev); void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev); void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable); +void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta, int pid, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 226b9ada89f6..99bd5939d33f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -202,6 +202,8 @@ #define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31) #define MT_WF_RMAC_MIB_RXTIME_EN BIT(30) +#define MT_WF_RMAC_MIB_AIRTIME0 MT_WF_RMAC(0x0380) + #define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8) #define MT_MIB_OBSSTIME_MASK GENMASK(23, 0) @@ -236,6 +238,7 @@ #define MT_WTBL_UPDATE MT_WTBL_OFF(0x030) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0) #define MT_WTBL_UPDATE_RXINFO_UPDATE BIT(11) +#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) #define MT_WTBL_UPDATE_RATE_UPDATE BIT(13) #define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14) #define MT_WTBL_UPDATE_BUSY BIT(31) -- cgit v1.2.3-59-g8ed1b From 55857ab857975080d9e400ca85a7c192f7986ab9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 6 Sep 2019 11:29:09 +0200 Subject: mt76: enable airtime fairness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is supported by all hardware drivers now Signed-off-by: Felix Fietkau Acked-by: Toke Høiland-Jørgensen --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 24b507fb06d8..d493437731b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -307,6 +307,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy->available_antennas_tx = dev->antenna_mask; wiphy->available_antennas_rx = dev->antenna_mask; -- cgit v1.2.3-59-g8ed1b From 36f7e2b2bb1de86f0072cd49ca93d82b9e8fd894 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 29 Sep 2019 22:04:37 +0200 Subject: mt76: do not use devm API for led classdev With the devm API, the unregister happens after the device cleanup is done, after which the struct mt76_dev which contains the led_cdev has already been freed. This leads to a use-after-free bug that can crash the system. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index d493437731b8..c4eb00d79ffc 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -105,7 +105,15 @@ static int mt76_led_init(struct mt76_dev *dev) dev->led_al = of_property_read_bool(np, "led-active-low"); } - return devm_led_classdev_register(dev->dev, &dev->led_cdev); + return led_classdev_register(dev->dev, &dev->led_cdev); +} + +static void mt76_led_cleanup(struct mt76_dev *dev) +{ + if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + return; + + led_classdev_unregister(&dev->led_cdev); } static void mt76_init_stream_cap(struct mt76_dev *dev, @@ -362,6 +370,7 @@ void mt76_unregister_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; + mt76_led_cleanup(dev); mt76_tx_status_check(dev, NULL, true); ieee80211_unregister_hw(hw); } -- cgit v1.2.3-59-g8ed1b From 1a817fa73c3b27a593aadf0029de24db1bbc1a3e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:32:14 +0200 Subject: mt76: add missing locking around ampdu action This is needed primarily to avoid races in dealing with rx aggregation related data structures Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 2 ++ 3 files changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 31cce1c005c6..a0632ca198f1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -575,6 +575,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -603,6 +604,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 602add1be029..7e1e1481219a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -489,6 +489,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, @@ -518,6 +519,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 23134bb8690b..ceb0325e1fd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -372,6 +372,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mtxq = (struct mt76_txq *)txq->drv_priv; + mutex_lock(&dev->mt76.mutex); switch (action) { case IEEE80211_AMPDU_RX_START: mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, @@ -400,6 +401,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); return 0; } -- cgit v1.2.3-59-g8ed1b From fb7d95c6ee4f71ba131c9b3c65d658369ffd1128 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 15:30:18 +0200 Subject: mt76: drop rcu read lock in mt76_rx_aggr_stop A rcu read locked section is not allowed to sleep, and the rcu lock here isn't actually necessary, because we're holding dev->mutex. Fixes an issue when the tid work item is still running while freeing a station or stopping the aggregation session Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 2276fd4e9ec3..b05d439dca3b 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -277,17 +277,13 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) { - struct mt76_rx_tid *tid; - - rcu_read_lock(); + struct mt76_rx_tid *tid = NULL; - tid = rcu_dereference(wcid->aggr[tidno]); + rcu_swap_protected(wcid->aggr[tidno], tid, + lockdep_is_held(&dev->mutex)); if (tid) { - rcu_assign_pointer(wcid->aggr[tidno], NULL); mt76_rx_aggr_shutdown(dev, tid); kfree_rcu(tid, rcu_head); } - - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); -- cgit v1.2.3-59-g8ed1b From e7aaa72f4728451487d7a3fe54225796d08ab1e5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:30:46 +0200 Subject: mt76: fix aggregation stop issue Cancel the workqueue after the tid has been cleaned up, in order to avoid a possible rescheduling from within the work function. Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/agg-rx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index b05d439dca3b..53b5a4b2dcc5 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -130,8 +130,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) return; spin_lock_bh(&tid->lock); - mt76_rx_aggr_release_frames(tid, frames, seqno); - mt76_rx_aggr_release_head(tid, frames); + if (!tid->stopped) { + mt76_rx_aggr_release_frames(tid, frames, seqno); + mt76_rx_aggr_release_head(tid, frames); + } spin_unlock_bh(&tid->lock); } @@ -257,8 +259,6 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; - cancel_delayed_work_sync(&tid->reorder_work); - spin_lock_bh(&tid->lock); tid->stopped = true; @@ -273,6 +273,8 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) } spin_unlock_bh(&tid->lock); + + cancel_delayed_work_sync(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) -- cgit v1.2.3-59-g8ed1b From 3e0705acd4de7821d42bea7fb01938ff05fd4d58 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 7 Oct 2019 12:33:39 +0200 Subject: mt76: avoid enabling interrupt if NAPI poll is still pending if napi_complete() returns false, it means that polling is still pending. Interrupts should not fire until the polling is no longer scheduled Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 6442a45ba303..3de744fb5e7a 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -539,10 +539,8 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget) rcu_read_unlock(); - if (done < budget) { - napi_complete(napi); + if (done < budget && napi_complete(napi)) dev->drv->rx_poll_complete(dev, qid); - } return done; } -- cgit v1.2.3-59-g8ed1b From d1bc9bf2072c04e3303339437788fe224a33a7fa Mon Sep 17 00:00:00 2001 From: Pawel Dembicki Date: Fri, 4 Oct 2019 15:23:49 +0200 Subject: mt76: mt76x0: eeprom: add support for MAC address from OF mt76x0e driver only supports MAC addresses from calibration data eeprom. Many routers however do not have a valid stock address set in this field. This patch makes it possible to take a MAC address from OF (e.g. from mtd). Signed-off-by: Pawel Dembicki [adjusted for kernel submission] Signed-off-by: Adrian Schmutzler Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 96368fac4228..a03e2d01fba7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -343,6 +343,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) version, fae); mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + mt76_eeprom_override(&dev->mt76); mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); -- cgit v1.2.3-59-g8ed1b From 237312c5e485804417e0f809f948112c3eb7fc96 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 15 Oct 2019 17:16:43 +0200 Subject: mt76: refactor cc_lock locking scheme Read busy counters not holding cc_lock spinlock since usb read can't be performed in interrupt context. Move cc_active and cc_rx counters out of cc_lock since they are not modified in interrupt context. Grab cc_lock updating cur_cc_bss_rx in mt76_airtime_report and do not hold rx_lock in mt76_update_survey. Moreover grab mt76 mutex in mt76_get_survey before running mt76_update_survey. This patch fixes the following 'schedule while atomic' [ 291.790866] BUG: scheduling while atomic: iw/2161/0x00000202 [ 291.791002] Preemption disabled at: [ 291.791007] [<0000000000000000>] 0x0 [ 291.791015] CPU: 0 PID: 2161 Comm: iw Tainted: G W 5.4.= 0-rc2-3-ARCH-00104-g9e208aa06c21 #1 [ 291.791017] Hardware name: LENOVO 2349QM6/2349QM6, BIOS G1ETC2WW (2.82=) 08/07/2019 [ 291.791019] Call Trace: [ 291.791042] dump_stack+0x5c/0x80 [ 291.791049] __schedule_bug.cold+0x8e/0x9b [ 291.791055] __schedule+0x5f8/0x770 [ 291.791062] schedule+0x43/0xd0 [ 291.791068] schedule_preempt_disabled+0x14/0x20 [ 291.791074] __mutex_lock.isra.0+0x18a/0x530 [ 291.791099] mt76u_rr+0x1f/0x40 [mt76_usb] [ 291.791113] mt76x02_update_channel+0x22/0x40 [mt76x02_lib] [ 291.791122] mt76_update_survey+0x42/0xe0 [mt76] [ 291.791129] mt76_get_survey+0x2f/0x1b0 [mt76] [ 291.791170] ieee80211_dump_survey+0x5e/0x140 [mac80211] [ 291.791217] nl80211_dump_survey+0x13c/0x2f0 [cfg80211] [ 291.791222] ? __kmalloc_reserve.isra.0+0x2d/0x70 [ 291.791225] ? __alloc_skb+0x96/0x1d0 [ 291.791229] netlink_dump+0x17b/0x370 [ 291.791247] __netlink_dump_start+0x16f/0x1e0 [ 291.791253] genl_family_rcv_msg+0x396/0x410 [ 291.791290] ? nl80211_prepare_wdev_dump+0x1b0/0x1b0 [cfg80211] [ 291.791297] ? _raw_spin_unlock_irqrestore+0x20/0x40 [ 291.791312] ? __wake_up_common_lock+0x8a/0xc0 [ 291.791316] genl_rcv_msg+0x47/0x90 [ 291.791320] ? genl_family_rcv_msg+0x410/0x410 [ 291.791323] netlink_rcv_skb+0x49/0x110 [ 291.791329] genl_rcv+0x24/0x40 [ 291.791333] netlink_unicast+0x171/0x200 [ 291.791340] netlink_sendmsg+0x208/0x3d0 [ 291.791358] sock_sendmsg+0x5e/0x60 [ 291.791361] ___sys_sendmsg+0x2ae/0x330 [ 291.791368] ? filemap_map_pages+0x272/0x390 [ 291.791374] ? _raw_spin_unlock+0x16/0x30 [ 291.791379] ? __handle_mm_fault+0x112f/0x1390 [ 291.791388] __sys_sendmsg+0x59/0xa0 [ 291.791396] do_syscall_64+0x5b/0x1a0 [ 291.791400] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [ 291.791404] RIP: 0033:0x7f5d0c7f37b7 [ 291.791418] Code: 64 89 02 48 c7 c0 ff ff ff ff eb bb 0f 1f 80 00 00 0= 0 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 2e 00 00 00 0f 05= <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 89 54 24 1c 48 89 74 24 10 [ 291.791421] RSP: 002b:00007ffe8b5d0538 EFLAGS: 00000246 ORIG_RAX: 0000= 00000000002e [ 291.791426] RAX: ffffffffffffffda RBX: 000055a038e6c390 RCX: 00007f5d0= c7f37b7 [ 291.791430] RDX: 0000000000000000 RSI: 00007ffe8b5d0570 RDI: 000000000= 0000003 [ 291.791434] RBP: 000055a038e718c0 R08: 000055a038e6c02a R09: 000000000= 0000002 [ 291.791438] R10: 000055a03808cb00 R11: 0000000000000246 R12: 000055a03= 8e71780 [ 291.791440] R13: 00007ffe8b5d0570 R14: 000055a038e717d0 R15: 000055a03= 8e718c0 [ 291.791480] NOHZ: local_softirq_pending 202 Fixes: 168aea24f4bb ("mt76: mt76x02u: enable survey support") Tested-by: Markus Theil Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 29 +++++++++++++----------- drivers/net/wireless/mediatek/mt76/mt76x02_mac.c | 3 +++ 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index c4eb00d79ffc..4e6f14ca00f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -432,8 +432,6 @@ void mt76_update_survey(struct mt76_dev *dev) if (!test_bit(MT76_STATE_RUNNING, &dev->state)) return; - spin_lock_bh(&dev->cc_lock); - if (dev->drv->update_survey) dev->drv->update_survey(dev); @@ -442,15 +440,11 @@ void mt76_update_survey(struct mt76_dev *dev) dev->survey_time)); dev->survey_time = cur_time; - spin_unlock_bh(&dev->cc_lock); - if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - spin_lock_bh(&dev->rx_lock); - spin_lock(&dev->cc_lock); + spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; dev->cur_cc_bss_rx = 0; - spin_unlock(&dev->cc_lock); - spin_unlock_bh(&dev->rx_lock); + spin_unlock_bh(&dev->cc_lock); } } EXPORT_SYMBOL_GPL(mt76_update_survey); @@ -485,6 +479,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct mt76_channel_state *state; int ret = 0; + mutex_lock(&dev->mutex); if (idx == 0 && dev->drv->update_survey) mt76_update_survey(dev); @@ -494,8 +489,10 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, sband = &dev->sband_5g; } - if (idx >= sband->sband.n_channels) - return -ENOENT; + if (idx >= sband->sband.n_channels) { + ret = -ENOENT; + goto out; + } chan = &sband->sband.channels[idx]; state = mt76_channel_state(dev, chan); @@ -511,14 +508,18 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->filled |= SURVEY_INFO_TIME_BSS_RX; } - spin_lock_bh(&dev->cc_lock); - survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); - survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_rx = div_u64(state->cc_rx, 1000); + survey->time = div_u64(state->cc_active, 1000); + + spin_lock_bh(&dev->cc_lock); + survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); +out: + mutex_unlock(&dev->mutex); + return ret; } EXPORT_SYMBOL_GPL(mt76_get_survey); @@ -622,7 +623,9 @@ mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, u32 airtime; airtime = mt76_calc_rx_airtime(dev, status, len); + spin_lock(&dev->cc_lock); dev->cur_cc_bss_rx += airtime; + spin_unlock(&dev->cc_lock); if (!wcid || !wcid->sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 38329ebca572..4460548f346a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1020,8 +1020,11 @@ void mt76x02_update_channel(struct mt76_dev *mdev) state = mdev->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); + + spin_lock_bh(&dev->mt76.cc_lock); state->cc_tx += dev->tx_airtime; dev->tx_airtime = 0; + spin_unlock_bh(&dev->mt76.cc_lock); } EXPORT_SYMBOL_GPL(mt76x02_update_channel); -- cgit v1.2.3-59-g8ed1b From bf5238b25ac373cb2a544fe8554fd66fc9e04efc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 10 Oct 2019 21:59:46 +0200 Subject: mt76: add sanity check for a-mpdu rx wcid index Avoid dereferencing invalid ids Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 4e6f14ca00f2..a3975e3795ee 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -644,7 +644,7 @@ mt76_airtime_flush_ampdu(struct mt76_dev *dev) return; wcid_idx = dev->rx_ampdu_status.wcid_idx; - if (dev->rx_ampdu_status.wcid_idx != 0xff) + if (wcid_idx < ARRAY_SIZE(dev->wcid)) wcid = rcu_dereference(dev->wcid[wcid_idx]); else wcid = NULL; -- cgit v1.2.3-59-g8ed1b From 3473750cd412e5506213e773e9fdd0729d1affe5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 14 Oct 2019 12:01:09 +0200 Subject: mt76: remove obsolete .add_buf() from struct mt76_queue_ops It hasn't been used in a while Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index f50a12252158..4bdf8c44c6d2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -152,10 +152,6 @@ struct mt76_queue_ops { int idx, int n_desc, int bufsize, u32 ring_base); - int (*add_buf)(struct mt76_dev *dev, struct mt76_queue *q, - struct mt76_queue_buf *buf, int nbufs, u32 info, - struct sk_buff *skb, void *txwi); - int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta); -- cgit v1.2.3-59-g8ed1b From b86b173f634f9d53ae226c8e7e8af9e163f759c0 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Oct 2019 00:50:04 +0200 Subject: mt76: mt76x02u: update ewma pkt len in mt76x02u_tx_prepare_skb Update ewma packet length in mt76x02u_tx_prepare_skb as it is done for pci counterpart in order to properly estimate tx time on current channel Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 4294ffc0478b..d03d3c8e296c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -120,6 +120,12 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data, if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv) flags |= MT_TXD_INFO_WIV; + if (sta) { + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; + + ewma_pktlen_add(&msta->pktlen, tx_info->skb->len); + } + return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags); } EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb); -- cgit v1.2.3-59-g8ed1b From 2ec1e82bbf92c3031307beb89b59b589206c318c Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 18 Oct 2019 23:31:23 +0200 Subject: mt76: mt76x0: remove 350ms delay in mt76x0_phy_calibrate Since mt76x0 does not save the phy calibration data it is not necessary to wait 350ms in mt76x0_phy_calibrate Tested-by: Sid Hayn Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 711a352dfd5c..61e1a086f3cb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -899,7 +899,6 @@ void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on) } mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val); - msleep(350); mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz); usleep_range(15000, 20000); -- cgit v1.2.3-59-g8ed1b From 5d1ad7d7bab0e9519c6f2a75fde6ab193279c5b3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 25 Oct 2019 17:16:16 +0800 Subject: mt76: mt7615: remove unneeded semicolon remove unneeded semicolon. This is detected by coccinelle. Signed-off-by: YueHaibing Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 7e1e1481219a..4f7cdb4f08fb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -60,7 +60,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask) default: WARN_ON(1); break; - }; + } return -1; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 842cd81704db..164619f8a9ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1076,7 +1076,7 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif, default: WARN_ON(1); break; - }; + } if (en) { req.basic.conn_state = CONN_STATE_PORT_SECURE; -- cgit v1.2.3-59-g8ed1b From 80df01f4dc79abbed724bbe0851cab3fe8ad9d99 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Oct 2019 16:21:41 +0100 Subject: mt76: mt76u: rely on usb_interface instead of usb_dev usb drivers are supposed to communicate using usb_interface instead mt76x{0,2}u is now registering through usb_device. Fix it by passing usb_intf device to mt76_alloc_device routine. Fixes: 112f980ac8926 ("mt76usb: use usb_dev private data") Signed-off-by: Lorenzo Bianconi Tested-By: Zero_Chaos Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 3 ++- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 2 +- drivers/net/wireless/mediatek/mt76/usb.c | 12 +++++++++--- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 4bdf8c44c6d2..ac439fd4f312 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -804,7 +804,8 @@ static inline int mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len, int timeout) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); struct mt76_usb *usb = &dev->usb; unsigned int pipe; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index ade6312c7367..b9fd41433106 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -221,7 +221,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, u32 mac_rev; int ret; - mdev = mt76_alloc_device(&usb_dev->dev, sizeof(*dev), &mt76x0u_ops, + mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), &mt76x0u_ops, &drv_ops); if (!mdev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index e6d778456e5e..48b9017813b5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -41,7 +41,7 @@ static int mt76x2u_probe(struct usb_interface *intf, struct mt76_dev *mdev; int err; - mdev = mt76_alloc_device(&udev->dev, sizeof(*dev), &mt76x2u_ops, + mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops, &drv_ops); if (!mdev) return -ENOMEM; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index cac058fc41ef..be19038ea7dd 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -19,7 +19,8 @@ static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, u16 val, u16 offset, void *buf, size_t len) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; int i, ret; @@ -234,7 +235,8 @@ mt76u_rd_rp(struct mt76_dev *dev, u32 base, static bool mt76u_check_sg(struct mt76_dev *dev) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); return (!disable_usb_sg && udev->bus->sg_tablesize > 0 && (udev->bus->no_sg_constraint || @@ -369,7 +371,8 @@ mt76u_fill_bulk_urb(struct mt76_dev *dev, int dir, int index, struct urb *urb, usb_complete_t complete_fn, void *context) { - struct usb_device *udev = to_usb_device(dev->dev); + struct usb_interface *uintf = to_usb_interface(dev->dev); + struct usb_device *udev = interface_to_usbdev(uintf); unsigned int pipe; if (dir == USB_DIR_IN) @@ -951,6 +954,7 @@ int mt76u_init(struct mt76_dev *dev, .rd_rp = mt76u_rd_rp, .type = MT76_BUS_USB, }; + struct usb_device *udev = interface_to_usbdev(intf); struct mt76_usb *usb = &dev->usb; tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev); @@ -964,6 +968,8 @@ int mt76u_init(struct mt76_dev *dev, dev->bus = &mt76u_ops; dev->queue_ops = &usb_queue_ops; + dev_set_drvdata(&udev->dev, dev); + usb->sg_en = mt76u_check_sg(dev); return mt76u_set_endpoints(intf, usb); -- cgit v1.2.3-59-g8ed1b From 284efb473ef5f02a7f2c13fdf8d516ecc589bdf1 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Mon, 28 Oct 2019 17:38:05 +0100 Subject: mt76: mt76u: rely on a dedicated stats workqueue rate controller and throughput are very sensitive to tx status timing. In order to improve performances when the system is heavily loaded, substitute stat_work delayed_work with a regular work_struct and create a mt76u dedicated workqueue for tx status reporting Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 +++- drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 2 ++ drivers/net/wireless/mediatek/mt76/mt76x2/usb.c | 2 ++ drivers/net/wireless/mediatek/mt76/usb.c | 27 ++++++++++++++++--------- 4 files changed, 25 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index ac439fd4f312..a65890cebf0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -387,7 +387,8 @@ struct mt76_usb { }; struct tasklet_struct rx_tasklet; - struct delayed_work stat_work; + struct workqueue_struct *stat_wq; + struct work_struct stat_work; u8 out_ep[__MT_EP_OUT_MAX]; u8 in_ep[__MT_EP_IN_MAX]; @@ -823,6 +824,7 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req, void mt76u_single_wr(struct mt76_dev *dev, const u8 req, const u16 offset, const u32 val); int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf); +void mt76u_deinit(struct mt76_dev *dev); int mt76u_alloc_queues(struct mt76_dev *dev); void mt76u_stop_tx(struct mt76_dev *dev); void mt76u_stop_rx(struct mt76_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index b9fd41433106..a8ab8df075c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -273,6 +273,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, err: usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(mdev->hw); return ret; @@ -292,6 +293,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf) usb_set_intfdata(usb_intf, NULL); usb_put_dev(interface_to_usbdev(usb_intf)); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(dev->mt76.hw); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 48b9017813b5..b64ad816cc25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -73,6 +73,7 @@ static int mt76x2u_probe(struct usb_interface *intf, err: ieee80211_free_hw(mt76_hw(dev)); + mt76u_deinit(&dev->mt76); usb_set_intfdata(intf, NULL); usb_put_dev(udev); @@ -88,6 +89,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf) set_bit(MT76_REMOVED, &dev->mt76.state); ieee80211_unregister_hw(hw); mt76x2u_cleanup(dev); + mt76u_deinit(&dev->mt76); ieee80211_free_hw(hw); usb_set_intfdata(intf, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index be19038ea7dd..d6d47081e281 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -697,10 +697,7 @@ static void mt76u_tx_tasklet(unsigned long data) mt76_txq_schedule(dev, i); if (!test_and_set_bit(MT76_READING_STATS, &dev->state)) - ieee80211_queue_delayed_work(dev->hw, - &dev->usb.stat_work, - msecs_to_jiffies(10)); - + queue_work(dev->usb.stat_wq, &dev->usb.stat_work); if (wake) ieee80211_wake_queue(dev->hw, i); } @@ -713,7 +710,7 @@ static void mt76u_tx_status_data(struct work_struct *work) u8 update = 1; u16 count = 0; - usb = container_of(work, struct mt76_usb, stat_work.work); + usb = container_of(work, struct mt76_usb, stat_work); dev = container_of(usb, struct mt76_dev, usb); while (true) { @@ -726,8 +723,7 @@ static void mt76u_tx_status_data(struct work_struct *work) } if (count && test_bit(MT76_STATE_RUNNING, &dev->state)) - ieee80211_queue_delayed_work(dev->hw, &usb->stat_work, - msecs_to_jiffies(10)); + queue_work(usb->stat_wq, &usb->stat_work); else clear_bit(MT76_READING_STATS, &dev->state); } @@ -908,7 +904,7 @@ void mt76u_stop_tx(struct mt76_dev *dev) } } - cancel_delayed_work_sync(&dev->usb.stat_work); + cancel_work_sync(&dev->usb.stat_work); clear_bit(MT76_READING_STATS, &dev->state); mt76_tx_status_check(dev, NULL, true); @@ -959,9 +955,13 @@ int mt76u_init(struct mt76_dev *dev, tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev); tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev); - INIT_DELAYED_WORK(&usb->stat_work, mt76u_tx_status_data); + INIT_WORK(&usb->stat_work, mt76u_tx_status_data); skb_queue_head_init(&dev->rx_skb[MT_RXQ_MAIN]); + usb->stat_wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0); + if (!usb->stat_wq) + return -ENOMEM; + mutex_init(&usb->mcu.mutex); mutex_init(&usb->usb_ctrl_mtx); @@ -976,5 +976,14 @@ int mt76u_init(struct mt76_dev *dev, } EXPORT_SYMBOL_GPL(mt76u_init); +void mt76u_deinit(struct mt76_dev *dev) +{ + if (dev->usb.stat_wq) { + destroy_workqueue(dev->usb.stat_wq); + dev->usb.stat_wq = NULL; + } +} +EXPORT_SYMBOL_GPL(mt76u_deinit); + MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3-59-g8ed1b From cc53b52daa091ee875372d843255728c3ec941e4 Mon Sep 17 00:00:00 2001 From: zhengbin Date: Tue, 29 Oct 2019 12:48:39 +0800 Subject: mt76: Remove set but not used variable 'idx' Fixes gcc '-Wunused-but-set-variable' warning: drivers/net/wireless/mediatek/mt76/dma.c: In function mt76_dma_rx_fill: drivers/net/wireless/mediatek/mt76/dma.c:377:6: warning: variable idx set but not used [-Wunused-but-set-variable] It is not used since commit 17f1de56df05 ("mt76: add common code shared between multiple chipsets") Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 3de744fb5e7a..6173c80189ba 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -365,7 +365,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) int frames = 0; int len = SKB_WITH_OVERHEAD(q->buf_size); int offset = q->buf_offset; - int idx; spin_lock_bh(&q->lock); @@ -384,7 +383,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) qbuf.addr = addr + offset; qbuf.len = len - offset; - idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); + mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); frames++; } -- cgit v1.2.3-59-g8ed1b From 61c51a74a4e58673e28e79447f44279b0a52686b Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 29 Oct 2019 14:34:44 +0100 Subject: mt76: use mt76_dev in mt76_is_{mmio,usb} Convert mt76_is_mmio and mt76_is_usb to rely on mt76_dev instead of mt76x02_dev since this is a property not strictly related to hw chipset and it will be more reusable Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/main.c | 4 ++-- drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h | 2 +- drivers/net/wireless/mediatek/mt76/mt76x0/phy.c | 12 ++++++------ drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c | 2 +- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 +++--- 6 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index a65890cebf0f..881b91c19ec3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -49,8 +49,8 @@ struct mt76_bus_ops { enum mt76_bus_type type; }; -#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB) -#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO) +#define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB) +#define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO) enum mt76_txq_id { MT_TXQ_VO = IEEE80211_AC_VO, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index f7682bd2e5a8..b2ccf50512dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -13,7 +13,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { cancel_delayed_work_sync(&dev->cal_work); mt76x02_pre_tbtt_enable(dev, false); - if (mt76_is_mmio(dev)) + if (mt76_is_mmio(&dev->mt76)) tasklet_disable(&dev->dfs_pd.dfs_tasklet); mt76_set_channel(&dev->mt76); @@ -22,7 +22,7 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) mt76x02_mac_cc_reset(dev); mt76x02_edcca_init(dev); - if (mt76_is_mmio(dev)) { + if (mt76_is_mmio(&dev->mt76)) { mt76x02_dfs_init_params(dev); tasklet_enable(&dev->dfs_pd.dfs_tasklet); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 82f5b481b723..6953f253a28a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -30,7 +30,7 @@ static inline bool is_mt7610e(struct mt76x02_dev *dev) { - if (!mt76_is_mmio(dev)) + if (!mt76_is_mmio(&dev->mt76)) return false; return mt76_chip(&dev->mt76) == 0x7610; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 61e1a086f3cb..2ecd45f8af90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -102,7 +102,7 @@ out: static int mt76x0_rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val) { - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { struct mt76_reg_pair pair = { .reg = offset, .value = val, @@ -121,7 +121,7 @@ static int mt76x0_rf_rr(struct mt76x02_dev *dev, u32 offset) int ret; u32 val; - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { struct mt76_reg_pair pair = { .reg = offset, }; @@ -176,7 +176,7 @@ mt76x0_phy_rf_csr_wr_rp(struct mt76x02_dev *dev, } #define RF_RANDOM_WRITE(dev, tab) do { \ - if (mt76_is_mmio(dev)) \ + if (mt76_is_mmio(&dev->mt76)) \ mt76x0_phy_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \ else \ mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\ @@ -744,7 +744,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode, if (!tx_mode) { data = mt76_rr(dev, MT_BBP(CORE, 1)); - if (is_mt7630(dev) && mt76_is_mmio(dev)) { + if (is_mt7630(dev) && mt76_is_mmio(&dev->mt76)) { int offset; /* 2.3 * 8192 or 1.5 * 8192 */ @@ -966,7 +966,7 @@ void mt76x0_phy_set_channel(struct mt76x02_dev *dev, break; } - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { mt76x0_phy_bbp_set_bw(dev, chandef->width); } else { if (chandef->width == NL80211_CHAN_WIDTH_80 || @@ -1122,7 +1122,7 @@ static void mt76x0_rf_patch_reg_array(struct mt76x02_dev *dev, switch (reg) { case MT_RF(0, 3): - if (mt76_is_mmio(dev)) { + if (mt76_is_mmio(&dev->mt76)) { if (is_mt7630(dev)) val = 0x70; else diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 4be7a24097cc..6274b6a24b07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -114,7 +114,7 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param) .id = cpu_to_le32(type), .value = cpu_to_le32(param), }; - bool is_mt76x2e = mt76_is_mmio(dev) && is_mt76x2(dev); + bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev); int ret; if (is_mt76x2e) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index ceb0325e1fd0..50401ea0b82d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -161,7 +161,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev) #endif BIT(NL80211_IFTYPE_ADHOC); - if (mt76_is_usb(dev)) { + if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; wiphy->iface_combinations = mt76x02u_if_comb; @@ -445,7 +445,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, * data registers and sent via HW beacons engine, they require to * be already encrypted. */ - if (mt76_is_usb(dev) && + if (mt76_is_usb(&dev->mt76) && vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; @@ -626,7 +626,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, int idx = msta->wcid.idx; mt76_stop_tx_queues(&dev->mt76, sta, true); - if (mt76_is_mmio(dev)) + if (mt76_is_mmio(mdev)) mt76x02_mac_wcid_set_drop(dev, idx, ps); } EXPORT_SYMBOL_GPL(mt76x02_sta_ps); -- cgit v1.2.3-59-g8ed1b From 19d0affadd6e6122742381813809f2d9f5c49eca Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Oct 2019 09:15:09 +0100 Subject: mt76: move SUPPORTS_REORDERING_BUFFER hw property in mt76_register_device Move SUPPORTS_REORDERING_BUFFER hw property configuration from chip specific code to mt76_register_device since it is supported by all mt76 drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 1 + drivers/net/wireless/mediatek/mt76/mt7603/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt7615/init.c | 1 - drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index a3975e3795ee..070c96e983df 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -337,6 +337,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 3a2927a524c3..50c6a2828c18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -556,7 +556,6 @@ int mt7603_register_device(struct mt7603_dev *dev) wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); /* init led callbacks */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 1e7723aceee2..537b1b5ba128 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -289,7 +289,6 @@ int mt7615_register_device(struct mt7615_dev *dev) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 50401ea0b82d..1cb323091c76 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -190,7 +190,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev) hw->vif_data_size = sizeof(struct mt76x02_vif); ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); dev->mt76.global_wcid.idx = 255; dev->mt76.global_wcid.hw_key_idx = -1; -- cgit v1.2.3-59-g8ed1b From 7f4b7920318b601bcea353b71d569a21846ffac5 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 8 Oct 2019 00:49:00 +0200 Subject: mt76: mt7615: add ibss support Enable IFTYPE_ADHOC support on 7615 devices. The feature has been tested using a mt76x2 device as wireless peer. Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 6 ++++++ drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 8 ++++++++ 3 files changed, 15 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 537b1b5ba128..888ca8bbdef0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -177,6 +177,9 @@ static struct ieee80211_rate mt7615_rates[] = { static const struct ieee80211_iface_limit if_limits[] = { { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { .max = MT7615_MAX_INTERFACES, .types = BIT(NL80211_IFTYPE_AP) | #ifdef CONFIG_MAC80211_MESH @@ -289,6 +292,8 @@ int mt7615_register_device(struct mt7615_dev *dev) wiphy->reg_notifier = mt7615_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; @@ -303,6 +308,7 @@ int mt7615_register_device(struct mt7615_dev *dev) dev->dfs_state = -1; wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | #ifdef CONFIG_MAC80211_MESH BIT(NL80211_IFTYPE_MESH_POINT) | #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 4f7cdb4f08fb..982e578df4ba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -41,6 +41,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask) switch (type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_ADHOC: /* ap use hw bssid 0 and ext bssid */ if (~mask & BIT(HW_BSSID_0)) return HW_BSSID_0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 164619f8a9ed..8371387ca772 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -848,6 +848,11 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, conn_type = CONNECTION_INFRA_STA; break; } + case NL80211_IFTYPE_ADHOC: + conn_type = CONNECTION_IBSS_ADHOC; + tx_wlan_idx = mvif->sta.wcid.idx; + net_type = NETWORK_IBSS; + break; default: WARN_ON(1); break; @@ -1073,6 +1078,9 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif, case NL80211_IFTYPE_STATION: req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP); break; + case NL80211_IFTYPE_ADHOC: + req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); + break; default: WARN_ON(1); break; -- cgit v1.2.3-59-g8ed1b From 0eb8c104fd8dfc2a8636b09b3f908170f7c9d037 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 31 Oct 2019 11:03:12 +0100 Subject: mt76: move interface_modes definition in mt76_core module Move interface modes declaration in common code since now mt76 chipsets support all modes (NL80211_IFTYPE_STATION, NL80211_IFTYPE_AP, NL80211_IFTYPE_MESH_POINT and NL80211_IFTYPE_ADHOC) Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 7 +++++++ drivers/net/wireless/mediatek/mt76/mt7603/init.c | 9 --------- drivers/net/wireless/mediatek/mt76/mt7615/init.c | 7 ------- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 8 -------- 4 files changed, 7 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 070c96e983df..bbe38caca71a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -340,6 +340,13 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); if (dev->cap.has_2ghz) { ret = mt76_init_sband_2g(dev, rates, n_rates); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 50c6a2828c18..0696dbf28c5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -564,16 +564,7 @@ int mt7603_register_device(struct mt7603_dev *dev) dev->mt76.led_cdev.blink_set = mt7603_led_set_blink; } - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; - wiphy->reg_notifier = mt7603_regd_notifier; ret = mt76_register_device(&dev->mt76, true, mt7603_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 888ca8bbdef0..128a6ee1fa6d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -307,13 +307,6 @@ int mt7615_register_device(struct mt7615_dev *dev) dev->mt76.antenna_mask = 0xf; dev->dfs_state = -1; - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP); - ret = mt76_register_device(&dev->mt76, true, mt7615_rates, ARRAY_SIZE(mt7615_rates)); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 1cb323091c76..bdc83838d346 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -153,14 +153,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev) hw->max_rate_tries = 1; hw->extra_tx_headroom = 2; - wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_ADHOC); - if (mt76_is_usb(&dev->mt76)) { hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + MT_DMA_HDR_LEN; -- cgit v1.2.3-59-g8ed1b From 2b5d1b91e1741c48f00682dec7b1a0845f9792f3 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Fri, 1 Nov 2019 23:21:07 +0100 Subject: mt76: mt7615: disable radar pattern detector during scanning Set switch_reason to CH_SWITCH_SCAN_BYPASS_DPD during frequency scanning in order to disable radar pattern detector Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index 8371387ca772..f229c9ce9f65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -1305,8 +1305,10 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev) }; int ret; - if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && - chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; + else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) && + chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) req.switch_reason = CH_SWITCH_DFS; else req.switch_reason = CH_SWITCH_NORMAL; -- cgit v1.2.3-59-g8ed1b From 45876d6ebbd26d2df178d1d5410642e73a289f67 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 5 Nov 2019 11:00:32 +0100 Subject: Revert "mt76: mt76x0e: don't use hw encryption for MT7630E" This reverts commit 34b0e9b767bfa09ae233ca0d6ceb299bf2e24600. Since commit 7bd0650be63c ("mt76: dma: fix buffer unmap with non-linear skbs") is no longer necessary to disable HW encryption for MT7630E. Disabling HW encryption helped previously because somehow fragmented skb's are not created if mac80211 encrypt frames, so buffer unmap bug of non-linear skbs was not triggered. Now since this bug is properly fixed by commit 7bd0650be63c ("mt76: dma: fix buffer unmap with non-linear skbs") , we can enable HW encryption back. Signed-off-by: Stanislaw Gruszka Acked-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 9621e7b16eaf..5605056dfbe2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -51,19 +51,6 @@ static void mt76x0e_stop(struct ieee80211_hw *hw) mt76x0e_stop_hw(dev); } -static int -mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - struct mt76x02_dev *dev = hw->priv; - - if (is_mt7630(dev)) - return -EOPNOTSUPP; - - return mt76x02_set_key(hw, cmd, vif, sta, key); -} - static void mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) @@ -80,7 +67,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .configure_filter = mt76x02_configure_filter, .bss_info_changed = mt76x02_bss_info_changed, .sta_state = mt76_sta_state, - .set_key = mt76x0e_set_key, + .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, -- cgit v1.2.3-59-g8ed1b From e8b970c8e367e85fab9b8ac4f36080e5d653c38e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 7 Nov 2019 01:01:58 +0200 Subject: mt76: fix possible out-of-bound access in mt7615_fill_txs/mt7603_fill_txs Fix possible out-of-bound access of status rates array in mt7615_fill_txs/mt7603_fill_txs routines Fixes: c5211e997eca ("mt76: mt7603: rework and fix tx status reporting") Fixes: 4af81f02b49c ("mt76: mt7615: sync with mt7603 rate control changes") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7603/mac.c | 4 +++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 1497d5ec649e..812d081ad943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1136,8 +1136,10 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; - if (i == ARRAY_SIZE(info->status.rates)) + if (i == ARRAY_SIZE(info->status.rates)) { + i--; break; + } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 2b810ba359ae..c77adc5d2552 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1039,8 +1039,10 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (idx && (cur_rate->idx != info->status.rates[i].idx || cur_rate->flags != info->status.rates[i].flags)) { i++; - if (i == ARRAY_SIZE(info->status.rates)) + if (i == ARRAY_SIZE(info->status.rates)) { + i--; break; + } info->status.rates[i] = *cur_rate; info->status.rates[i].count = 0; -- cgit v1.2.3-59-g8ed1b From e49c76d455a93b6cc978ae9e9fab2a1e551c147e Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Nov 2019 17:12:07 +0200 Subject: mt76: move mt76_get_antenna in mt76_core module Move mt76_get_antenna in mac80211.c in order to be reused by all drivers. Initialize .get_antenna function pointer for mt76x0, mt7603, mt7615 and mt76x2u drivers Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mac80211.c | 13 +++++++++++++ drivers/net/wireless/mediatek/mt76/mt76.h | 1 + drivers/net/wireless/mediatek/mt76/mt7603/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt7615/main.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/pci.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x0/usb.c | 1 + drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c | 15 +-------------- drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c | 1 + 8 files changed, 20 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index bbe38caca71a..b9f2a401041a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1037,3 +1037,16 @@ void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) clear_bit(MT76_SCANNING, &dev->state); } EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); + +int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct mt76_dev *dev = hw->priv; + + mutex_lock(&dev->mutex); + *tx_ant = dev->antenna_mask; + *rx_ant = dev->antenna_mask; + mutex_unlock(&dev->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mt76_get_antenna); diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 881b91c19ec3..afdbcfb96cba 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -761,6 +761,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void mt76_csa_check(struct mt76_dev *dev); void mt76_csa_finish(struct mt76_dev *dev); +int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); int mt76_get_rate(struct mt76_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index a0632ca198f1..281387c3f4f4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -691,6 +691,7 @@ const struct ieee80211_ops mt7603_ops = { .set_coverage_class = mt7603_set_coverage_class, .set_tim = mt76_set_tim, .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 982e578df4ba..240dab919327 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -547,4 +547,5 @@ const struct ieee80211_ops mt7615_ops = { .get_txpower = mt76_get_txpower, .channel_switch_beacon = mt7615_channel_switch_beacon, .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 5605056dfbe2..e2974e0ae1fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -81,6 +81,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x02_set_coverage_class, .set_rts_threshold = mt76x02_set_rts_threshold, + .get_antenna = mt76_get_antenna, }; static int mt76x0e_register_device(struct mt76x02_dev *dev) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index a8ab8df075c3..65ba9fc6ea0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -138,6 +138,7 @@ static const struct ieee80211_ops mt76x0u_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, + .get_antenna = mt76_get_antenna, }; static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 1387f3172d7f..cfe8905ce73f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -135,19 +135,6 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, return 0; } -static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, - u32 *rx_ant) -{ - struct mt76x02_dev *dev = hw->priv; - - mutex_lock(&dev->mt76.mutex); - *tx_ant = dev->mt76.antenna_mask; - *rx_ant = dev->mt76.antenna_mask; - mutex_unlock(&dev->mt76.mutex); - - return 0; -} - const struct ieee80211_ops mt76x2_ops = { .tx = mt76x02_tx, .start = mt76x2_start, @@ -172,7 +159,7 @@ const struct ieee80211_ops mt76x2_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .set_antenna = mt76x2_set_antenna, - .get_antenna = mt76x2_get_antenna, + .get_antenna = mt76_get_antenna, .set_rts_threshold = mt76x02_set_rts_threshold, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index a76a40dcd261..9e97204841f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -119,4 +119,5 @@ const struct ieee80211_ops mt76x2u_ops = { .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, + .get_antenna = mt76_get_antenna, }; -- cgit v1.2.3-59-g8ed1b From acf5457fd99db6c9a42ef280494dfee949ee1e09 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 14 Nov 2019 22:21:11 +0200 Subject: mt76: mt7615: read {tx,rx} mask from eeprom Parse configured {tx,rx} mask from eeprom data instead of just setting it to four tx-rx streams Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 18 ++++++++++++++++++ drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h | 3 +++ drivers/net/wireless/mediatek/mt76/mt7615/init.c | 2 -- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 2 ++ 4 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index 515bb58e19fd..eccad4987ac8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -93,6 +93,7 @@ static int mt7615_check_eeprom(struct mt76_dev *dev) static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) { u8 val, *eeprom = dev->mt76.eeprom.data; + u8 tx_mask, rx_mask, max_nss; val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL, eeprom[MT_EE_WIFI_CONF]); @@ -108,6 +109,23 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev) dev->mt76.cap.has_5ghz = true; break; } + + /* read tx-rx mask from eeprom */ + val = mt76_rr(dev, MT_TOP_STRAP_STA); + max_nss = val & MT_TOP_3NSS ? 3 : 4; + + rx_mask = FIELD_GET(MT_EE_NIC_CONF_RX_MASK, + eeprom[MT_EE_NIC_CONF_0]); + if (!rx_mask || rx_mask > max_nss) + rx_mask = max_nss; + + tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK, + eeprom[MT_EE_NIC_CONF_0]); + if (!tx_mask || tx_mask > max_nss) + tx_mask = max_nss; + + dev->mt76.chainmask = tx_mask << 8 | rx_mask; + dev->mt76.antenna_mask = BIT(tx_mask) - 1; } int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index f4a4280768d2..c3bc69ac210e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -24,6 +24,9 @@ enum mt7615_eeprom_field { __MT_EE_MAX = 0x3bf }; +#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4) +#define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0) + #define MT_EE_NIC_CONF_TSSI_2G BIT(5) #define MT_EE_NIC_CONF_TSSI_5G BIT(6) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 128a6ee1fa6d..553bd4d988f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -303,8 +303,6 @@ int mt7615_register_device(struct mt7615_dev *dev) IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK | IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; - dev->mt76.chainmask = 0x404; - dev->mt76.antenna_mask = 0xf; dev->dfs_state = -1; ret = mt76_register_device(&dev->mt76, true, mt7615_rates, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 99bd5939d33f..61a4aa9ac6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -6,6 +6,8 @@ #define MT_HW_REV 0x1000 #define MT_HW_CHIPID 0x1008 +#define MT_TOP_STRAP_STA 0x1010 +#define MT_TOP_3NSS BIT(24) #define MT_TOP_MISC2 0x1134 #define MT_TOP_MISC2_FW_STATE GENMASK(2, 0) -- cgit v1.2.3-59-g8ed1b From 23cb16d2ccb5f819d7acff602e5a153157bf2884 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Sun, 17 Nov 2019 14:26:14 +0200 Subject: mt76: mt76u: fix endpoint definition order Even if they are not currently used fix BK/BE endpoint definition order. Fixes: b40b15e1521f ("mt76: add usb support to mt76 layer") Signed-off-by: Lorenzo Bianconi Signed-off-by: Felix Fietkau --- drivers/net/wireless/mediatek/mt76/mt76.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index afdbcfb96cba..fb077760347a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -366,8 +366,8 @@ enum mt76u_in_ep { enum mt76u_out_ep { MT_EP_OUT_INBAND_CMD, - MT_EP_OUT_AC_BK, MT_EP_OUT_AC_BE, + MT_EP_OUT_AC_BK, MT_EP_OUT_AC_VI, MT_EP_OUT_AC_VO, MT_EP_OUT_HCCA, -- cgit v1.2.3-59-g8ed1b From 7fe579dfb90fcdf0c7722f33c772d5f0d1bc7cb6 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 20 Nov 2019 00:19:13 +0200 Subject: net: ethernet: ti: ale: clean ale tbl on init and intf restart Clean CPSW ALE on init and intf restart (up/down) to avoid reading obsolete or garbage entries from ALE table. Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw_ale.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 84025dcc78d5..e7c24396933e 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -779,6 +779,7 @@ void cpsw_ale_start(struct cpsw_ale *ale) void cpsw_ale_stop(struct cpsw_ale *ale) { del_timer_sync(&ale->timer); + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); cpsw_ale_control_set(ale, 0, ALE_ENABLE, 0); } @@ -862,6 +863,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) ALE_UNKNOWNVLAN_FORCE_UNTAG_EGRESS; } + cpsw_ale_control_set(ale, 0, ALE_CLEAR, 1); return ale; } -- cgit v1.2.3-59-g8ed1b From 4b41d34367960e8b582cf3c51b954c07e0e3a1aa Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 20 Nov 2019 00:19:14 +0200 Subject: net: ethernet: ti: cpsw: allow untagged traffic on host port Now untagged vlan traffic is not support on Host P0 port. This patch adds in ALE context bitmap of VLANs for which Host P0 port bit set in Force Untagged Packet Egress bitmask in VLANs ALE entries, and adds corresponding check in VLAN incapsulation header parsing function cpsw_rx_vlan_encap(). Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 17 ++++++++--------- drivers/net/ethernet/ti/cpsw_ale.c | 23 ++++++++++++++++++++++- drivers/net/ethernet/ti/cpsw_ale.h | 5 +++++ 3 files changed, 35 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 329671e66fe4..15a76d3842c5 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -428,17 +428,16 @@ static void cpsw_rx_vlan_encap(struct sk_buff *skb) /* Ignore vid 0 and pass packet as is */ if (!vid) return; - /* Ignore default vlans in dual mac mode */ - if (cpsw->data.dual_emac && - vid == cpsw->slaves[priv->emac_port].port_vlan) - return; - prio = (rx_vlan_encap_hdr >> - CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) & - CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK; + /* Untag P0 packets if set for vlan */ + if (!cpsw_ale_get_vlan_p0_untag(cpsw->ale, vid)) { + prio = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) & + CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK; - vtag = (prio << VLAN_PRIO_SHIFT) | vid; - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag); + vtag = (prio << VLAN_PRIO_SHIFT) | vid; + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag); + } /* strip vlan tag for VLAN-tagged packet */ if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG) { diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index e7c24396933e..723f742e6437 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -5,6 +5,8 @@ * Copyright (C) 2012 Texas Instruments * */ +#include +#include #include #include #include @@ -415,6 +417,17 @@ static void cpsw_ale_set_vlan_mcast(struct cpsw_ale *ale, u32 *ale_entry, writel(unreg_mcast, ale->params.ale_regs + ALE_VLAN_MASK_MUX(idx)); } +static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry, + u16 vid, int untag_mask) +{ + cpsw_ale_set_vlan_untag_force(ale_entry, + untag_mask, ale->vlan_field_bits); + if (untag_mask & ALE_PORT_HOST) + bitmap_set(ale->p0_untag_vid_mask, vid, 1); + else + bitmap_clear(ale->p0_untag_vid_mask, vid, 1); +} + int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, int reg_mcast, int unreg_mcast) { @@ -427,8 +440,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); cpsw_ale_set_vlan_id(ale_entry, vid); + cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag); - cpsw_ale_set_vlan_untag_force(ale_entry, untag, ale->vlan_field_bits); if (!ale->params.nu_switch_ale) { cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, ale->vlan_field_bits); @@ -460,6 +473,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) return -ENOENT; cpsw_ale_read(ale, idx, ale_entry); + cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0); if (port_mask) cpsw_ale_set_vlan_member_list(ale_entry, port_mask, @@ -792,6 +806,13 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params) if (!ale) return NULL; + ale->p0_untag_vid_mask = + devm_kmalloc_array(params->dev, BITS_TO_LONGS(VLAN_N_VID), + sizeof(unsigned long), + GFP_KERNEL); + if (!ale->p0_untag_vid_mask) + return ERR_PTR(-ENOMEM); + ale->params = *params; ale->ageout = ale->params.ale_ageout * HZ; diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index 370df254eb12..93d6d56d12f4 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -35,6 +35,7 @@ struct cpsw_ale { u32 port_mask_bits; u32 port_num_bits; u32 vlan_field_bits; + unsigned long *p0_untag_vid_mask; }; enum cpsw_ale_control { @@ -115,4 +116,8 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control, int value); void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data); +static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid) +{ + return test_bit(vid, ale->p0_untag_vid_mask); +} #endif -- cgit v1.2.3-59-g8ed1b From e85c14370783bf9339a95cab9da0fa54dc770a72 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 20 Nov 2019 00:19:15 +0200 Subject: net: ethernet: ti: ale: modify vlan/mdb api for switchdev A following patch introduces switchdev functionality, so modify ALE engine VLANs/MDBs API: - cpsw_ale_del_mcast(): update so it will remove only selected ports from mcast port_mask or delete whole mcast record if !port_mask - cpsw_ale_del_vlan(): update so it will remove only selected ports from all VLAN record's masks or delete whole VLAN record if !port_mask - add cpsw_ale_vlan_add_modify() to add or modify existing VLAN record's masks - add cpsw_ale_set_unreg_mcast() for enabling unreg mcast on port VLANs Signed-off-by: Ilias Apalodimas Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw_ale.c | 127 ++++++++++++++++++++++++++++++++++--- drivers/net/ethernet/ti/cpsw_ale.h | 6 ++ 2 files changed, 123 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c index 723f742e6437..929f3d3354e3 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.c +++ b/drivers/net/ethernet/ti/cpsw_ale.c @@ -384,6 +384,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, int flags, u16 vid) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int mcast_members; int idx; idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); @@ -392,11 +393,15 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, const u8 *addr, int port_mask, cpsw_ale_read(ale, idx, ale_entry); - if (port_mask) - cpsw_ale_set_port_mask(ale_entry, port_mask, + if (port_mask) { + mcast_members = cpsw_ale_get_port_mask(ale_entry, + ale->port_mask_bits); + mcast_members &= ~port_mask; + cpsw_ale_set_port_mask(ale_entry, mcast_members, ale->port_mask_bits); - else + } else { cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); + } cpsw_ale_write(ale, idx, ale_entry); return 0; @@ -428,7 +433,7 @@ static void cpsw_ale_set_vlan_untag(struct cpsw_ale *ale, u32 *ale_entry, bitmap_clear(ale->p0_untag_vid_mask, vid, 1); } -int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port_mask, int untag, int reg_mcast, int unreg_mcast) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; @@ -450,7 +455,8 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, } else { cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, unreg_mcast); } - cpsw_ale_set_vlan_member_list(ale_entry, port, ale->vlan_field_bits); + cpsw_ale_set_vlan_member_list(ale_entry, port_mask, + ale->vlan_field_bits); if (idx < 0) idx = cpsw_ale_match_free(ale); @@ -463,6 +469,41 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, return 0; } +static void cpsw_ale_del_vlan_modify(struct cpsw_ale *ale, u32 *ale_entry, + u16 vid, int port_mask) +{ + int reg_mcast, unreg_mcast; + int members, untag; + + members = cpsw_ale_get_vlan_member_list(ale_entry, + ale->vlan_field_bits); + members &= ~port_mask; + + untag = cpsw_ale_get_vlan_untag_force(ale_entry, + ale->vlan_field_bits); + reg_mcast = cpsw_ale_get_vlan_reg_mcast(ale_entry, + ale->vlan_field_bits); + unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); + untag &= members; + reg_mcast &= members; + unreg_mcast &= members; + + cpsw_ale_set_vlan_untag(ale, ale_entry, vid, untag); + + if (!ale->params.nu_switch_ale) { + cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast, + ale->vlan_field_bits); + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast, + ale->vlan_field_bits); + } else { + cpsw_ale_set_vlan_mcast(ale, ale_entry, reg_mcast, + unreg_mcast); + } + cpsw_ale_set_vlan_member_list(ale_entry, members, + ale->vlan_field_bits); +} + int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) { u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; @@ -473,18 +514,84 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) return -ENOENT; cpsw_ale_read(ale, idx, ale_entry); - cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0); - if (port_mask) - cpsw_ale_set_vlan_member_list(ale_entry, port_mask, - ale->vlan_field_bits); - else + if (port_mask) { + cpsw_ale_del_vlan_modify(ale, ale_entry, vid, port_mask); + } else { + cpsw_ale_set_vlan_untag(ale, ale_entry, vid, 0); cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); + } cpsw_ale_write(ale, idx, ale_entry); + return 0; } +int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mask, int unreg_mask) +{ + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; + int reg_mcast_members, unreg_mcast_members; + int vlan_members, untag_members; + int idx, ret = 0; + + idx = cpsw_ale_match_vlan(ale, vid); + if (idx >= 0) + cpsw_ale_read(ale, idx, ale_entry); + + vlan_members = cpsw_ale_get_vlan_member_list(ale_entry, + ale->vlan_field_bits); + reg_mcast_members = cpsw_ale_get_vlan_reg_mcast(ale_entry, + ale->vlan_field_bits); + unreg_mcast_members = + cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); + untag_members = cpsw_ale_get_vlan_untag_force(ale_entry, + ale->vlan_field_bits); + + vlan_members |= port_mask; + untag_members = (untag_members & ~port_mask) | untag_mask; + reg_mcast_members = (reg_mcast_members & ~port_mask) | reg_mask; + unreg_mcast_members = (unreg_mcast_members & ~port_mask) | unreg_mask; + + ret = cpsw_ale_add_vlan(ale, vid, vlan_members, untag_members, + reg_mcast_members, unreg_mcast_members); + if (ret) { + dev_err(ale->params.dev, "Unable to add vlan\n"); + return ret; + } + dev_dbg(ale->params.dev, "port mask 0x%x untag 0x%x\n", vlan_members, + untag_mask); + + return ret; +} + +void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add) +{ + u32 ale_entry[ALE_ENTRY_WORDS]; + int unreg_members = 0; + int type, idx; + + for (idx = 0; idx < ale->params.ale_entries; idx++) { + cpsw_ale_read(ale, idx, ale_entry); + type = cpsw_ale_get_entry_type(ale_entry); + if (type != ALE_TYPE_VLAN) + continue; + + unreg_members = + cpsw_ale_get_vlan_unreg_mcast(ale_entry, + ale->vlan_field_bits); + if (add) + unreg_members |= unreg_mcast_mask; + else + unreg_members &= ~unreg_mcast_mask; + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_members, + ale->vlan_field_bits); + cpsw_ale_write(ale, idx, ale_entry); + } +} + void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti, int port) { u32 ale_entry[ALE_ENTRY_WORDS]; diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h index 93d6d56d12f4..70d0955c2652 100644 --- a/drivers/net/ethernet/ti/cpsw_ale.h +++ b/drivers/net/ethernet/ti/cpsw_ale.h @@ -120,4 +120,10 @@ static inline int cpsw_ale_get_vlan_p0_untag(struct cpsw_ale *ale, u16 vid) { return test_bit(vid, ale->p0_untag_vid_mask); } + +int cpsw_ale_vlan_add_modify(struct cpsw_ale *ale, u16 vid, int port_mask, + int untag_mask, int reg_mcast, int unreg_mcast); +void cpsw_ale_set_unreg_mcast(struct cpsw_ale *ale, int unreg_mcast_mask, + bool add); + #endif -- cgit v1.2.3-59-g8ed1b From 51a9533797b07b44374346fbd36ae0aa4f36ccd3 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 20 Nov 2019 00:19:16 +0200 Subject: net: ethernet: ti: cpsw: resolve build deps of cpsw drivers A following patches introduce new CPSW switchdev driver which uses common code with legacy CPSW driver. This will introduce build dependency between CPSW switchdev and CPSW legacy drivers related to for_each_slave() and cpsw_slave_index() - they can be compiled both, but only one of them will be not functional depending in Kconfig settings due to duffrences in Slave Ports indexes calculation. To fix this make for_each_slave() local (it's used now only by legacy CPSW driver) and convert cpsw_slave_index() to be a function pointer which is assigned in probe. Driver to probe is defined by DT. Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 13 +++++++++++++ drivers/net/ethernet/ti/cpsw_priv.c | 2 ++ drivers/net/ethernet/ti/cpsw_priv.h | 10 ++-------- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 15a76d3842c5..225e5351752a 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -87,6 +87,17 @@ MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool"); #define CPSW_XDP_CONSUMED 1 #define CPSW_XDP_PASS 0 +static int cpsw_slave_index_priv(struct cpsw_common *cpsw, + struct cpsw_priv *priv) +{ + return cpsw->data.dual_emac ? priv->emac_port : cpsw->data.active_slave; +} + +static int cpsw_get_slave_port(u32 slave_num) +{ + return slave_num + 1; +} + static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid); @@ -2774,6 +2785,8 @@ static int cpsw_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, cpsw); + cpsw_slave_index = cpsw_slave_index_priv; + cpsw->dev = dev; mode = devm_gpiod_get_array_optional(dev, "mode", GPIOD_OUT_LOW); diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c index 476d050a022c..a1c83af64835 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.c +++ b/drivers/net/ethernet/ti/cpsw_priv.c @@ -19,6 +19,8 @@ #include "cpsw_sl.h" #include "davinci_cpdma.h" +int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv); + int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, int ale_ageout, phys_addr_t desc_mem_phys, int descs_pool_size) diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 8bfa761fa552..65f0e410344d 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -373,14 +373,8 @@ struct cpsw_priv { #define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw) #define napi_to_cpsw(napi) container_of(napi, struct cpsw_common, napi) -#define cpsw_slave_index(cpsw, priv) \ - ((cpsw->data.dual_emac) ? priv->emac_port : \ - cpsw->data.active_slave) - -static inline int cpsw_get_slave_port(u32 slave_num) -{ - return slave_num + 1; -} +extern int (*cpsw_slave_index)(struct cpsw_common *cpsw, + struct cpsw_priv *priv); struct addr_sync_ctx { struct net_device *ndev; -- cgit v1.2.3-59-g8ed1b From c5013ac1dd0e11267f81c855d50bd974fc8f88fe Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 20 Nov 2019 00:19:17 +0200 Subject: net: ethernet: ti: cpsw: move set of common functions in cpsw_priv As a preparatory patch to add support for a switchdev based cpsw driver, move common functions to cpsw-priv.c so that they can be used across both drivers. Signed-off-by: Ilias Apalodimas Signed-off-by: Murali Karicheri Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/cpsw.c | 1302 +---------------------------------- drivers/net/ethernet/ti/cpsw_priv.c | 1235 +++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_priv.h | 52 ++ 3 files changed, 1309 insertions(+), 1280 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 225e5351752a..6ae4a72e6f43 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -64,10 +63,6 @@ static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT; module_param(descs_pool_size, int, 0444); MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool"); -/* The buf includes headroom compatible with both skb and xdpf */ -#define CPSW_HEADROOM_NA (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + NET_IP_ALIGN) -#define CPSW_HEADROOM ALIGN(CPSW_HEADROOM_NA, sizeof(long)) - #define for_each_slave(priv, func, arg...) \ do { \ struct cpsw_slave *slave; \ @@ -82,11 +77,6 @@ MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool"); (func)(slave++, ##arg); \ } while (0) -#define CPSW_XMETA_OFFSET ALIGN(sizeof(struct xdp_frame), sizeof(long)) - -#define CPSW_XDP_CONSUMED 1 -#define CPSW_XDP_PASS 0 - static int cpsw_slave_index_priv(struct cpsw_common *cpsw, struct cpsw_priv *priv) { @@ -343,217 +333,6 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) cpsw_del_mc_addr); } -void cpsw_intr_enable(struct cpsw_common *cpsw) -{ - writel_relaxed(0xFF, &cpsw->wr_regs->tx_en); - writel_relaxed(0xFF, &cpsw->wr_regs->rx_en); - - cpdma_ctlr_int_ctrl(cpsw->dma, true); - return; -} - -void cpsw_intr_disable(struct cpsw_common *cpsw) -{ - writel_relaxed(0, &cpsw->wr_regs->tx_en); - writel_relaxed(0, &cpsw->wr_regs->rx_en); - - cpdma_ctlr_int_ctrl(cpsw->dma, false); - return; -} - -static int cpsw_is_xdpf_handle(void *handle) -{ - return (unsigned long)handle & BIT(0); -} - -static void *cpsw_xdpf_to_handle(struct xdp_frame *xdpf) -{ - return (void *)((unsigned long)xdpf | BIT(0)); -} - -static struct xdp_frame *cpsw_handle_to_xdpf(void *handle) -{ - return (struct xdp_frame *)((unsigned long)handle & ~BIT(0)); -} - -struct __aligned(sizeof(long)) cpsw_meta_xdp { - struct net_device *ndev; - int ch; -}; - -void cpsw_tx_handler(void *token, int len, int status) -{ - struct cpsw_meta_xdp *xmeta; - struct xdp_frame *xdpf; - struct net_device *ndev; - struct netdev_queue *txq; - struct sk_buff *skb; - int ch; - - if (cpsw_is_xdpf_handle(token)) { - xdpf = cpsw_handle_to_xdpf(token); - xmeta = (void *)xdpf + CPSW_XMETA_OFFSET; - ndev = xmeta->ndev; - ch = xmeta->ch; - xdp_return_frame(xdpf); - } else { - skb = token; - ndev = skb->dev; - ch = skb_get_queue_mapping(skb); - cpts_tx_timestamp(ndev_to_cpsw(ndev)->cpts, skb); - dev_kfree_skb_any(skb); - } - - /* Check whether the queue is stopped due to stalled tx dma, if the - * queue is stopped then start the queue as we have free desc for tx - */ - txq = netdev_get_tx_queue(ndev, ch); - if (unlikely(netif_tx_queue_stopped(txq))) - netif_tx_wake_queue(txq); - - ndev->stats.tx_packets++; - ndev->stats.tx_bytes += len; -} - -static void cpsw_rx_vlan_encap(struct sk_buff *skb) -{ - struct cpsw_priv *priv = netdev_priv(skb->dev); - struct cpsw_common *cpsw = priv->cpsw; - u32 rx_vlan_encap_hdr = *((u32 *)skb->data); - u16 vtag, vid, prio, pkt_type; - - /* Remove VLAN header encapsulation word */ - skb_pull(skb, CPSW_RX_VLAN_ENCAP_HDR_SIZE); - - pkt_type = (rx_vlan_encap_hdr >> - CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT) & - CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK; - /* Ignore unknown & Priority-tagged packets*/ - if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV || - pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG) - return; - - vid = (rx_vlan_encap_hdr >> - CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT) & - VLAN_VID_MASK; - /* Ignore vid 0 and pass packet as is */ - if (!vid) - return; - - /* Untag P0 packets if set for vlan */ - if (!cpsw_ale_get_vlan_p0_untag(cpsw->ale, vid)) { - prio = (rx_vlan_encap_hdr >> - CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) & - CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK; - - vtag = (prio << VLAN_PRIO_SHIFT) | vid; - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag); - } - - /* strip vlan tag for VLAN-tagged packet */ - if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG) { - memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); - skb_pull(skb, VLAN_HLEN); - } -} - -static int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, - struct page *page) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_meta_xdp *xmeta; - struct cpdma_chan *txch; - dma_addr_t dma; - int ret, port; - - xmeta = (void *)xdpf + CPSW_XMETA_OFFSET; - xmeta->ndev = priv->ndev; - xmeta->ch = 0; - txch = cpsw->txv[0].ch; - - port = priv->emac_port + cpsw->data.dual_emac; - if (page) { - dma = page_pool_get_dma_addr(page); - dma += xdpf->headroom + sizeof(struct xdp_frame); - ret = cpdma_chan_submit_mapped(txch, cpsw_xdpf_to_handle(xdpf), - dma, xdpf->len, port); - } else { - if (sizeof(*xmeta) > xdpf->headroom) { - xdp_return_frame_rx_napi(xdpf); - return -EINVAL; - } - - ret = cpdma_chan_submit(txch, cpsw_xdpf_to_handle(xdpf), - xdpf->data, xdpf->len, port); - } - - if (ret) { - priv->ndev->stats.tx_dropped++; - xdp_return_frame_rx_napi(xdpf); - } - - return ret; -} - -static int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, - struct page *page) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct net_device *ndev = priv->ndev; - int ret = CPSW_XDP_CONSUMED; - struct xdp_frame *xdpf; - struct bpf_prog *prog; - u32 act; - - rcu_read_lock(); - - prog = READ_ONCE(priv->xdp_prog); - if (!prog) { - ret = CPSW_XDP_PASS; - goto out; - } - - act = bpf_prog_run_xdp(prog, xdp); - switch (act) { - case XDP_PASS: - ret = CPSW_XDP_PASS; - break; - case XDP_TX: - xdpf = convert_to_xdp_frame(xdp); - if (unlikely(!xdpf)) - goto drop; - - cpsw_xdp_tx_frame(priv, xdpf, page); - break; - case XDP_REDIRECT: - if (xdp_do_redirect(ndev, xdp, prog)) - goto drop; - - /* Have to flush here, per packet, instead of doing it in bulk - * at the end of the napi handler. The RX devices on this - * particular hardware is sharing a common queue, so the - * incoming device might change per packet. - */ - xdp_do_flush_map(); - break; - default: - bpf_warn_invalid_xdp_action(act); - /* fall through */ - case XDP_ABORTED: - trace_xdp_exception(ndev, prog, act); - /* fall through -- handle aborts by dropping packet */ - case XDP_DROP: - goto drop; - } -out: - rcu_read_unlock(); - return ret; -drop: - rcu_read_unlock(); - page_pool_recycle_direct(cpsw->page_pool[ch], page); - return ret; -} - static unsigned int cpsw_rxbuf_total_len(unsigned int len) { len += CPSW_HEADROOM; @@ -562,123 +341,6 @@ static unsigned int cpsw_rxbuf_total_len(unsigned int len) return SKB_DATA_ALIGN(len); } -static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw, - int size) -{ - struct page_pool_params pp_params; - struct page_pool *pool; - - pp_params.order = 0; - pp_params.flags = PP_FLAG_DMA_MAP; - pp_params.pool_size = size; - pp_params.nid = NUMA_NO_NODE; - pp_params.dma_dir = DMA_BIDIRECTIONAL; - pp_params.dev = cpsw->dev; - - pool = page_pool_create(&pp_params); - if (IS_ERR(pool)) - dev_err(cpsw->dev, "cannot create rx page pool\n"); - - return pool; -} - -static int cpsw_ndev_create_xdp_rxq(struct cpsw_priv *priv, int ch) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct xdp_rxq_info *rxq; - struct page_pool *pool; - int ret; - - pool = cpsw->page_pool[ch]; - rxq = &priv->xdp_rxq[ch]; - - ret = xdp_rxq_info_reg(rxq, priv->ndev, ch); - if (ret) - return ret; - - ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool); - if (ret) - xdp_rxq_info_unreg(rxq); - - return ret; -} - -static void cpsw_ndev_destroy_xdp_rxq(struct cpsw_priv *priv, int ch) -{ - struct xdp_rxq_info *rxq = &priv->xdp_rxq[ch]; - - if (!xdp_rxq_info_is_reg(rxq)) - return; - - xdp_rxq_info_unreg(rxq); -} - -static int cpsw_create_rx_pool(struct cpsw_common *cpsw, int ch) -{ - struct page_pool *pool; - int ret = 0, pool_size; - - pool_size = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch); - pool = cpsw_create_page_pool(cpsw, pool_size); - if (IS_ERR(pool)) - ret = PTR_ERR(pool); - else - cpsw->page_pool[ch] = pool; - - return ret; -} - -void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw) -{ - struct net_device *ndev; - int i, ch; - - for (ch = 0; ch < cpsw->rx_ch_num; ch++) { - for (i = 0; i < cpsw->data.slaves; i++) { - ndev = cpsw->slaves[i].ndev; - if (!ndev) - continue; - - cpsw_ndev_destroy_xdp_rxq(netdev_priv(ndev), ch); - } - - page_pool_destroy(cpsw->page_pool[ch]); - cpsw->page_pool[ch] = NULL; - } -} - -int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) -{ - struct net_device *ndev; - int i, ch, ret; - - for (ch = 0; ch < cpsw->rx_ch_num; ch++) { - ret = cpsw_create_rx_pool(cpsw, ch); - if (ret) - goto err_cleanup; - - /* using same page pool is allowed as no running rx handlers - * simultaneously for both ndevs - */ - for (i = 0; i < cpsw->data.slaves; i++) { - ndev = cpsw->slaves[i].ndev; - if (!ndev) - continue; - - ret = cpsw_ndev_create_xdp_rxq(netdev_priv(ndev), ch); - if (ret) - goto err_cleanup; - } - } - - return 0; - -err_cleanup: - cpsw_destroy_xdp_rxqs(cpsw); - - return ret; -} - static void cpsw_rx_handler(void *token, int len, int status) { struct page *new_page, *page = token; @@ -745,7 +407,8 @@ static void cpsw_rx_handler(void *token, int len, int status) xdp.data_hard_start = pa; xdp.rxq = &priv->xdp_rxq[ch]; - ret = cpsw_run_xdp(priv, ch, &xdp, page); + port = priv->emac_port + cpsw->data.dual_emac; + ret = cpsw_run_xdp(priv, ch, &xdp, page, port); if (ret != CPSW_XDP_PASS) goto requeue; @@ -795,274 +458,6 @@ requeue: } } -void cpsw_split_res(struct cpsw_common *cpsw) -{ - u32 consumed_rate = 0, bigest_rate = 0; - struct cpsw_vector *txv = cpsw->txv; - int i, ch_weight, rlim_ch_num = 0; - int budget, bigest_rate_ch = 0; - u32 ch_rate, max_rate; - int ch_budget = 0; - - for (i = 0; i < cpsw->tx_ch_num; i++) { - ch_rate = cpdma_chan_get_rate(txv[i].ch); - if (!ch_rate) - continue; - - rlim_ch_num++; - consumed_rate += ch_rate; - } - - if (cpsw->tx_ch_num == rlim_ch_num) { - max_rate = consumed_rate; - } else if (!rlim_ch_num) { - ch_budget = CPSW_POLL_WEIGHT / cpsw->tx_ch_num; - bigest_rate = 0; - max_rate = consumed_rate; - } else { - max_rate = cpsw->speed * 1000; - - /* if max_rate is less then expected due to reduced link speed, - * split proportionally according next potential max speed - */ - if (max_rate < consumed_rate) - max_rate *= 10; - - if (max_rate < consumed_rate) - max_rate *= 10; - - ch_budget = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate; - ch_budget = (CPSW_POLL_WEIGHT - ch_budget) / - (cpsw->tx_ch_num - rlim_ch_num); - bigest_rate = (max_rate - consumed_rate) / - (cpsw->tx_ch_num - rlim_ch_num); - } - - /* split tx weight/budget */ - budget = CPSW_POLL_WEIGHT; - for (i = 0; i < cpsw->tx_ch_num; i++) { - ch_rate = cpdma_chan_get_rate(txv[i].ch); - if (ch_rate) { - txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate; - if (!txv[i].budget) - txv[i].budget++; - if (ch_rate > bigest_rate) { - bigest_rate_ch = i; - bigest_rate = ch_rate; - } - - ch_weight = (ch_rate * 100) / max_rate; - if (!ch_weight) - ch_weight++; - cpdma_chan_set_weight(cpsw->txv[i].ch, ch_weight); - } else { - txv[i].budget = ch_budget; - if (!bigest_rate_ch) - bigest_rate_ch = i; - cpdma_chan_set_weight(cpsw->txv[i].ch, 0); - } - - budget -= txv[i].budget; - } - - if (budget) - txv[bigest_rate_ch].budget += budget; - - /* split rx budget */ - budget = CPSW_POLL_WEIGHT; - ch_budget = budget / cpsw->rx_ch_num; - for (i = 0; i < cpsw->rx_ch_num; i++) { - cpsw->rxv[i].budget = ch_budget; - budget -= ch_budget; - } - - if (budget) - cpsw->rxv[0].budget += budget; -} - -static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) -{ - struct cpsw_common *cpsw = dev_id; - - writel(0, &cpsw->wr_regs->tx_en); - cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_TX); - - if (cpsw->quirk_irq) { - disable_irq_nosync(cpsw->irqs_table[1]); - cpsw->tx_irq_disabled = true; - } - - napi_schedule(&cpsw->napi_tx); - return IRQ_HANDLED; -} - -static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) -{ - struct cpsw_common *cpsw = dev_id; - - cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX); - writel(0, &cpsw->wr_regs->rx_en); - - if (cpsw->quirk_irq) { - disable_irq_nosync(cpsw->irqs_table[0]); - cpsw->rx_irq_disabled = true; - } - - napi_schedule(&cpsw->napi_rx); - return IRQ_HANDLED; -} - -static int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) -{ - u32 ch_map; - int num_tx, cur_budget, ch; - struct cpsw_common *cpsw = napi_to_cpsw(napi_tx); - struct cpsw_vector *txv; - - /* process every unprocessed channel */ - ch_map = cpdma_ctrl_txchs_state(cpsw->dma); - for (ch = 0, num_tx = 0; ch_map & 0xff; ch_map <<= 1, ch++) { - if (!(ch_map & 0x80)) - continue; - - txv = &cpsw->txv[ch]; - if (unlikely(txv->budget > budget - num_tx)) - cur_budget = budget - num_tx; - else - cur_budget = txv->budget; - - num_tx += cpdma_chan_process(txv->ch, cur_budget); - if (num_tx >= budget) - break; - } - - if (num_tx < budget) { - napi_complete(napi_tx); - writel(0xff, &cpsw->wr_regs->tx_en); - } - - return num_tx; -} - -static int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) -{ - struct cpsw_common *cpsw = napi_to_cpsw(napi_tx); - int num_tx; - - num_tx = cpdma_chan_process(cpsw->txv[0].ch, budget); - if (num_tx < budget) { - napi_complete(napi_tx); - writel(0xff, &cpsw->wr_regs->tx_en); - if (cpsw->tx_irq_disabled) { - cpsw->tx_irq_disabled = false; - enable_irq(cpsw->irqs_table[1]); - } - } - - return num_tx; -} - -static int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) -{ - u32 ch_map; - int num_rx, cur_budget, ch; - struct cpsw_common *cpsw = napi_to_cpsw(napi_rx); - struct cpsw_vector *rxv; - - /* process every unprocessed channel */ - ch_map = cpdma_ctrl_rxchs_state(cpsw->dma); - for (ch = 0, num_rx = 0; ch_map; ch_map >>= 1, ch++) { - if (!(ch_map & 0x01)) - continue; - - rxv = &cpsw->rxv[ch]; - if (unlikely(rxv->budget > budget - num_rx)) - cur_budget = budget - num_rx; - else - cur_budget = rxv->budget; - - num_rx += cpdma_chan_process(rxv->ch, cur_budget); - if (num_rx >= budget) - break; - } - - if (num_rx < budget) { - napi_complete_done(napi_rx, num_rx); - writel(0xff, &cpsw->wr_regs->rx_en); - } - - return num_rx; -} - -static int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) -{ - struct cpsw_common *cpsw = napi_to_cpsw(napi_rx); - int num_rx; - - num_rx = cpdma_chan_process(cpsw->rxv[0].ch, budget); - if (num_rx < budget) { - napi_complete_done(napi_rx, num_rx); - writel(0xff, &cpsw->wr_regs->rx_en); - if (cpsw->rx_irq_disabled) { - cpsw->rx_irq_disabled = false; - enable_irq(cpsw->irqs_table[0]); - } - } - - return num_rx; -} - -static inline void soft_reset(const char *module, void __iomem *reg) -{ - unsigned long timeout = jiffies + HZ; - - writel_relaxed(1, reg); - do { - cpu_relax(); - } while ((readl_relaxed(reg) & 1) && time_after(timeout, jiffies)); - - WARN(readl_relaxed(reg) & 1, "failed to soft-reset %s\n", module); -} - -static void cpsw_set_slave_mac(struct cpsw_slave *slave, - struct cpsw_priv *priv) -{ - slave_write(slave, mac_hi(priv->mac_addr), SA_HI); - slave_write(slave, mac_lo(priv->mac_addr), SA_LO); -} - -static bool cpsw_shp_is_off(struct cpsw_priv *priv) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - u32 shift, mask, val; - - val = readl_relaxed(&cpsw->regs->ptype); - - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; - mask = 7 << shift; - val = val & mask; - - return !val; -} - -static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - u32 shift, mask, val; - - val = readl_relaxed(&cpsw->regs->ptype); - - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; - mask = (1 << --fifo) << shift; - val = on ? val | mask : val & ~mask; - - writel_relaxed(val, &cpsw->regs->ptype); -} - static void _cpsw_adjust_link(struct cpsw_slave *slave, struct cpsw_priv *priv, bool *link) { @@ -1128,63 +523,25 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave, slave->mac_control = mac_control; } -static int cpsw_get_common_speed(struct cpsw_common *cpsw) +static void cpsw_adjust_link(struct net_device *ndev) { - int i, speed; + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + bool link = false; - for (i = 0, speed = 0; i < cpsw->data.slaves; i++) - if (cpsw->slaves[i].phy && cpsw->slaves[i].phy->link) - speed += cpsw->slaves[i].phy->speed; + for_each_slave(priv, _cpsw_adjust_link, priv, &link); + + if (link) { + if (cpsw_need_resplit(cpsw)) + cpsw_split_res(cpsw); - return speed; -} - -static int cpsw_need_resplit(struct cpsw_common *cpsw) -{ - int i, rlim_ch_num; - int speed, ch_rate; - - /* re-split resources only in case speed was changed */ - speed = cpsw_get_common_speed(cpsw); - if (speed == cpsw->speed || !speed) - return 0; - - cpsw->speed = speed; - - for (i = 0, rlim_ch_num = 0; i < cpsw->tx_ch_num; i++) { - ch_rate = cpdma_chan_get_rate(cpsw->txv[i].ch); - if (!ch_rate) - break; - - rlim_ch_num++; - } - - /* cases not dependent on speed */ - if (!rlim_ch_num || rlim_ch_num == cpsw->tx_ch_num) - return 0; - - return 1; -} - -static void cpsw_adjust_link(struct net_device *ndev) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; - bool link = false; - - for_each_slave(priv, _cpsw_adjust_link, priv, &link); - - if (link) { - if (cpsw_need_resplit(cpsw)) - cpsw_split_res(cpsw); - - netif_carrier_on(ndev); - if (netif_running(ndev)) - netif_tx_wake_all_queues(ndev); - } else { - netif_carrier_off(ndev); - netif_tx_stop_all_queues(ndev); - } + netif_carrier_on(ndev); + if (netif_running(ndev)) + netif_tx_wake_all_queues(ndev); + } else { + netif_carrier_off(ndev); + netif_tx_stop_all_queues(ndev); + } } static inline void cpsw_add_dual_emac_def_ale_entries( @@ -1358,51 +715,6 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) } } -int cpsw_fill_rx_channels(struct cpsw_priv *priv) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_meta_xdp *xmeta; - struct page_pool *pool; - struct page *page; - int ch_buf_num; - int ch, i, ret; - dma_addr_t dma; - - for (ch = 0; ch < cpsw->rx_ch_num; ch++) { - pool = cpsw->page_pool[ch]; - ch_buf_num = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch); - for (i = 0; i < ch_buf_num; i++) { - page = page_pool_dev_alloc_pages(pool); - if (!page) { - cpsw_err(priv, ifup, "allocate rx page err\n"); - return -ENOMEM; - } - - xmeta = page_address(page) + CPSW_XMETA_OFFSET; - xmeta->ndev = priv->ndev; - xmeta->ch = ch; - - dma = page_pool_get_dma_addr(page) + CPSW_HEADROOM; - ret = cpdma_chan_idle_submit_mapped(cpsw->rxv[ch].ch, - page, dma, - cpsw->rx_packet_max, - 0); - if (ret < 0) { - cpsw_err(priv, ifup, - "cannot submit page to channel %d rx, error %d\n", - ch, ret); - page_pool_recycle_direct(pool, page); - return ret; - } - } - - cpsw_info(priv, ifup, "ch %d rx, submitted %d descriptors\n", - ch, ch_buf_num); - } - - return 0; -} - static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_common *cpsw) { u32 slave_port; @@ -1420,221 +732,6 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_common *cpsw) cpsw_sl_ctl_reset(slave->mac_sl); } -static int cpsw_tc_to_fifo(int tc, int num_tc) -{ - if (tc == num_tc - 1) - return 0; - - return CPSW_FIFO_SHAPERS_NUM - tc; -} - -static int cpsw_set_fifo_bw(struct cpsw_priv *priv, int fifo, int bw) -{ - struct cpsw_common *cpsw = priv->cpsw; - u32 val = 0, send_pct, shift; - struct cpsw_slave *slave; - int pct = 0, i; - - if (bw > priv->shp_cfg_speed * 1000) - goto err; - - /* shaping has to stay enabled for highest fifos linearly - * and fifo bw no more then interface can allow - */ - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - send_pct = slave_read(slave, SEND_PERCENT); - for (i = CPSW_FIFO_SHAPERS_NUM; i > 0; i--) { - if (!bw) { - if (i >= fifo || !priv->fifo_bw[i]) - continue; - - dev_warn(priv->dev, "Prev FIFO%d is shaped", i); - continue; - } - - if (!priv->fifo_bw[i] && i > fifo) { - dev_err(priv->dev, "Upper FIFO%d is not shaped", i); - return -EINVAL; - } - - shift = (i - 1) * 8; - if (i == fifo) { - send_pct &= ~(CPSW_PCT_MASK << shift); - val = DIV_ROUND_UP(bw, priv->shp_cfg_speed * 10); - if (!val) - val = 1; - - send_pct |= val << shift; - pct += val; - continue; - } - - if (priv->fifo_bw[i]) - pct += (send_pct >> shift) & CPSW_PCT_MASK; - } - - if (pct >= 100) - goto err; - - slave_write(slave, send_pct, SEND_PERCENT); - priv->fifo_bw[fifo] = bw; - - dev_warn(priv->dev, "set FIFO%d bw = %d\n", fifo, - DIV_ROUND_CLOSEST(val * priv->shp_cfg_speed, 100)); - - return 0; -err: - dev_err(priv->dev, "Bandwidth doesn't fit in tc configuration"); - return -EINVAL; -} - -static int cpsw_set_fifo_rlimit(struct cpsw_priv *priv, int fifo, int bw) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - u32 tx_in_ctl_rg, val; - int ret; - - ret = cpsw_set_fifo_bw(priv, fifo, bw); - if (ret) - return ret; - - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - tx_in_ctl_rg = cpsw->version == CPSW_VERSION_1 ? - CPSW1_TX_IN_CTL : CPSW2_TX_IN_CTL; - - if (!bw) - cpsw_fifo_shp_on(priv, fifo, bw); - - val = slave_read(slave, tx_in_ctl_rg); - if (cpsw_shp_is_off(priv)) { - /* disable FIFOs rate limited queues */ - val &= ~(0xf << CPSW_FIFO_RATE_EN_SHIFT); - - /* set type of FIFO queues to normal priority mode */ - val &= ~(3 << CPSW_FIFO_QUEUE_TYPE_SHIFT); - - /* set type of FIFO queues to be rate limited */ - if (bw) - val |= 2 << CPSW_FIFO_QUEUE_TYPE_SHIFT; - else - priv->shp_cfg_speed = 0; - } - - /* toggle a FIFO rate limited queue */ - if (bw) - val |= BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); - else - val &= ~BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); - slave_write(slave, val, tx_in_ctl_rg); - - /* FIFO transmit shape enable */ - cpsw_fifo_shp_on(priv, fifo, bw); - return 0; -} - -/* Defaults: - * class A - prio 3 - * class B - prio 2 - * shaping for class A should be set first - */ -static int cpsw_set_cbs(struct net_device *ndev, - struct tc_cbs_qopt_offload *qopt) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - int prev_speed = 0; - int tc, ret, fifo; - u32 bw = 0; - - tc = netdev_txq_to_tc(priv->ndev, qopt->queue); - - /* enable channels in backward order, as highest FIFOs must be rate - * limited first and for compliance with CPDMA rate limited channels - * that also used in bacward order. FIFO0 cannot be rate limited. - */ - fifo = cpsw_tc_to_fifo(tc, ndev->num_tc); - if (!fifo) { - dev_err(priv->dev, "Last tc%d can't be rate limited", tc); - return -EINVAL; - } - - /* do nothing, it's disabled anyway */ - if (!qopt->enable && !priv->fifo_bw[fifo]) - return 0; - - /* shapers can be set if link speed is known */ - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - if (slave->phy && slave->phy->link) { - if (priv->shp_cfg_speed && - priv->shp_cfg_speed != slave->phy->speed) - prev_speed = priv->shp_cfg_speed; - - priv->shp_cfg_speed = slave->phy->speed; - } - - if (!priv->shp_cfg_speed) { - dev_err(priv->dev, "Link speed is not known"); - return -1; - } - - ret = pm_runtime_get_sync(cpsw->dev); - if (ret < 0) { - pm_runtime_put_noidle(cpsw->dev); - return ret; - } - - bw = qopt->enable ? qopt->idleslope : 0; - ret = cpsw_set_fifo_rlimit(priv, fifo, bw); - if (ret) { - priv->shp_cfg_speed = prev_speed; - prev_speed = 0; - } - - if (bw && prev_speed) - dev_warn(priv->dev, - "Speed was changed, CBS shaper speeds are changed!"); - - pm_runtime_put_sync(cpsw->dev); - return ret; -} - -static void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) -{ - int fifo, bw; - - for (fifo = CPSW_FIFO_SHAPERS_NUM; fifo > 0; fifo--) { - bw = priv->fifo_bw[fifo]; - if (!bw) - continue; - - cpsw_set_fifo_rlimit(priv, fifo, bw); - } -} - -static void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) -{ - struct cpsw_common *cpsw = priv->cpsw; - u32 tx_prio_map = 0; - int i, tc, fifo; - u32 tx_prio_rg; - - if (!priv->mqprio_hw) - return; - - for (i = 0; i < 8; i++) { - tc = netdev_get_prio_tc_map(priv->ndev, i); - fifo = CPSW_FIFO_SHAPERS_NUM - tc; - tx_prio_map |= fifo << (4 * i); - } - - tx_prio_rg = cpsw->version == CPSW_VERSION_1 ? - CPSW1_TX_PRI_MAP : CPSW2_TX_PRI_MAP; - - slave_write(slave, tx_prio_map, tx_prio_rg); -} - static int cpsw_restore_vlans(struct net_device *vdev, int vid, void *arg) { struct cpsw_priv *priv = arg; @@ -1863,207 +960,6 @@ fail: return NETDEV_TX_BUSY; } -#if IS_ENABLED(CONFIG_TI_CPTS) - -static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) -{ - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave = &cpsw->slaves[cpsw->data.active_slave]; - u32 ts_en, seq_id; - - if (!priv->tx_ts_enabled && !priv->rx_ts_enabled) { - slave_write(slave, 0, CPSW1_TS_CTL); - return; - } - - seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588; - ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS; - - if (priv->tx_ts_enabled) - ts_en |= CPSW_V1_TS_TX_EN; - - if (priv->rx_ts_enabled) - ts_en |= CPSW_V1_TS_RX_EN; - - slave_write(slave, ts_en, CPSW1_TS_CTL); - slave_write(slave, seq_id, CPSW1_TS_SEQ_LTYPE); -} - -static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) -{ - struct cpsw_slave *slave; - struct cpsw_common *cpsw = priv->cpsw; - u32 ctrl, mtype; - - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - - ctrl = slave_read(slave, CPSW2_CONTROL); - switch (cpsw->version) { - case CPSW_VERSION_2: - ctrl &= ~CTRL_V2_ALL_TS_MASK; - - if (priv->tx_ts_enabled) - ctrl |= CTRL_V2_TX_TS_BITS; - - if (priv->rx_ts_enabled) - ctrl |= CTRL_V2_RX_TS_BITS; - break; - case CPSW_VERSION_3: - default: - ctrl &= ~CTRL_V3_ALL_TS_MASK; - - if (priv->tx_ts_enabled) - ctrl |= CTRL_V3_TX_TS_BITS; - - if (priv->rx_ts_enabled) - ctrl |= CTRL_V3_RX_TS_BITS; - break; - } - - mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS; - - slave_write(slave, mtype, CPSW2_TS_SEQ_MTYPE); - slave_write(slave, ctrl, CPSW2_CONTROL); - writel_relaxed(ETH_P_1588, &cpsw->regs->ts_ltype); - writel_relaxed(ETH_P_8021Q, &cpsw->regs->vlan_ltype); -} - -static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) -{ - struct cpsw_priv *priv = netdev_priv(dev); - struct hwtstamp_config cfg; - struct cpsw_common *cpsw = priv->cpsw; - - if (cpsw->version != CPSW_VERSION_1 && - cpsw->version != CPSW_VERSION_2 && - cpsw->version != CPSW_VERSION_3) - return -EOPNOTSUPP; - - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - /* reserved for future extensions */ - if (cfg.flags) - return -EINVAL; - - if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON) - return -ERANGE; - - switch (cfg.rx_filter) { - case HWTSTAMP_FILTER_NONE: - priv->rx_ts_enabled = 0; - break; - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_NTP_ALL: - return -ERANGE; - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; - break; - case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V2_EVENT; - cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - break; - default: - return -ERANGE; - } - - priv->tx_ts_enabled = cfg.tx_type == HWTSTAMP_TX_ON; - - switch (cpsw->version) { - case CPSW_VERSION_1: - cpsw_hwtstamp_v1(priv); - break; - case CPSW_VERSION_2: - case CPSW_VERSION_3: - cpsw_hwtstamp_v2(priv); - break; - default: - WARN_ON(1); - } - - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; -} - -static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) -{ - struct cpsw_common *cpsw = ndev_to_cpsw(dev); - struct cpsw_priv *priv = netdev_priv(dev); - struct hwtstamp_config cfg; - - if (cpsw->version != CPSW_VERSION_1 && - cpsw->version != CPSW_VERSION_2 && - cpsw->version != CPSW_VERSION_3) - return -EOPNOTSUPP; - - cfg.flags = 0; - cfg.tx_type = priv->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; - cfg.rx_filter = priv->rx_ts_enabled; - - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; -} -#else -static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) -{ - return -EOPNOTSUPP; -} - -static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) -{ - return -EOPNOTSUPP; -} -#endif /*CONFIG_TI_CPTS*/ - -static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -{ - struct cpsw_priv *priv = netdev_priv(dev); - struct cpsw_common *cpsw = priv->cpsw; - int slave_no = cpsw_slave_index(cpsw, priv); - - if (!netif_running(dev)) - return -EINVAL; - - switch (cmd) { - case SIOCSHWTSTAMP: - return cpsw_hwtstamp_set(dev, req); - case SIOCGHWTSTAMP: - return cpsw_hwtstamp_get(dev, req); - } - - if (!cpsw->slaves[slave_no].phy) - return -EOPNOTSUPP; - return phy_mii_ioctl(cpsw->slaves[slave_no].phy, req, cmd); -} - -static void cpsw_ndo_tx_timeout(struct net_device *ndev) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; - int ch; - - cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n"); - ndev->stats.tx_errors++; - cpsw_intr_disable(cpsw); - for (ch = 0; ch < cpsw->tx_ch_num; ch++) { - cpdma_chan_stop(cpsw->txv[ch].ch); - cpdma_chan_start(cpsw->txv[ch].ch); - } - - cpsw_intr_enable(cpsw); - netif_trans_update(ndev); - netif_tx_wake_all_queues(ndev); -} - static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) { struct cpsw_priv *priv = netdev_priv(ndev); @@ -2225,168 +1121,13 @@ err: return ret; } -static int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; - struct cpsw_slave *slave; - u32 min_rate; - u32 ch_rate; - int i, ret; - - ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate; - if (ch_rate == rate) - return 0; - - ch_rate = rate * 1000; - min_rate = cpdma_chan_get_min_rate(cpsw->dma); - if ((ch_rate < min_rate && ch_rate)) { - dev_err(priv->dev, "The channel rate cannot be less than %dMbps", - min_rate); - return -EINVAL; - } - - if (rate > cpsw->speed) { - dev_err(priv->dev, "The channel rate cannot be more than 2Gbps"); - return -EINVAL; - } - - ret = pm_runtime_get_sync(cpsw->dev); - if (ret < 0) { - pm_runtime_put_noidle(cpsw->dev); - return ret; - } - - ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, ch_rate); - pm_runtime_put(cpsw->dev); - - if (ret) - return ret; - - /* update rates for slaves tx queues */ - for (i = 0; i < cpsw->data.slaves; i++) { - slave = &cpsw->slaves[i]; - if (!slave->ndev) - continue; - - netdev_get_tx_queue(slave->ndev, queue)->tx_maxrate = rate; - } - - cpsw_split_res(cpsw); - return ret; -} - -static int cpsw_set_mqprio(struct net_device *ndev, void *type_data) -{ - struct tc_mqprio_qopt_offload *mqprio = type_data; - struct cpsw_priv *priv = netdev_priv(ndev); - struct cpsw_common *cpsw = priv->cpsw; - int fifo, num_tc, count, offset; - struct cpsw_slave *slave; - u32 tx_prio_map = 0; - int i, tc, ret; - - num_tc = mqprio->qopt.num_tc; - if (num_tc > CPSW_TC_NUM) - return -EINVAL; - - if (mqprio->mode != TC_MQPRIO_MODE_DCB) - return -EINVAL; - - ret = pm_runtime_get_sync(cpsw->dev); - if (ret < 0) { - pm_runtime_put_noidle(cpsw->dev); - return ret; - } - - if (num_tc) { - for (i = 0; i < 8; i++) { - tc = mqprio->qopt.prio_tc_map[i]; - fifo = cpsw_tc_to_fifo(tc, num_tc); - tx_prio_map |= fifo << (4 * i); - } - - netdev_set_num_tc(ndev, num_tc); - for (i = 0; i < num_tc; i++) { - count = mqprio->qopt.count[i]; - offset = mqprio->qopt.offset[i]; - netdev_set_tc_queue(ndev, i, count, offset); - } - } - - if (!mqprio->qopt.hw) { - /* restore default configuration */ - netdev_reset_tc(ndev); - tx_prio_map = TX_PRIORITY_MAPPING; - } - - priv->mqprio_hw = mqprio->qopt.hw; - - offset = cpsw->version == CPSW_VERSION_1 ? - CPSW1_TX_PRI_MAP : CPSW2_TX_PRI_MAP; - - slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; - slave_write(slave, tx_prio_map, offset); - - pm_runtime_put_sync(cpsw->dev); - - return 0; -} - -static int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, - void *type_data) -{ - switch (type) { - case TC_SETUP_QDISC_CBS: - return cpsw_set_cbs(ndev, type_data); - - case TC_SETUP_QDISC_MQPRIO: - return cpsw_set_mqprio(ndev, type_data); - - default: - return -EOPNOTSUPP; - } -} - -static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf) -{ - struct bpf_prog *prog = bpf->prog; - - if (!priv->xdpi.prog && !prog) - return 0; - - if (!xdp_attachment_flags_ok(&priv->xdpi, bpf)) - return -EBUSY; - - WRITE_ONCE(priv->xdp_prog, prog); - - xdp_attachment_setup(&priv->xdpi, bpf); - - return 0; -} - -static int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - - switch (bpf->command) { - case XDP_SETUP_PROG: - return cpsw_xdp_prog_setup(priv, bpf); - - case XDP_QUERY_PROG: - return xdp_attachment_query(&priv->xdpi, bpf); - - default: - return -EINVAL; - } -} - static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, struct xdp_frame **frames, u32 flags) { struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; struct xdp_frame *xdpf; - int i, drops = 0; + int i, drops = 0, port; if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) return -EINVAL; @@ -2399,7 +1140,8 @@ static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, continue; } - if (cpsw_xdp_tx_frame(priv, xdpf, NULL)) + port = priv->emac_port + cpsw->data.dual_emac; + if (cpsw_xdp_tx_frame(priv, xdpf, NULL, port)) drops++; } diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c index a1c83af64835..bbc9b413b5c3 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.c +++ b/drivers/net/ethernet/ti/cpsw_priv.c @@ -5,14 +5,22 @@ * Copyright (C) 2019 Texas Instruments */ +#include +#include #include #include +#include #include #include +#include #include #include +#include #include +#include +#include +#include "cpsw.h" #include "cpts.h" #include "cpsw_ale.h" #include "cpsw_priv.h" @@ -21,6 +29,390 @@ int (*cpsw_slave_index)(struct cpsw_common *cpsw, struct cpsw_priv *priv); +void cpsw_intr_enable(struct cpsw_common *cpsw) +{ + writel_relaxed(0xFF, &cpsw->wr_regs->tx_en); + writel_relaxed(0xFF, &cpsw->wr_regs->rx_en); + + cpdma_ctlr_int_ctrl(cpsw->dma, true); +} + +void cpsw_intr_disable(struct cpsw_common *cpsw) +{ + writel_relaxed(0, &cpsw->wr_regs->tx_en); + writel_relaxed(0, &cpsw->wr_regs->rx_en); + + cpdma_ctlr_int_ctrl(cpsw->dma, false); +} + +void cpsw_tx_handler(void *token, int len, int status) +{ + struct cpsw_meta_xdp *xmeta; + struct xdp_frame *xdpf; + struct net_device *ndev; + struct netdev_queue *txq; + struct sk_buff *skb; + int ch; + + if (cpsw_is_xdpf_handle(token)) { + xdpf = cpsw_handle_to_xdpf(token); + xmeta = (void *)xdpf + CPSW_XMETA_OFFSET; + ndev = xmeta->ndev; + ch = xmeta->ch; + xdp_return_frame(xdpf); + } else { + skb = token; + ndev = skb->dev; + ch = skb_get_queue_mapping(skb); + cpts_tx_timestamp(ndev_to_cpsw(ndev)->cpts, skb); + dev_kfree_skb_any(skb); + } + + /* Check whether the queue is stopped due to stalled tx dma, if the + * queue is stopped then start the queue as we have free desc for tx + */ + txq = netdev_get_tx_queue(ndev, ch); + if (unlikely(netif_tx_queue_stopped(txq))) + netif_tx_wake_queue(txq); + + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += len; +} + +irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id) +{ + struct cpsw_common *cpsw = dev_id; + + writel(0, &cpsw->wr_regs->tx_en); + cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_TX); + + if (cpsw->quirk_irq) { + disable_irq_nosync(cpsw->irqs_table[1]); + cpsw->tx_irq_disabled = true; + } + + napi_schedule(&cpsw->napi_tx); + return IRQ_HANDLED; +} + +irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id) +{ + struct cpsw_common *cpsw = dev_id; + + cpdma_ctlr_eoi(cpsw->dma, CPDMA_EOI_RX); + writel(0, &cpsw->wr_regs->rx_en); + + if (cpsw->quirk_irq) { + disable_irq_nosync(cpsw->irqs_table[0]); + cpsw->rx_irq_disabled = true; + } + + napi_schedule(&cpsw->napi_rx); + return IRQ_HANDLED; +} + +int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget) +{ + struct cpsw_common *cpsw = napi_to_cpsw(napi_tx); + int num_tx, cur_budget, ch; + u32 ch_map; + struct cpsw_vector *txv; + + /* process every unprocessed channel */ + ch_map = cpdma_ctrl_txchs_state(cpsw->dma); + for (ch = 0, num_tx = 0; ch_map & 0xff; ch_map <<= 1, ch++) { + if (!(ch_map & 0x80)) + continue; + + txv = &cpsw->txv[ch]; + if (unlikely(txv->budget > budget - num_tx)) + cur_budget = budget - num_tx; + else + cur_budget = txv->budget; + + num_tx += cpdma_chan_process(txv->ch, cur_budget); + if (num_tx >= budget) + break; + } + + if (num_tx < budget) { + napi_complete(napi_tx); + writel(0xff, &cpsw->wr_regs->tx_en); + } + + return num_tx; +} + +int cpsw_tx_poll(struct napi_struct *napi_tx, int budget) +{ + struct cpsw_common *cpsw = napi_to_cpsw(napi_tx); + int num_tx; + + num_tx = cpdma_chan_process(cpsw->txv[0].ch, budget); + if (num_tx < budget) { + napi_complete(napi_tx); + writel(0xff, &cpsw->wr_regs->tx_en); + if (cpsw->tx_irq_disabled) { + cpsw->tx_irq_disabled = false; + enable_irq(cpsw->irqs_table[1]); + } + } + + return num_tx; +} + +int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget) +{ + struct cpsw_common *cpsw = napi_to_cpsw(napi_rx); + int num_rx, cur_budget, ch; + u32 ch_map; + struct cpsw_vector *rxv; + + /* process every unprocessed channel */ + ch_map = cpdma_ctrl_rxchs_state(cpsw->dma); + for (ch = 0, num_rx = 0; ch_map; ch_map >>= 1, ch++) { + if (!(ch_map & 0x01)) + continue; + + rxv = &cpsw->rxv[ch]; + if (unlikely(rxv->budget > budget - num_rx)) + cur_budget = budget - num_rx; + else + cur_budget = rxv->budget; + + num_rx += cpdma_chan_process(rxv->ch, cur_budget); + if (num_rx >= budget) + break; + } + + if (num_rx < budget) { + napi_complete_done(napi_rx, num_rx); + writel(0xff, &cpsw->wr_regs->rx_en); + } + + return num_rx; +} + +int cpsw_rx_poll(struct napi_struct *napi_rx, int budget) +{ + struct cpsw_common *cpsw = napi_to_cpsw(napi_rx); + int num_rx; + + num_rx = cpdma_chan_process(cpsw->rxv[0].ch, budget); + if (num_rx < budget) { + napi_complete_done(napi_rx, num_rx); + writel(0xff, &cpsw->wr_regs->rx_en); + if (cpsw->rx_irq_disabled) { + cpsw->rx_irq_disabled = false; + enable_irq(cpsw->irqs_table[0]); + } + } + + return num_rx; +} + +void cpsw_rx_vlan_encap(struct sk_buff *skb) +{ + struct cpsw_priv *priv = netdev_priv(skb->dev); + u32 rx_vlan_encap_hdr = *((u32 *)skb->data); + struct cpsw_common *cpsw = priv->cpsw; + u16 vtag, vid, prio, pkt_type; + + /* Remove VLAN header encapsulation word */ + skb_pull(skb, CPSW_RX_VLAN_ENCAP_HDR_SIZE); + + pkt_type = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT) & + CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK; + /* Ignore unknown & Priority-tagged packets*/ + if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV || + pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG) + return; + + vid = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT) & + VLAN_VID_MASK; + /* Ignore vid 0 and pass packet as is */ + if (!vid) + return; + + /* Untag P0 packets if set for vlan */ + if (!cpsw_ale_get_vlan_p0_untag(cpsw->ale, vid)) { + prio = (rx_vlan_encap_hdr >> + CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) & + CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK; + + vtag = (prio << VLAN_PRIO_SHIFT) | vid; + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag); + } + + /* strip vlan tag for VLAN-tagged packet */ + if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG) { + memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); + skb_pull(skb, VLAN_HLEN); + } +} + +void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ + slave_write(slave, mac_hi(priv->mac_addr), SA_HI); + slave_write(slave, mac_lo(priv->mac_addr), SA_LO); +} + +void soft_reset(const char *module, void __iomem *reg) +{ + unsigned long timeout = jiffies + HZ; + + writel_relaxed(1, reg); + do { + cpu_relax(); + } while ((readl_relaxed(reg) & 1) && time_after(timeout, jiffies)); + + WARN(readl_relaxed(reg) & 1, "failed to soft-reset %s\n", module); +} + +void cpsw_ndo_tx_timeout(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ch; + + cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n"); + ndev->stats.tx_errors++; + cpsw_intr_disable(cpsw); + for (ch = 0; ch < cpsw->tx_ch_num; ch++) { + cpdma_chan_stop(cpsw->txv[ch].ch); + cpdma_chan_start(cpsw->txv[ch].ch); + } + + cpsw_intr_enable(cpsw); + netif_trans_update(ndev); + netif_tx_wake_all_queues(ndev); +} + +static int cpsw_get_common_speed(struct cpsw_common *cpsw) +{ + int i, speed; + + for (i = 0, speed = 0; i < cpsw->data.slaves; i++) + if (cpsw->slaves[i].phy && cpsw->slaves[i].phy->link) + speed += cpsw->slaves[i].phy->speed; + + return speed; +} + +int cpsw_need_resplit(struct cpsw_common *cpsw) +{ + int i, rlim_ch_num; + int speed, ch_rate; + + /* re-split resources only in case speed was changed */ + speed = cpsw_get_common_speed(cpsw); + if (speed == cpsw->speed || !speed) + return 0; + + cpsw->speed = speed; + + for (i = 0, rlim_ch_num = 0; i < cpsw->tx_ch_num; i++) { + ch_rate = cpdma_chan_get_rate(cpsw->txv[i].ch); + if (!ch_rate) + break; + + rlim_ch_num++; + } + + /* cases not dependent on speed */ + if (!rlim_ch_num || rlim_ch_num == cpsw->tx_ch_num) + return 0; + + return 1; +} + +void cpsw_split_res(struct cpsw_common *cpsw) +{ + u32 consumed_rate = 0, bigest_rate = 0; + struct cpsw_vector *txv = cpsw->txv; + int i, ch_weight, rlim_ch_num = 0; + int budget, bigest_rate_ch = 0; + u32 ch_rate, max_rate; + int ch_budget = 0; + + for (i = 0; i < cpsw->tx_ch_num; i++) { + ch_rate = cpdma_chan_get_rate(txv[i].ch); + if (!ch_rate) + continue; + + rlim_ch_num++; + consumed_rate += ch_rate; + } + + if (cpsw->tx_ch_num == rlim_ch_num) { + max_rate = consumed_rate; + } else if (!rlim_ch_num) { + ch_budget = CPSW_POLL_WEIGHT / cpsw->tx_ch_num; + bigest_rate = 0; + max_rate = consumed_rate; + } else { + max_rate = cpsw->speed * 1000; + + /* if max_rate is less then expected due to reduced link speed, + * split proportionally according next potential max speed + */ + if (max_rate < consumed_rate) + max_rate *= 10; + + if (max_rate < consumed_rate) + max_rate *= 10; + + ch_budget = (consumed_rate * CPSW_POLL_WEIGHT) / max_rate; + ch_budget = (CPSW_POLL_WEIGHT - ch_budget) / + (cpsw->tx_ch_num - rlim_ch_num); + bigest_rate = (max_rate - consumed_rate) / + (cpsw->tx_ch_num - rlim_ch_num); + } + + /* split tx weight/budget */ + budget = CPSW_POLL_WEIGHT; + for (i = 0; i < cpsw->tx_ch_num; i++) { + ch_rate = cpdma_chan_get_rate(txv[i].ch); + if (ch_rate) { + txv[i].budget = (ch_rate * CPSW_POLL_WEIGHT) / max_rate; + if (!txv[i].budget) + txv[i].budget++; + if (ch_rate > bigest_rate) { + bigest_rate_ch = i; + bigest_rate = ch_rate; + } + + ch_weight = (ch_rate * 100) / max_rate; + if (!ch_weight) + ch_weight++; + cpdma_chan_set_weight(cpsw->txv[i].ch, ch_weight); + } else { + txv[i].budget = ch_budget; + if (!bigest_rate_ch) + bigest_rate_ch = i; + cpdma_chan_set_weight(cpsw->txv[i].ch, 0); + } + + budget -= txv[i].budget; + } + + if (budget) + txv[bigest_rate_ch].budget += budget; + + /* split rx budget */ + budget = CPSW_POLL_WEIGHT; + ch_budget = budget / cpsw->rx_ch_num; + for (i = 0; i < cpsw->rx_ch_num; i++) { + cpsw->rxv[i].budget = ch_budget; + budget -= ch_budget; + } + + if (budget) + cpsw->rxv[0].budget += budget; +} + int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, int ale_ageout, phys_addr_t desc_mem_phys, int descs_pool_size) @@ -132,3 +524,846 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, return ret; } + +#if IS_ENABLED(CONFIG_TI_CPTS) + +static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + u32 ts_en, seq_id; + + if (!priv->tx_ts_enabled && !priv->rx_ts_enabled) { + slave_write(slave, 0, CPSW1_TS_CTL); + return; + } + + seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588; + ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS; + + if (priv->tx_ts_enabled) + ts_en |= CPSW_V1_TS_TX_EN; + + if (priv->rx_ts_enabled) + ts_en |= CPSW_V1_TS_RX_EN; + + slave_write(slave, ts_en, CPSW1_TS_CTL); + slave_write(slave, seq_id, CPSW1_TS_SEQ_LTYPE); +} + +static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + u32 ctrl, mtype; + + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + + ctrl = slave_read(slave, CPSW2_CONTROL); + switch (cpsw->version) { + case CPSW_VERSION_2: + ctrl &= ~CTRL_V2_ALL_TS_MASK; + + if (priv->tx_ts_enabled) + ctrl |= CTRL_V2_TX_TS_BITS; + + if (priv->rx_ts_enabled) + ctrl |= CTRL_V2_RX_TS_BITS; + break; + case CPSW_VERSION_3: + default: + ctrl &= ~CTRL_V3_ALL_TS_MASK; + + if (priv->tx_ts_enabled) + ctrl |= CTRL_V3_TX_TS_BITS; + + if (priv->rx_ts_enabled) + ctrl |= CTRL_V3_RX_TS_BITS; + break; + } + + mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS; + + slave_write(slave, mtype, CPSW2_TS_SEQ_MTYPE); + slave_write(slave, ctrl, CPSW2_CONTROL); + writel_relaxed(ETH_P_1588, &cpsw->regs->ts_ltype); + writel_relaxed(ETH_P_8021Q, &cpsw->regs->vlan_ltype); +} + +static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +{ + struct cpsw_priv *priv = netdev_priv(dev); + struct cpsw_common *cpsw = priv->cpsw; + struct hwtstamp_config cfg; + + if (cpsw->version != CPSW_VERSION_1 && + cpsw->version != CPSW_VERSION_2 && + cpsw->version != CPSW_VERSION_3) + return -EOPNOTSUPP; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + /* reserved for future extensions */ + if (cfg.flags) + return -EINVAL; + + if (cfg.tx_type != HWTSTAMP_TX_OFF && cfg.tx_type != HWTSTAMP_TX_ON) + return -ERANGE; + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: + priv->rx_ts_enabled = 0; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_NTP_ALL: + return -ERANGE; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + priv->rx_ts_enabled = HWTSTAMP_FILTER_PTP_V2_EVENT; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + default: + return -ERANGE; + } + + priv->tx_ts_enabled = cfg.tx_type == HWTSTAMP_TX_ON; + + switch (cpsw->version) { + case CPSW_VERSION_1: + cpsw_hwtstamp_v1(priv); + break; + case CPSW_VERSION_2: + case CPSW_VERSION_3: + cpsw_hwtstamp_v2(priv); + break; + default: + WARN_ON(1); + } + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + +static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(dev); + struct cpsw_priv *priv = netdev_priv(dev); + struct hwtstamp_config cfg; + + if (cpsw->version != CPSW_VERSION_1 && + cpsw->version != CPSW_VERSION_2 && + cpsw->version != CPSW_VERSION_3) + return -EOPNOTSUPP; + + cfg.flags = 0; + cfg.tx_type = priv->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; + cfg.rx_filter = priv->rx_ts_enabled; + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} +#else +static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + +static int cpsw_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} +#endif /*CONFIG_TI_CPTS*/ + +int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + struct cpsw_priv *priv = netdev_priv(dev); + struct cpsw_common *cpsw = priv->cpsw; + int slave_no = cpsw_slave_index(cpsw, priv); + + if (!netif_running(dev)) + return -EINVAL; + + switch (cmd) { + case SIOCSHWTSTAMP: + return cpsw_hwtstamp_set(dev, req); + case SIOCGHWTSTAMP: + return cpsw_hwtstamp_get(dev, req); + } + + if (!cpsw->slaves[slave_no].phy) + return -EOPNOTSUPP; + return phy_mii_ioctl(cpsw->slaves[slave_no].phy, req, cmd); +} + +int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + u32 min_rate; + u32 ch_rate; + int i, ret; + + ch_rate = netdev_get_tx_queue(ndev, queue)->tx_maxrate; + if (ch_rate == rate) + return 0; + + ch_rate = rate * 1000; + min_rate = cpdma_chan_get_min_rate(cpsw->dma); + if ((ch_rate < min_rate && ch_rate)) { + dev_err(priv->dev, "The channel rate cannot be less than %dMbps", + min_rate); + return -EINVAL; + } + + if (rate > cpsw->speed) { + dev_err(priv->dev, "The channel rate cannot be more than 2Gbps"); + return -EINVAL; + } + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + ret = cpdma_chan_set_rate(cpsw->txv[queue].ch, ch_rate); + pm_runtime_put(cpsw->dev); + + if (ret) + return ret; + + /* update rates for slaves tx queues */ + for (i = 0; i < cpsw->data.slaves; i++) { + slave = &cpsw->slaves[i]; + if (!slave->ndev) + continue; + + netdev_get_tx_queue(slave->ndev, queue)->tx_maxrate = rate; + } + + cpsw_split_res(cpsw); + return ret; +} + +static int cpsw_tc_to_fifo(int tc, int num_tc) +{ + if (tc == num_tc - 1) + return 0; + + return CPSW_FIFO_SHAPERS_NUM - tc; +} + +bool cpsw_shp_is_off(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + u32 shift, mask, val; + + val = readl_relaxed(&cpsw->regs->ptype); + + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; + mask = 7 << shift; + val = val & mask; + + return !val; +} + +static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + u32 shift, mask, val; + + val = readl_relaxed(&cpsw->regs->ptype); + + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; + mask = (1 << --fifo) << shift; + val = on ? val | mask : val & ~mask; + + writel_relaxed(val, &cpsw->regs->ptype); +} + +static int cpsw_set_fifo_bw(struct cpsw_priv *priv, int fifo, int bw) +{ + struct cpsw_common *cpsw = priv->cpsw; + u32 val = 0, send_pct, shift; + struct cpsw_slave *slave; + int pct = 0, i; + + if (bw > priv->shp_cfg_speed * 1000) + goto err; + + /* shaping has to stay enabled for highest fifos linearly + * and fifo bw no more then interface can allow + */ + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + send_pct = slave_read(slave, SEND_PERCENT); + for (i = CPSW_FIFO_SHAPERS_NUM; i > 0; i--) { + if (!bw) { + if (i >= fifo || !priv->fifo_bw[i]) + continue; + + dev_warn(priv->dev, "Prev FIFO%d is shaped", i); + continue; + } + + if (!priv->fifo_bw[i] && i > fifo) { + dev_err(priv->dev, "Upper FIFO%d is not shaped", i); + return -EINVAL; + } + + shift = (i - 1) * 8; + if (i == fifo) { + send_pct &= ~(CPSW_PCT_MASK << shift); + val = DIV_ROUND_UP(bw, priv->shp_cfg_speed * 10); + if (!val) + val = 1; + + send_pct |= val << shift; + pct += val; + continue; + } + + if (priv->fifo_bw[i]) + pct += (send_pct >> shift) & CPSW_PCT_MASK; + } + + if (pct >= 100) + goto err; + + slave_write(slave, send_pct, SEND_PERCENT); + priv->fifo_bw[fifo] = bw; + + dev_warn(priv->dev, "set FIFO%d bw = %d\n", fifo, + DIV_ROUND_CLOSEST(val * priv->shp_cfg_speed, 100)); + + return 0; +err: + dev_err(priv->dev, "Bandwidth doesn't fit in tc configuration"); + return -EINVAL; +} + +static int cpsw_set_fifo_rlimit(struct cpsw_priv *priv, int fifo, int bw) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + u32 tx_in_ctl_rg, val; + int ret; + + ret = cpsw_set_fifo_bw(priv, fifo, bw); + if (ret) + return ret; + + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + tx_in_ctl_rg = cpsw->version == CPSW_VERSION_1 ? + CPSW1_TX_IN_CTL : CPSW2_TX_IN_CTL; + + if (!bw) + cpsw_fifo_shp_on(priv, fifo, bw); + + val = slave_read(slave, tx_in_ctl_rg); + if (cpsw_shp_is_off(priv)) { + /* disable FIFOs rate limited queues */ + val &= ~(0xf << CPSW_FIFO_RATE_EN_SHIFT); + + /* set type of FIFO queues to normal priority mode */ + val &= ~(3 << CPSW_FIFO_QUEUE_TYPE_SHIFT); + + /* set type of FIFO queues to be rate limited */ + if (bw) + val |= 2 << CPSW_FIFO_QUEUE_TYPE_SHIFT; + else + priv->shp_cfg_speed = 0; + } + + /* toggle a FIFO rate limited queue */ + if (bw) + val |= BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); + else + val &= ~BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); + slave_write(slave, val, tx_in_ctl_rg); + + /* FIFO transmit shape enable */ + cpsw_fifo_shp_on(priv, fifo, bw); + return 0; +} + +/* Defaults: + * class A - prio 3 + * class B - prio 2 + * shaping for class A should be set first + */ +static int cpsw_set_cbs(struct net_device *ndev, + struct tc_cbs_qopt_offload *qopt) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + int prev_speed = 0; + int tc, ret, fifo; + u32 bw = 0; + + tc = netdev_txq_to_tc(priv->ndev, qopt->queue); + + /* enable channels in backward order, as highest FIFOs must be rate + * limited first and for compliance with CPDMA rate limited channels + * that also used in bacward order. FIFO0 cannot be rate limited. + */ + fifo = cpsw_tc_to_fifo(tc, ndev->num_tc); + if (!fifo) { + dev_err(priv->dev, "Last tc%d can't be rate limited", tc); + return -EINVAL; + } + + /* do nothing, it's disabled anyway */ + if (!qopt->enable && !priv->fifo_bw[fifo]) + return 0; + + /* shapers can be set if link speed is known */ + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + if (slave->phy && slave->phy->link) { + if (priv->shp_cfg_speed && + priv->shp_cfg_speed != slave->phy->speed) + prev_speed = priv->shp_cfg_speed; + + priv->shp_cfg_speed = slave->phy->speed; + } + + if (!priv->shp_cfg_speed) { + dev_err(priv->dev, "Link speed is not known"); + return -1; + } + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + bw = qopt->enable ? qopt->idleslope : 0; + ret = cpsw_set_fifo_rlimit(priv, fifo, bw); + if (ret) { + priv->shp_cfg_speed = prev_speed; + prev_speed = 0; + } + + if (bw && prev_speed) + dev_warn(priv->dev, + "Speed was changed, CBS shaper speeds are changed!"); + + pm_runtime_put_sync(cpsw->dev); + return ret; +} + +static int cpsw_set_mqprio(struct net_device *ndev, void *type_data) +{ + struct tc_mqprio_qopt_offload *mqprio = type_data; + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int fifo, num_tc, count, offset; + struct cpsw_slave *slave; + u32 tx_prio_map = 0; + int i, tc, ret; + + num_tc = mqprio->qopt.num_tc; + if (num_tc > CPSW_TC_NUM) + return -EINVAL; + + if (mqprio->mode != TC_MQPRIO_MODE_DCB) + return -EINVAL; + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + if (num_tc) { + for (i = 0; i < 8; i++) { + tc = mqprio->qopt.prio_tc_map[i]; + fifo = cpsw_tc_to_fifo(tc, num_tc); + tx_prio_map |= fifo << (4 * i); + } + + netdev_set_num_tc(ndev, num_tc); + for (i = 0; i < num_tc; i++) { + count = mqprio->qopt.count[i]; + offset = mqprio->qopt.offset[i]; + netdev_set_tc_queue(ndev, i, count, offset); + } + } + + if (!mqprio->qopt.hw) { + /* restore default configuration */ + netdev_reset_tc(ndev); + tx_prio_map = TX_PRIORITY_MAPPING; + } + + priv->mqprio_hw = mqprio->qopt.hw; + + offset = cpsw->version == CPSW_VERSION_1 ? + CPSW1_TX_PRI_MAP : CPSW2_TX_PRI_MAP; + + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; + slave_write(slave, tx_prio_map, offset); + + pm_runtime_put_sync(cpsw->dev); + + return 0; +} + +int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data) +{ + switch (type) { + case TC_SETUP_QDISC_CBS: + return cpsw_set_cbs(ndev, type_data); + + case TC_SETUP_QDISC_MQPRIO: + return cpsw_set_mqprio(ndev, type_data); + + default: + return -EOPNOTSUPP; + } +} + +void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ + int fifo, bw; + + for (fifo = CPSW_FIFO_SHAPERS_NUM; fifo > 0; fifo--) { + bw = priv->fifo_bw[fifo]; + if (!bw) + continue; + + cpsw_set_fifo_rlimit(priv, fifo, bw); + } +} + +void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + u32 tx_prio_map = 0; + int i, tc, fifo; + u32 tx_prio_rg; + + if (!priv->mqprio_hw) + return; + + for (i = 0; i < 8; i++) { + tc = netdev_get_prio_tc_map(priv->ndev, i); + fifo = CPSW_FIFO_SHAPERS_NUM - tc; + tx_prio_map |= fifo << (4 * i); + } + + tx_prio_rg = cpsw->version == CPSW_VERSION_1 ? + CPSW1_TX_PRI_MAP : CPSW2_TX_PRI_MAP; + + slave_write(slave, tx_prio_map, tx_prio_rg); +} + +int cpsw_fill_rx_channels(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_meta_xdp *xmeta; + struct page_pool *pool; + struct page *page; + int ch_buf_num; + int ch, i, ret; + dma_addr_t dma; + + for (ch = 0; ch < cpsw->rx_ch_num; ch++) { + pool = cpsw->page_pool[ch]; + ch_buf_num = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch); + for (i = 0; i < ch_buf_num; i++) { + page = page_pool_dev_alloc_pages(pool); + if (!page) { + cpsw_err(priv, ifup, "allocate rx page err\n"); + return -ENOMEM; + } + + xmeta = page_address(page) + CPSW_XMETA_OFFSET; + xmeta->ndev = priv->ndev; + xmeta->ch = ch; + + dma = page_pool_get_dma_addr(page) + CPSW_HEADROOM; + ret = cpdma_chan_idle_submit_mapped(cpsw->rxv[ch].ch, + page, dma, + cpsw->rx_packet_max, + 0); + if (ret < 0) { + cpsw_err(priv, ifup, + "cannot submit page to channel %d rx, error %d\n", + ch, ret); + page_pool_recycle_direct(pool, page); + return ret; + } + } + + cpsw_info(priv, ifup, "ch %d rx, submitted %d descriptors\n", + ch, ch_buf_num); + } + + return 0; +} + +static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw, + int size) +{ + struct page_pool_params pp_params; + struct page_pool *pool; + + pp_params.order = 0; + pp_params.flags = PP_FLAG_DMA_MAP; + pp_params.pool_size = size; + pp_params.nid = NUMA_NO_NODE; + pp_params.dma_dir = DMA_BIDIRECTIONAL; + pp_params.dev = cpsw->dev; + + pool = page_pool_create(&pp_params); + if (IS_ERR(pool)) + dev_err(cpsw->dev, "cannot create rx page pool\n"); + + return pool; +} + +static int cpsw_create_rx_pool(struct cpsw_common *cpsw, int ch) +{ + struct page_pool *pool; + int ret = 0, pool_size; + + pool_size = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch); + pool = cpsw_create_page_pool(cpsw, pool_size); + if (IS_ERR(pool)) + ret = PTR_ERR(pool); + else + cpsw->page_pool[ch] = pool; + + return ret; +} + +static int cpsw_ndev_create_xdp_rxq(struct cpsw_priv *priv, int ch) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct xdp_rxq_info *rxq; + struct page_pool *pool; + int ret; + + pool = cpsw->page_pool[ch]; + rxq = &priv->xdp_rxq[ch]; + + ret = xdp_rxq_info_reg(rxq, priv->ndev, ch); + if (ret) + return ret; + + ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool); + if (ret) + xdp_rxq_info_unreg(rxq); + + return ret; +} + +static void cpsw_ndev_destroy_xdp_rxq(struct cpsw_priv *priv, int ch) +{ + struct xdp_rxq_info *rxq = &priv->xdp_rxq[ch]; + + if (!xdp_rxq_info_is_reg(rxq)) + return; + + xdp_rxq_info_unreg(rxq); +} + +void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw) +{ + struct net_device *ndev; + int i, ch; + + for (ch = 0; ch < cpsw->rx_ch_num; ch++) { + for (i = 0; i < cpsw->data.slaves; i++) { + ndev = cpsw->slaves[i].ndev; + if (!ndev) + continue; + + cpsw_ndev_destroy_xdp_rxq(netdev_priv(ndev), ch); + } + + page_pool_destroy(cpsw->page_pool[ch]); + cpsw->page_pool[ch] = NULL; + } +} + +int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw) +{ + struct net_device *ndev; + int i, ch, ret; + + for (ch = 0; ch < cpsw->rx_ch_num; ch++) { + ret = cpsw_create_rx_pool(cpsw, ch); + if (ret) + goto err_cleanup; + + /* using same page pool is allowed as no running rx handlers + * simultaneously for both ndevs + */ + for (i = 0; i < cpsw->data.slaves; i++) { + ndev = cpsw->slaves[i].ndev; + if (!ndev) + continue; + + ret = cpsw_ndev_create_xdp_rxq(netdev_priv(ndev), ch); + if (ret) + goto err_cleanup; + } + } + + return 0; + +err_cleanup: + cpsw_destroy_xdp_rxqs(cpsw); + + return ret; +} + +static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf) +{ + struct bpf_prog *prog = bpf->prog; + + if (!priv->xdpi.prog && !prog) + return 0; + + if (!xdp_attachment_flags_ok(&priv->xdpi, bpf)) + return -EBUSY; + + WRITE_ONCE(priv->xdp_prog, prog); + + xdp_attachment_setup(&priv->xdpi, bpf); + + return 0; +} + +int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + + switch (bpf->command) { + case XDP_SETUP_PROG: + return cpsw_xdp_prog_setup(priv, bpf); + + case XDP_QUERY_PROG: + return xdp_attachment_query(&priv->xdpi, bpf); + + default: + return -EINVAL; + } +} + +int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + struct page *page, int port) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_meta_xdp *xmeta; + struct cpdma_chan *txch; + dma_addr_t dma; + int ret; + + xmeta = (void *)xdpf + CPSW_XMETA_OFFSET; + xmeta->ndev = priv->ndev; + xmeta->ch = 0; + txch = cpsw->txv[0].ch; + + if (page) { + dma = page_pool_get_dma_addr(page); + dma += xdpf->headroom + sizeof(struct xdp_frame); + ret = cpdma_chan_submit_mapped(txch, cpsw_xdpf_to_handle(xdpf), + dma, xdpf->len, port); + } else { + if (sizeof(*xmeta) > xdpf->headroom) { + xdp_return_frame_rx_napi(xdpf); + return -EINVAL; + } + + ret = cpdma_chan_submit(txch, cpsw_xdpf_to_handle(xdpf), + xdpf->data, xdpf->len, port); + } + + if (ret) { + priv->ndev->stats.tx_dropped++; + xdp_return_frame_rx_napi(xdpf); + } + + return ret; +} + +int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + struct page *page, int port) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct net_device *ndev = priv->ndev; + int ret = CPSW_XDP_CONSUMED; + struct xdp_frame *xdpf; + struct bpf_prog *prog; + u32 act; + + rcu_read_lock(); + + prog = READ_ONCE(priv->xdp_prog); + if (!prog) { + ret = CPSW_XDP_PASS; + goto out; + } + + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_PASS: + ret = CPSW_XDP_PASS; + break; + case XDP_TX: + xdpf = convert_to_xdp_frame(xdp); + if (unlikely(!xdpf)) + goto drop; + + cpsw_xdp_tx_frame(priv, xdpf, page, port); + break; + case XDP_REDIRECT: + if (xdp_do_redirect(ndev, xdp, prog)) + goto drop; + + /* Have to flush here, per packet, instead of doing it in bulk + * at the end of the napi handler. The RX devices on this + * particular hardware is sharing a common queue, so the + * incoming device might change per packet. + */ + xdp_do_flush_map(); + break; + default: + bpf_warn_invalid_xdp_action(act); + /* fall through */ + case XDP_ABORTED: + trace_xdp_exception(ndev, prog, act); + /* fall through -- handle aborts by dropping packet */ + case XDP_DROP: + goto drop; + } +out: + rcu_read_unlock(); + return ret; +drop: + rcu_read_unlock(); + page_pool_recycle_direct(cpsw->page_pool[ch], page); + return ret; +} diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 65f0e410344d..0dd70e191cf1 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -383,6 +383,35 @@ struct addr_sync_ctx { int flush; /* flush flag */ }; +#define CPSW_XMETA_OFFSET ALIGN(sizeof(struct xdp_frame), sizeof(long)) + +#define CPSW_XDP_CONSUMED 1 +#define CPSW_XDP_PASS 0 + +struct __aligned(sizeof(long)) cpsw_meta_xdp { + struct net_device *ndev; + int ch; +}; + +/* The buf includes headroom compatible with both skb and xdpf */ +#define CPSW_HEADROOM_NA (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + NET_IP_ALIGN) +#define CPSW_HEADROOM ALIGN(CPSW_HEADROOM_NA, sizeof(long)) + +static inline int cpsw_is_xdpf_handle(void *handle) +{ + return (unsigned long)handle & BIT(0); +} + +static inline void *cpsw_xdpf_to_handle(struct xdp_frame *xdpf) +{ + return (void *)((unsigned long)xdpf | BIT(0)); +} + +static inline struct xdp_frame *cpsw_handle_to_xdpf(void *handle) +{ + return (struct xdp_frame *)((unsigned long)handle & ~BIT(0)); +} + int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, int ale_ageout, phys_addr_t desc_mem_phys, int descs_pool_size); @@ -393,6 +422,29 @@ void cpsw_intr_disable(struct cpsw_common *cpsw); void cpsw_tx_handler(void *token, int len, int status); int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw); void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw); +int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf); +int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf, + struct page *page, int port); +int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp, + struct page *page, int port); +irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id); +irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id); +int cpsw_tx_mq_poll(struct napi_struct *napi_tx, int budget); +int cpsw_tx_poll(struct napi_struct *napi_tx, int budget); +int cpsw_rx_mq_poll(struct napi_struct *napi_rx, int budget); +int cpsw_rx_poll(struct napi_struct *napi_rx, int budget); +void cpsw_rx_vlan_encap(struct sk_buff *skb); +void soft_reset(const char *module, void __iomem *reg); +void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv); +void cpsw_ndo_tx_timeout(struct net_device *ndev); +int cpsw_need_resplit(struct cpsw_common *cpsw); +int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd); +int cpsw_ndo_set_tx_maxrate(struct net_device *ndev, int queue, u32 rate); +int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type, + void *type_data); +bool cpsw_shp_is_off(struct cpsw_priv *priv); +void cpsw_cbs_resume(struct cpsw_slave *slave, struct cpsw_priv *priv); +void cpsw_mqprio_resume(struct cpsw_slave *slave, struct cpsw_priv *priv); /* ethtool */ u32 cpsw_get_msglevel(struct net_device *ndev); -- cgit v1.2.3-59-g8ed1b From ed3525eda4c4983fb8509e488de0a351788041ba Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 20 Nov 2019 00:19:19 +0200 Subject: net: ethernet: ti: introduce cpsw switchdev based driver part 1 - dual-emac Part 1: Introduce basic CPSW dual_mac driver (cpsw_new.c) which is operating in dual-emac mode by default, thus working as 2 individual network interfaces. Main differences from legacy CPSW driver are: - optimized promiscuous mode: The P0_UNI_FLOOD (both ports) is enabled in addition to ALLMULTI (current port) instead of ALE_BYPASS. So, Ports in promiscuous mode will keep possibility of mcast and vlan filtering, which is provides significant benefits when ports are joined to the same bridge, but without enabling "switch" mode, or to different bridges. - learning disabled on ports as it make not too much sense for segregated ports - no forwarding in HW. - enabled basic support for devlink. devlink dev show platform/48484000.switch devlink dev param show platform/48484000.switch: name ale_bypass type driver-specific values: cmode runtime value false - "ale_bypass" devlink driver parameter allows to enable ALE_CONTROL(4).BYPASS mode for debug purposes. - updated DT bindings. Signed-off-by: Ilias Apalodimas Signed-off-by: Murali Karicheri Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Kconfig | 19 +- drivers/net/ethernet/ti/Makefile | 2 + drivers/net/ethernet/ti/cpsw_new.c | 1673 +++++++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_priv.c | 9 +- drivers/net/ethernet/ti/cpsw_priv.h | 12 +- 5 files changed, 1710 insertions(+), 5 deletions(-) create mode 100644 drivers/net/ethernet/ti/cpsw_new.c (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 137632b09c72..9170572346b5 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -59,9 +59,24 @@ config TI_CPSW To compile this driver as a module, choose M here: the module will be called cpsw. +config TI_CPSW_SWITCHDEV + tristate "TI CPSW Switch Support with switchdev" + depends on ARCH_DAVINCI || ARCH_OMAP2PLUS || COMPILE_TEST + select NET_SWITCHDEV + select TI_DAVINCI_MDIO + select MFD_SYSCON + select REGMAP + select NET_DEVLINK + imply PHY_TI_GMII_SEL + help + This driver supports TI's CPSW Ethernet Switch. + + To compile this driver as a module, choose M here: the module + will be called cpsw_new. + config TI_CPTS bool "TI Common Platform Time Sync (CPTS) Support" - depends on TI_CPSW || TI_KEYSTONE_NETCP || COMPILE_TEST + depends on TI_CPSW || TI_KEYSTONE_NETCP || TI_CPSW_SWITCHDEV || COMPILE_TEST depends on COMMON_CLK depends on POSIX_TIMERS ---help--- @@ -73,7 +88,7 @@ config TI_CPTS config TI_CPTS_MOD tristate depends on TI_CPTS - default y if TI_CPSW=y || TI_KEYSTONE_NETCP=y + default y if TI_CPSW=y || TI_KEYSTONE_NETCP=y || TI_CPSW_SWITCHDEV=y select NET_PTP_CLASSIFY imply PTP_1588_CLOCK default m diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index ed12e1e5df2f..c59670956ed3 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -15,6 +15,8 @@ obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o obj-$(CONFIG_TI_CPTS_MOD) += cpts.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o +obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o +ti_cpsw_new-y := cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o keystone_netcp-y := netcp_core.o cpsw_ale.o diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c new file mode 100644 index 000000000000..25e59d328342 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -0,0 +1,1673 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments Ethernet Switch Driver + * + * Copyright (C) 2019 Texas Instruments + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "cpsw.h" +#include "cpsw_ale.h" +#include "cpsw_priv.h" +#include "cpsw_sl.h" +#include "cpts.h" +#include "davinci_cpdma.h" + +#include + +static int debug_level; +static int ale_ageout = CPSW_ALE_AGEOUT_DEFAULT; +static int rx_packet_max = CPSW_MAX_PACKET_SIZE; +static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT; + +struct cpsw_devlink { + struct cpsw_common *cpsw; +}; + +enum cpsw_devlink_param_id { + CPSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + CPSW_DL_PARAM_ALE_BYPASS, +}; + +/* struct cpsw_common is not needed, kept here for compatibility + * reasons witrh the old driver + */ +static int cpsw_slave_index_priv(struct cpsw_common *cpsw, + struct cpsw_priv *priv) +{ + if (priv->emac_port == HOST_PORT_NUM) + return -1; + + return priv->emac_port - 1; +} + +static void cpsw_set_promiscious(struct net_device *ndev, bool enable) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + bool enable_uni = false; + int i; + + /* Enabling promiscuous mode for one interface will be + * common for both the interface as the interface shares + * the same hardware resource. + */ + for (i = 0; i < cpsw->data.slaves; i++) + if (cpsw->slaves[i].ndev && + (cpsw->slaves[i].ndev->flags & IFF_PROMISC)) + enable_uni = true; + + if (!enable && enable_uni) { + enable = enable_uni; + dev_dbg(cpsw->dev, "promiscuity not disabled as the other interface is still in promiscuity mode\n"); + } + + if (enable) { + /* Enable unknown unicast, reg/unreg mcast */ + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, + ALE_P0_UNI_FLOOD, 1); + + dev_dbg(cpsw->dev, "promiscuity enabled\n"); + } else { + /* Disable unknown unicast */ + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, + ALE_P0_UNI_FLOOD, 0); + dev_dbg(cpsw->dev, "promiscuity disabled\n"); + } +} + +/** + * cpsw_set_mc - adds multicast entry to the table if it's not added or deletes + * if it's not deleted + * @ndev: device to sync + * @addr: address to be added or deleted + * @vid: vlan id, if vid < 0 set/unset address for real device + * @add: add address if the flag is set or remove otherwise + */ +static int cpsw_set_mc(struct net_device *ndev, const u8 *addr, + int vid, int add) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int mask, flags, ret, slave_no; + + slave_no = cpsw_slave_index(cpsw, priv); + if (vid < 0) + vid = cpsw->slaves[slave_no].port_vlan; + + mask = ALE_PORT_HOST; + flags = vid ? ALE_VLAN : 0; + + if (add) + ret = cpsw_ale_add_mcast(cpsw->ale, addr, mask, flags, vid, 0); + else + ret = cpsw_ale_del_mcast(cpsw->ale, addr, 0, flags, vid); + + return ret; +} + +static int cpsw_update_vlan_mc(struct net_device *vdev, int vid, void *ctx) +{ + struct addr_sync_ctx *sync_ctx = ctx; + struct netdev_hw_addr *ha; + int found = 0, ret = 0; + + if (!vdev || !(vdev->flags & IFF_UP)) + return 0; + + /* vlan address is relevant if its sync_cnt != 0 */ + netdev_for_each_mc_addr(ha, vdev) { + if (ether_addr_equal(ha->addr, sync_ctx->addr)) { + found = ha->sync_cnt; + break; + } + } + + if (found) + sync_ctx->consumed++; + + if (sync_ctx->flush) { + if (!found) + cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 0); + return 0; + } + + if (found) + ret = cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 1); + + return ret; +} + +static int cpsw_add_mc_addr(struct net_device *ndev, const u8 *addr, int num) +{ + struct addr_sync_ctx sync_ctx; + int ret; + + sync_ctx.consumed = 0; + sync_ctx.addr = addr; + sync_ctx.ndev = ndev; + sync_ctx.flush = 0; + + ret = vlan_for_each(ndev, cpsw_update_vlan_mc, &sync_ctx); + if (sync_ctx.consumed < num && !ret) + ret = cpsw_set_mc(ndev, addr, -1, 1); + + return ret; +} + +static int cpsw_del_mc_addr(struct net_device *ndev, const u8 *addr, int num) +{ + struct addr_sync_ctx sync_ctx; + + sync_ctx.consumed = 0; + sync_ctx.addr = addr; + sync_ctx.ndev = ndev; + sync_ctx.flush = 1; + + vlan_for_each(ndev, cpsw_update_vlan_mc, &sync_ctx); + if (sync_ctx.consumed == num) + cpsw_set_mc(ndev, addr, -1, 0); + + return 0; +} + +static int cpsw_purge_vlan_mc(struct net_device *vdev, int vid, void *ctx) +{ + struct addr_sync_ctx *sync_ctx = ctx; + struct netdev_hw_addr *ha; + int found = 0; + + if (!vdev || !(vdev->flags & IFF_UP)) + return 0; + + /* vlan address is relevant if its sync_cnt != 0 */ + netdev_for_each_mc_addr(ha, vdev) { + if (ether_addr_equal(ha->addr, sync_ctx->addr)) { + found = ha->sync_cnt; + break; + } + } + + if (!found) + return 0; + + sync_ctx->consumed++; + cpsw_set_mc(sync_ctx->ndev, sync_ctx->addr, vid, 0); + return 0; +} + +static int cpsw_purge_all_mc(struct net_device *ndev, const u8 *addr, int num) +{ + struct addr_sync_ctx sync_ctx; + + sync_ctx.addr = addr; + sync_ctx.ndev = ndev; + sync_ctx.consumed = 0; + + vlan_for_each(ndev, cpsw_purge_vlan_mc, &sync_ctx); + if (sync_ctx.consumed < num) + cpsw_set_mc(ndev, addr, -1, 0); + + return 0; +} + +static void cpsw_ndo_set_rx_mode(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + if (ndev->flags & IFF_PROMISC) { + /* Enable promiscuous mode */ + cpsw_set_promiscious(ndev, true); + cpsw_ale_set_allmulti(cpsw->ale, IFF_ALLMULTI, priv->emac_port); + return; + } + + /* Disable promiscuous mode */ + cpsw_set_promiscious(ndev, false); + + /* Restore allmulti on vlans if necessary */ + cpsw_ale_set_allmulti(cpsw->ale, + ndev->flags & IFF_ALLMULTI, priv->emac_port); + + /* add/remove mcast address either for real netdev or for vlan */ + __hw_addr_ref_sync_dev(&ndev->mc, ndev, cpsw_add_mc_addr, + cpsw_del_mc_addr); +} + +static unsigned int cpsw_rxbuf_total_len(unsigned int len) +{ + len += CPSW_HEADROOM; + len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); + + return SKB_DATA_ALIGN(len); +} + +static void cpsw_rx_handler(void *token, int len, int status) +{ + struct page *new_page, *page = token; + void *pa = page_address(page); + int headroom = CPSW_HEADROOM; + struct cpsw_meta_xdp *xmeta; + struct cpsw_common *cpsw; + struct net_device *ndev; + int port, ch, pkt_size; + struct cpsw_priv *priv; + struct page_pool *pool; + struct sk_buff *skb; + struct xdp_buff xdp; + int ret = 0; + dma_addr_t dma; + + xmeta = pa + CPSW_XMETA_OFFSET; + cpsw = ndev_to_cpsw(xmeta->ndev); + ndev = xmeta->ndev; + pkt_size = cpsw->rx_packet_max; + ch = xmeta->ch; + + if (status >= 0) { + port = CPDMA_RX_SOURCE_PORT(status); + if (port) + ndev = cpsw->slaves[--port].ndev; + } + + priv = netdev_priv(ndev); + pool = cpsw->page_pool[ch]; + + if (unlikely(status < 0) || unlikely(!netif_running(ndev))) { + /* In dual emac mode check for all interfaces */ + if (cpsw->usage_count && status >= 0) { + /* The packet received is for the interface which + * is already down and the other interface is up + * and running, instead of freeing which results + * in reducing of the number of rx descriptor in + * DMA engine, requeue page back to cpdma. + */ + new_page = page; + goto requeue; + } + + /* the interface is going down, pages are purged */ + page_pool_recycle_direct(pool, page); + return; + } + + new_page = page_pool_dev_alloc_pages(pool); + if (unlikely(!new_page)) { + new_page = page; + ndev->stats.rx_dropped++; + goto requeue; + } + + if (priv->xdp_prog) { + if (status & CPDMA_RX_VLAN_ENCAP) { + xdp.data = pa + CPSW_HEADROOM + + CPSW_RX_VLAN_ENCAP_HDR_SIZE; + xdp.data_end = xdp.data + len - + CPSW_RX_VLAN_ENCAP_HDR_SIZE; + } else { + xdp.data = pa + CPSW_HEADROOM; + xdp.data_end = xdp.data + len; + } + + xdp_set_data_meta_invalid(&xdp); + + xdp.data_hard_start = pa; + xdp.rxq = &priv->xdp_rxq[ch]; + + ret = cpsw_run_xdp(priv, ch, &xdp, page, priv->emac_port); + if (ret != CPSW_XDP_PASS) + goto requeue; + + /* XDP prog might have changed packet data and boundaries */ + len = xdp.data_end - xdp.data; + headroom = xdp.data - xdp.data_hard_start; + + /* XDP prog can modify vlan tag, so can't use encap header */ + status &= ~CPDMA_RX_VLAN_ENCAP; + } + + /* pass skb to netstack if no XDP prog or returned XDP_PASS */ + skb = build_skb(pa, cpsw_rxbuf_total_len(pkt_size)); + if (!skb) { + ndev->stats.rx_dropped++; + page_pool_recycle_direct(pool, page); + goto requeue; + } + + skb_reserve(skb, headroom); + skb_put(skb, len); + skb->dev = ndev; + if (status & CPDMA_RX_VLAN_ENCAP) + cpsw_rx_vlan_encap(skb); + if (priv->rx_ts_enabled) + cpts_rx_timestamp(cpsw->cpts, skb); + skb->protocol = eth_type_trans(skb, ndev); + + /* unmap page as no netstack skb page recycling */ + page_pool_release_page(pool, page); + netif_receive_skb(skb); + + ndev->stats.rx_bytes += len; + ndev->stats.rx_packets++; + +requeue: + xmeta = page_address(new_page) + CPSW_XMETA_OFFSET; + xmeta->ndev = ndev; + xmeta->ch = ch; + + dma = page_pool_get_dma_addr(new_page) + CPSW_HEADROOM; + ret = cpdma_chan_submit_mapped(cpsw->rxv[ch].ch, new_page, dma, + pkt_size, 0); + if (ret < 0) { + WARN_ON(ret == -ENOMEM); + page_pool_recycle_direct(pool, new_page); + } +} + +static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, + unsigned short vid) +{ + struct cpsw_common *cpsw = priv->cpsw; + int unreg_mcast_mask = 0; + int mcast_mask; + u32 port_mask; + int ret; + + port_mask = (1 << priv->emac_port) | ALE_PORT_HOST; + + mcast_mask = ALE_PORT_HOST; + if (priv->ndev->flags & IFF_ALLMULTI) + unreg_mcast_mask = mcast_mask; + + ret = cpsw_ale_add_vlan(cpsw->ale, vid, port_mask, 0, port_mask, + unreg_mcast_mask); + if (ret != 0) + return ret; + + ret = cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); + if (ret != 0) + goto clean_vid; + + ret = cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, + mcast_mask, ALE_VLAN, vid, 0); + if (ret != 0) + goto clean_vlan_ucast; + return 0; + +clean_vlan_ucast: + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); +clean_vid: + cpsw_ale_del_vlan(cpsw->ale, vid, 0); + return ret; +} + +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, + __be16 proto, u16 vid) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ret, i; + + if (vid == cpsw->data.default_vlan) + return 0; + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + /* In dual EMAC, reserved VLAN id should not be used for + * creating VLAN interfaces as this can break the dual + * EMAC port separation + */ + for (i = 0; i < cpsw->data.slaves; i++) { + if (cpsw->slaves[i].ndev && + vid == cpsw->slaves[i].port_vlan) { + ret = -EINVAL; + goto err; + } + } + + dev_dbg(priv->dev, "Adding vlanid %d to vlan filter\n", vid); + ret = cpsw_add_vlan_ale_entry(priv, vid); +err: + pm_runtime_put(cpsw->dev); + return ret; +} + +static int cpsw_restore_vlans(struct net_device *vdev, int vid, void *arg) +{ + struct cpsw_priv *priv = arg; + + if (!vdev || !vid) + return 0; + + cpsw_ndo_vlan_rx_add_vid(priv->ndev, 0, vid); + return 0; +} + +/* restore resources after port reset */ +static void cpsw_restore(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + + /* restore vlan configurations */ + vlan_for_each(priv->ndev, cpsw_restore_vlans, priv); + + /* restore MQPRIO offload */ + cpsw_mqprio_resume(&cpsw->slaves[priv->emac_port - 1], priv); + + /* restore CBS offload */ + cpsw_cbs_resume(&cpsw->slaves[priv->emac_port - 1], priv); +} + +static void cpsw_init_host_port_dual_mac(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + int vlan = cpsw->data.default_vlan; + + writel(CPSW_FIFO_DUAL_MAC_MODE, &cpsw->host_port_regs->tx_in_ctl); + + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 0); + dev_dbg(cpsw->dev, "unset P0_UNI_FLOOD\n"); + + writel(vlan, &cpsw->host_port_regs->port_vlan); + + cpsw_ale_add_vlan(cpsw->ale, vlan, ALE_ALL_PORTS, ALE_ALL_PORTS, 0, 0); + /* learning make no sense in dual_mac mode */ + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 1); +} + +static void cpsw_init_host_port(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + u32 control_reg; + + /* soft reset the controller and initialize ale */ + soft_reset("cpsw", &cpsw->regs->soft_reset); + cpsw_ale_start(cpsw->ale); + + /* switch to vlan unaware mode */ + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_VLAN_AWARE, + CPSW_ALE_VLAN_AWARE); + control_reg = readl(&cpsw->regs->control); + control_reg |= CPSW_VLAN_AWARE | CPSW_RX_VLAN_ENCAP; + writel(control_reg, &cpsw->regs->control); + + /* setup host port priority mapping */ + writel_relaxed(CPDMA_TX_PRIORITY_MAP, + &cpsw->host_port_regs->cpdma_tx_pri_map); + writel_relaxed(0, &cpsw->host_port_regs->cpdma_rx_chan_map); + + /* disable priority elevation */ + writel_relaxed(0, &cpsw->regs->ptype); + + /* enable statistics collection only on all ports */ + writel_relaxed(0x7, &cpsw->regs->stat_port_en); + + /* Enable internal fifo flow control */ + writel(0x7, &cpsw->regs->flow_control); + + cpsw_init_host_port_dual_mac(priv); + + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); +} + +static void cpsw_port_add_dual_emac_def_ale_entries(struct cpsw_priv *priv, + struct cpsw_slave *slave) +{ + u32 port_mask = 1 << priv->emac_port | ALE_PORT_HOST; + struct cpsw_common *cpsw = priv->cpsw; + u32 reg; + + reg = (cpsw->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : + CPSW2_PORT_VLAN; + slave_write(slave, slave->port_vlan, reg); + + cpsw_ale_add_vlan(cpsw->ale, slave->port_vlan, port_mask, + port_mask, port_mask, 0); + cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, + ALE_PORT_HOST, ALE_VLAN, slave->port_vlan, + ALE_MCAST_FWD); + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN | + ALE_SECURE, slave->port_vlan); + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_DROP_UNKNOWN_VLAN, 1); + /* learning make no sense in dual_mac mode */ + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_NOLEARN, 1); +} + +static void cpsw_adjust_link(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + struct phy_device *phy; + u32 mac_control = 0; + + slave = &cpsw->slaves[priv->emac_port - 1]; + phy = slave->phy; + + if (!phy) + return; + + if (phy->link) { + mac_control = CPSW_SL_CTL_GMII_EN; + + if (phy->speed == 1000) + mac_control |= CPSW_SL_CTL_GIG; + if (phy->duplex) + mac_control |= CPSW_SL_CTL_FULLDUPLEX; + + /* set speed_in input in case RMII mode is used in 100Mbps */ + if (phy->speed == 100) + mac_control |= CPSW_SL_CTL_IFCTL_A; + /* in band mode only works in 10Mbps RGMII mode */ + else if ((phy->speed == 10) && phy_interface_is_rgmii(phy)) + mac_control |= CPSW_SL_CTL_EXT_EN; /* In Band mode */ + + if (priv->rx_pause) + mac_control |= CPSW_SL_CTL_RX_FLOW_EN; + + if (priv->tx_pause) + mac_control |= CPSW_SL_CTL_TX_FLOW_EN; + + if (mac_control != slave->mac_control) + cpsw_sl_ctl_set(slave->mac_sl, mac_control); + + /* enable forwarding */ + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); + + netif_tx_wake_all_queues(ndev); + + if (priv->shp_cfg_speed && + priv->shp_cfg_speed != slave->phy->speed && + !cpsw_shp_is_off(priv)) + dev_warn(priv->dev, "Speed was changed, CBS shaper speeds are changed!"); + } else { + netif_tx_stop_all_queues(ndev); + + mac_control = 0; + /* disable forwarding */ + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); + + cpsw_sl_wait_for_idle(slave->mac_sl, 100); + + cpsw_sl_ctl_reset(slave->mac_sl); + } + + if (mac_control != slave->mac_control) + phy_print_status(phy); + + slave->mac_control = mac_control; + + if (phy->link && cpsw_need_resplit(cpsw)) + cpsw_split_res(cpsw); +} + +static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + struct phy_device *phy; + + cpsw_sl_reset(slave->mac_sl, 100); + cpsw_sl_ctl_reset(slave->mac_sl); + + /* setup priority mapping */ + cpsw_sl_reg_write(slave->mac_sl, CPSW_SL_RX_PRI_MAP, + RX_PRIORITY_MAPPING); + + switch (cpsw->version) { + case CPSW_VERSION_1: + slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS); + break; + case CPSW_VERSION_2: + case CPSW_VERSION_3: + case CPSW_VERSION_4: + slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS); + break; + } + + /* setup max packet size, and mac address */ + cpsw_sl_reg_write(slave->mac_sl, CPSW_SL_RX_MAXLEN, + cpsw->rx_packet_max); + cpsw_set_slave_mac(slave, priv); + + slave->mac_control = 0; /* no link yet */ + + cpsw_port_add_dual_emac_def_ale_entries(priv, slave); + + if (!slave->data->phy_node) + dev_err(priv->dev, "no phy found on slave %d\n", + slave->slave_num); + phy = of_phy_connect(priv->ndev, slave->data->phy_node, + &cpsw_adjust_link, 0, slave->data->phy_if); + if (!phy) { + dev_err(priv->dev, "phy \"%pOF\" not found on slave %d\n", + slave->data->phy_node, + slave->slave_num); + return; + } + slave->phy = phy; + + phy_attached_info(slave->phy); + + phy_start(slave->phy); + + /* Configure GMII_SEL register */ + phy_set_mode_ext(slave->data->ifphy, PHY_MODE_ETHERNET, + slave->data->phy_if); +} + +static int cpsw_ndo_stop(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpsw_slave *slave; + + cpsw_info(priv, ifdown, "shutting down ndev\n"); + slave = &cpsw->slaves[priv->emac_port - 1]; + if (slave->phy) + phy_stop(slave->phy); + + netif_tx_stop_all_queues(priv->ndev); + + if (slave->phy) { + phy_disconnect(slave->phy); + slave->phy = NULL; + } + + __hw_addr_ref_unsync_dev(&ndev->mc, ndev, cpsw_purge_all_mc); + + if (cpsw->usage_count <= 1) { + napi_disable(&cpsw->napi_rx); + napi_disable(&cpsw->napi_tx); + cpts_unregister(cpsw->cpts); + cpsw_intr_disable(cpsw); + cpdma_ctlr_stop(cpsw->dma); + cpsw_ale_stop(cpsw->ale); + cpsw_destroy_xdp_rxqs(cpsw); + } + + if (cpsw_need_resplit(cpsw)) + cpsw_split_res(cpsw); + + cpsw->usage_count--; + pm_runtime_put_sync(cpsw->dev); + return 0; +} + +static int cpsw_ndo_open(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ret; + + cpsw_info(priv, ifdown, "starting ndev\n"); + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + /* Notify the stack of the actual queue counts. */ + ret = netif_set_real_num_tx_queues(ndev, cpsw->tx_ch_num); + if (ret) { + dev_err(priv->dev, "cannot set real number of tx queues\n"); + goto pm_cleanup; + } + + ret = netif_set_real_num_rx_queues(ndev, cpsw->rx_ch_num); + if (ret) { + dev_err(priv->dev, "cannot set real number of rx queues\n"); + goto pm_cleanup; + } + + /* Initialize host and slave ports */ + if (!cpsw->usage_count) + cpsw_init_host_port(priv); + cpsw_slave_open(&cpsw->slaves[priv->emac_port - 1], priv); + + /* initialize shared resources for every ndev */ + if (!cpsw->usage_count) { + /* create rxqs for both infs in dual mac as they use same pool + * and must be destroyed together when no users. + */ + ret = cpsw_create_xdp_rxqs(cpsw); + if (ret < 0) + goto err_cleanup; + + ret = cpsw_fill_rx_channels(priv); + if (ret < 0) + goto err_cleanup; + + if (cpts_register(cpsw->cpts)) + dev_err(priv->dev, "error registering cpts device\n"); + + napi_enable(&cpsw->napi_rx); + napi_enable(&cpsw->napi_tx); + + if (cpsw->tx_irq_disabled) { + cpsw->tx_irq_disabled = false; + enable_irq(cpsw->irqs_table[1]); + } + + if (cpsw->rx_irq_disabled) { + cpsw->rx_irq_disabled = false; + enable_irq(cpsw->irqs_table[0]); + } + } + + cpsw_restore(priv); + + /* Enable Interrupt pacing if configured */ + if (cpsw->coal_intvl != 0) { + struct ethtool_coalesce coal; + + coal.rx_coalesce_usecs = cpsw->coal_intvl; + cpsw_set_coalesce(ndev, &coal); + } + + cpdma_ctlr_start(cpsw->dma); + cpsw_intr_enable(cpsw); + cpsw->usage_count++; + + return 0; + +err_cleanup: + cpsw_ndo_stop(ndev); + +pm_cleanup: + pm_runtime_put_sync(cpsw->dev); + return ret; +} + +static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + struct cpts *cpts = cpsw->cpts; + struct netdev_queue *txq; + struct cpdma_chan *txch; + int ret, q_idx; + + if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) { + cpsw_err(priv, tx_err, "packet pad failed\n"); + ndev->stats.tx_dropped++; + return NET_XMIT_DROP; + } + + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && + priv->tx_ts_enabled && cpts_can_timestamp(cpts, skb)) + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + + q_idx = skb_get_queue_mapping(skb); + if (q_idx >= cpsw->tx_ch_num) + q_idx = q_idx % cpsw->tx_ch_num; + + txch = cpsw->txv[q_idx].ch; + txq = netdev_get_tx_queue(ndev, q_idx); + skb_tx_timestamp(skb); + ret = cpdma_chan_submit(txch, skb, skb->data, skb->len, + priv->emac_port); + if (unlikely(ret != 0)) { + cpsw_err(priv, tx_err, "desc submit failed\n"); + goto fail; + } + + /* If there is no more tx desc left free then we need to + * tell the kernel to stop sending us tx frames. + */ + if (unlikely(!cpdma_check_free_tx_desc(txch))) { + netif_tx_stop_queue(txq); + + /* Barrier, so that stop_queue visible to other cpus */ + smp_mb__after_atomic(); + + if (cpdma_check_free_tx_desc(txch)) + netif_tx_wake_queue(txq); + } + + return NETDEV_TX_OK; +fail: + ndev->stats.tx_dropped++; + netif_tx_stop_queue(txq); + + /* Barrier, so that stop_queue visible to other cpus */ + smp_mb__after_atomic(); + + if (cpdma_check_free_tx_desc(txch)) + netif_tx_wake_queue(txq); + + return NETDEV_TX_BUSY; +} + +static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) +{ + struct sockaddr *addr = (struct sockaddr *)p; + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ret, slave_no; + int flags = 0; + u16 vid = 0; + + slave_no = cpsw_slave_index(cpsw, priv); + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + vid = cpsw->slaves[slave_no].port_vlan; + flags = ALE_VLAN | ALE_SECURE; + + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, HOST_PORT_NUM, + flags, vid); + cpsw_ale_add_ucast(cpsw->ale, addr->sa_data, HOST_PORT_NUM, + flags, vid); + + ether_addr_copy(priv->mac_addr, addr->sa_data); + ether_addr_copy(ndev->dev_addr, priv->mac_addr); + cpsw_set_slave_mac(&cpsw->slaves[slave_no], priv); + + pm_runtime_put(cpsw->dev); + + return 0; +} + +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, + __be16 proto, u16 vid) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + int ret; + int i; + + if (vid == cpsw->data.default_vlan) + return 0; + + ret = pm_runtime_get_sync(cpsw->dev); + if (ret < 0) { + pm_runtime_put_noidle(cpsw->dev); + return ret; + } + + for (i = 0; i < cpsw->data.slaves; i++) { + if (cpsw->slaves[i].ndev && + vid == cpsw->slaves[i].port_vlan) + goto err; + } + + dev_dbg(priv->dev, "removing vlanid %d from vlan filter\n", vid); + cpsw_ale_del_vlan(cpsw->ale, vid, 0); + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); + cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast, + 0, ALE_VLAN, vid); + cpsw_ale_flush_multicast(cpsw->ale, 0, vid); +err: + pm_runtime_put(cpsw->dev); + return ret; +} + +static int cpsw_ndo_get_phys_port_name(struct net_device *ndev, char *name, + size_t len) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + int err; + + err = snprintf(name, len, "p%d", priv->emac_port); + + if (err >= len) + return -EINVAL; + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void cpsw_ndo_poll_controller(struct net_device *ndev) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + + cpsw_intr_disable(cpsw); + cpsw_rx_interrupt(cpsw->irqs_table[0], cpsw); + cpsw_tx_interrupt(cpsw->irqs_table[1], cpsw); + cpsw_intr_enable(cpsw); +} +#endif + +static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, + struct xdp_frame **frames, u32 flags) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct xdp_frame *xdpf; + int i, drops = 0; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + for (i = 0; i < n; i++) { + xdpf = frames[i]; + if (xdpf->len < CPSW_MIN_PACKET_SIZE) { + xdp_return_frame_rx_napi(xdpf); + drops++; + continue; + } + + if (cpsw_xdp_tx_frame(priv, xdpf, NULL, priv->emac_port)) + drops++; + } + + return n - drops; +} + +static const struct net_device_ops cpsw_netdev_ops = { + .ndo_open = cpsw_ndo_open, + .ndo_stop = cpsw_ndo_stop, + .ndo_start_xmit = cpsw_ndo_start_xmit, + .ndo_set_mac_address = cpsw_ndo_set_mac_address, + .ndo_do_ioctl = cpsw_ndo_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = cpsw_ndo_tx_timeout, + .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, + .ndo_set_tx_maxrate = cpsw_ndo_set_tx_maxrate, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cpsw_ndo_poll_controller, +#endif + .ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid, + .ndo_setup_tc = cpsw_ndo_setup_tc, + .ndo_get_phys_port_name = cpsw_ndo_get_phys_port_name, + .ndo_bpf = cpsw_ndo_bpf, + .ndo_xdp_xmit = cpsw_ndo_xdp_xmit, +}; + +static void cpsw_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + struct platform_device *pdev; + + pdev = to_platform_device(cpsw->dev); + strlcpy(info->driver, "cpsw-switch", sizeof(info->driver)); + strlcpy(info->version, "2.0", sizeof(info->version)); + strlcpy(info->bus_info, pdev->name, sizeof(info->bus_info)); +} + +static int cpsw_set_pauseparam(struct net_device *ndev, + struct ethtool_pauseparam *pause) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + struct cpsw_priv *priv = netdev_priv(ndev); + int slave_no; + + slave_no = cpsw_slave_index(cpsw, priv); + if (!cpsw->slaves[slave_no].phy) + return -EINVAL; + + if (!phy_validate_pause(cpsw->slaves[slave_no].phy, pause)) + return -EINVAL; + + priv->rx_pause = pause->rx_pause ? true : false; + priv->tx_pause = pause->tx_pause ? true : false; + + phy_set_asym_pause(cpsw->slaves[slave_no].phy, + priv->rx_pause, priv->tx_pause); + + return 0; +} + +static int cpsw_set_channels(struct net_device *ndev, + struct ethtool_channels *chs) +{ + return cpsw_set_channels_common(ndev, chs, cpsw_rx_handler); +} + +static const struct ethtool_ops cpsw_ethtool_ops = { + .get_drvinfo = cpsw_get_drvinfo, + .get_msglevel = cpsw_get_msglevel, + .set_msglevel = cpsw_set_msglevel, + .get_link = ethtool_op_get_link, + .get_ts_info = cpsw_get_ts_info, + .get_coalesce = cpsw_get_coalesce, + .set_coalesce = cpsw_set_coalesce, + .get_sset_count = cpsw_get_sset_count, + .get_strings = cpsw_get_strings, + .get_ethtool_stats = cpsw_get_ethtool_stats, + .get_pauseparam = cpsw_get_pauseparam, + .set_pauseparam = cpsw_set_pauseparam, + .get_wol = cpsw_get_wol, + .set_wol = cpsw_set_wol, + .get_regs_len = cpsw_get_regs_len, + .get_regs = cpsw_get_regs, + .begin = cpsw_ethtool_op_begin, + .complete = cpsw_ethtool_op_complete, + .get_channels = cpsw_get_channels, + .set_channels = cpsw_set_channels, + .get_link_ksettings = cpsw_get_link_ksettings, + .set_link_ksettings = cpsw_set_link_ksettings, + .get_eee = cpsw_get_eee, + .set_eee = cpsw_set_eee, + .nway_reset = cpsw_nway_reset, + .get_ringparam = cpsw_get_ringparam, + .set_ringparam = cpsw_set_ringparam, +}; + +static int cpsw_probe_dt(struct cpsw_common *cpsw) +{ + struct device_node *node = cpsw->dev->of_node, *tmp_node, *port_np; + struct cpsw_platform_data *data = &cpsw->data; + struct device *dev = cpsw->dev; + int ret; + u32 prop; + + if (!node) + return -EINVAL; + + tmp_node = of_get_child_by_name(node, "ethernet-ports"); + if (!tmp_node) + return -ENOENT; + data->slaves = of_get_child_count(tmp_node); + if (data->slaves != CPSW_SLAVE_PORTS_NUM) { + of_node_put(tmp_node); + return -ENOENT; + } + + data->active_slave = 0; + data->channels = CPSW_MAX_QUEUES; + data->ale_entries = CPSW_ALE_NUM_ENTRIES; + data->dual_emac = 1; + data->bd_ram_size = CPSW_BD_RAM_SIZE; + data->mac_control = 0; + + data->slave_data = devm_kcalloc(dev, CPSW_SLAVE_PORTS_NUM, + sizeof(struct cpsw_slave_data), + GFP_KERNEL); + if (!data->slave_data) + return -ENOMEM; + + /* Populate all the child nodes here... + */ + ret = devm_of_platform_populate(dev); + /* We do not want to force this, as in some cases may not have child */ + if (ret) + dev_warn(dev, "Doesn't have any child node\n"); + + for_each_child_of_node(tmp_node, port_np) { + struct cpsw_slave_data *slave_data; + const void *mac_addr; + u32 port_id; + + ret = of_property_read_u32(port_np, "reg", &port_id); + if (ret < 0) { + dev_err(dev, "%pOF error reading port_id %d\n", + port_np, ret); + goto err_node_put; + } + + if (!port_id || port_id > CPSW_SLAVE_PORTS_NUM) { + dev_err(dev, "%pOF has invalid port_id %u\n", + port_np, port_id); + ret = -EINVAL; + goto err_node_put; + } + + slave_data = &data->slave_data[port_id - 1]; + + slave_data->disabled = !of_device_is_available(port_np); + if (slave_data->disabled) + continue; + + slave_data->slave_node = port_np; + slave_data->ifphy = devm_of_phy_get(dev, port_np, NULL); + if (IS_ERR(slave_data->ifphy)) { + ret = PTR_ERR(slave_data->ifphy); + dev_err(dev, "%pOF: Error retrieving port phy: %d\n", + port_np, ret); + goto err_node_put; + } + + if (of_phy_is_fixed_link(port_np)) { + ret = of_phy_register_fixed_link(port_np); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "%pOF failed to register fixed-link phy: %d\n", + port_np, ret); + goto err_node_put; + } + slave_data->phy_node = of_node_get(port_np); + } else { + slave_data->phy_node = + of_parse_phandle(port_np, "phy-handle", 0); + } + + if (!slave_data->phy_node) { + dev_err(dev, "%pOF no phy found\n", port_np); + ret = -ENODEV; + goto err_node_put; + } + + ret = of_get_phy_mode(port_np, &slave_data->phy_if); + if (ret) { + dev_err(dev, "%pOF read phy-mode err %d\n", + port_np, ret); + goto err_node_put; + } + + mac_addr = of_get_mac_address(port_np); + if (!IS_ERR(mac_addr)) { + ether_addr_copy(slave_data->mac_addr, mac_addr); + } else { + ret = ti_cm_get_macid(dev, port_id - 1, + slave_data->mac_addr); + if (ret) + goto err_node_put; + } + + if (of_property_read_u32(port_np, "ti,dual-emac-pvid", + &prop)) { + dev_err(dev, "%pOF Missing dual_emac_res_vlan in DT.\n", + port_np); + slave_data->dual_emac_res_vlan = port_id; + dev_err(dev, "%pOF Using %d as Reserved VLAN\n", + port_np, slave_data->dual_emac_res_vlan); + } else { + slave_data->dual_emac_res_vlan = prop; + } + } + + of_node_put(tmp_node); + return 0; + +err_node_put: + of_node_put(port_np); + return ret; +} + +static void cpsw_remove_dt(struct cpsw_common *cpsw) +{ + struct cpsw_platform_data *data = &cpsw->data; + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave_data *slave_data = &data->slave_data[i]; + struct device_node *port_np = slave_data->phy_node; + + if (port_np) { + if (of_phy_is_fixed_link(port_np)) + of_phy_deregister_fixed_link(port_np); + + of_node_put(port_np); + } + } +} + +static int cpsw_create_ports(struct cpsw_common *cpsw) +{ + struct cpsw_platform_data *data = &cpsw->data; + struct net_device *ndev, *napi_ndev = NULL; + struct device *dev = cpsw->dev; + struct cpsw_priv *priv; + int ret = 0, i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave_data *slave_data = &data->slave_data[i]; + + if (slave_data->disabled) + continue; + + ndev = devm_alloc_etherdev_mqs(dev, sizeof(struct cpsw_priv), + CPSW_MAX_QUEUES, + CPSW_MAX_QUEUES); + if (!ndev) { + dev_err(dev, "error allocating net_device\n"); + return -ENOMEM; + } + + priv = netdev_priv(ndev); + priv->cpsw = cpsw; + priv->ndev = ndev; + priv->dev = dev; + priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); + priv->emac_port = i + 1; + + if (is_valid_ether_addr(slave_data->mac_addr)) { + ether_addr_copy(priv->mac_addr, slave_data->mac_addr); + dev_info(cpsw->dev, "Detected MACID = %pM\n", + priv->mac_addr); + } else { + eth_random_addr(slave_data->mac_addr); + dev_info(cpsw->dev, "Random MACID = %pM\n", + priv->mac_addr); + } + ether_addr_copy(ndev->dev_addr, slave_data->mac_addr); + ether_addr_copy(priv->mac_addr, slave_data->mac_addr); + + cpsw->slaves[i].ndev = ndev; + + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_NETNS_LOCAL; + + ndev->netdev_ops = &cpsw_netdev_ops; + ndev->ethtool_ops = &cpsw_ethtool_ops; + SET_NETDEV_DEV(ndev, dev); + + if (!napi_ndev) { + /* CPSW Host port CPDMA interface is shared between + * ports and there is only one TX and one RX IRQs + * available for all possible TX and RX channels + * accordingly. + */ + netif_napi_add(ndev, &cpsw->napi_rx, + cpsw->quirk_irq ? + cpsw_rx_poll : cpsw_rx_mq_poll, + CPSW_POLL_WEIGHT); + netif_tx_napi_add(ndev, &cpsw->napi_tx, + cpsw->quirk_irq ? + cpsw_tx_poll : cpsw_tx_mq_poll, + CPSW_POLL_WEIGHT); + } + + napi_ndev = ndev; + } + + return ret; +} + +static void cpsw_unregister_ports(struct cpsw_common *cpsw) +{ + int i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { + if (!cpsw->slaves[i].ndev) + continue; + + unregister_netdev(cpsw->slaves[i].ndev); + } +} + +static int cpsw_register_ports(struct cpsw_common *cpsw) +{ + int ret = 0, i = 0; + + for (i = 0; i < cpsw->data.slaves; i++) { + if (!cpsw->slaves[i].ndev) + continue; + + /* register the network device */ + ret = register_netdev(cpsw->slaves[i].ndev); + if (ret) { + dev_err(cpsw->dev, + "cpsw: err registering net device%d\n", i); + cpsw->slaves[i].ndev = NULL; + break; + } + } + + if (ret) + cpsw_unregister_ports(cpsw); + return ret; +} + +static const struct devlink_ops cpsw_devlink_ops; + +static int cpsw_dl_ale_ctrl_get(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct cpsw_devlink *dl_priv = devlink_priv(dl); + struct cpsw_common *cpsw = dl_priv->cpsw; + + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); + + switch (id) { + case CPSW_DL_PARAM_ALE_BYPASS: + ctx->val.vbool = cpsw_ale_control_get(cpsw->ale, 0, ALE_BYPASS); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int cpsw_dl_ale_ctrl_set(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct cpsw_devlink *dl_priv = devlink_priv(dl); + struct cpsw_common *cpsw = dl_priv->cpsw; + int ret = -EOPNOTSUPP; + + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); + + switch (id) { + case CPSW_DL_PARAM_ALE_BYPASS: + ret = cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, + ctx->val.vbool); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static const struct devlink_param cpsw_devlink_params[] = { + DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_ALE_BYPASS, + "ale_bypass", DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + cpsw_dl_ale_ctrl_get, cpsw_dl_ale_ctrl_set, NULL), +}; + +static int cpsw_register_devlink(struct cpsw_common *cpsw) +{ + struct device *dev = cpsw->dev; + struct cpsw_devlink *dl_priv; + int ret = 0; + + cpsw->devlink = devlink_alloc(&cpsw_devlink_ops, sizeof(*dl_priv)); + if (!cpsw->devlink) + return -ENOMEM; + + dl_priv = devlink_priv(cpsw->devlink); + dl_priv->cpsw = cpsw; + + ret = devlink_register(cpsw->devlink, dev); + if (ret) { + dev_err(dev, "DL reg fail ret:%d\n", ret); + goto dl_free; + } + + ret = devlink_params_register(cpsw->devlink, cpsw_devlink_params, + ARRAY_SIZE(cpsw_devlink_params)); + if (ret) { + dev_err(dev, "DL params reg fail ret:%d\n", ret); + goto dl_unreg; + } + + devlink_params_publish(cpsw->devlink); + return ret; + +dl_unreg: + devlink_unregister(cpsw->devlink); +dl_free: + devlink_free(cpsw->devlink); + return ret; +} + +static void cpsw_unregister_devlink(struct cpsw_common *cpsw) +{ + devlink_params_unpublish(cpsw->devlink); + devlink_params_unregister(cpsw->devlink, cpsw_devlink_params, + ARRAY_SIZE(cpsw_devlink_params)); + devlink_unregister(cpsw->devlink); + devlink_free(cpsw->devlink); +} + +static const struct of_device_id cpsw_of_mtable[] = { + { .compatible = "ti,cpsw-switch"}, + { .compatible = "ti,am335x-cpsw-switch"}, + { .compatible = "ti,am4372-cpsw-switch"}, + { .compatible = "ti,dra7-cpsw-switch"}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cpsw_of_mtable); + +static const struct soc_device_attribute cpsw_soc_devices[] = { + { .family = "AM33xx", .revision = "ES1.0"}, + { /* sentinel */ } +}; + +static int cpsw_probe(struct platform_device *pdev) +{ + const struct soc_device_attribute *soc; + struct device *dev = &pdev->dev; + struct cpsw_common *cpsw; + struct resource *ss_res; + struct gpio_descs *mode; + void __iomem *ss_regs; + int ret = 0, ch; + struct clk *clk; + int irq; + + cpsw = devm_kzalloc(dev, sizeof(struct cpsw_common), GFP_KERNEL); + if (!cpsw) + return -ENOMEM; + + cpsw_slave_index = cpsw_slave_index_priv; + + cpsw->dev = dev; + + cpsw->slaves = devm_kcalloc(dev, + CPSW_SLAVE_PORTS_NUM, + sizeof(struct cpsw_slave), + GFP_KERNEL); + if (!cpsw->slaves) + return -ENOMEM; + + mode = devm_gpiod_get_array_optional(dev, "mode", GPIOD_OUT_LOW); + if (IS_ERR(mode)) { + ret = PTR_ERR(mode); + dev_err(dev, "gpio request failed, ret %d\n", ret); + return ret; + } + + clk = devm_clk_get(dev, "fck"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "fck is not found %d\n", ret); + return ret; + } + cpsw->bus_freq_mhz = clk_get_rate(clk) / 1000000; + + ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ss_regs = devm_ioremap_resource(dev, ss_res); + if (IS_ERR(ss_regs)) { + ret = PTR_ERR(ss_regs); + return ret; + } + cpsw->regs = ss_regs; + + irq = platform_get_irq_byname(pdev, "rx"); + if (irq < 0) + return irq; + cpsw->irqs_table[0] = irq; + + irq = platform_get_irq_byname(pdev, "tx"); + if (irq < 0) + return irq; + cpsw->irqs_table[1] = irq; + + platform_set_drvdata(pdev, cpsw); + /* This may be required here for child devices. */ + pm_runtime_enable(dev); + + /* Need to enable clocks with runtime PM api to access module + * registers + */ + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return ret; + } + + ret = cpsw_probe_dt(cpsw); + if (ret) + goto clean_dt_ret; + + soc = soc_device_match(cpsw_soc_devices); + if (soc) + cpsw->quirk_irq = 1; + + cpsw->rx_packet_max = rx_packet_max; + cpsw->descs_pool_size = descs_pool_size; + + ret = cpsw_init_common(cpsw, ss_regs, ale_ageout, + (u32 __force)ss_res->start + CPSW2_BD_OFFSET, + descs_pool_size); + if (ret) + goto clean_dt_ret; + + cpsw->wr_regs = cpsw->version == CPSW_VERSION_1 ? + ss_regs + CPSW1_WR_OFFSET : + ss_regs + CPSW2_WR_OFFSET; + + ch = cpsw->quirk_irq ? 0 : 7; + cpsw->txv[0].ch = cpdma_chan_create(cpsw->dma, ch, cpsw_tx_handler, 0); + if (IS_ERR(cpsw->txv[0].ch)) { + dev_err(dev, "error initializing tx dma channel\n"); + ret = PTR_ERR(cpsw->txv[0].ch); + goto clean_cpts; + } + + cpsw->rxv[0].ch = cpdma_chan_create(cpsw->dma, 0, cpsw_rx_handler, 1); + if (IS_ERR(cpsw->rxv[0].ch)) { + dev_err(dev, "error initializing rx dma channel\n"); + ret = PTR_ERR(cpsw->rxv[0].ch); + goto clean_cpts; + } + cpsw_split_res(cpsw); + + /* setup netdevs */ + ret = cpsw_create_ports(cpsw); + if (ret) + goto clean_unregister_netdev; + + /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and + * MISC IRQs which are always kept disabled with this driver so + * we will not request them. + * + * If anyone wants to implement support for those, make sure to + * first request and append them to irqs_table array. + */ + + ret = devm_request_irq(dev, cpsw->irqs_table[0], cpsw_rx_interrupt, + 0, dev_name(dev), cpsw); + if (ret < 0) { + dev_err(dev, "error attaching irq (%d)\n", ret); + goto clean_unregister_netdev; + } + + ret = devm_request_irq(dev, cpsw->irqs_table[1], cpsw_tx_interrupt, + 0, dev_name(dev), cpsw); + if (ret < 0) { + dev_err(dev, "error attaching irq (%d)\n", ret); + goto clean_unregister_netdev; + } + + ret = cpsw_register_devlink(cpsw); + if (ret) + goto clean_unregister_notifiers; + + ret = cpsw_register_ports(cpsw); + if (ret) + goto clean_unregister_notifiers; + + dev_notice(dev, "initialized (regs %pa, pool size %d) hw_ver:%08X %d.%d (%d)\n", + &ss_res->start, descs_pool_size, + cpsw->version, CPSW_MAJOR_VERSION(cpsw->version), + CPSW_MINOR_VERSION(cpsw->version), + CPSW_RTL_VERSION(cpsw->version)); + + pm_runtime_put(dev); + + return 0; + +clean_unregister_notifiers: + cpsw_unregister_notifiers(cpsw); +clean_unregister_netdev: + cpsw_unregister_ports(cpsw); +clean_cpts: + cpts_release(cpsw->cpts); + cpdma_ctlr_destroy(cpsw->dma); +clean_dt_ret: + cpsw_remove_dt(cpsw); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return ret; +} + +static int cpsw_remove(struct platform_device *pdev) +{ + struct cpsw_common *cpsw = platform_get_drvdata(pdev); + int ret; + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(&pdev->dev); + return ret; + } + + cpsw_unregister_devlink(cpsw); + cpsw_unregister_ports(cpsw); + + cpts_release(cpsw->cpts); + cpdma_ctlr_destroy(cpsw->dma); + cpsw_remove_dt(cpsw); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static struct platform_driver cpsw_driver = { + .driver = { + .name = "cpsw-switch", + .of_match_table = cpsw_of_mtable, + }, + .probe = cpsw_probe, + .remove = cpsw_remove, +}; + +module_platform_driver(cpsw_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("TI CPSW switchdev Ethernet driver"); diff --git a/drivers/net/ethernet/ti/cpsw_priv.c b/drivers/net/ethernet/ti/cpsw_priv.c index bbc9b413b5c3..b833cc1d188c 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.c +++ b/drivers/net/ethernet/ti/cpsw_priv.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -422,6 +423,7 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, struct cpsw_platform_data *data; struct cpdma_params dma_params; struct device *dev = cpsw->dev; + struct device_node *cpts_node; void __iomem *cpts_regs; int ret = 0, i; @@ -516,11 +518,16 @@ int cpsw_init_common(struct cpsw_common *cpsw, void __iomem *ss_regs, return -ENOMEM; } - cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpsw->dev->of_node); + cpts_node = of_get_child_by_name(cpsw->dev->of_node, "cpts"); + if (!cpts_node) + cpts_node = cpsw->dev->of_node; + + cpsw->cpts = cpts_create(cpsw->dev, cpts_regs, cpts_node); if (IS_ERR(cpsw->cpts)) { ret = PTR_ERR(cpsw->cpts); cpdma_ctlr_destroy(cpsw->dma); } + of_node_put(cpts_node); return ret; } diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 0dd70e191cf1..ac84a43cba09 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -54,6 +54,7 @@ do { \ #define HOST_PORT_NUM 0 #define CPSW_ALE_PORTS_NUM 3 +#define CPSW_SLAVE_PORTS_NUM 2 #define SLIVER_SIZE 0x40 #define CPSW1_HOST_PORT_OFFSET 0x028 @@ -65,6 +66,7 @@ do { \ #define CPSW1_CPTS_OFFSET 0x500 #define CPSW1_ALE_OFFSET 0x600 #define CPSW1_SLIVER_OFFSET 0x700 +#define CPSW1_WR_OFFSET 0x900 #define CPSW2_HOST_PORT_OFFSET 0x108 #define CPSW2_SLAVE_OFFSET 0x200 @@ -76,6 +78,7 @@ do { \ #define CPSW2_ALE_OFFSET 0xd00 #define CPSW2_SLIVER_OFFSET 0xd80 #define CPSW2_BD_OFFSET 0x2000 +#define CPSW2_WR_OFFSET 0x1200 #define CPDMA_RXTHRESH 0x0c0 #define CPDMA_RXFREE 0x0e0 @@ -113,12 +116,15 @@ do { \ #define IRQ_NUM 2 #define CPSW_MAX_QUEUES 8 #define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256 +#define CPSW_ALE_AGEOUT_DEFAULT 10 /* sec */ +#define CPSW_ALE_NUM_ENTRIES 1024 #define CPSW_FIFO_QUEUE_TYPE_SHIFT 16 #define CPSW_FIFO_SHAPE_EN_SHIFT 16 #define CPSW_FIFO_RATE_EN_SHIFT 20 #define CPSW_TC_NUM 4 #define CPSW_FIFO_SHAPERS_NUM (CPSW_TC_NUM - 1) #define CPSW_PCT_MASK 0x7f +#define CPSW_BD_RAM_SIZE 0x2000 #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT 29 #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK GENMASK(2, 0) @@ -279,6 +285,7 @@ struct cpsw_slave_data { u8 mac_addr[ETH_ALEN]; u16 dual_emac_res_vlan; /* Reserved VLAN for DualEMAC */ struct phy *ifphy; + bool disabled; }; struct cpsw_platform_data { @@ -286,9 +293,9 @@ struct cpsw_platform_data { u32 ss_reg_ofs; /* Subsystem control register offset */ u32 channels; /* number of cpdma channels (symmetric) */ u32 slaves; /* number of slave cpgmac ports */ - u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */ + u32 active_slave;/* time stamping, ethtool and SIOCGMIIPHY slave */ u32 ale_entries; /* ale table size */ - u32 bd_ram_size; /*buffer descriptor ram size */ + u32 bd_ram_size; /*buffer descriptor ram size */ u32 mac_control; /* Mac control register */ u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/ bool dual_emac; /* Enable Dual EMAC mode */ @@ -344,6 +351,7 @@ struct cpsw_common { bool tx_irq_disabled; u32 irqs_table[IRQ_NUM]; struct cpts *cpts; + struct devlink *devlink; int rx_ch_num, tx_ch_num; int speed; int usage_count; -- cgit v1.2.3-59-g8ed1b From 111cf1ab4da393416b8b79c2a7598378bfaf07e4 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Wed, 20 Nov 2019 00:19:20 +0200 Subject: net: ethernet: ti: introduce cpsw switchdev based driver part 2 - switch CPSW switchdev based driver which is operating in dual-emac mode by default, thus working as 2 individual network interfaces. The Switch mode can be enabled by configuring devlink driver parameter "switch_mode" to 1: devlink dev param set platform/48484000.switch \ name switch_mode value 1 cmode runtime This can be done regardless of the state of Port's netdevs - UP/DOWN, but Port's netdev devices have to be UP before joining the bridge to avoid overwriting of bridge configuration as CPSW switch driver completely reloads its configuration when first Port changes its state to UP. When the both interfaces joined the bridge - CPSW switch driver will start marking packets with offload_fwd_mark flag unless "ale_bypass=0". All configuration is implemented via switchdev API and notifiers. Supported: - SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS - SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: BR_MCAST_FLOOD - SWITCHDEV_ATTR_ID_PORT_STP_STATE - SWITCHDEV_OBJ_ID_PORT_VLAN - SWITCHDEV_OBJ_ID_PORT_MDB - SWITCHDEV_OBJ_ID_HOST_MDB Hence CPSW switchdev driver supports: - FDB offloading - MDB offloading - VLAN filtering and offloading - STP Signed-off-by: Ilias Apalodimas Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/Makefile | 2 +- drivers/net/ethernet/ti/cpsw_new.c | 391 +++++++++++++++++++- drivers/net/ethernet/ti/cpsw_priv.h | 5 + drivers/net/ethernet/ti/cpsw_switchdev.c | 589 +++++++++++++++++++++++++++++++ drivers/net/ethernet/ti/cpsw_switchdev.h | 15 + 5 files changed, 993 insertions(+), 9 deletions(-) create mode 100644 drivers/net/ethernet/ti/cpsw_switchdev.c create mode 100644 drivers/net/ethernet/ti/cpsw_switchdev.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile index c59670956ed3..d34df8e5cf94 100644 --- a/drivers/net/ethernet/ti/Makefile +++ b/drivers/net/ethernet/ti/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_TI_CPTS_MOD) += cpts.o obj-$(CONFIG_TI_CPSW) += ti_cpsw.o ti_cpsw-y := cpsw.o davinci_cpdma.o cpsw_ale.o cpsw_priv.o cpsw_sl.o cpsw_ethtool.o obj-$(CONFIG_TI_CPSW_SWITCHDEV) += ti_cpsw_new.o -ti_cpsw_new-y := cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o +ti_cpsw_new-y := cpsw_switchdev.o cpsw_new.o davinci_cpdma.o cpsw_ale.o cpsw_sl.o cpsw_priv.o cpsw_ethtool.o obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o keystone_netcp-y := netcp_core.o cpsw_ale.o diff --git a/drivers/net/ethernet/ti/cpsw_new.c b/drivers/net/ethernet/ti/cpsw_new.c index 25e59d328342..71215db7934b 100644 --- a/drivers/net/ethernet/ti/cpsw_new.c +++ b/drivers/net/ethernet/ti/cpsw_new.c @@ -35,6 +35,7 @@ #include "cpsw_ale.h" #include "cpsw_priv.h" #include "cpsw_sl.h" +#include "cpsw_switchdev.h" #include "cpts.h" #include "davinci_cpdma.h" @@ -51,6 +52,7 @@ struct cpsw_devlink { enum cpsw_devlink_param_id { CPSW_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + CPSW_DL_PARAM_SWITCH_MODE, CPSW_DL_PARAM_ALE_BYPASS, }; @@ -66,12 +68,20 @@ static int cpsw_slave_index_priv(struct cpsw_common *cpsw, return priv->emac_port - 1; } +static bool cpsw_is_switch_en(struct cpsw_common *cpsw) +{ + return !cpsw->data.dual_emac; +} + static void cpsw_set_promiscious(struct net_device *ndev, bool enable) { struct cpsw_common *cpsw = ndev_to_cpsw(ndev); bool enable_uni = false; int i; + if (cpsw_is_switch_en(cpsw)) + return; + /* Enabling promiscuous mode for one interface will be * common for both the interface as the interface shares * the same hardware resource. @@ -359,6 +369,7 @@ static void cpsw_rx_handler(void *token, int len, int status) goto requeue; } + skb->offload_fwd_mark = priv->offload_fwd_mark; skb_reserve(skb, headroom); skb_put(skb, len); skb->dev = ndev; @@ -389,8 +400,8 @@ requeue: } } -static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, - unsigned short vid) +static int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, + unsigned short vid) { struct cpsw_common *cpsw = priv->cpsw; int unreg_mcast_mask = 0; @@ -435,6 +446,11 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, struct cpsw_common *cpsw = priv->cpsw; int ret, i; + if (cpsw_is_switch_en(cpsw)) { + dev_dbg(cpsw->dev, ".ndo_vlan_rx_add_vid called in switch mode\n"); + return 0; + } + if (vid == cpsw->data.default_vlan) return 0; @@ -489,9 +505,36 @@ static void cpsw_restore(struct cpsw_priv *priv) cpsw_cbs_resume(&cpsw->slaves[priv->emac_port - 1], priv); } -static void cpsw_init_host_port_dual_mac(struct cpsw_priv *priv) +static void cpsw_init_stp_ale_entry(struct cpsw_common *cpsw) +{ + char stpa[] = {0x01, 0x80, 0xc2, 0x0, 0x0, 0x0}; + + cpsw_ale_add_mcast(cpsw->ale, stpa, + ALE_PORT_HOST, ALE_SUPER, 0, + ALE_MCAST_BLOCK_LEARN_FWD); +} + +static void cpsw_init_host_port_switch(struct cpsw_common *cpsw) +{ + int vlan = cpsw->data.default_vlan; + + writel(CPSW_FIFO_NORMAL_MODE, &cpsw->host_port_regs->tx_in_ctl); + + writel(vlan, &cpsw->host_port_regs->port_vlan); + + cpsw_ale_add_vlan(cpsw->ale, vlan, ALE_ALL_PORTS, + ALE_ALL_PORTS, ALE_ALL_PORTS, + ALE_PORT_1 | ALE_PORT_2); + + cpsw_init_stp_ale_entry(cpsw); + + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 1); + dev_dbg(cpsw->dev, "Set P0_UNI_FLOOD\n"); + cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 0); +} + +static void cpsw_init_host_port_dual_mac(struct cpsw_common *cpsw) { - struct cpsw_common *cpsw = priv->cpsw; int vlan = cpsw->data.default_vlan; writel(CPSW_FIFO_DUAL_MAC_MODE, &cpsw->host_port_regs->tx_in_ctl); @@ -536,7 +579,10 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) /* Enable internal fifo flow control */ writel(0x7, &cpsw->regs->flow_control); - cpsw_init_host_port_dual_mac(priv); + if (cpsw_is_switch_en(cpsw)) + cpsw_init_host_port_switch(cpsw); + else + cpsw_init_host_port_dual_mac(cpsw); cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); @@ -568,6 +614,41 @@ static void cpsw_port_add_dual_emac_def_ale_entries(struct cpsw_priv *priv, ALE_PORT_NOLEARN, 1); } +static void cpsw_port_add_switch_def_ale_entries(struct cpsw_priv *priv, + struct cpsw_slave *slave) +{ + u32 port_mask = 1 << priv->emac_port | ALE_PORT_HOST; + struct cpsw_common *cpsw = priv->cpsw; + u32 reg; + + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_DROP_UNKNOWN_VLAN, 0); + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_NOLEARN, 0); + /* disabling SA_UPDATE required to make stp work, without this setting + * Host MAC addresses will jump between ports. + * As per TRM MAC address can be defined as unicast supervisory (super) + * by setting both (ALE_BLOCKED | ALE_SECURE) which should prevent + * SA_UPDATE, but HW seems works incorrectly and setting ALE_SECURE + * causes STP packets to be dropped due to ingress filter + * if (source address found) and (secure) and + * (receive port number != port_number)) + * then discard the packet + */ + cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_NO_SA_UPDATE, 1); + + cpsw_ale_add_mcast(cpsw->ale, priv->ndev->broadcast, + port_mask, ALE_VLAN, slave->port_vlan, + ALE_MCAST_FWD_2); + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, slave->port_vlan); + + reg = (cpsw->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : + CPSW2_PORT_VLAN; + slave_write(slave, slave->port_vlan, reg); +} + static void cpsw_adjust_link(struct net_device *ndev) { struct cpsw_priv *priv = netdev_priv(ndev); @@ -680,7 +761,10 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) slave->mac_control = 0; /* no link yet */ - cpsw_port_add_dual_emac_def_ale_entries(priv, slave); + if (cpsw_is_switch_en(cpsw)) + cpsw_port_add_switch_def_ale_entries(priv, slave); + else + cpsw_port_add_dual_emac_def_ale_entries(priv, slave); if (!slave->data->phy_node) dev_err(priv->dev, "no phy found on slave %d\n", @@ -748,7 +832,8 @@ static int cpsw_ndo_open(struct net_device *ndev) struct cpsw_common *cpsw = priv->cpsw; int ret; - cpsw_info(priv, ifdown, "starting ndev\n"); + dev_info(priv->dev, "starting ndev. mode: %s\n", + cpsw_is_switch_en(cpsw) ? "switch" : "dual_mac"); ret = pm_runtime_get_sync(cpsw->dev); if (ret < 0) { pm_runtime_put_noidle(cpsw->dev); @@ -932,6 +1017,11 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, int ret; int i; + if (cpsw_is_switch_en(cpsw)) { + dev_dbg(cpsw->dev, "ndo del vlan is called in switch mode\n"); + return 0; + } + if (vid == cpsw->data.default_vlan) return 0; @@ -1010,6 +1100,17 @@ static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n, return n - drops; } +static int cpsw_get_port_parent_id(struct net_device *ndev, + struct netdev_phys_item_id *ppid) +{ + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + + ppid->id_len = sizeof(cpsw->base_mac); + memcpy(&ppid->id, &cpsw->base_mac, ppid->id_len); + + return 0; +} + static const struct net_device_ops cpsw_netdev_ops = { .ndo_open = cpsw_ndo_open, .ndo_stop = cpsw_ndo_stop, @@ -1029,6 +1130,7 @@ static const struct net_device_ops cpsw_netdev_ops = { .ndo_get_phys_port_name = cpsw_ndo_get_phys_port_name, .ndo_bpf = cpsw_ndo_bpf, .ndo_xdp_xmit = cpsw_ndo_xdp_xmit, + .ndo_get_port_parent_id = cpsw_get_port_parent_id, }; static void cpsw_get_drvinfo(struct net_device *ndev, @@ -1358,7 +1460,265 @@ static int cpsw_register_ports(struct cpsw_common *cpsw) return ret; } -static const struct devlink_ops cpsw_devlink_ops; +bool cpsw_port_dev_check(const struct net_device *ndev) +{ + if (ndev->netdev_ops == &cpsw_netdev_ops) { + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); + + return !cpsw->data.dual_emac; + } + + return false; +} + +static void cpsw_port_offload_fwd_mark_update(struct cpsw_common *cpsw) +{ + int set_val = 0; + int i; + + if (!cpsw->ale_bypass && + (cpsw->br_members == (ALE_PORT_1 | ALE_PORT_2))) + set_val = 1; + + dev_dbg(cpsw->dev, "set offload_fwd_mark %d\n", set_val); + + for (i = 0; i < cpsw->data.slaves; i++) { + struct net_device *sl_ndev = cpsw->slaves[i].ndev; + struct cpsw_priv *priv = netdev_priv(sl_ndev); + + priv->offload_fwd_mark = set_val; + } +} + +static int cpsw_netdevice_port_link(struct net_device *ndev, + struct net_device *br_ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + if (!cpsw->br_members) { + cpsw->hw_bridge_dev = br_ndev; + } else { + /* This is adding the port to a second bridge, this is + * unsupported + */ + if (cpsw->hw_bridge_dev != br_ndev) + return -EOPNOTSUPP; + } + + cpsw->br_members |= BIT(priv->emac_port); + + cpsw_port_offload_fwd_mark_update(cpsw); + + return NOTIFY_DONE; +} + +static void cpsw_netdevice_port_unlink(struct net_device *ndev) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + struct cpsw_common *cpsw = priv->cpsw; + + cpsw->br_members &= ~BIT(priv->emac_port); + + cpsw_port_offload_fwd_mark_update(cpsw); + + if (!cpsw->br_members) + cpsw->hw_bridge_dev = NULL; +} + +/* netdev notifier */ +static int cpsw_netdevice_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info; + int ret = NOTIFY_DONE; + + if (!cpsw_port_dev_check(ndev)) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_CHANGEUPPER: + info = ptr; + + if (netif_is_bridge_master(info->upper_dev)) { + if (info->linking) + ret = cpsw_netdevice_port_link(ndev, + info->upper_dev); + else + cpsw_netdevice_port_unlink(ndev); + } + break; + default: + return NOTIFY_DONE; + } + + return notifier_from_errno(ret); +} + +static struct notifier_block cpsw_netdevice_nb __read_mostly = { + .notifier_call = cpsw_netdevice_event, +}; + +static int cpsw_register_notifiers(struct cpsw_common *cpsw) +{ + int ret = 0; + + ret = register_netdevice_notifier(&cpsw_netdevice_nb); + if (ret) { + dev_err(cpsw->dev, "can't register netdevice notifier\n"); + return ret; + } + + ret = cpsw_switchdev_register_notifiers(cpsw); + if (ret) + unregister_netdevice_notifier(&cpsw_netdevice_nb); + + return ret; +} + +static void cpsw_unregister_notifiers(struct cpsw_common *cpsw) +{ + cpsw_switchdev_unregister_notifiers(cpsw); + unregister_netdevice_notifier(&cpsw_netdevice_nb); +} + +static const struct devlink_ops cpsw_devlink_ops = { +}; + +static int cpsw_dl_switch_mode_get(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct cpsw_devlink *dl_priv = devlink_priv(dl); + struct cpsw_common *cpsw = dl_priv->cpsw; + + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); + + if (id != CPSW_DL_PARAM_SWITCH_MODE) + return -EOPNOTSUPP; + + ctx->val.vbool = !cpsw->data.dual_emac; + + return 0; +} + +static int cpsw_dl_switch_mode_set(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct cpsw_devlink *dl_priv = devlink_priv(dl); + struct cpsw_common *cpsw = dl_priv->cpsw; + int vlan = cpsw->data.default_vlan; + bool switch_en = ctx->val.vbool; + bool if_running = false; + int i; + + dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id); + + if (id != CPSW_DL_PARAM_SWITCH_MODE) + return -EOPNOTSUPP; + + if (switch_en == !cpsw->data.dual_emac) + return 0; + + if (!switch_en && cpsw->br_members) { + dev_err(cpsw->dev, "Remove ports from BR before disabling switch mode\n"); + return -EINVAL; + } + + rtnl_lock(); + + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave *slave = &cpsw->slaves[i]; + struct net_device *sl_ndev = slave->ndev; + + if (!sl_ndev || !netif_running(sl_ndev)) + continue; + + if_running = true; + } + + if (!if_running) { + /* all ndevs are down */ + cpsw->data.dual_emac = !switch_en; + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave *slave = &cpsw->slaves[i]; + struct net_device *sl_ndev = slave->ndev; + struct cpsw_priv *priv; + + if (!sl_ndev) + continue; + + priv = netdev_priv(sl_ndev); + if (switch_en) + vlan = cpsw->data.default_vlan; + else + vlan = slave->data->dual_emac_res_vlan; + slave->port_vlan = vlan; + } + goto exit; + } + + if (switch_en) { + dev_info(cpsw->dev, "Enable switch mode\n"); + + /* enable bypass - no forwarding; all traffic goes to Host */ + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1); + + /* clean up ALE table */ + cpsw_ale_control_set(cpsw->ale, 0, ALE_CLEAR, 1); + cpsw_ale_control_get(cpsw->ale, 0, ALE_AGEOUT); + + cpsw_init_host_port_switch(cpsw); + + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave *slave = &cpsw->slaves[i]; + struct net_device *sl_ndev = slave->ndev; + struct cpsw_priv *priv; + + if (!sl_ndev) + continue; + + priv = netdev_priv(sl_ndev); + slave->port_vlan = vlan; + if (netif_running(sl_ndev)) + cpsw_port_add_switch_def_ale_entries(priv, + slave); + } + + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 0); + cpsw->data.dual_emac = false; + } else { + dev_info(cpsw->dev, "Disable switch mode\n"); + + /* enable bypass - no forwarding; all traffic goes to Host */ + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1); + + cpsw_ale_control_set(cpsw->ale, 0, ALE_CLEAR, 1); + cpsw_ale_control_get(cpsw->ale, 0, ALE_AGEOUT); + + cpsw_init_host_port_dual_mac(cpsw); + + for (i = 0; i < cpsw->data.slaves; i++) { + struct cpsw_slave *slave = &cpsw->slaves[i]; + struct net_device *sl_ndev = slave->ndev; + struct cpsw_priv *priv; + + if (!sl_ndev) + continue; + + priv = netdev_priv(slave->ndev); + slave->port_vlan = slave->data->dual_emac_res_vlan; + cpsw_port_add_dual_emac_def_ale_entries(priv, slave); + } + + cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 0); + cpsw->data.dual_emac = true; + } +exit: + rtnl_unlock(); + + return 0; +} static int cpsw_dl_ale_ctrl_get(struct devlink *dl, u32 id, struct devlink_param_gset_ctx *ctx) @@ -1392,6 +1752,10 @@ static int cpsw_dl_ale_ctrl_set(struct devlink *dl, u32 id, case CPSW_DL_PARAM_ALE_BYPASS: ret = cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, ctx->val.vbool); + if (!ret) { + cpsw->ale_bypass = ctx->val.vbool; + cpsw_port_offload_fwd_mark_update(cpsw); + } break; default: return -EOPNOTSUPP; @@ -1401,6 +1765,11 @@ static int cpsw_dl_ale_ctrl_set(struct devlink *dl, u32 id, } static const struct devlink_param cpsw_devlink_params[] = { + DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_SWITCH_MODE, + "switch_mode", DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + cpsw_dl_switch_mode_get, cpsw_dl_switch_mode_set, + NULL), DEVLINK_PARAM_DRIVER(CPSW_DL_PARAM_ALE_BYPASS, "ale_bypass", DEVLINK_PARAM_TYPE_BOOL, BIT(DEVLINK_PARAM_CMODE_RUNTIME), @@ -1550,6 +1919,7 @@ static int cpsw_probe(struct platform_device *pdev) cpsw->rx_packet_max = rx_packet_max; cpsw->descs_pool_size = descs_pool_size; + eth_random_addr(cpsw->base_mac); ret = cpsw_init_common(cpsw, ss_regs, ale_ageout, (u32 __force)ss_res->start + CPSW2_BD_OFFSET, @@ -1604,6 +1974,10 @@ static int cpsw_probe(struct platform_device *pdev) goto clean_unregister_netdev; } + ret = cpsw_register_notifiers(cpsw); + if (ret) + goto clean_unregister_netdev; + ret = cpsw_register_devlink(cpsw); if (ret) goto clean_unregister_notifiers; @@ -1647,6 +2021,7 @@ static int cpsw_remove(struct platform_device *pdev) return ret; } + cpsw_unregister_notifiers(cpsw); cpsw_unregister_devlink(cpsw); cpsw_unregister_ports(cpsw); diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index ac84a43cba09..bc726356a72c 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -356,6 +356,10 @@ struct cpsw_common { int speed; int usage_count; struct page_pool *page_pool[CPSW_MAX_QUEUES]; + u8 br_members; + struct net_device *hw_bridge_dev; + bool ale_bypass; + u8 base_mac[ETH_ALEN]; }; struct cpsw_priv { @@ -376,6 +380,7 @@ struct cpsw_priv { u32 emac_port; struct cpsw_common *cpsw; + int offload_fwd_mark; }; #define ndev_to_cpsw(ndev) (((struct cpsw_priv *)netdev_priv(ndev))->cpsw) diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c new file mode 100644 index 000000000000..985a929bb957 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_switchdev.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Texas Instruments switchdev Driver + * + * Copyright (C) 2019 Texas Instruments + * + */ + +#include +#include +#include +#include +#include + +#include "cpsw.h" +#include "cpsw_ale.h" +#include "cpsw_priv.h" +#include "cpsw_switchdev.h" + +struct cpsw_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct cpsw_priv *priv; + unsigned long event; +}; + +static int cpsw_port_stp_state_set(struct cpsw_priv *priv, + struct switchdev_trans *trans, u8 state) +{ + struct cpsw_common *cpsw = priv->cpsw; + u8 cpsw_state; + int ret = 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + switch (state) { + case BR_STATE_FORWARDING: + cpsw_state = ALE_PORT_STATE_FORWARD; + break; + case BR_STATE_LEARNING: + cpsw_state = ALE_PORT_STATE_LEARN; + break; + case BR_STATE_DISABLED: + cpsw_state = ALE_PORT_STATE_DISABLE; + break; + case BR_STATE_LISTENING: + case BR_STATE_BLOCKING: + cpsw_state = ALE_PORT_STATE_BLOCK; + break; + default: + return -EOPNOTSUPP; + } + + ret = cpsw_ale_control_set(cpsw->ale, priv->emac_port, + ALE_PORT_STATE, cpsw_state); + dev_dbg(priv->dev, "ale state: %u\n", cpsw_state); + + return ret; +} + +static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv, + struct switchdev_trans *trans, + struct net_device *orig_dev, + unsigned long brport_flags) +{ + struct cpsw_common *cpsw = priv->cpsw; + bool unreg_mcast_add = false; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (brport_flags & BR_MCAST_FLOOD) + unreg_mcast_add = true; + dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n", + unreg_mcast_add, priv->emac_port); + + cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port), + unreg_mcast_add); + + return 0; +} + +static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, + struct switchdev_trans *trans, + unsigned long flags) +{ + if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD)) + return -EINVAL; + + return 0; +} + +static int cpsw_port_attr_set(struct net_device *ndev, + const struct switchdev_attr *attr, + struct switchdev_trans *trans) +{ + struct cpsw_priv *priv = netdev_priv(ndev); + int ret; + + dev_dbg(priv->dev, "attr: id %u port: %u\n", attr->id, priv->emac_port); + + switch (attr->id) { + case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: + ret = cpsw_port_attr_br_flags_pre_set(ndev, trans, + attr->u.brport_flags); + break; + case SWITCHDEV_ATTR_ID_PORT_STP_STATE: + ret = cpsw_port_stp_state_set(priv, trans, attr->u.stp_state); + dev_dbg(priv->dev, "stp state: %u\n", attr->u.stp_state); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + ret = cpsw_port_attr_br_flags_set(priv, trans, attr->orig_dev, + attr->u.brport_flags); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static u16 cpsw_get_pvid(struct cpsw_priv *priv) +{ + struct cpsw_common *cpsw = priv->cpsw; + u32 __iomem *port_vlan_reg; + u32 pvid; + + if (priv->emac_port) { + int reg = CPSW2_PORT_VLAN; + + if (cpsw->version == CPSW_VERSION_1) + reg = CPSW1_PORT_VLAN; + pvid = slave_read(cpsw->slaves + (priv->emac_port - 1), reg); + } else { + port_vlan_reg = &cpsw->host_port_regs->port_vlan; + pvid = readl(port_vlan_reg); + } + + pvid = pvid & 0xfff; + + return pvid; +} + +static void cpsw_set_pvid(struct cpsw_priv *priv, u16 vid, bool cfi, u32 cos) +{ + struct cpsw_common *cpsw = priv->cpsw; + void __iomem *port_vlan_reg; + u32 pvid; + + pvid = vid; + pvid |= cfi ? BIT(12) : 0; + pvid |= (cos & 0x7) << 13; + + if (priv->emac_port) { + int reg = CPSW2_PORT_VLAN; + + if (cpsw->version == CPSW_VERSION_1) + reg = CPSW1_PORT_VLAN; + /* no barrier */ + slave_write(cpsw->slaves + (priv->emac_port - 1), pvid, reg); + } else { + /* CPU port */ + port_vlan_reg = &cpsw->host_port_regs->port_vlan; + writel(pvid, port_vlan_reg); + } +} + +static int cpsw_port_vlan_add(struct cpsw_priv *priv, bool untag, bool pvid, + u16 vid, struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int unreg_mcast_mask = 0; + int reg_mcast_mask = 0; + int untag_mask = 0; + int port_mask; + int ret = 0; + u32 flags; + + if (cpu_port) { + port_mask = BIT(HOST_PORT_NUM); + flags = orig_dev->flags; + unreg_mcast_mask = port_mask; + } else { + port_mask = BIT(priv->emac_port); + flags = priv->ndev->flags; + } + + if (flags & IFF_MULTICAST) + reg_mcast_mask = port_mask; + + if (untag) + untag_mask = port_mask; + + ret = cpsw_ale_vlan_add_modify(cpsw->ale, vid, port_mask, untag_mask, + reg_mcast_mask, unreg_mcast_mask); + if (ret) { + dev_err(priv->dev, "Unable to add vlan\n"); + return ret; + } + + if (cpu_port) + cpsw_ale_add_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); + if (!pvid) + return ret; + + cpsw_set_pvid(priv, vid, 0, 0); + + dev_dbg(priv->dev, "VID add: %s: vid:%u ports:%X\n", + priv->ndev->name, vid, port_mask); + return ret; +} + +static int cpsw_port_vlan_del(struct cpsw_priv *priv, u16 vid, + struct net_device *orig_dev) +{ + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int port_mask; + int ret = 0; + + if (cpu_port) + port_mask = BIT(HOST_PORT_NUM); + else + port_mask = BIT(priv->emac_port); + + ret = cpsw_ale_del_vlan(cpsw->ale, vid, port_mask); + if (ret != 0) + return ret; + + /* We don't care for the return value here, error is returned only if + * the unicast entry is not present + */ + if (cpu_port) + cpsw_ale_del_ucast(cpsw->ale, priv->mac_addr, + HOST_PORT_NUM, ALE_VLAN, vid); + + if (vid == cpsw_get_pvid(priv)) + cpsw_set_pvid(priv, 0, 0, 0); + + /* We don't care for the return value here, error is returned only if + * the multicast entry is not present + */ + cpsw_ale_del_mcast(cpsw->ale, priv->ndev->broadcast, + port_mask, ALE_VLAN, vid); + dev_dbg(priv->dev, "VID del: %s: vid:%u ports:%X\n", + priv->ndev->name, vid, port_mask); + + return ret; +} + +static int cpsw_port_vlans_add(struct cpsw_priv *priv, + const struct switchdev_obj_port_vlan *vlan, + struct switchdev_trans *trans) +{ + bool untag = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct net_device *orig_dev = vlan->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; + u16 vid; + + dev_dbg(priv->dev, "VID add: %s: vid:%u flags:%X\n", + priv->ndev->name, vlan->vid_begin, vlan->flags); + + if (cpu_port && !(vlan->flags & BRIDGE_VLAN_INFO_BRENTRY)) + return 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; + + err = cpsw_port_vlan_add(priv, untag, pvid, vid, orig_dev); + if (err) + return err; + } + + return 0; +} + +static int cpsw_port_vlans_del(struct cpsw_priv *priv, + const struct switchdev_obj_port_vlan *vlan) + +{ + struct net_device *orig_dev = vlan->obj.orig_dev; + u16 vid; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { + int err; + + err = cpsw_port_vlan_del(priv, vid, orig_dev); + if (err) + return err; + } + + return 0; +} + +static int cpsw_port_mdb_add(struct cpsw_priv *priv, + struct switchdev_obj_port_mdb *mdb, + struct switchdev_trans *trans) + +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int port_mask; + int err; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (cpu_port) + port_mask = BIT(HOST_PORT_NUM); + else + port_mask = BIT(priv->emac_port); + + err = cpsw_ale_add_mcast(cpsw->ale, mdb->addr, port_mask, + ALE_VLAN, mdb->vid, 0); + dev_dbg(priv->dev, "MDB add: %s: vid %u:%pM ports: %X\n", + priv->ndev->name, mdb->vid, mdb->addr, port_mask); + + return err; +} + +static int cpsw_port_mdb_del(struct cpsw_priv *priv, + struct switchdev_obj_port_mdb *mdb) + +{ + struct net_device *orig_dev = mdb->obj.orig_dev; + bool cpu_port = netif_is_bridge_master(orig_dev); + struct cpsw_common *cpsw = priv->cpsw; + int del_mask; + int err; + + if (cpu_port) + del_mask = BIT(HOST_PORT_NUM); + else + del_mask = BIT(priv->emac_port); + + err = cpsw_ale_del_mcast(cpsw->ale, mdb->addr, del_mask, + ALE_VLAN, mdb->vid); + dev_dbg(priv->dev, "MDB del: %s: vid %u:%pM ports: %X\n", + priv->ndev->name, mdb->vid, mdb->addr, del_mask); + + return err; +} + +static int cpsw_port_obj_add(struct net_device *ndev, + const struct switchdev_obj *obj, + struct switchdev_trans *trans, + struct netlink_ext_ack *extack) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct cpsw_priv *priv = netdev_priv(ndev); + int err = 0; + + dev_dbg(priv->dev, "obj_add: id %u port: %u\n", + obj->id, priv->emac_port); + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = cpsw_port_vlans_add(priv, vlan, trans); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = cpsw_port_mdb_add(priv, mdb, trans); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static int cpsw_port_obj_del(struct net_device *ndev, + const struct switchdev_obj *obj) +{ + struct switchdev_obj_port_vlan *vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + struct switchdev_obj_port_mdb *mdb = SWITCHDEV_OBJ_PORT_MDB(obj); + struct cpsw_priv *priv = netdev_priv(ndev); + int err = 0; + + dev_dbg(priv->dev, "obj_del: id %u port: %u\n", + obj->id, priv->emac_port); + + switch (obj->id) { + case SWITCHDEV_OBJ_ID_PORT_VLAN: + err = cpsw_port_vlans_del(priv, vlan); + break; + case SWITCHDEV_OBJ_ID_PORT_MDB: + case SWITCHDEV_OBJ_ID_HOST_MDB: + err = cpsw_port_mdb_del(priv, mdb); + break; + default: + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static void cpsw_fdb_offload_notify(struct net_device *ndev, + struct switchdev_notifier_fdb_info *rcv) +{ + struct switchdev_notifier_fdb_info info; + + info.addr = rcv->addr; + info.vid = rcv->vid; + info.offloaded = true; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + ndev, &info.info, NULL); +} + +static void cpsw_switchdev_event_work(struct work_struct *work) +{ + struct cpsw_switchdev_event_work *switchdev_work = + container_of(work, struct cpsw_switchdev_event_work, work); + struct cpsw_priv *priv = switchdev_work->priv; + struct switchdev_notifier_fdb_info *fdb; + struct cpsw_common *cpsw = priv->cpsw; + int port = priv->emac_port; + + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + + dev_dbg(cpsw->dev, "cpsw_fdb_add: MACID = %pM vid = %u flags = %u %u -- port %d\n", + fdb->addr, fdb->vid, fdb->added_by_user, + fdb->offloaded, port); + + if (!fdb->added_by_user) + break; + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) + port = HOST_PORT_NUM; + + cpsw_ale_add_ucast(cpsw->ale, (u8 *)fdb->addr, port, + fdb->vid ? ALE_VLAN : 0, fdb->vid); + cpsw_fdb_offload_notify(priv->ndev, fdb); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb = &switchdev_work->fdb_info; + + dev_dbg(cpsw->dev, "cpsw_fdb_del: MACID = %pM vid = %u flags = %u %u -- port %d\n", + fdb->addr, fdb->vid, fdb->added_by_user, + fdb->offloaded, port); + + if (!fdb->added_by_user) + break; + if (memcmp(priv->mac_addr, (u8 *)fdb->addr, ETH_ALEN) == 0) + port = HOST_PORT_NUM; + + cpsw_ale_del_ucast(cpsw->ale, (u8 *)fdb->addr, port, + fdb->vid ? ALE_VLAN : 0, fdb->vid); + break; + default: + break; + } + rtnl_unlock(); + + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(priv->ndev); +} + +/* called under rcu_read_lock() */ +static int cpsw_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *ndev = switchdev_notifier_info_to_dev(ptr); + struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct cpsw_switchdev_event_work *switchdev_work; + struct cpsw_priv *priv = netdev_priv(ndev); + int err; + + if (event == SWITCHDEV_PORT_ATTR_SET) { + err = switchdev_handle_port_attr_set(ndev, ptr, + cpsw_port_dev_check, + cpsw_port_attr_set); + return notifier_from_errno(err); + } + + if (!cpsw_port_dev_check(ndev)) + return NOTIFY_DONE; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (WARN_ON(!switchdev_work)) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, cpsw_switchdev_event_work); + switchdev_work->priv = priv; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + if (!switchdev_work->fdb_info.addr) + goto err_addr_alloc; + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + dev_hold(ndev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + queue_work(system_long_wq, &switchdev_work->work); + + return NOTIFY_DONE; + +err_addr_alloc: + kfree(switchdev_work); + return NOTIFY_BAD; +} + +static struct notifier_block cpsw_switchdev_notifier = { + .notifier_call = cpsw_switchdev_event, +}; + +static int cpsw_switchdev_blocking_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + int err; + + switch (event) { + case SWITCHDEV_PORT_OBJ_ADD: + err = switchdev_handle_port_obj_add(dev, ptr, + cpsw_port_dev_check, + cpsw_port_obj_add); + return notifier_from_errno(err); + case SWITCHDEV_PORT_OBJ_DEL: + err = switchdev_handle_port_obj_del(dev, ptr, + cpsw_port_dev_check, + cpsw_port_obj_del); + return notifier_from_errno(err); + case SWITCHDEV_PORT_ATTR_SET: + err = switchdev_handle_port_attr_set(dev, ptr, + cpsw_port_dev_check, + cpsw_port_attr_set); + return notifier_from_errno(err); + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block cpsw_switchdev_bl_notifier = { + .notifier_call = cpsw_switchdev_blocking_event, +}; + +int cpsw_switchdev_register_notifiers(struct cpsw_common *cpsw) +{ + int ret = 0; + + ret = register_switchdev_notifier(&cpsw_switchdev_notifier); + if (ret) { + dev_err(cpsw->dev, "register switchdev notifier fail ret:%d\n", + ret); + return ret; + } + + ret = register_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier); + if (ret) { + dev_err(cpsw->dev, "register switchdev blocking notifier ret:%d\n", + ret); + unregister_switchdev_notifier(&cpsw_switchdev_notifier); + } + + return ret; +} + +void cpsw_switchdev_unregister_notifiers(struct cpsw_common *cpsw) +{ + unregister_switchdev_blocking_notifier(&cpsw_switchdev_bl_notifier); + unregister_switchdev_notifier(&cpsw_switchdev_notifier); +} diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.h b/drivers/net/ethernet/ti/cpsw_switchdev.h new file mode 100644 index 000000000000..04a045dba7d4 --- /dev/null +++ b/drivers/net/ethernet/ti/cpsw_switchdev.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Texas Instruments Ethernet Switch Driver + */ + +#ifndef DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ +#define DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ + +#include + +bool cpsw_port_dev_check(const struct net_device *dev); +int cpsw_switchdev_register_notifiers(struct cpsw_common *cpsw); +void cpsw_switchdev_unregister_notifiers(struct cpsw_common *cpsw); + +#endif /* DRIVERS_NET_ETHERNET_TI_CPSW_SWITCHDEV_H_ */ -- cgit v1.2.3-59-g8ed1b From 6849c6d86bada8bd269fe0ee0c4a93892ccaf2c3 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Wed, 20 Nov 2019 00:15:21 +0000 Subject: net/mlx5e: Rx, Update page pool numa node when changed Once every napi poll cycle, check if numa node is different than the page pool's numa id, and update it using page_pool_update_nid(). Alternatively, we could have registered an irq affinity change handler, but page_pool_update_nid() must be called from napi context anyways, so the handler won't actually help. Performance testing: XDP drop/tx rate and TCP single/multi stream, on mlx5 driver while migrating rx ring irq from close to far numa: mlx5 internal page cache was locally disabled to get pure page pool results. CPU: Intel(R) Xeon(R) CPU E5-2603 v4 @ 1.70GHz NIC: Mellanox Technologies MT27700 Family [ConnectX-4] (100G) XDP Drop/TX single core: NUMA | XDP | Before | After --------------------------------------- Close | Drop | 11 Mpps | 10.9 Mpps Far | Drop | 4.4 Mpps | 5.8 Mpps Close | TX | 6.5 Mpps | 6.5 Mpps Far | TX | 3.5 Mpps | 4 Mpps Improvement is about 30% drop packet rate, 15% tx packet rate for numa far test. No degradation for numa close tests. TCP single/multi cpu/stream: NUMA | #cpu | Before | After -------------------------------------- Close | 1 | 18 Gbps | 18 Gbps Far | 1 | 15 Gbps | 18 Gbps Close | 12 | 80 Gbps | 80 Gbps Far | 12 | 68 Gbps | 80 Gbps In all test cases we see improvement for the far numa case, and no impact on the close numa case. Signed-off-by: Saeed Mahameed Acked-by: Jonathan Lemon Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 82cffb3a9964..9e9960146e5b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1386,6 +1386,9 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget) if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state))) return 0; + if (rq->page_pool) + page_pool_nid_changed(rq->page_pool, numa_mem_id()); + if (rq->cqd.left) { work_done += mlx5e_decompress_cqes_cont(rq, cqwq, 0, budget); if (rq->cqd.left || work_done >= budget) -- cgit v1.2.3-59-g8ed1b From 4ec4762d8ec6edcfe59fd806472d2b7518debe52 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Wed, 20 Nov 2019 05:46:06 +0530 Subject: cxgb4: add TC-MATCHALL classifier egress offload Add TC-MATCHALL classifier offload with TC-POLICE action applied for all outgoing traffic on the underlying interface. Split flow block offload to support both egress and ingress classification. For example, to rate limit all outgoing traffic to 1 Gbps: $ tc qdisc add dev enp2s0f4 clsact $ tc filter add dev enp2s0f4 egress matchall skip_sw \ action police rate 1Gbit burst 8Kbit Note that skip_sw is important. Otherwise, both stack and hardware will end up doing policing. Policing can't be shared across flow blocks. Only 1 egress matchall rule can be active at a time on the underlying interface. v5: - No change. v4: - Removed check to reject police offload if prio is not 1. - Moved TC_SETUP_BLOCK code to separate function. v3: - Added check to reject police offload if prio is not 1. - Assign block_shared variable only for TC_SETUP_BLOCK. v2: - Added check to reject flow block sharing for policers. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/Makefile | 3 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 6 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 84 +++++++- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c | 213 +++++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h | 35 ++++ .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 5 +- drivers/net/ethernet/chelsio/cxgb4/sched.c | 56 ++++-- drivers/net/ethernet/chelsio/cxgb4/sched.h | 1 + drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 11 +- 9 files changed, 381 insertions(+), 33 deletions(-) create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c create mode 100644 drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile index 49a19308073b..a4b4d475abf8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/Makefile +++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile @@ -8,7 +8,8 @@ obj-$(CONFIG_CHELSIO_T4) += cxgb4.o cxgb4-objs := cxgb4_main.o l2t.o smt.o t4_hw.o sge.o clip_tbl.o cxgb4_ethtool.o \ cxgb4_uld.o srq.o sched.o cxgb4_filter.o cxgb4_tc_u32.o \ cxgb4_ptp.o cxgb4_tc_flower.o cxgb4_cudbg.o cxgb4_mps.o \ - cudbg_common.o cudbg_lib.o cudbg_zlib.o cxgb4_tc_mqprio.o + cudbg_common.o cudbg_lib.o cudbg_zlib.o cxgb4_tc_mqprio.o \ + cxgb4_tc_matchall.o cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o cxgb4-$(CONFIG_CHELSIO_T4_FCOE) += cxgb4_fcoe.o cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1fb273b294a1..9376be6e51a3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -603,6 +603,8 @@ struct port_info { u8 vivld; u8 smt_idx; u8 rx_cchan; + + bool tc_block_shared; }; struct dentry; @@ -1101,6 +1103,9 @@ struct adapter { /* TC MQPRIO offload */ struct cxgb4_tc_mqprio *tc_mqprio; + + /* TC MATCHALL classifier offload */ + struct cxgb4_tc_matchall *tc_matchall; }; /* Support for "sched-class" command to allow a TX Scheduling Class to be @@ -1130,6 +1135,7 @@ enum { enum { SCHED_CLASS_LEVEL_CL_RL = 0, /* class rate limiter */ + SCHED_CLASS_LEVEL_CH_RL = 2, /* channel rate limiter */ }; enum { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index b5148c57e8bf..f04f9c858d52 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -84,6 +84,7 @@ #include "cxgb4_tc_u32.h" #include "cxgb4_tc_flower.h" #include "cxgb4_tc_mqprio.h" +#include "cxgb4_tc_matchall.h" #include "cxgb4_ptp.h" #include "cxgb4_cudbg.h" @@ -3234,8 +3235,28 @@ static int cxgb_setup_tc_cls_u32(struct net_device *dev, } } -static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data, - void *cb_priv) +static int cxgb_setup_tc_matchall(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall) +{ + struct adapter *adap = netdev2adap(dev); + + if (!adap->tc_matchall) + return -ENOMEM; + + switch (cls_matchall->command) { + case TC_CLSMATCHALL_REPLACE: + return cxgb4_tc_matchall_replace(dev, cls_matchall); + case TC_CLSMATCHALL_DESTROY: + return cxgb4_tc_matchall_destroy(dev, cls_matchall); + default: + break; + } + + return -EOPNOTSUPP; +} + +static int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) { struct net_device *dev = cb_priv; struct port_info *pi = netdev2pinfo(dev); @@ -3261,6 +3282,33 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data, } } +static int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type, + void *type_data, void *cb_priv) +{ + struct net_device *dev = cb_priv; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + + if (!(adap->flags & CXGB4_FULL_INIT_DONE)) { + dev_err(adap->pdev_dev, + "Failed to setup tc on port %d. Link Down?\n", + pi->port_id); + return -EINVAL; + } + + if (!tc_cls_can_offload_and_chain0(dev, type_data)) + return -EOPNOTSUPP; + + switch (type) { + case TC_SETUP_CLSMATCHALL: + return cxgb_setup_tc_matchall(dev, type_data); + default: + break; + } + + return -EOPNOTSUPP; +} + static int cxgb_setup_tc_mqprio(struct net_device *dev, struct tc_mqprio_qopt_offload *mqprio) { @@ -3274,19 +3322,34 @@ static int cxgb_setup_tc_mqprio(struct net_device *dev, static LIST_HEAD(cxgb_block_cb_list); +static int cxgb_setup_tc_block(struct net_device *dev, + struct flow_block_offload *f) +{ + struct port_info *pi = netdev_priv(dev); + flow_setup_cb_t *cb; + bool ingress_only; + + pi->tc_block_shared = f->block_shared; + if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) { + cb = cxgb_setup_tc_block_egress_cb; + ingress_only = false; + } else { + cb = cxgb_setup_tc_block_ingress_cb; + ingress_only = true; + } + + return flow_block_cb_setup_simple(f, &cxgb_block_cb_list, + cb, pi, dev, ingress_only); +} + static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data) { - struct port_info *pi = netdev2pinfo(dev); - switch (type) { case TC_SETUP_QDISC_MQPRIO: return cxgb_setup_tc_mqprio(dev, type_data); case TC_SETUP_BLOCK: - return flow_block_cb_setup_simple(type_data, - &cxgb_block_cb_list, - cxgb_setup_tc_block_cb, - pi, dev, true); + return cxgb_setup_tc_block(dev, type_data); default: return -EOPNOTSUPP; } @@ -5741,6 +5804,7 @@ static void free_some_resources(struct adapter *adapter) kvfree(adapter->srq); t4_cleanup_sched(adapter); kvfree(adapter->tids.tid_tab); + cxgb4_cleanup_tc_matchall(adapter); cxgb4_cleanup_tc_mqprio(adapter); cxgb4_cleanup_tc_flower(adapter); cxgb4_cleanup_tc_u32(adapter); @@ -6315,6 +6379,10 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (cxgb4_init_tc_mqprio(adapter)) dev_warn(&pdev->dev, "could not offload tc mqprio, continuing\n"); + + if (cxgb4_init_tc_matchall(adapter)) + dev_warn(&pdev->dev, + "could not offload tc matchall, continuing\n"); } if (is_offload(adapter) || is_hashfilter(adapter)) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c new file mode 100644 index 000000000000..85bf0a238a49 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2019 Chelsio Communications. All rights reserved. */ + +#include "cxgb4.h" +#include "cxgb4_tc_matchall.h" +#include "sched.h" + +static int cxgb4_matchall_egress_validate(struct net_device *dev, + struct tc_cls_matchall_offload *cls) +{ + struct netlink_ext_ack *extack = cls->common.extack; + struct flow_action *actions = &cls->rule->action; + struct port_info *pi = netdev2pinfo(dev); + struct flow_action_entry *entry; + u64 max_link_rate; + u32 i, speed; + int ret; + + if (!flow_action_has_entries(actions)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress MATCHALL offload needs at least 1 policing action"); + return -EINVAL; + } else if (!flow_offload_has_one_action(actions)) { + NL_SET_ERR_MSG_MOD(extack, + "Egress MATCHALL offload only supports 1 policing action"); + return -EINVAL; + } else if (pi->tc_block_shared) { + NL_SET_ERR_MSG_MOD(extack, + "Egress MATCHALL offload not supported with shared blocks"); + return -EINVAL; + } + + ret = t4_get_link_params(pi, NULL, &speed, NULL); + if (ret) { + NL_SET_ERR_MSG_MOD(extack, + "Failed to get max speed supported by the link"); + return -EINVAL; + } + + /* Convert from Mbps to bps */ + max_link_rate = (u64)speed * 1000 * 1000; + + flow_action_for_each(i, entry, actions) { + switch (entry->id) { + case FLOW_ACTION_POLICE: + /* Convert bytes per second to bits per second */ + if (entry->police.rate_bytes_ps * 8 > max_link_rate) { + NL_SET_ERR_MSG_MOD(extack, + "Specified policing max rate is larger than underlying link speed"); + return -ERANGE; + } + break; + default: + NL_SET_ERR_MSG_MOD(extack, + "Only policing action supported with Egress MATCHALL offload"); + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int cxgb4_matchall_alloc_tc(struct net_device *dev, + struct tc_cls_matchall_offload *cls) +{ + struct ch_sched_params p = { + .type = SCHED_CLASS_TYPE_PACKET, + .u.params.level = SCHED_CLASS_LEVEL_CH_RL, + .u.params.mode = SCHED_CLASS_MODE_CLASS, + .u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS, + .u.params.ratemode = SCHED_CLASS_RATEMODE_ABS, + .u.params.class = SCHED_CLS_NONE, + .u.params.minrate = 0, + .u.params.weight = 0, + .u.params.pktsize = dev->mtu, + }; + struct netlink_ext_ack *extack = cls->common.extack; + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct flow_action_entry *entry; + struct sched_class *e; + u32 i; + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + + flow_action_for_each(i, entry, &cls->rule->action) + if (entry->id == FLOW_ACTION_POLICE) + break; + + /* Convert from bytes per second to Kbps */ + p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000); + p.u.params.channel = pi->tx_chan; + e = cxgb4_sched_class_alloc(dev, &p); + if (!e) { + NL_SET_ERR_MSG_MOD(extack, + "No free traffic class available for policing action"); + return -ENOMEM; + } + + tc_port_matchall->egress.hwtc = e->idx; + tc_port_matchall->egress.cookie = cls->cookie; + tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_ENABLED; + return 0; +} + +static void cxgb4_matchall_free_tc(struct net_device *dev) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + cxgb4_sched_class_free(dev, tc_port_matchall->egress.hwtc); + + tc_port_matchall->egress.hwtc = SCHED_CLS_NONE; + tc_port_matchall->egress.cookie = 0; + tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_DISABLED; +} + +int cxgb4_tc_matchall_replace(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall) +{ + struct netlink_ext_ack *extack = cls_matchall->common.extack; + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + int ret; + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) { + NL_SET_ERR_MSG_MOD(extack, + "Only 1 Egress MATCHALL can be offloaded"); + return -ENOMEM; + } + + ret = cxgb4_matchall_egress_validate(dev, cls_matchall); + if (ret) + return ret; + + return cxgb4_matchall_alloc_tc(dev, cls_matchall); +} + +int cxgb4_tc_matchall_destroy(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (cls_matchall->cookie != tc_port_matchall->egress.cookie) + return -ENOENT; + + cxgb4_matchall_free_tc(dev); + return 0; +} + +static void cxgb4_matchall_disable_offload(struct net_device *dev) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) + cxgb4_matchall_free_tc(dev); +} + +int cxgb4_init_tc_matchall(struct adapter *adap) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct cxgb4_tc_matchall *tc_matchall; + int ret; + + tc_matchall = kzalloc(sizeof(*tc_matchall), GFP_KERNEL); + if (!tc_matchall) + return -ENOMEM; + + tc_port_matchall = kcalloc(adap->params.nports, + sizeof(*tc_port_matchall), + GFP_KERNEL); + if (!tc_port_matchall) { + ret = -ENOMEM; + goto out_free_matchall; + } + + tc_matchall->port_matchall = tc_port_matchall; + adap->tc_matchall = tc_matchall; + return 0; + +out_free_matchall: + kfree(tc_matchall); + return ret; +} + +void cxgb4_cleanup_tc_matchall(struct adapter *adap) +{ + u8 i; + + if (adap->tc_matchall) { + if (adap->tc_matchall->port_matchall) { + for (i = 0; i < adap->params.nports; i++) { + struct net_device *dev = adap->port[i]; + + if (dev) + cxgb4_matchall_disable_offload(dev); + } + kfree(adap->tc_matchall->port_matchall); + } + kfree(adap->tc_matchall); + } +} diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h new file mode 100644 index 000000000000..ce5b0800f0d8 --- /dev/null +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2019 Chelsio Communications. All rights reserved. */ + +#ifndef __CXGB4_TC_MATCHALL_H__ +#define __CXGB4_TC_MATCHALL_H__ + +#include + +enum cxgb4_matchall_state { + CXGB4_MATCHALL_STATE_DISABLED = 0, + CXGB4_MATCHALL_STATE_ENABLED, +}; + +struct cxgb4_matchall_egress_entry { + enum cxgb4_matchall_state state; /* Current MATCHALL offload state */ + u8 hwtc; /* Traffic class bound to port */ + u64 cookie; /* Used to identify the MATCHALL rule offloaded */ +}; + +struct cxgb4_tc_port_matchall { + struct cxgb4_matchall_egress_entry egress; /* Egress offload info */ +}; + +struct cxgb4_tc_matchall { + struct cxgb4_tc_port_matchall *port_matchall; /* Per port entry */ +}; + +int cxgb4_tc_matchall_replace(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall); +int cxgb4_tc_matchall_destroy(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall); + +int cxgb4_init_tc_matchall(struct adapter *adap); +void cxgb4_cleanup_tc_matchall(struct adapter *adap); +#endif /* __CXGB4_TC_MATCHALL_H__ */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index ce442c63f496..db55673b77bd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -11,8 +11,7 @@ static int cxgb4_mqprio_validate(struct net_device *dev, u64 min_rate = 0, max_rate = 0, max_link_rate; struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); - u32 qcount = 0, qoffset = 0; - u32 link_ok, speed, mtu; + u32 speed, qcount = 0, qoffset = 0; int ret; u8 i; @@ -35,7 +34,7 @@ static int cxgb4_mqprio_validate(struct net_device *dev, return -ERANGE; } - ret = t4_get_link_params(pi, &link_ok, &speed, &mtu); + ret = t4_get_link_params(pi, NULL, &speed, NULL); if (ret) { netdev_err(dev, "Failed to get link speed, ret: %d\n", ret); return -EINVAL; diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.c b/drivers/net/ethernet/chelsio/cxgb4/sched.c index 0a98c4dbb36b..3e61bd5d0c29 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.c @@ -50,6 +50,7 @@ static int t4_sched_class_fw_cmd(struct port_info *pi, e = &s->tab[p->u.params.class]; switch (op) { case SCHED_FW_OP_ADD: + case SCHED_FW_OP_DEL: err = t4_sched_params(adap, p->type, p->u.params.level, p->u.params.mode, p->u.params.rateunit, @@ -188,10 +189,8 @@ static int t4_sched_queue_unbind(struct port_info *pi, struct ch_sched_queue *p) e = &pi->sched_tbl->tab[qe->param.class]; list_del(&qe->list); kvfree(qe); - if (atomic_dec_and_test(&e->refcnt)) { - e->state = SCHED_STATE_UNUSED; - memset(&e->info, 0, sizeof(e->info)); - } + if (atomic_dec_and_test(&e->refcnt)) + cxgb4_sched_class_free(adap->port[pi->port_id], e->idx); } return err; } @@ -261,10 +260,8 @@ static int t4_sched_flowc_unbind(struct port_info *pi, struct ch_sched_flowc *p) e = &pi->sched_tbl->tab[fe->param.class]; list_del(&fe->list); kvfree(fe); - if (atomic_dec_and_test(&e->refcnt)) { - e->state = SCHED_STATE_UNUSED; - memset(&e->info, 0, sizeof(e->info)); - } + if (atomic_dec_and_test(&e->refcnt)) + cxgb4_sched_class_free(adap->port[pi->port_id], e->idx); } return err; } @@ -469,10 +466,7 @@ static struct sched_class *t4_sched_class_lookup(struct port_info *pi, struct sched_class *found = NULL; struct sched_class *e, *end; - /* Only allow tc to be shared among SCHED_FLOWC types. For - * other types, always allocate a new tc. - */ - if (!p || p->u.params.mode != SCHED_CLASS_MODE_FLOW) { + if (!p) { /* Get any available unused class */ end = &s->tab[s->sched_size]; for (e = &s->tab[0]; e != end; ++e) { @@ -514,7 +508,7 @@ static struct sched_class *t4_sched_class_lookup(struct port_info *pi, static struct sched_class *t4_sched_class_alloc(struct port_info *pi, struct ch_sched_params *p) { - struct sched_class *e; + struct sched_class *e = NULL; u8 class_id; int err; @@ -529,10 +523,13 @@ static struct sched_class *t4_sched_class_alloc(struct port_info *pi, if (class_id != SCHED_CLS_NONE) return NULL; - /* See if there's an exisiting class with same - * requested sched params + /* See if there's an exisiting class with same requested sched + * params. Classes can only be shared among FLOWC types. For + * other types, always request a new class. */ - e = t4_sched_class_lookup(pi, p); + if (p->u.params.mode == SCHED_CLASS_MODE_FLOW) + e = t4_sched_class_lookup(pi, p); + if (!e) { struct ch_sched_params np; @@ -592,10 +589,35 @@ void cxgb4_sched_class_free(struct net_device *dev, u8 classid) { struct port_info *pi = netdev2pinfo(dev); struct sched_table *s = pi->sched_tbl; + struct ch_sched_params p; struct sched_class *e; + u32 speed; + int ret; e = &s->tab[classid]; - if (!atomic_read(&e->refcnt)) { + if (!atomic_read(&e->refcnt) && e->state != SCHED_STATE_UNUSED) { + /* Port based rate limiting needs explicit reset back + * to max rate. But, we'll do explicit reset for all + * types, instead of just port based type, to be on + * the safer side. + */ + memcpy(&p, &e->info, sizeof(p)); + /* Always reset mode to 0. Otherwise, FLOWC mode will + * still be enabled even after resetting the traffic + * class. + */ + p.u.params.mode = 0; + p.u.params.minrate = 0; + p.u.params.pktsize = 0; + + ret = t4_get_link_params(pi, NULL, &speed, NULL); + if (!ret) + p.u.params.maxrate = speed * 1000; /* Mbps to Kbps */ + else + p.u.params.maxrate = SCHED_MAX_RATE_KBPS; + + t4_sched_class_fw_cmd(pi, &p, SCHED_FW_OP_DEL); + e->state = SCHED_STATE_UNUSED; memset(&e->info, 0, sizeof(e->info)); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h index 80bed8e59362..e92ff68bdd0a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sched.h +++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h @@ -52,6 +52,7 @@ enum { enum sched_fw_ops { SCHED_FW_OP_ADD, + SCHED_FW_OP_DEL, }; enum sched_bind_type { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index f2a7824da42b..19d18acfc9a6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -8777,8 +8777,8 @@ int t4_get_link_params(struct port_info *pi, unsigned int *link_okp, unsigned int *speedp, unsigned int *mtup) { unsigned int fw_caps = pi->adapter->params.fw_caps_support; - struct fw_port_cmd port_cmd; unsigned int action, link_ok, mtu; + struct fw_port_cmd port_cmd; fw_port_cap32_t linkattr; int ret; @@ -8813,9 +8813,12 @@ int t4_get_link_params(struct port_info *pi, unsigned int *link_okp, be32_to_cpu(port_cmd.u.info32.auxlinfo32_mtu32)); } - *link_okp = link_ok; - *speedp = fwcap_to_speed(linkattr); - *mtup = mtu; + if (link_okp) + *link_okp = link_ok; + if (speedp) + *speedp = fwcap_to_speed(linkattr); + if (mtup) + *mtup = mtu; return 0; } -- cgit v1.2.3-59-g8ed1b From 41ec03e534ca450939edae01d9f2037a6262e6de Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Wed, 20 Nov 2019 05:46:07 +0530 Subject: cxgb4: check rule prio conflicts before offload Only offload rule if it satisfies both of the following conditions: 1. The immediate previous rule has priority <= current rule's priority. 2. The immediate next rule has priority >= current rule's priority. Also rework free entry fetch logic to search from end of TCAM, instead of beginning, because higher indices have lower priority than lower indices. This is similar to how TC auto generates priority values. v5: - Fixed commit message and comment to include comparison for equal priority. v4: - Patch added in this version. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 5 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 114 ++++++++++++++++----- drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h | 1 + .../net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 31 +++++- drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c | 36 ++++--- 5 files changed, 143 insertions(+), 44 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 9376be6e51a3..3121ed83d8e2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1286,8 +1286,11 @@ struct ch_filter_specification { u16 nat_lport; /* local port to use after NAT'ing */ u16 nat_fport; /* foreign port to use after NAT'ing */ + u32 tc_prio; /* TC's filter priority index */ + u64 tc_cookie; /* Unique cookie identifying TC rules */ + /* reservation for future additions */ - u8 rsvd[24]; + u8 rsvd[12]; /* Filter rule value/mask pairs. */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index 43b0f8c57da7..8bdcccea47d5 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -440,36 +440,48 @@ int cxgb4_get_free_ftid(struct net_device *dev, int family) { struct adapter *adap = netdev2adap(dev); struct tid_info *t = &adap->tids; + bool found = false; + u8 i, n, cnt; int ftid; - spin_lock_bh(&t->ftid_lock); - if (family == PF_INET) { - ftid = find_first_zero_bit(t->ftid_bmap, t->nftids); - if (ftid >= t->nftids) - ftid = -1; - } else { - if (is_t6(adap->params.chip)) { - ftid = bitmap_find_free_region(t->ftid_bmap, - t->nftids, 1); - if (ftid < 0) - goto out_unlock; - - /* this is only a lookup, keep the found region - * unallocated - */ - bitmap_release_region(t->ftid_bmap, ftid, 1); - } else { - ftid = bitmap_find_free_region(t->ftid_bmap, - t->nftids, 2); - if (ftid < 0) - goto out_unlock; + /* IPv4 occupy 1 slot. IPv6 occupy 2 slots on T6 and 4 slots + * on T5. + */ + n = 1; + if (family == PF_INET6) { + n++; + if (CHELSIO_CHIP_VERSION(adap->params.chip) < CHELSIO_T6) + n += 2; + } + + if (n > t->nftids) + return -ENOMEM; - bitmap_release_region(t->ftid_bmap, ftid, 2); + /* Find free filter slots from the end of TCAM. Appropriate + * checks must be done by caller later to ensure the prio + * passed by TC doesn't conflict with prio saved by existing + * rules in the TCAM. + */ + spin_lock_bh(&t->ftid_lock); + ftid = t->nftids - 1; + while (ftid >= n - 1) { + cnt = 0; + for (i = 0; i < n; i++) { + if (test_bit(ftid - i, t->ftid_bmap)) + break; + cnt++; } + if (cnt == n) { + ftid &= ~(n - 1); + found = true; + break; + } + + ftid -= n; } -out_unlock: spin_unlock_bh(&t->ftid_lock); - return ftid; + + return found ? ftid : -ENOMEM; } static int cxgb4_set_ftid(struct tid_info *t, int fidx, int family, @@ -510,6 +522,60 @@ static void cxgb4_clear_ftid(struct tid_info *t, int fidx, int family, spin_unlock_bh(&t->ftid_lock); } +bool cxgb4_filter_prio_in_range(struct net_device *dev, u32 idx, u32 prio) +{ + struct adapter *adap = netdev2adap(dev); + struct filter_entry *prev_fe, *next_fe; + struct tid_info *t = &adap->tids; + u32 prev_ftid, next_ftid; + bool valid = true; + + /* Only insert the rule if both of the following conditions + * are met: + * 1. The immediate previous rule has priority <= @prio. + * 2. The immediate next rule has priority >= @prio. + */ + spin_lock_bh(&t->ftid_lock); + /* Don't insert if there's a rule already present at @idx. */ + if (test_bit(idx, t->ftid_bmap)) { + valid = false; + goto out_unlock; + } + + next_ftid = find_next_bit(t->ftid_bmap, t->nftids, idx); + if (next_ftid >= t->nftids) + next_ftid = idx; + + next_fe = &adap->tids.ftid_tab[next_ftid]; + + prev_ftid = find_last_bit(t->ftid_bmap, idx); + if (prev_ftid >= idx) + prev_ftid = idx; + + /* See if the filter entry belongs to an IPv6 rule, which + * occupy 4 slots on T5 and 2 slots on T6. Adjust the + * reference to the previously inserted filter entry + * accordingly. + */ + if (CHELSIO_CHIP_VERSION(adap->params.chip) < CHELSIO_T6) { + prev_fe = &adap->tids.ftid_tab[prev_ftid & ~0x3]; + if (!prev_fe->fs.type) + prev_fe = &adap->tids.ftid_tab[prev_ftid]; + } else { + prev_fe = &adap->tids.ftid_tab[prev_ftid & ~0x1]; + if (!prev_fe->fs.type) + prev_fe = &adap->tids.ftid_tab[prev_ftid]; + } + + if ((prev_fe->valid && prio < prev_fe->fs.tc_prio) || + (next_fe->valid && prio > next_fe->fs.tc_prio)) + valid = false; + +out_unlock: + spin_unlock_bh(&t->ftid_lock); + return valid; +} + /* Delete the filter at a specified index. */ static int del_filter_wr(struct adapter *adapter, int fidx) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h index b0751c0611ec..b3e4a645043d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.h @@ -53,4 +53,5 @@ void clear_all_filters(struct adapter *adapter); void init_hash_filter(struct adapter *adap); bool is_filter_exact_match(struct adapter *adap, struct ch_filter_specification *fs); +bool cxgb4_filter_prio_in_range(struct net_device *dev, u32 idx, u32 prio); #endif /* __CXGB4_FILTER_H */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index e447976bdd3e..5179ad23be3c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -636,12 +636,12 @@ static int cxgb4_validate_flow_actions(struct net_device *dev, int cxgb4_tc_flower_replace(struct net_device *dev, struct flow_cls_offload *cls) { + struct netlink_ext_ack *extack = cls->common.extack; struct adapter *adap = netdev2adap(dev); struct ch_tc_flower_entry *ch_flower; struct ch_filter_specification *fs; struct filter_ctx ctx; - int fidx; - int ret; + int fidx, ret; if (cxgb4_validate_flow_actions(dev, cls)) return -EOPNOTSUPP; @@ -664,14 +664,35 @@ int cxgb4_tc_flower_replace(struct net_device *dev, if (fs->hash) { fidx = 0; } else { - fidx = cxgb4_get_free_ftid(dev, fs->type ? PF_INET6 : PF_INET); - if (fidx < 0) { - netdev_err(dev, "%s: No fidx for offload.\n", __func__); + u8 inet_family; + + inet_family = fs->type ? PF_INET6 : PF_INET; + + /* Note that TC uses prio 0 to indicate stack to + * generate automatic prio and hence doesn't pass prio + * 0 to driver. However, the hardware TCAM index + * starts from 0. Hence, the -1 here. + */ + if (cls->common.prio <= adap->tids.nftids) + fidx = cls->common.prio - 1; + else + fidx = cxgb4_get_free_ftid(dev, inet_family); + + /* Only insert FLOWER rule if its priority doesn't + * conflict with existing rules in the LETCAM. + */ + if (fidx < 0 || + !cxgb4_filter_prio_in_range(dev, fidx, cls->common.prio)) { + NL_SET_ERR_MSG_MOD(extack, + "No free LETCAM index available"); ret = -ENOMEM; goto free_entry; } } + fs->tc_prio = cls->common.prio; + fs->tc_cookie = cls->cookie; + init_completion(&ctx.completion); ret = __cxgb4_set_filter(dev, fidx, fs, &ctx); if (ret) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c index 02fc63fa7f25..133f8623ba86 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_u32.c @@ -36,6 +36,7 @@ #include #include "cxgb4.h" +#include "cxgb4_filter.h" #include "cxgb4_tc_u32_parse.h" #include "cxgb4_tc_u32.h" @@ -148,6 +149,7 @@ static int fill_action_fields(struct adapter *adap, int cxgb4_config_knode(struct net_device *dev, struct tc_cls_u32_offload *cls) { const struct cxgb4_match_field *start, *link_start = NULL; + struct netlink_ext_ack *extack = cls->common.extack; struct adapter *adapter = netdev2adap(dev); __be16 protocol = cls->common.protocol; struct ch_filter_specification fs; @@ -164,14 +166,21 @@ int cxgb4_config_knode(struct net_device *dev, struct tc_cls_u32_offload *cls) if (protocol != htons(ETH_P_IP) && protocol != htons(ETH_P_IPV6)) return -EOPNOTSUPP; - /* Fetch the location to insert the filter. */ - filter_id = cls->knode.handle & 0xFFFFF; + /* Note that TC uses prio 0 to indicate stack to generate + * automatic prio and hence doesn't pass prio 0 to driver. + * However, the hardware TCAM index starts from 0. Hence, the + * -1 here. + */ + filter_id = TC_U32_NODE(cls->knode.handle) - 1; - if (filter_id > adapter->tids.nftids) { - dev_err(adapter->pdev_dev, - "Location %d out of range for insertion. Max: %d\n", - filter_id, adapter->tids.nftids); - return -ERANGE; + /* Only insert U32 rule if its priority doesn't conflict with + * existing rules in the LETCAM. + */ + if (filter_id >= adapter->tids.nftids || + !cxgb4_filter_prio_in_range(dev, filter_id, cls->common.prio)) { + NL_SET_ERR_MSG_MOD(extack, + "No free LETCAM index available"); + return -ENOMEM; } t = adapter->tc_u32; @@ -190,6 +199,9 @@ int cxgb4_config_knode(struct net_device *dev, struct tc_cls_u32_offload *cls) memset(&fs, 0, sizeof(fs)); + fs.tc_prio = cls->common.prio; + fs.tc_cookie = cls->knode.handle; + if (protocol == htons(ETH_P_IPV6)) { start = cxgb4_ipv6_fields; is_ipv6 = true; @@ -350,14 +362,10 @@ int cxgb4_delete_knode(struct net_device *dev, struct tc_cls_u32_offload *cls) return -EOPNOTSUPP; /* Fetch the location to delete the filter. */ - filter_id = cls->knode.handle & 0xFFFFF; - - if (filter_id > adapter->tids.nftids) { - dev_err(adapter->pdev_dev, - "Location %d out of range for deletion. Max: %d\n", - filter_id, adapter->tids.nftids); + filter_id = TC_U32_NODE(cls->knode.handle) - 1; + if (filter_id >= adapter->tids.nftids || + cls->knode.handle != adapter->tids.ftid_tab[filter_id].fs.tc_cookie) return -ERANGE; - } t = adapter->tc_u32; handle = cls->knode.handle; -- cgit v1.2.3-59-g8ed1b From 21c4c60b7696346c48ed11478f4bffec6d1b2dcb Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Wed, 20 Nov 2019 05:46:08 +0530 Subject: cxgb4: add TC-MATCHALL classifier ingress offload Add TC-MATCHALL classifier ingress offload support. The same actions supported by existing TC-FLOWER offload can be applied to all incoming traffic on the underlying interface. Ensure the rule priority doesn't conflict with existing rules in the TCAM. Only 1 ingress matchall rule can be active at a time on the underlying interface. v5: - No change. v4: - Added check to ensure the matchall rule's prio doesn't conflict with other rules in TCAM. - Added logic to fill default mask for VIID, if none has been provided, to prevent conflict with duplicate VIID rules. - Used existing variables in private structure to fill VIID info, instead of extracting the info manually. v3: - No change. v2: - Removed logic to fetch free index from end of TCAM. Must maintain same ordering as in kernel. Signed-off-by: Rahul Lakkireddy Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c | 6 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 15 ++- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c | 21 ++- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h | 6 + .../net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c | 145 ++++++++++++++++++++- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h | 18 ++- 6 files changed, 192 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c index 8bdcccea47d5..1d39fca11810 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c @@ -872,6 +872,12 @@ static void fill_default_mask(struct ch_filter_specification *fs) fs->mask.tos |= ~0; if (fs->val.proto && !fs->mask.proto) fs->mask.proto |= ~0; + if (fs->val.pfvf_vld && !fs->mask.pfvf_vld) + fs->mask.pfvf_vld |= ~0; + if (fs->val.pf && !fs->mask.pf) + fs->mask.pf |= ~0; + if (fs->val.vf && !fs->mask.vf) + fs->mask.vf |= ~0; for (i = 0; i < ARRAY_SIZE(fs->val.lip); i++) { lip |= fs->val.lip[i]; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f04f9c858d52..e8a1826a1e90 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3236,7 +3236,8 @@ static int cxgb_setup_tc_cls_u32(struct net_device *dev, } static int cxgb_setup_tc_matchall(struct net_device *dev, - struct tc_cls_matchall_offload *cls_matchall) + struct tc_cls_matchall_offload *cls_matchall, + bool ingress) { struct adapter *adap = netdev2adap(dev); @@ -3245,9 +3246,13 @@ static int cxgb_setup_tc_matchall(struct net_device *dev, switch (cls_matchall->command) { case TC_CLSMATCHALL_REPLACE: - return cxgb4_tc_matchall_replace(dev, cls_matchall); + return cxgb4_tc_matchall_replace(dev, cls_matchall, ingress); case TC_CLSMATCHALL_DESTROY: - return cxgb4_tc_matchall_destroy(dev, cls_matchall); + return cxgb4_tc_matchall_destroy(dev, cls_matchall, ingress); + case TC_CLSMATCHALL_STATS: + if (ingress) + return cxgb4_tc_matchall_stats(dev, cls_matchall); + break; default: break; } @@ -3277,6 +3282,8 @@ static int cxgb_setup_tc_block_ingress_cb(enum tc_setup_type type, return cxgb_setup_tc_cls_u32(dev, type_data); case TC_SETUP_CLSFLOWER: return cxgb_setup_tc_flower(dev, type_data); + case TC_SETUP_CLSMATCHALL: + return cxgb_setup_tc_matchall(dev, type_data, true); default: return -EOPNOTSUPP; } @@ -3301,7 +3308,7 @@ static int cxgb_setup_tc_block_egress_cb(enum tc_setup_type type, switch (type) { case TC_SETUP_CLSMATCHALL: - return cxgb_setup_tc_matchall(dev, type_data); + return cxgb_setup_tc_matchall(dev, type_data, false); default: break; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c index 5179ad23be3c..0fa80bef575d 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.c @@ -378,15 +378,14 @@ static void process_pedit_field(struct ch_filter_specification *fs, u32 val, } } -static void cxgb4_process_flow_actions(struct net_device *in, - struct flow_cls_offload *cls, - struct ch_filter_specification *fs) +void cxgb4_process_flow_actions(struct net_device *in, + struct flow_action *actions, + struct ch_filter_specification *fs) { - struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct flow_action_entry *act; int i; - flow_action_for_each(i, act, &rule->action) { + flow_action_for_each(i, act, actions) { switch (act->id) { case FLOW_ACTION_ACCEPT: fs->action = FILTER_PASS; @@ -544,17 +543,16 @@ static bool valid_pedit_action(struct net_device *dev, return true; } -static int cxgb4_validate_flow_actions(struct net_device *dev, - struct flow_cls_offload *cls) +int cxgb4_validate_flow_actions(struct net_device *dev, + struct flow_action *actions) { - struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct flow_action_entry *act; bool act_redir = false; bool act_pedit = false; bool act_vlan = false; int i; - flow_action_for_each(i, act, &rule->action) { + flow_action_for_each(i, act, actions) { switch (act->id) { case FLOW_ACTION_ACCEPT: case FLOW_ACTION_DROP: @@ -636,6 +634,7 @@ static int cxgb4_validate_flow_actions(struct net_device *dev, int cxgb4_tc_flower_replace(struct net_device *dev, struct flow_cls_offload *cls) { + struct flow_rule *rule = flow_cls_offload_flow_rule(cls); struct netlink_ext_ack *extack = cls->common.extack; struct adapter *adap = netdev2adap(dev); struct ch_tc_flower_entry *ch_flower; @@ -643,7 +642,7 @@ int cxgb4_tc_flower_replace(struct net_device *dev, struct filter_ctx ctx; int fidx, ret; - if (cxgb4_validate_flow_actions(dev, cls)) + if (cxgb4_validate_flow_actions(dev, &rule->action)) return -EOPNOTSUPP; if (cxgb4_validate_flow_match(dev, cls)) @@ -658,7 +657,7 @@ int cxgb4_tc_flower_replace(struct net_device *dev, fs = &ch_flower->fs; fs->hitcnts = 1; cxgb4_process_flow_match(dev, cls, fs); - cxgb4_process_flow_actions(dev, cls, fs); + cxgb4_process_flow_actions(dev, &rule->action, fs); fs->hash = is_filter_exact_match(adap, fs); if (fs->hash) { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h index eb4c95248baf..e132516e9868 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_flower.h @@ -108,6 +108,12 @@ struct ch_tc_pedit_fields { #define PEDIT_TCP_SPORT_DPORT 0x0 #define PEDIT_UDP_SPORT_DPORT 0x0 +void cxgb4_process_flow_actions(struct net_device *in, + struct flow_action *actions, + struct ch_filter_specification *fs); +int cxgb4_validate_flow_actions(struct net_device *dev, + struct flow_action *actions); + int cxgb4_tc_flower_replace(struct net_device *dev, struct flow_cls_offload *cls); int cxgb4_tc_flower_destroy(struct net_device *dev, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c index 85bf0a238a49..102b370fbd3e 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c @@ -4,6 +4,9 @@ #include "cxgb4.h" #include "cxgb4_tc_matchall.h" #include "sched.h" +#include "cxgb4_uld.h" +#include "cxgb4_filter.h" +#include "cxgb4_tc_flower.h" static int cxgb4_matchall_egress_validate(struct net_device *dev, struct tc_cls_matchall_offload *cls) @@ -118,8 +121,85 @@ static void cxgb4_matchall_free_tc(struct net_device *dev) tc_port_matchall->egress.state = CXGB4_MATCHALL_STATE_DISABLED; } +static int cxgb4_matchall_alloc_filter(struct net_device *dev, + struct tc_cls_matchall_offload *cls) +{ + struct netlink_ext_ack *extack = cls->common.extack; + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + struct ch_filter_specification *fs; + int ret, fidx; + + /* Note that TC uses prio 0 to indicate stack to generate + * automatic prio and hence doesn't pass prio 0 to driver. + * However, the hardware TCAM index starts from 0. Hence, the + * -1 here. 1 slot is enough to create a wildcard matchall + * VIID rule. + */ + if (cls->common.prio <= adap->tids.nftids) + fidx = cls->common.prio - 1; + else + fidx = cxgb4_get_free_ftid(dev, PF_INET); + + /* Only insert MATCHALL rule if its priority doesn't conflict + * with existing rules in the LETCAM. + */ + if (fidx < 0 || + !cxgb4_filter_prio_in_range(dev, fidx, cls->common.prio)) { + NL_SET_ERR_MSG_MOD(extack, + "No free LETCAM index available"); + return -ENOMEM; + } + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + fs = &tc_port_matchall->ingress.fs; + memset(fs, 0, sizeof(*fs)); + + fs->tc_prio = cls->common.prio; + fs->tc_cookie = cls->cookie; + fs->hitcnts = 1; + + fs->val.pfvf_vld = 1; + fs->val.pf = adap->pf; + fs->val.vf = pi->vin; + + cxgb4_process_flow_actions(dev, &cls->rule->action, fs); + + ret = cxgb4_set_filter(dev, fidx, fs); + if (ret) + return ret; + + tc_port_matchall->ingress.tid = fidx; + tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_ENABLED; + return 0; +} + +static int cxgb4_matchall_free_filter(struct net_device *dev) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + int ret; + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + + ret = cxgb4_del_filter(dev, tc_port_matchall->ingress.tid, + &tc_port_matchall->ingress.fs); + if (ret) + return ret; + + tc_port_matchall->ingress.packets = 0; + tc_port_matchall->ingress.bytes = 0; + tc_port_matchall->ingress.last_used = 0; + tc_port_matchall->ingress.tid = 0; + tc_port_matchall->ingress.state = CXGB4_MATCHALL_STATE_DISABLED; + return 0; +} + int cxgb4_tc_matchall_replace(struct net_device *dev, - struct tc_cls_matchall_offload *cls_matchall) + struct tc_cls_matchall_offload *cls_matchall, + bool ingress) { struct netlink_ext_ack *extack = cls_matchall->common.extack; struct cxgb4_tc_port_matchall *tc_port_matchall; @@ -128,6 +208,22 @@ int cxgb4_tc_matchall_replace(struct net_device *dev, int ret; tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (ingress) { + if (tc_port_matchall->ingress.state == + CXGB4_MATCHALL_STATE_ENABLED) { + NL_SET_ERR_MSG_MOD(extack, + "Only 1 Ingress MATCHALL can be offloaded"); + return -ENOMEM; + } + + ret = cxgb4_validate_flow_actions(dev, + &cls_matchall->rule->action); + if (ret) + return ret; + + return cxgb4_matchall_alloc_filter(dev, cls_matchall); + } + if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) { NL_SET_ERR_MSG_MOD(extack, "Only 1 Egress MATCHALL can be offloaded"); @@ -142,13 +238,22 @@ int cxgb4_tc_matchall_replace(struct net_device *dev, } int cxgb4_tc_matchall_destroy(struct net_device *dev, - struct tc_cls_matchall_offload *cls_matchall) + struct tc_cls_matchall_offload *cls_matchall, + bool ingress) { struct cxgb4_tc_port_matchall *tc_port_matchall; struct port_info *pi = netdev2pinfo(dev); struct adapter *adap = netdev2adap(dev); tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (ingress) { + if (cls_matchall->cookie != + tc_port_matchall->ingress.fs.tc_cookie) + return -ENOENT; + + return cxgb4_matchall_free_filter(dev); + } + if (cls_matchall->cookie != tc_port_matchall->egress.cookie) return -ENOENT; @@ -156,6 +261,39 @@ int cxgb4_tc_matchall_destroy(struct net_device *dev, return 0; } +int cxgb4_tc_matchall_stats(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall) +{ + struct cxgb4_tc_port_matchall *tc_port_matchall; + struct port_info *pi = netdev2pinfo(dev); + struct adapter *adap = netdev2adap(dev); + u64 packets, bytes; + int ret; + + tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; + if (tc_port_matchall->ingress.state == CXGB4_MATCHALL_STATE_DISABLED) + return -ENOENT; + + ret = cxgb4_get_filter_counters(dev, tc_port_matchall->ingress.tid, + &packets, &bytes, + tc_port_matchall->ingress.fs.hash); + if (ret) + return ret; + + if (tc_port_matchall->ingress.packets != packets) { + flow_stats_update(&cls_matchall->stats, + bytes - tc_port_matchall->ingress.bytes, + packets - tc_port_matchall->ingress.packets, + tc_port_matchall->ingress.last_used); + + tc_port_matchall->ingress.packets = packets; + tc_port_matchall->ingress.bytes = bytes; + tc_port_matchall->ingress.last_used = jiffies; + } + + return 0; +} + static void cxgb4_matchall_disable_offload(struct net_device *dev) { struct cxgb4_tc_port_matchall *tc_port_matchall; @@ -165,6 +303,9 @@ static void cxgb4_matchall_disable_offload(struct net_device *dev) tc_port_matchall = &adap->tc_matchall->port_matchall[pi->port_id]; if (tc_port_matchall->egress.state == CXGB4_MATCHALL_STATE_ENABLED) cxgb4_matchall_free_tc(dev); + + if (tc_port_matchall->ingress.state == CXGB4_MATCHALL_STATE_ENABLED) + cxgb4_matchall_free_filter(dev); } int cxgb4_init_tc_matchall(struct adapter *adap) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h index ce5b0800f0d8..ab6b5683dfd3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.h @@ -17,8 +17,18 @@ struct cxgb4_matchall_egress_entry { u64 cookie; /* Used to identify the MATCHALL rule offloaded */ }; +struct cxgb4_matchall_ingress_entry { + enum cxgb4_matchall_state state; /* Current MATCHALL offload state */ + u32 tid; /* Index to hardware filter entry */ + struct ch_filter_specification fs; /* Filter entry */ + u64 bytes; /* # of bytes hitting the filter */ + u64 packets; /* # of packets hitting the filter */ + u64 last_used; /* Last updated jiffies time */ +}; + struct cxgb4_tc_port_matchall { struct cxgb4_matchall_egress_entry egress; /* Egress offload info */ + struct cxgb4_matchall_ingress_entry ingress; /* Ingress offload info */ }; struct cxgb4_tc_matchall { @@ -26,9 +36,13 @@ struct cxgb4_tc_matchall { }; int cxgb4_tc_matchall_replace(struct net_device *dev, - struct tc_cls_matchall_offload *cls_matchall); + struct tc_cls_matchall_offload *cls_matchall, + bool ingress); int cxgb4_tc_matchall_destroy(struct net_device *dev, - struct tc_cls_matchall_offload *cls_matchall); + struct tc_cls_matchall_offload *cls_matchall, + bool ingress); +int cxgb4_tc_matchall_stats(struct net_device *dev, + struct tc_cls_matchall_offload *cls_matchall); int cxgb4_init_tc_matchall(struct adapter *adap); void cxgb4_cleanup_tc_matchall(struct adapter *adap); -- cgit v1.2.3-59-g8ed1b From f383b2950070ce4f34e74db94f70bb565b746e97 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 20 Nov 2019 16:54:17 +0200 Subject: net: mvneta: rely on page_pool_recycle_direct in mvneta_run_xdp Rely on page_pool_recycle_direct and not on xdp_return_buff in mvneta_run_xdp. This is a preliminary patch to limit the dma sync len to the one strictly necessary Signed-off-by: Lorenzo Bianconi Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 12e03b15f0ab..f7713c2c68e1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2097,7 +2097,8 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, err = xdp_do_redirect(pp->dev, xdp, prog); if (err) { ret = MVNETA_XDP_DROPPED; - xdp_return_buff(xdp); + page_pool_recycle_direct(rxq->page_pool, + virt_to_head_page(xdp->data)); } else { ret = MVNETA_XDP_REDIR; } @@ -2106,7 +2107,8 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, case XDP_TX: ret = mvneta_xdp_xmit_back(pp, xdp); if (ret != MVNETA_XDP_TX) - xdp_return_buff(xdp); + page_pool_recycle_direct(rxq->page_pool, + virt_to_head_page(xdp->data)); break; default: bpf_warn_invalid_xdp_action(act); -- cgit v1.2.3-59-g8ed1b From 07e13edbb6a6a9a407d6772a355836270e924aa8 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Wed, 20 Nov 2019 16:54:19 +0200 Subject: net: mvneta: get rid of huge dma sync in mvneta_rx_refill Get rid of costly dma_sync_single_for_device in mvneta_rx_refill since now the driver can let page_pool API to manage needed DMA sync with a proper size. - XDP_DROP DMA sync managed by mvneta driver: ~420Kpps - XDP_DROP DMA sync managed by page_pool API: ~585Kpps Tested-by: Matteo Croce Signed-off-by: Lorenzo Bianconi Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index f7713c2c68e1..a06d109c9e80 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -1846,7 +1846,6 @@ static int mvneta_rx_refill(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, gfp_t gfp_mask) { - enum dma_data_direction dma_dir; dma_addr_t phys_addr; struct page *page; @@ -1856,9 +1855,6 @@ static int mvneta_rx_refill(struct mvneta_port *pp, return -ENOMEM; phys_addr = page_pool_get_dma_addr(page) + pp->rx_offset_correction; - dma_dir = page_pool_get_dma_dir(rxq->page_pool); - dma_sync_single_for_device(pp->dev->dev.parent, phys_addr, - MVNETA_MAX_RX_BUF_SIZE, dma_dir); mvneta_rx_desc_fill(rx_desc, phys_addr, page, rxq); return 0; @@ -2097,8 +2093,10 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, err = xdp_do_redirect(pp->dev, xdp, prog); if (err) { ret = MVNETA_XDP_DROPPED; - page_pool_recycle_direct(rxq->page_pool, - virt_to_head_page(xdp->data)); + __page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), + xdp->data_end - xdp->data_hard_start, + true); } else { ret = MVNETA_XDP_REDIR; } @@ -2107,8 +2105,10 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, case XDP_TX: ret = mvneta_xdp_xmit_back(pp, xdp); if (ret != MVNETA_XDP_TX) - page_pool_recycle_direct(rxq->page_pool, - virt_to_head_page(xdp->data)); + __page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), + xdp->data_end - xdp->data_hard_start, + true); break; default: bpf_warn_invalid_xdp_action(act); @@ -2117,8 +2117,10 @@ mvneta_run_xdp(struct mvneta_port *pp, struct mvneta_rx_queue *rxq, trace_xdp_exception(pp->dev, prog, act); /* fall through */ case XDP_DROP: - page_pool_recycle_direct(rxq->page_pool, - virt_to_head_page(xdp->data)); + __page_pool_put_page(rxq->page_pool, + virt_to_head_page(xdp->data), + xdp->data_end - xdp->data_hard_start, + true); ret = MVNETA_XDP_DROPPED; break; } @@ -3067,11 +3069,13 @@ static int mvneta_create_page_pool(struct mvneta_port *pp, struct bpf_prog *xdp_prog = READ_ONCE(pp->xdp_prog); struct page_pool_params pp_params = { .order = 0, - .flags = PP_FLAG_DMA_MAP, + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, .pool_size = size, .nid = cpu_to_node(0), .dev = pp->dev->dev.parent, .dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE, + .offset = pp->rx_offset_correction, + .max_len = MVNETA_MAX_RX_BUF_SIZE, }; int err; -- cgit v1.2.3-59-g8ed1b From e20c43dbdf960e8a03381aa455ddea56504bdbc4 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 20 Nov 2019 21:06:58 +0100 Subject: r8169: change mdelay to msleep in rtl_fw_write_firmware We're not in atomic context here, therefore switch to msleep. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index 8f54a2c832eb..52241508473a 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -198,7 +198,7 @@ void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw) index += regno; break; case PHY_DELAY_MS: - mdelay(data); + msleep(data); break; } } -- cgit v1.2.3-59-g8ed1b From cfccde80e8b1d935e611d40c0f0bba3ed0557bd8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 20 Nov 2019 21:07:41 +0100 Subject: r8169: use macro FIELD_SIZEOF in definition of FW_OPCODE_SIZE Using macro FIELD_SIZEOF makes this define easier understandable. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index 52241508473a..927bb46b32d7 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -37,7 +37,7 @@ struct fw_info { u8 chksum; } __packed; -#define FW_OPCODE_SIZE sizeof(typeof(*((struct rtl_fw_phy_action *)0)->code)) +#define FW_OPCODE_SIZE FIELD_SIZEOF(struct rtl_fw_phy_action, code[0]) static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw) { -- cgit v1.2.3-59-g8ed1b From df0120f12f93f2e11eb67d00ed8270de92d0134d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 20 Nov 2019 21:08:47 +0100 Subject: r8169: add check for PHY_MDIO_CHG to rtl_nic_fw_data_ok Only values 0 and 1 are currently defined as parameters for PHY_MDIO_CHG. Instead of silently ignoring unknown values and misinterpreting the firmware code let's explicitly check. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169_firmware.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index 927bb46b32d7..355cc810e322 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -92,19 +92,24 @@ static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw) for (index = 0; index < pa->size; index++) { u32 action = le32_to_cpu(pa->code[index]); + u32 val = action & 0x0000ffff; u32 regno = (action & 0x0fff0000) >> 16; switch (action >> 28) { case PHY_READ: case PHY_DATA_OR: case PHY_DATA_AND: - case PHY_MDIO_CHG: case PHY_CLEAR_READCOUNT: case PHY_WRITE: case PHY_WRITE_PREVIOUS: case PHY_DELAY_MS: break; + case PHY_MDIO_CHG: + if (val > 1) + goto out; + break; + case PHY_BJMPN: if (regno > index) goto out; @@ -164,12 +169,12 @@ void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw) index -= (regno + 1); break; case PHY_MDIO_CHG: - if (data == 0) { - fw_write = rtl_fw->phy_write; - fw_read = rtl_fw->phy_read; - } else if (data == 1) { + if (data) { fw_write = rtl_fw->mac_mcu_write; fw_read = rtl_fw->mac_mcu_read; + } else { + fw_write = rtl_fw->phy_write; + fw_read = rtl_fw->phy_read; } break; -- cgit v1.2.3-59-g8ed1b From b34bb2cb5b62c7397c28fcc335e8047a687eada4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 20 Nov 2019 11:42:42 +0000 Subject: net: sfp: add support for module quirks Add support for applying module quirks to the list of supported ethtool link modes. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/sfp-bus.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index c5398a023440..30529345581a 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -10,6 +10,12 @@ #include "sfp.h" +struct sfp_quirk { + const char *vendor; + const char *part; + void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); +}; + /** * struct sfp_bus - internal representation of a sfp bus */ @@ -22,6 +28,7 @@ struct sfp_bus { const struct sfp_socket_ops *socket_ops; struct device *sfp_dev; struct sfp *sfp; + const struct sfp_quirk *sfp_quirk; const struct sfp_upstream_ops *upstream_ops; void *upstream; @@ -31,6 +38,46 @@ struct sfp_bus { bool started; }; +static const struct sfp_quirk sfp_quirks[] = { +}; + +static size_t sfp_strlen(const char *str, size_t maxlen) +{ + size_t size, i; + + /* Trailing characters should be filled with space chars */ + for (i = 0, size = 0; i < maxlen; i++) + if (str[i] != ' ') + size = i + 1; + + return size; +} + +static bool sfp_match(const char *qs, const char *str, size_t len) +{ + if (!qs) + return true; + if (strlen(qs) != len) + return false; + return !strncmp(qs, str, len); +} + +static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id) +{ + const struct sfp_quirk *q; + unsigned int i; + size_t vs, ps; + + vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name)); + ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn)); + + for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++) + if (sfp_match(q->vendor, id->base.vendor_name, vs) && + sfp_match(q->part, id->base.vendor_pn, ps)) + return q; + + return NULL; +} /** * sfp_parse_port() - Parse the EEPROM base ID, setting the port type * @bus: a pointer to the &struct sfp_bus structure for the sfp module @@ -234,6 +281,9 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, phylink_set(modes, 1000baseX_Full); } + if (bus->sfp_quirk) + bus->sfp_quirk->modes(id, modes); + bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS); phylink_set(support, Autoneg); @@ -610,6 +660,8 @@ int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id) const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); int ret = 0; + bus->sfp_quirk = sfp_lookup_quirk(id); + if (ops && ops->module_insert) ret = ops->module_insert(bus->upstream, id); @@ -623,6 +675,8 @@ void sfp_module_remove(struct sfp_bus *bus) if (ops && ops->module_remove) ops->module_remove(bus->upstream); + + bus->sfp_quirk = NULL; } EXPORT_SYMBOL_GPL(sfp_module_remove); -- cgit v1.2.3-59-g8ed1b From b0eae33b2583dceb36224619f9fd85e6140ae594 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 20 Nov 2019 11:42:47 +0000 Subject: net: sfp: add some quirks for GPON modules Marc Micalizzi reports that Huawei MA5671A and Alcatel/Lucent G-010S-P modules are capable of 2500base-X, but incorrectly report their capabilities in the EEPROM. It seems rather common that GPON modules mis-report. Let's fix these modules by adding some quirks. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/sfp-bus.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c index 30529345581a..5a72093ab6e7 100644 --- a/drivers/net/phy/sfp-bus.c +++ b/drivers/net/phy/sfp-bus.c @@ -38,7 +38,32 @@ struct sfp_bus { bool started; }; +static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, + unsigned long *modes) +{ + phylink_set(modes, 2500baseX_Full); +} + static const struct sfp_quirk sfp_quirks[] = { + { + // Alcatel Lucent G-010S-P can operate at 2500base-X, but + // incorrectly report 2500MBd NRZ in their EEPROM + .vendor = "ALCATELLUCENT", + .part = "G010SP", + .modes = sfp_quirk_2500basex, + }, { + // Alcatel Lucent G-010S-A can operate at 2500base-X, but + // report 3.2GBd NRZ in their EEPROM + .vendor = "ALCATELLUCENT", + .part = "3FE46541AA", + .modes = sfp_quirk_2500basex, + }, { + // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd + // NRZ in their EEPROM + .vendor = "HUAWEI", + .part = "MA5671A", + .modes = sfp_quirk_2500basex, + }, }; static size_t sfp_strlen(const char *str, size_t maxlen) -- cgit v1.2.3-59-g8ed1b From f3c9a666b28572b1a0ae691a47d9a7de4d9cefb3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 20 Nov 2019 12:29:59 +0000 Subject: net: sfp: soft status and control support Add support for the soft status and control register, which allows TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We make use of this when the board does not support GPIOs for these signals. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/sfp.c | 110 +++++++++++++++++++++++++++++++++++++++++--------- include/linux/sfp.h | 4 ++ 2 files changed, 94 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index b0f88c2c0153..bdbbb76f8fd3 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -201,7 +201,10 @@ struct sfp { struct gpio_desc *gpio[GPIO_MAX]; int gpio_irq[GPIO_MAX]; + bool need_poll; + struct mutex st_mutex; /* Protects state */ + unsigned int state_soft_mask; unsigned int state; struct delayed_work poll; struct delayed_work timeout; @@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) } /* Interface */ -static unsigned int sfp_get_state(struct sfp *sfp) +static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) { - return sfp->get_state(sfp); + return sfp->read(sfp, a2, addr, buf, len); } -static void sfp_set_state(struct sfp *sfp, unsigned int state) +static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) { - sfp->set_state(sfp, state); + return sfp->write(sfp, a2, addr, buf, len); } -static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) +static unsigned int sfp_soft_get_state(struct sfp *sfp) { - return sfp->read(sfp, a2, addr, buf, len); + unsigned int state = 0; + u8 status; + + if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == + sizeof(status)) { + if (status & SFP_STATUS_RX_LOS) + state |= SFP_F_LOS; + if (status & SFP_STATUS_TX_FAULT) + state |= SFP_F_TX_FAULT; + } + + return state & sfp->state_soft_mask; } -static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) +static void sfp_soft_set_state(struct sfp *sfp, unsigned int state) { - return sfp->write(sfp, a2, addr, buf, len); + u8 status; + + if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) == + sizeof(status)) { + if (state & SFP_F_TX_DISABLE) + status |= SFP_STATUS_TX_DISABLE_FORCE; + else + status &= ~SFP_STATUS_TX_DISABLE_FORCE; + + sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status)); + } +} + +static void sfp_soft_start_poll(struct sfp *sfp) +{ + const struct sfp_eeprom_id *id = &sfp->id; + + sfp->state_soft_mask = 0; + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && + !sfp->gpio[GPIO_TX_DISABLE]) + sfp->state_soft_mask |= SFP_F_TX_DISABLE; + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && + !sfp->gpio[GPIO_TX_FAULT]) + sfp->state_soft_mask |= SFP_F_TX_FAULT; + if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && + !sfp->gpio[GPIO_LOS]) + sfp->state_soft_mask |= SFP_F_LOS; + + if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && + !sfp->need_poll) + mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); +} + +static void sfp_soft_stop_poll(struct sfp *sfp) +{ + sfp->state_soft_mask = 0; +} + +static unsigned int sfp_get_state(struct sfp *sfp) +{ + unsigned int state = sfp->get_state(sfp); + + if (state & SFP_F_PRESENT && + sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) + state |= sfp_soft_get_state(sfp); + + return state; +} + +static void sfp_set_state(struct sfp *sfp, unsigned int state) +{ + sfp->set_state(sfp, state); + + if (state & SFP_F_PRESENT && + sfp->state_soft_mask & SFP_F_TX_DISABLE) + sfp_soft_set_state(sfp, state); } static unsigned int sfp_check(void *buf, size_t len) @@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) } } -static void sfp_sm_mod_init(struct sfp *sfp) -{ - sfp_module_tx_enable(sfp); -} - static void sfp_sm_probe_for_phy(struct sfp *sfp) { /* Setting the serdes link mode is guesswork: there's no @@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) (int)sizeof(id.ext.datecode), id.ext.datecode); /* Check whether we support this module */ - if (!sfp->type->module_supported(&sfp->id)) { + if (!sfp->type->module_supported(&id)) { dev_err(sfp->dev, "module is not supported - phys id 0x%02x 0x%02x\n", sfp->id.base.phys_id, sfp->id.base.phys_ext_id); @@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) if (sfp->mod_phy) sfp_sm_phy_detach(sfp); sfp_module_tx_disable(sfp); + sfp_soft_stop_poll(sfp); sfp_sm_next(sfp, SFP_S_DOWN, 0); return; } @@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) sfp->sm_dev_state != SFP_DEV_UP) break; - sfp_sm_mod_init(sfp); + if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)) + sfp_soft_start_poll(sfp); + + sfp_module_tx_enable(sfp); /* Initialise the fault clearance retries */ sfp->sm_retries = 5; @@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct *work) struct sfp *sfp = container_of(work, struct sfp, poll.work); sfp_check_state(sfp); - mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); + + if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) || + sfp->need_poll) + mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); } static struct sfp *sfp_alloc(struct device *dev) @@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_device *pdev) const struct sff_data *sff; struct i2c_adapter *i2c; struct sfp *sfp; - bool poll = false; int err, i; sfp = sfp_alloc(&pdev->dev); @@ -2183,7 +2253,7 @@ static int sfp_probe(struct platform_device *pdev) sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]); if (!sfp->gpio_irq[i]) { - poll = true; + sfp->need_poll = true; continue; } @@ -2195,11 +2265,11 @@ static int sfp_probe(struct platform_device *pdev) dev_name(sfp->dev), sfp); if (err) { sfp->gpio_irq[i] = 0; - poll = true; + sfp->need_poll = true; } } - if (poll) + if (sfp->need_poll) mod_delayed_work(system_wq, &sfp->poll, poll_jiffies); /* We could have an issue in cases no Tx disable pin is available or diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 3b35efd85bb1..487fd9412d10 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -428,6 +428,10 @@ enum { SFP_TEC_CUR = 0x6c, SFP_STATUS = 0x6e, + SFP_STATUS_TX_DISABLE = BIT(7), + SFP_STATUS_TX_DISABLE_FORCE = BIT(6), + SFP_STATUS_TX_FAULT = BIT(2), + SFP_STATUS_RX_LOS = BIT(1), SFP_ALARM0 = 0x70, SFP_ALARM0_TEMP_HIGH = BIT(7), SFP_ALARM0_TEMP_LOW = BIT(6), -- cgit v1.2.3-59-g8ed1b From 05d6c8cfdbd6cefac6b373bad72775fcc4193c80 Mon Sep 17 00:00:00 2001 From: Markus Theil Date: Wed, 20 Nov 2019 21:05:31 +0100 Subject: mt76: fix fix ampdu locking The current ampdu locking code does not unlock its mutex in the early return case. This patch fixes it. Signed-off-by: Markus Theil Acked-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/mediatek/mt76/mt7603/main.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt7615/main.c | 6 ++++-- drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 281387c3f4f4..962e2822d19f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -569,6 +569,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 ssn = params->ssn; u8 ba_size = params->buf_size; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; @@ -597,7 +598,8 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - return IEEE80211_AMPDU_TX_START_IMMEDIATE; + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1); @@ -606,7 +608,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } mutex_unlock(&dev->mt76.mutex); - return 0; + return ret; } static void diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 240dab919327..070b03403894 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -484,6 +484,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; @@ -513,7 +514,8 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - return IEEE80211_AMPDU_TX_START_IMMEDIATE; + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; mt7615_mcu_set_tx_ba(dev, params, 0); @@ -522,7 +524,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } mutex_unlock(&dev->mt76.mutex); - return 0; + return ret; } const struct ieee80211_ops mt7615_ops = { diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index bdc83838d346..0960fc56b672 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -357,6 +357,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; @@ -386,7 +387,8 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, break; case IEEE80211_AMPDU_TX_START: mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); - return IEEE80211_AMPDU_TX_START_IMMEDIATE; + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); @@ -394,7 +396,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } mutex_unlock(&dev->mt76.mutex); - return 0; + return ret; } EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); -- cgit v1.2.3-59-g8ed1b From 0617aa988dacb9d8c1cb42fbb6c79896c7507e08 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 21 Nov 2019 12:21:46 +0300 Subject: octeontx2-af: Fix uninitialized variable in debugfs If rvu_get_blkaddr() fails, then this rvu_cgx_nix_cuml_stats() returns zero and we write some uninitialized data into the debugfs output. On the error paths, the use of the uninitialized "*stat" is harmless, but it will lead to a Smatch warning (static analysis) and a UBSan warning (runtime analysis) so we should prevent that as well. Fixes: f967488d095e ("octeontx2-af: Add per CGX port level NIX Rx/Tx counters") Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c index 0bbb2eb1446e..11e5921c55b9 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c @@ -608,6 +608,8 @@ int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, u16 pcifunc; int pf, lf; + *stat = 0; + if (!cgxd || !rvu) return -EINVAL; @@ -624,7 +626,6 @@ int rvu_cgx_nix_cuml_stats(struct rvu *rvu, void *cgxd, int lmac_id, return 0; block = &rvu->hw->block[blkaddr]; - *stat = 0; for (lf = 0; lf < block->lf.max; lf++) { /* Check if a lf is attached to this PF or one of its VFs */ if (!((block->fn_map[lf] & ~RVU_PFVF_FUNC_MASK) == (pcifunc & -- cgit v1.2.3-59-g8ed1b From 5421cf84af69a94ebb179fec252f3772c4681cca Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Nov 2019 21:28:28 +0800 Subject: drivers: net: Fix Kconfig indentation, continued Adjust indentation from spaces to tab (+optional two spaces) as in coding style. This fixes various indentation mixups (seven spaces, tab+one space, etc). Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- drivers/net/Kconfig | 64 +++++++++++++------------- drivers/net/caif/Kconfig | 36 +++++++-------- drivers/net/ethernet/freescale/fs_enet/Kconfig | 8 ++-- drivers/net/ieee802154/Kconfig | 12 ++--- drivers/net/wireless/ath/Kconfig | 12 ++--- drivers/net/wireless/ath/ar5523/Kconfig | 14 +++--- drivers/net/wireless/ath/ath9k/Kconfig | 58 +++++++++++------------ drivers/net/wireless/atmel/Kconfig | 42 ++++++++--------- drivers/net/wireless/ralink/rt2x00/Kconfig | 44 +++++++++--------- drivers/net/wireless/ti/wl12xx/Kconfig | 8 ++-- 10 files changed, 149 insertions(+), 149 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index df1c7989e13d..d02f12a5254e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -153,22 +153,22 @@ config IPVLAN_L3S select NET_L3_MASTER_DEV config IPVLAN - tristate "IP-VLAN support" - depends on INET - depends on IPV6 || !IPV6 - ---help--- - This allows one to create virtual devices off of a main interface - and packets will be delivered based on the dest L3 (IPv6/IPv4 addr) - on packets. All interfaces (including the main interface) share L2 - making it transparent to the connected L2 switch. + tristate "IP-VLAN support" + depends on INET + depends on IPV6 || !IPV6 + ---help--- + This allows one to create virtual devices off of a main interface + and packets will be delivered based on the dest L3 (IPv6/IPv4 addr) + on packets. All interfaces (including the main interface) share L2 + making it transparent to the connected L2 switch. - Ipvlan devices can be added using the "ip" command from the - iproute2 package starting with the iproute2-3.19 release: + Ipvlan devices can be added using the "ip" command from the + iproute2 package starting with the iproute2-3.19 release: - "ip link add link [ NAME ] type ipvlan" + "ip link add link [ NAME ] type ipvlan" - To compile this driver as a module, choose M here: the module - will be called ipvlan. + To compile this driver as a module, choose M here: the module + will be called ipvlan. config IPVTAP tristate "IP-VLAN based tap driver" @@ -185,11 +185,11 @@ config IPVTAP will be called ipvtap. config VXLAN - tristate "Virtual eXtensible Local Area Network (VXLAN)" - depends on INET - select NET_UDP_TUNNEL - select GRO_CELLS - ---help--- + tristate "Virtual eXtensible Local Area Network (VXLAN)" + depends on INET + select NET_UDP_TUNNEL + select GRO_CELLS + ---help--- This allows one to create vxlan virtual interfaces that provide Layer 2 Networks over Layer 3 Networks. VXLAN is often used to tunnel virtual network infrastructure in virtualized environments. @@ -200,12 +200,12 @@ config VXLAN will be called vxlan. config GENEVE - tristate "Generic Network Virtualization Encapsulation" - depends on INET - depends on IPV6 || !IPV6 - select NET_UDP_TUNNEL - select GRO_CELLS - ---help--- + tristate "Generic Network Virtualization Encapsulation" + depends on INET + depends on IPV6 || !IPV6 + select NET_UDP_TUNNEL + select GRO_CELLS + ---help--- This allows one to create geneve virtual interfaces that provide Layer 2 Networks over Layer 3 Networks. GENEVE is often used to tunnel virtual network infrastructure in virtualized environments. @@ -244,8 +244,8 @@ config MACSEC config NETCONSOLE tristate "Network console logging support" ---help--- - If you want to log kernel messages over the network, enable this. - See for details. + If you want to log kernel messages over the network, enable this. + See for details. config NETCONSOLE_DYNAMIC bool "Dynamic reconfiguration of logging targets" @@ -362,12 +362,12 @@ config NET_VRF support enables VRF devices. config VSOCKMON - tristate "Virtual vsock monitoring device" - depends on VHOST_VSOCK - ---help--- - This option enables a monitoring net device for vsock sockets. It is - mostly intended for developers or support to debug vsock issues. If - unsure, say N. + tristate "Virtual vsock monitoring device" + depends on VHOST_VSOCK + ---help--- + This option enables a monitoring net device for vsock sockets. It is + mostly intended for developers or support to debug vsock issues. If + unsure, say N. endif # NET_CORE diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index 96d7cef3289f..e74e2bb61236 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -16,37 +16,37 @@ config CAIF_TTY depends on CAIF && TTY default n ---help--- - The CAIF TTY transport driver is a Line Discipline (ldisc) - identified as N_CAIF. When this ldisc is opened from user space - it will redirect the TTY's traffic into the CAIF stack. + The CAIF TTY transport driver is a Line Discipline (ldisc) + identified as N_CAIF. When this ldisc is opened from user space + it will redirect the TTY's traffic into the CAIF stack. config CAIF_SPI_SLAVE tristate "CAIF SPI transport driver for slave interface" depends on CAIF && HAS_DMA default n ---help--- - The CAIF Link layer SPI Protocol driver for Slave SPI interface. - This driver implements a platform driver to accommodate for a - platform specific SPI device. A sample CAIF SPI Platform device is - provided in . + The CAIF Link layer SPI Protocol driver for Slave SPI interface. + This driver implements a platform driver to accommodate for a + platform specific SPI device. A sample CAIF SPI Platform device is + provided in . config CAIF_SPI_SYNC bool "Next command and length in start of frame" depends on CAIF_SPI_SLAVE default n ---help--- - Putting the next command and length in the start of the frame can - help to synchronize to the next transfer in case of over or under-runs. - This option also needs to be enabled on the modem. + Putting the next command and length in the start of the frame can + help to synchronize to the next transfer in case of over or under-runs. + This option also needs to be enabled on the modem. config CAIF_HSI - tristate "CAIF HSI transport driver" - depends on CAIF - default n - ---help--- - The CAIF low level driver for CAIF over HSI. - Be aware that if you enable this then you also need to - enable a low-level HSI driver. + tristate "CAIF HSI transport driver" + depends on CAIF + default n + ---help--- + The CAIF low level driver for CAIF over HSI. + Be aware that if you enable this then you also need to + enable a low-level HSI driver. config CAIF_VIRTIO tristate "CAIF virtio transport driver" @@ -56,7 +56,7 @@ config CAIF_VIRTIO select GENERIC_ALLOCATOR default n ---help--- - The CAIF driver for CAIF over Virtio. + The CAIF driver for CAIF over Virtio. if CAIF_VIRTIO source "drivers/vhost/Kconfig.vringh" diff --git a/drivers/net/ethernet/freescale/fs_enet/Kconfig b/drivers/net/ethernet/freescale/fs_enet/Kconfig index 245d9a68a71f..7f20840fde07 100644 --- a/drivers/net/ethernet/freescale/fs_enet/Kconfig +++ b/drivers/net/ethernet/freescale/fs_enet/Kconfig @@ -1,9 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config FS_ENET - tristate "Freescale Ethernet Driver" - depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x) - select MII - select PHYLIB + tristate "Freescale Ethernet Driver" + depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x) + select MII + select PHYLIB config FS_ENET_MPC5121_FEC def_bool y if (FS_ENET && PPC_MPC512x) diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 8af5b7e9f4ed..c92a62dbf398 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -74,9 +74,9 @@ config IEEE802154_ATUSB The module will be called 'atusb'. config IEEE802154_ADF7242 - tristate "ADF7242 transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 - depends on SPI + tristate "ADF7242 transceiver driver" + depends on IEEE802154_DRIVERS && MAC802154 + depends on SPI ---help--- Say Y here to enable the ADF7242 SPI 802.15.4 wireless controller. @@ -107,9 +107,9 @@ config IEEE802154_CA8210_DEBUGFS management entities. config IEEE802154_MCR20A - tristate "MCR20A transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 - depends on SPI + tristate "MCR20A transceiver driver" + depends on IEEE802154_DRIVERS && MAC802154 + depends on SPI ---help--- Say Y here to enable the MCR20A SPI 802.15.4 wireless controller. diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index 56616d988c96..7b90b8546162 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -30,12 +30,12 @@ config ATH_DEBUG Right now only ath9k makes use of this. config ATH_TRACEPOINTS - bool "Atheros wireless tracing" - depends on ATH_DEBUG - depends on EVENT_TRACING - ---help--- - This option enables tracepoints for atheros wireless drivers. - Currently, ath9k makes use of this facility. + bool "Atheros wireless tracing" + depends on ATH_DEBUG + depends on EVENT_TRACING + ---help--- + This option enables tracepoints for atheros wireless drivers. + Currently, ath9k makes use of this facility. config ATH_REG_DYNAMIC_USER_REG_HINTS bool "Atheros dynamic user regulatory hints" diff --git a/drivers/net/wireless/ath/ar5523/Kconfig b/drivers/net/wireless/ath/ar5523/Kconfig index 65b39c7d035d..e82df5f1ea67 100644 --- a/drivers/net/wireless/ath/ar5523/Kconfig +++ b/drivers/net/wireless/ath/ar5523/Kconfig @@ -1,9 +1,9 @@ # SPDX-License-Identifier: ISC config AR5523 - tristate "Atheros AR5523 wireless driver support" - depends on MAC80211 && USB - select ATH_COMMON - select FW_LOADER - ---help--- - This module add support for AR5523 based USB dongles such as D-Link - DWL-G132, Netgear WPN111 and many more. + tristate "Atheros AR5523 wireless driver support" + depends on MAC80211 && USB + select ATH_COMMON + select FW_LOADER + ---help--- + This module add support for AR5523 based USB dongles such as D-Link + DWL-G132, Netgear WPN111 and many more. diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index c99f42284465..78620c6b64a2 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -144,13 +144,13 @@ config ATH9K_RFKILL a platform that can toggle the RF-Kill GPIO. config ATH9K_CHANNEL_CONTEXT - bool "Channel Context support" - depends on ATH9K - default n - ---help--- - This option enables channel context support in ath9k, which is needed - for multi-channel concurrency. Enable this if P2P PowerSave support - is required. + bool "Channel Context support" + depends on ATH9K + default n + ---help--- + This option enables channel context support in ath9k, which is needed + for multi-channel concurrency. Enable this if P2P PowerSave support + is required. config ATH9K_PCOEM bool "Atheros ath9k support for PC OEM cards" if EXPERT @@ -162,32 +162,32 @@ config ATH9K_PCI_NO_EEPROM depends on ATH9K_PCI default n help - This separate driver provides a loader in order to support the - AR500X to AR92XX-generation of ath9k PCI(e) WiFi chips, which have - their initialization data (which contains the real PCI Device ID - that ath9k will need) stored together with the calibration data out - of reach for the ath9k chip. + This separate driver provides a loader in order to support the + AR500X to AR92XX-generation of ath9k PCI(e) WiFi chips, which have + their initialization data (which contains the real PCI Device ID + that ath9k will need) stored together with the calibration data out + of reach for the ath9k chip. - These devices are usually various network appliances, routers or - access Points and such. + These devices are usually various network appliances, routers or + access Points and such. - If unsure say N. + If unsure say N. config ATH9K_HTC - tristate "Atheros HTC based wireless cards support" - depends on USB && MAC80211 - select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH9K_COMMON - ---help--- - Support for Atheros HTC based cards. - Chipsets supported: AR9271 - - For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc - - The built module will be ath9k_htc. + tristate "Atheros HTC based wireless cards support" + depends on USB && MAC80211 + select ATH9K_HW + select MAC80211_LEDS + select LEDS_CLASS + select NEW_LEDS + select ATH9K_COMMON + ---help--- + Support for Atheros HTC based cards. + Chipsets supported: AR9271 + + For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc + + The built module will be ath9k_htc. config ATH9K_HTC_DEBUGFS bool "Atheros ath9k_htc debugging" diff --git a/drivers/net/wireless/atmel/Kconfig b/drivers/net/wireless/atmel/Kconfig index 4c0556b3a5ba..c2142c70f25d 100644 --- a/drivers/net/wireless/atmel/Kconfig +++ b/drivers/net/wireless/atmel/Kconfig @@ -13,29 +13,29 @@ config WLAN_VENDOR_ATMEL if WLAN_VENDOR_ATMEL config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - ---help--- - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - + tristate "Atmel at76c50x chipset 802.11b support" + depends on CFG80211 && (PCI || PCMCIA) + select WIRELESS_EXT + select WEXT_PRIV + select FW_LOADER + select CRC32 + ---help--- + A driver 802.11b wireless cards based on the Atmel fast-vnet + chips. This driver supports standard Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - ---help--- - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. + tristate "Atmel at76c506 PCI cards" + depends on ATMEL && PCI + ---help--- + Enable support for PCI and mini-PCI cards containing the + Atmel at76c506 chip. config PCMCIA_ATMEL tristate "Atmel at76c502/at76c504 PCMCIA cards" diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index f8a9244ce012..d4969d617822 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -95,20 +95,20 @@ config RT2800PCI_RT35XX config RT2800PCI_RT53XX - bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt53xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT5390 + bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" + default y + ---help--- + This adds support for rt53xx wireless chipset family to the + rt2800pci driver. + Supported chips: RT5390 config RT2800PCI_RT3290 - bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt3290 wireless chipset family to the - rt2800pci driver. - Supported chips: RT3290 + bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)" + default y + ---help--- + This adds support for rt3290 wireless chipset family to the + rt2800pci driver. + Supported chips: RT3290 endif config RT2500USB @@ -174,18 +174,18 @@ config RT2800USB_RT3573 in the rt2800usb driver. config RT2800USB_RT53XX - bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" - ---help--- - This adds support for rt53xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT5370 + bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" + ---help--- + This adds support for rt53xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT5370 config RT2800USB_RT55XX - bool "rt2800usb - Include support for rt55xx devices (EXPERIMENTAL)" - ---help--- - This adds support for rt55xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT5572 + bool "rt2800usb - Include support for rt55xx devices (EXPERIMENTAL)" + ---help--- + This adds support for rt55xx wireless chipset family to the + rt2800usb driver. + Supported chips: RT5572 config RT2800USB_UNKNOWN bool "rt2800usb - Include support for unknown (USB) devices" diff --git a/drivers/net/wireless/ti/wl12xx/Kconfig b/drivers/net/wireless/ti/wl12xx/Kconfig index e409042ee9a0..9c4511604b67 100644 --- a/drivers/net/wireless/ti/wl12xx/Kconfig +++ b/drivers/net/wireless/ti/wl12xx/Kconfig @@ -1,10 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only config WL12XX - tristate "TI wl12xx support" + tristate "TI wl12xx support" depends on MAC80211 - select WLCORE - ---help--- + select WLCORE + ---help--- This module adds support for wireless adapters based on TI wl1271, wl1273, wl1281 and wl1283 chipsets. This module does *not* include support for wl1251. For wl1251 support, use the separate homonymous - driver instead. + driver instead. -- cgit v1.2.3-59-g8ed1b From f145922ddcaa1cb9688b3d053622c98d9f9a7fff Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 20 Nov 2019 16:23:14 +0800 Subject: net: mscc: ocelot: export ocelot_hwstamp_get/set functions Export ocelot_hwstamp_get/set functions so that DSA driver is able to reuse them. Signed-off-by: Yangbo Lu Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 8 ++++---- include/soc/mscc/ocelot.h | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 90c46ba763d7..7302724a9261 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1049,15 +1049,14 @@ static int ocelot_get_port_parent_id(struct net_device *dev, return 0; } -static int ocelot_hwstamp_get(struct ocelot *ocelot, int port, - struct ifreq *ifr) +int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr) { return copy_to_user(ifr->ifr_data, &ocelot->hwtstamp_config, sizeof(ocelot->hwtstamp_config)) ? -EFAULT : 0; } +EXPORT_SYMBOL(ocelot_hwstamp_get); -static int ocelot_hwstamp_set(struct ocelot *ocelot, int port, - struct ifreq *ifr) +int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr) { struct ocelot_port *ocelot_port = ocelot->ports[port]; struct hwtstamp_config cfg; @@ -1120,6 +1119,7 @@ static int ocelot_hwstamp_set(struct ocelot *ocelot, int port, return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } +EXPORT_SYMBOL(ocelot_hwstamp_set); static int ocelot_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index a836afe8f68e..2bac4bc34cf6 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -533,6 +533,8 @@ int ocelot_fdb_del(struct ocelot *ocelot, int port, int ocelot_vlan_add(struct ocelot *ocelot, int port, u16 vid, bool pvid, bool untagged); int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); +int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr); +int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts); -- cgit v1.2.3-59-g8ed1b From e23a7b3e8daa4be3d91544d8ba210f96d2266de9 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 20 Nov 2019 16:23:15 +0800 Subject: net: mscc: ocelot: convert to use ocelot_get_txtstamp() The method getting TX timestamp by reading timestamp FIFO and matching skbs list is common for DSA Felix driver too. So move code out of ocelot_board.c, convert to use ocelot_get_txtstamp() function and export it. Signed-off-by: Yangbo Lu Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 62 ++++++++++++++++++++++++++++++-- drivers/net/ethernet/mscc/ocelot.h | 6 ---- drivers/net/ethernet/mscc/ocelot_board.c | 53 +-------------------------- include/soc/mscc/ocelot.h | 9 ++++- 4 files changed, 69 insertions(+), 61 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 7302724a9261..a58d2ed5b590 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -661,7 +661,8 @@ out: return NETDEV_TX_OK; } -void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts) +static void ocelot_get_hwtimestamp(struct ocelot *ocelot, + struct timespec64 *ts) { unsigned long flags; u32 val; @@ -686,7 +687,64 @@ void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts) spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags); } -EXPORT_SYMBOL(ocelot_get_hwtimestamp); + +void ocelot_get_txtstamp(struct ocelot *ocelot) +{ + int budget = OCELOT_PTP_QUEUE_SZ; + + while (budget--) { + struct skb_shared_hwtstamps shhwtstamps; + struct list_head *pos, *tmp; + struct sk_buff *skb = NULL; + struct ocelot_skb *entry; + struct ocelot_port *port; + struct timespec64 ts; + u32 val, id, txport; + + val = ocelot_read(ocelot, SYS_PTP_STATUS); + + /* Check if a timestamp can be retrieved */ + if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD)) + break; + + WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL); + + /* Retrieve the ts ID and Tx port */ + id = SYS_PTP_STATUS_PTP_MESS_ID_X(val); + txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val); + + /* Retrieve its associated skb */ + port = ocelot->ports[txport]; + + list_for_each_safe(pos, tmp, &port->skbs) { + entry = list_entry(pos, struct ocelot_skb, head); + if (entry->id != id) + continue; + + skb = entry->skb; + + list_del(pos); + kfree(entry); + } + + /* Next ts */ + ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); + + if (unlikely(!skb)) + continue; + + /* Get the h/w timestamp */ + ocelot_get_hwtimestamp(ocelot, &ts); + + /* Set the timestamp into the skb */ + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + skb_tstamp_tx(skb, &shhwtstamps); + + dev_kfree_skb_any(skb); + } +} +EXPORT_SYMBOL(ocelot_get_txtstamp); static int ocelot_mc_unsync(struct net_device *dev, const unsigned char *addr) { diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 32fef4f495aa..c259114c48fd 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -74,12 +74,6 @@ struct ocelot_port_private { struct ocelot_port_tc tc; }; -struct ocelot_skb { - struct list_head head; - struct sk_buff *skb; - u8 id; -}; - u32 ocelot_port_readl(struct ocelot_port *port, u32 reg); void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg); diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 5541ec26f953..2da8eee27e98 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -190,60 +190,9 @@ static irqreturn_t ocelot_xtr_irq_handler(int irq, void *arg) static irqreturn_t ocelot_ptp_rdy_irq_handler(int irq, void *arg) { - int budget = OCELOT_PTP_QUEUE_SZ; struct ocelot *ocelot = arg; - while (budget--) { - struct skb_shared_hwtstamps shhwtstamps; - struct list_head *pos, *tmp; - struct sk_buff *skb = NULL; - struct ocelot_skb *entry; - struct ocelot_port *port; - struct timespec64 ts; - u32 val, id, txport; - - val = ocelot_read(ocelot, SYS_PTP_STATUS); - - /* Check if a timestamp can be retrieved */ - if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD)) - break; - - WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL); - - /* Retrieve the ts ID and Tx port */ - id = SYS_PTP_STATUS_PTP_MESS_ID_X(val); - txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val); - - /* Retrieve its associated skb */ - port = ocelot->ports[txport]; - - list_for_each_safe(pos, tmp, &port->skbs) { - entry = list_entry(pos, struct ocelot_skb, head); - if (entry->id != id) - continue; - - skb = entry->skb; - - list_del(pos); - kfree(entry); - } - - /* Next ts */ - ocelot_write(ocelot, SYS_PTP_NXT_PTP_NXT, SYS_PTP_NXT); - - if (unlikely(!skb)) - continue; - - /* Get the h/w timestamp */ - ocelot_get_hwtimestamp(ocelot, &ts); - - /* Set the timestamp into the skb */ - memset(&shhwtstamps, 0, sizeof(shhwtstamps)); - shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); - skb_tstamp_tx(skb, &shhwtstamps); - - dev_kfree_skb_any(skb); - } + ocelot_get_txtstamp(ocelot); return IRQ_HANDLED; } diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 2bac4bc34cf6..1a5cb1b2ac5d 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -406,6 +406,13 @@ struct ocelot_ops { int (*reset)(struct ocelot *ocelot); }; +struct ocelot_skb { + struct list_head head; + struct sk_buff *skb; + u8 id; +}; + + struct ocelot_port { struct ocelot *ocelot; @@ -536,6 +543,6 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); -void ocelot_get_hwtimestamp(struct ocelot *ocelot, struct timespec64 *ts); +void ocelot_get_txtstamp(struct ocelot *ocelot); #endif -- cgit v1.2.3-59-g8ed1b From 400928bf928be153cddd76d9ac4e39978cb43fd3 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 20 Nov 2019 16:23:16 +0800 Subject: net: mscc: ocelot: convert to use ocelot_port_add_txtstamp_skb() Convert to use ocelot_port_add_txtstamp_skb() for adding skbs which require TX timestamp into list. Export it so that DSA Felix driver could reuse it too. Signed-off-by: Yangbo Lu Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/mscc/ocelot.c | 43 ++++++++++++++++++++++++-------------- include/soc/mscc/ocelot.h | 2 ++ 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index a58d2ed5b590..0e96ffab3b05 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -575,6 +575,32 @@ static int ocelot_gen_ifh(u32 *ifh, struct frame_info *info) return 0; } +int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, + struct sk_buff *skb) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct ocelot *ocelot = ocelot_port->ocelot; + + if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && + ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { + struct ocelot_skb *oskb = + kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC); + + if (unlikely(!oskb)) + return -ENOMEM; + + shinfo->tx_flags |= SKBTX_IN_PROGRESS; + + oskb->skb = skb; + oskb->id = ocelot_port->ts_id % 4; + + list_add_tail(&oskb->head, &ocelot_port->skbs); + return 0; + } + return -ENODATA; +} +EXPORT_SYMBOL(ocelot_port_add_txtstamp_skb); + static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) { struct ocelot_port_private *priv = netdev_priv(dev); @@ -637,26 +663,11 @@ static int ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; - if (ocelot->ptp && shinfo->tx_flags & SKBTX_HW_TSTAMP && - ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { - struct ocelot_skb *oskb = - kzalloc(sizeof(struct ocelot_skb), GFP_ATOMIC); - - if (unlikely(!oskb)) - goto out; - - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; - - oskb->skb = skb; - oskb->id = ocelot_port->ts_id % 4; + if (!ocelot_port_add_txtstamp_skb(ocelot_port, skb)) { ocelot_port->ts_id++; - - list_add_tail(&oskb->head, &ocelot_port->skbs); - return NETDEV_TX_OK; } -out: dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 1a5cb1b2ac5d..e1108a5f4f17 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -543,6 +543,8 @@ int ocelot_vlan_del(struct ocelot *ocelot, int port, u16 vid); int ocelot_hwstamp_get(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr); int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); +int ocelot_port_add_txtstamp_skb(struct ocelot_port *ocelot_port, + struct sk_buff *skb); void ocelot_get_txtstamp(struct ocelot *ocelot); #endif -- cgit v1.2.3-59-g8ed1b From 5df66c48bc4e4019f92a8c62d0b74a97d102ba8d Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 20 Nov 2019 16:23:17 +0800 Subject: net: dsa: ocelot: define PTP registers for felix_vsc9959 This patch is to define PTP registers for felix_vsc9959. Signed-off-by: Yangbo Lu Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix_vsc9959.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index d67bd14a48e0..b9758b0d18c7 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -282,6 +282,16 @@ static const u32 vsc9959_sys_regmap[] = { REG_RESERVED(SYS_CM_DATA), }; +static const u32 vsc9959_ptp_regmap[] = { + REG(PTP_PIN_CFG, 0x000000), + REG(PTP_PIN_TOD_SEC_MSB, 0x000004), + REG(PTP_PIN_TOD_SEC_LSB, 0x000008), + REG(PTP_PIN_TOD_NSEC, 0x00000c), + REG(PTP_CFG_MISC, 0x0000a0), + REG(PTP_CLK_CFG_ADJ_CFG, 0x0000a4), + REG(PTP_CLK_CFG_ADJ_FREQ, 0x0000a8), +}; + static const u32 vsc9959_gcb_regmap[] = { REG(GCB_SOFT_RST, 0x000004), }; @@ -293,6 +303,7 @@ static const u32 *vsc9959_regmap[] = { [REW] = vsc9959_rew_regmap, [SYS] = vsc9959_sys_regmap, [S2] = vsc9959_s2_regmap, + [PTP] = vsc9959_ptp_regmap, [GCB] = vsc9959_gcb_regmap, }; @@ -330,6 +341,11 @@ static struct resource vsc9959_target_io_res[] = { .end = 0x00603ff, .name = "s2", }, + [PTP] = { + .start = 0x0090000, + .end = 0x00900cb, + .name = "ptp", + }, [GCB] = { .start = 0x0070000, .end = 0x00701ff, -- cgit v1.2.3-59-g8ed1b From c0bcf537667cf88bbcbb377d01d2b79c45265741 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Wed, 20 Nov 2019 16:23:18 +0800 Subject: net: dsa: ocelot: add hardware timestamping support for Felix This patch is to reuse ocelot functions as possible to enable PTP clock and to support hardware timestamping on Felix. On TX path, timestamping works on packet which requires timestamp. The injection header will be configured accordingly, and skb clone requires timestamp will be added into a list. The TX timestamp is final handled in threaded interrupt handler when PTP timestamp FIFO is ready. On RX path, timestamping is always working. The RX timestamp could be got from extraction header. Signed-off-by: Yangbo Lu Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 89 ++++++++++++++++++++++++++++++++++++++++++ net/dsa/tag_ocelot.c | 14 ++++++- 2 files changed, 102 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index ce3637b504dd..167e41549cdd 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -3,6 +3,7 @@ */ #include #include +#include #include #include #include @@ -303,6 +304,62 @@ static void felix_teardown(struct dsa_switch *ds) ocelot_deinit(ocelot); } +static int felix_hwtstamp_get(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_hwstamp_get(ocelot, port, ifr); +} + +static int felix_hwtstamp_set(struct dsa_switch *ds, int port, + struct ifreq *ifr) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_hwstamp_set(ocelot, port, ifr); +} + +static bool felix_rxtstamp(struct dsa_switch *ds, int port, + struct sk_buff *skb, unsigned int type) +{ + struct skb_shared_hwtstamps *shhwtstamps; + struct ocelot *ocelot = ds->priv; + u8 *extraction = skb->data - ETH_HLEN - OCELOT_TAG_LEN; + u32 tstamp_lo, tstamp_hi; + struct timespec64 ts; + u64 tstamp, val; + + ocelot_ptp_gettime64(&ocelot->ptp_info, &ts); + tstamp = ktime_set(ts.tv_sec, ts.tv_nsec); + + packing(extraction, &val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0); + tstamp_lo = (u32)val; + + tstamp_hi = tstamp >> 32; + if ((tstamp & 0xffffffff) < tstamp_lo) + tstamp_hi--; + + tstamp = ((u64)tstamp_hi << 32) | tstamp_lo; + + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); + shhwtstamps->hwtstamp = tstamp; + return false; +} + +bool felix_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *clone, unsigned int type) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + if (!ocelot_port_add_txtstamp_skb(ocelot_port, clone)) + return true; + + return false; +} + static const struct dsa_switch_ops felix_switch_ops = { .get_tag_protocol = felix_get_tag_protocol, .setup = felix_setup, @@ -325,12 +382,33 @@ static const struct dsa_switch_ops felix_switch_ops = { .port_vlan_filtering = felix_vlan_filtering, .port_vlan_add = felix_vlan_add, .port_vlan_del = felix_vlan_del, + .port_hwtstamp_get = felix_hwtstamp_get, + .port_hwtstamp_set = felix_hwtstamp_set, + .port_rxtstamp = felix_rxtstamp, + .port_txtstamp = felix_txtstamp, }; static struct felix_info *felix_instance_tbl[] = { [FELIX_INSTANCE_VSC9959] = &felix_info_vsc9959, }; +static irqreturn_t felix_irq_handler(int irq, void *data) +{ + struct ocelot *ocelot = (struct ocelot *)data; + + /* The INTB interrupt is used for both PTP TX timestamp interrupt + * and preemption status change interrupt on each port. + * + * - Get txtstamp if have + * - TODO: handle preemption. Without handling it, driver may get + * interrupt storm. + */ + + ocelot_get_txtstamp(ocelot); + + return IRQ_HANDLED; +} + static int felix_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -372,6 +450,16 @@ static int felix_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); + err = devm_request_threaded_irq(&pdev->dev, pdev->irq, NULL, + &felix_irq_handler, IRQF_ONESHOT, + "felix-intb", ocelot); + if (err) { + dev_err(&pdev->dev, "Failed to request irq\n"); + goto err_alloc_irq; + } + + ocelot->ptp = 1; + ds = kzalloc(sizeof(struct dsa_switch), GFP_KERNEL); if (!ds) { err = -ENOMEM; @@ -396,6 +484,7 @@ static int felix_pci_probe(struct pci_dev *pdev, err_register_ds: kfree(ds); err_alloc_ds: +err_alloc_irq: err_alloc_felix: kfree(felix); err_dma: diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c index 078d4790669d..8e3e7283d430 100644 --- a/net/dsa/tag_ocelot.c +++ b/net/dsa/tag_ocelot.c @@ -137,9 +137,11 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, struct net_device *netdev) { struct dsa_port *dp = dsa_slave_to_port(netdev); - u64 bypass, dest, src, qos_class; + u64 bypass, dest, src, qos_class, rew_op; struct dsa_switch *ds = dp->ds; int port = dp->index; + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; u8 *injection; if (unlikely(skb_cow_head(skb, OCELOT_TAG_LEN) < 0)) { @@ -161,6 +163,16 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, packing(injection, &src, 46, 43, OCELOT_TAG_LEN, PACK, 0); packing(injection, &qos_class, 19, 17, OCELOT_TAG_LEN, PACK, 0); + if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { + rew_op = ocelot_port->ptp_cmd; + if (ocelot_port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) { + rew_op |= (ocelot_port->ts_id % 4) << 3; + ocelot_port->ts_id++; + } + + packing(injection, &rew_op, 125, 117, OCELOT_TAG_LEN, PACK, 0); + } + return skb; } -- cgit v1.2.3-59-g8ed1b From 13baf667fa8e23aed12516776de6e50f7617820a Mon Sep 17 00:00:00 2001 From: Mao Wenan Date: Fri, 22 Nov 2019 10:52:40 +0800 Subject: enetc: make enetc_setup_tc_mqprio static While using ARCH=mips CROSS_COMPILE=mips-linux-gnu- command to compile, make C=2 drivers/net/ethernet/freescale/enetc/enetc.o one warning can be found: drivers/net/ethernet/freescale/enetc/enetc.c:1439:5: warning: symbol 'enetc_setup_tc_mqprio' was not declared. Should it be static? This patch make symbol enetc_setup_tc_mqprio static. Fixes: 34c6adf1977b ("enetc: Configure the Time-Aware Scheduler via tc-taprio offload") Signed-off-by: Mao Wenan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/enetc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index f6b00c68451b..27f6fd1708f0 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1436,7 +1436,7 @@ int enetc_close(struct net_device *ndev) return 0; } -int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) +static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) { struct enetc_ndev_priv *priv = netdev_priv(ndev); struct tc_mqprio_qopt *mqprio = type_data; -- cgit v1.2.3-59-g8ed1b From bc71d8b580ba81b55b6e15b1c0320632515b4bac Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Thu, 21 Nov 2019 12:26:45 +0000 Subject: virt_wifi: fix use-after-free in virt_wifi_newlink() When virt_wifi interface is created, virt_wifi_newlink() is called and it calls register_netdevice(). if register_netdevice() fails, it internally would call ->priv_destructor(), which is virt_wifi_net_device_destructor() and it frees netdev. but virt_wifi_newlink() still use netdev. So, use-after-free would occur in virt_wifi_newlink(). Test commands: ip link add dummy0 type dummy modprobe bonding ip link add bonding_masters link dummy0 type virt_wifi Splat looks like: [ 202.220554] BUG: KASAN: use-after-free in virt_wifi_newlink+0x88b/0x9a0 [virt_wifi] [ 202.221659] Read of size 8 at addr ffff888061629cb8 by task ip/852 [ 202.222896] CPU: 1 PID: 852 Comm: ip Not tainted 5.4.0-rc5 #3 [ 202.223765] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 202.225073] Call Trace: [ 202.225532] dump_stack+0x7c/0xbb [ 202.226869] print_address_description.constprop.5+0x1be/0x360 [ 202.229362] __kasan_report+0x12a/0x16f [ 202.230714] kasan_report+0xe/0x20 [ 202.232595] virt_wifi_newlink+0x88b/0x9a0 [virt_wifi] [ 202.233370] __rtnl_newlink+0xb9f/0x11b0 [ 202.244909] rtnl_newlink+0x65/0x90 [ ... ] Cc: stable@vger.kernel.org Fixes: c7cdba31ed8b ("mac80211-next: rtnetlink wifi simulation device") Signed-off-by: Taehee Yoo Link: https://lore.kernel.org/r/20191121122645.9355-1-ap420073@gmail.com [trim stack dump a bit] Signed-off-by: Johannes Berg --- drivers/net/wireless/virt_wifi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index 7997cc6de334..01305ba2d3aa 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c @@ -450,7 +450,6 @@ static void virt_wifi_net_device_destructor(struct net_device *dev) */ kfree(dev->ieee80211_ptr); dev->ieee80211_ptr = NULL; - free_netdev(dev); } /* No lock interaction. */ @@ -458,7 +457,7 @@ static void virt_wifi_setup(struct net_device *dev) { ether_setup(dev); dev->netdev_ops = &virt_wifi_ops; - dev->priv_destructor = virt_wifi_net_device_destructor; + dev->needs_free_netdev = true; } /* Called in a RCU read critical section from netif_receive_skb */ @@ -544,6 +543,7 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev, goto unregister_netdev; } + dev->priv_destructor = virt_wifi_net_device_destructor; priv->being_deleted = false; priv->is_connected = false; priv->is_up = false; -- cgit v1.2.3-59-g8ed1b From 3243e04ab1c06e7cb1402aff609c83de97956489 Mon Sep 17 00:00:00 2001 From: Chen Wandun Date: Fri, 22 Nov 2019 20:32:45 +0800 Subject: net: dsa: ocelot: fix "should it be static?" warnings Fix following sparse warnings: drivers/net/dsa/ocelot/felix.c:351:6: warning: symbol 'felix_txtstamp' was not declared. Should it be static? Signed-off-by: Chen Wandun Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 167e41549cdd..b7f92464815d 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -348,8 +348,8 @@ static bool felix_rxtstamp(struct dsa_switch *ds, int port, return false; } -bool felix_txtstamp(struct dsa_switch *ds, int port, - struct sk_buff *clone, unsigned int type) +static bool felix_txtstamp(struct dsa_switch *ds, int port, + struct sk_buff *clone, unsigned int type) { struct ocelot *ocelot = ds->priv; struct ocelot_port *ocelot_port = ocelot->ports[port]; -- cgit v1.2.3-59-g8ed1b From eae1bbb2a4519ad6c920a061dc49035ab5c36f1f Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 8 Nov 2019 06:23:17 -0800 Subject: ice: Store number of functions for the device Store the number of functions the device has and use this number when setting safe mode capabilities instead of calculating it. Signed-off-by: Bruce Allan Co-developed-by: Kevin Scott Signed-off-by: Kevin Scott Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 21 ++++++++++----------- drivers/net/ethernet/intel/ice/ice_type.h | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 36be501ae623..e92eaec19c83 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1673,6 +1673,10 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, ice_debug(hw, ICE_DBG_INIT, "%s: valid_functions (bitmap) = %d\n", prefix, caps->valid_functions); + + /* store func count for resource management purposes */ + if (dev_p) + dev_p->num_funcs = hweight32(number); break; case ICE_AQC_CAPS_SRIOV: caps->sr_iov_1_1 = (number == 1); @@ -1875,8 +1879,7 @@ void ice_set_safe_mode_caps(struct ice_hw *hw) struct ice_hw_dev_caps *dev_caps = &hw->dev_caps; u32 valid_func, rxq_first_id, txq_first_id; u32 msix_vector_first_id, max_mtu; - u32 num_func = 0; - u8 i; + u32 num_funcs; /* cache some func_caps values that should be restored after memset */ valid_func = func_caps->common_cap.valid_functions; @@ -1909,6 +1912,7 @@ void ice_set_safe_mode_caps(struct ice_hw *hw) rxq_first_id = dev_caps->common_cap.rxq_first_id; msix_vector_first_id = dev_caps->common_cap.msix_vector_first_id; max_mtu = dev_caps->common_cap.max_mtu; + num_funcs = dev_caps->num_funcs; /* unset dev capabilities */ memset(dev_caps, 0, sizeof(*dev_caps)); @@ -1919,19 +1923,14 @@ void ice_set_safe_mode_caps(struct ice_hw *hw) dev_caps->common_cap.rxq_first_id = rxq_first_id; dev_caps->common_cap.msix_vector_first_id = msix_vector_first_id; dev_caps->common_cap.max_mtu = max_mtu; - - /* valid_func is a bitmap. get number of functions */ -#define ICE_MAX_FUNCS 8 - for (i = 0; i < ICE_MAX_FUNCS; i++) - if (valid_func & BIT(i)) - num_func++; + dev_caps->num_funcs = num_funcs; /* one Tx and one Rx queue per function in safe mode */ - dev_caps->common_cap.num_rxq = num_func; - dev_caps->common_cap.num_txq = num_func; + dev_caps->common_cap.num_rxq = num_funcs; + dev_caps->common_cap.num_txq = num_funcs; /* two MSIX vectors per function */ - dev_caps->common_cap.num_msix_vectors = 2 * num_func; + dev_caps->common_cap.num_msix_vectors = 2 * num_funcs; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index eba8b04b8cbd..c4854a987130 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -202,6 +202,7 @@ struct ice_hw_dev_caps { struct ice_hw_common_caps common_cap; u32 num_vfs_exposed; /* Total number of VFs exposed */ u32 num_vsi_allocd_to_host; /* Excluding EMP VSI */ + u32 num_funcs; }; /* MAC info */ -- cgit v1.2.3-59-g8ed1b From 9164f761c99493a947dcbf3889a157943b46e738 Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 8 Nov 2019 06:23:18 -0800 Subject: ice: Correct capabilities reporting of max TCs Firmware always returns 8 as the max number of supported TCs. However on devices with more than 4 ports, the maximum number of TCs per port is limited to 4. Check and, if necessary, correct the reporting of capabilities for devices with more than 4 ports. Signed-off-by: Bruce Allan Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index e92eaec19c83..fb1d930470c7 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1783,6 +1783,18 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count, break; } } + + /* Re-calculate capabilities that are dependent on the number of + * physical ports; i.e. some features are not supported or function + * differently on devices with more than 4 ports. + */ + if (hw->dev_caps.num_funcs > 4) { + /* Max 4 TCs per port */ + caps->maxtc = 4; + ice_debug(hw, ICE_DBG_INIT, + "%s: maxtc = %d (based on #ports)\n", prefix, + caps->maxtc); + } } /** -- cgit v1.2.3-59-g8ed1b From d4bc4e2d6b57712206abfc4e7751ff629b713070 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Nov 2019 06:23:19 -0800 Subject: ice: Disallow VF VLAN opcodes if VLAN offloads disabled Currently if the host disables VLAN offloads on the VF by not setting the VIRTCHNL_VF_OFFLOAD_VLAN capability bit we will still honor VF VLAN configuration messages over VIRTCHNL. These messages (i.e. enable/disable VLAN stripping and VLAN filtering) should be blocked when the feature is not supported. Fix that by adding a helper function to determine if the VF is allowed to do VLAN operations based on the host's VF configuration. Also, mirror the VF communicated capabilities in the host's VF configuration. Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 2ac83ad3d1a6..3cb394bdfe51 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1686,6 +1686,9 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) ether_addr_copy(vfres->vsi_res[0].default_mac_addr, vf->dflt_lan_addr.addr); + /* match guest capabilities */ + vf->driver_caps = vfres->vf_cap_flags; + set_bit(ICE_VF_STATE_ACTIVE, vf->vf_states); err: @@ -2653,6 +2656,17 @@ error_set_pvid: return ret; } +/** + * ice_vf_vlan_offload_ena - determine if capabilities support VLAN offloads + * @caps: VF driver negotiated capabilities + * + * Return true if VIRTCHNL_VF_OFFLOAD_VLAN capability is set, else return false + */ +static bool ice_vf_vlan_offload_ena(u32 caps) +{ + return !!(caps & VIRTCHNL_VF_OFFLOAD_VLAN); +} + /** * ice_vc_process_vlan_msg * @vf: pointer to the VF info @@ -2679,6 +2693,11 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) goto error_param; } + if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + if (!ice_vc_isvalid_vsi_id(vf, vfl->vsi_id)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; @@ -2864,6 +2883,11 @@ static int ice_vc_ena_vlan_stripping(struct ice_vf *vf) goto error_param; } + if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + vsi = pf->vsi[vf->lan_vsi_idx]; if (ice_vsi_manage_vlan_stripping(vsi, true)) v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2890,6 +2914,11 @@ static int ice_vc_dis_vlan_stripping(struct ice_vf *vf) goto error_param; } + if (!ice_vf_vlan_offload_ena(vf->driver_caps)) { + v_ret = VIRTCHNL_STATUS_ERR_PARAM; + goto error_param; + } + vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; -- cgit v1.2.3-59-g8ed1b From 2f9ec2419820350ee70b49a3c4feaa5b7b242f33 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Nov 2019 06:23:20 -0800 Subject: ice: Don't modify stripping for add/del VLANs on VF Currently when adding/deleting vlans in ice_vc_process_vlan_msg() we are calling ice_vsi_manage_vlan_stripping() to enable/disable when adding and deleting a VLAN respectively. This is wrong because adding/deleting VLANs has nothing to do with configuring VLAN stripping. VLAN stripping is configured through the following VIRTCHNL operations: VIRTCHNL_OP_ENABLE_VLAN_STRIPPING VIRTCHNL_OP_DISABLE_VLAN_STRIPPING Unfortunately we can't just remove this because then stripping will never be configured on VF initialization. Fix this by adding a new function that initializes (disables/enables) VLAN stripping for the VF based on the device supported capabilities. This allows us to remove the call to ice_vsi_manage_vlan_stripping() in ice_vc_process_vlan_msg(). Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 39 +++++++++++++++++++----- 1 file changed, 31 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 3cb394bdfe51..fd419230a6c0 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -2735,14 +2735,6 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) goto error_param; } - if (ice_vsi_manage_vlan_stripping(vsi, add_v)) { - dev_err(&pf->pdev->dev, - "%sable VLAN stripping failed for VSI %i\n", - add_v ? "en" : "dis", vsi->vsi_num); - v_ret = VIRTCHNL_STATUS_ERR_PARAM; - goto error_param; - } - if (test_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states) || test_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states)) vlan_promisc = true; @@ -2933,6 +2925,33 @@ error_param: v_ret, NULL, 0); } +/** + * ice_vf_init_vlan_stripping - enable/disable VLAN stripping on initialization + * @vf: VF to enable/disable VLAN stripping for on initialization + * + * If the VIRTCHNL_VF_OFFLOAD_VLAN flag is set enable VLAN stripping, else if + * the flag is cleared then we want to disable stripping. For example, the flag + * will be cleared when port VLANs are configured by the administrator before + * passing the VF to the guest or if the AVF driver doesn't support VLAN + * offloads. + */ +static int ice_vf_init_vlan_stripping(struct ice_vf *vf) +{ + struct ice_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx]; + + if (!vsi) + return -EINVAL; + + /* don't modify stripping if port VLAN is configured */ + if (vsi->info.pvid) + return 0; + + if (ice_vf_vlan_offload_ena(vf->driver_caps)) + return ice_vsi_manage_vlan_stripping(vsi, true); + else + return ice_vsi_manage_vlan_stripping(vsi, false); +} + /** * ice_vc_process_vf_msg - Process request from VF * @pf: pointer to the PF structure @@ -2987,6 +3006,10 @@ error_handler: break; case VIRTCHNL_OP_GET_VF_RESOURCES: err = ice_vc_get_vf_res_msg(vf, msg); + if (ice_vf_init_vlan_stripping(vf)) + dev_err(&pf->pdev->dev, + "Failed to initialize VLAN stripping for VF %d\n", + vf->vf_id); ice_vc_notify_vf_link_state(vf); break; case VIRTCHNL_OP_RESET_VF: -- cgit v1.2.3-59-g8ed1b From 949375de945f7042df2b6488228a1a2b36e69f35 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 8 Nov 2019 06:23:21 -0800 Subject: ice: fix stack leakage In the case of an invalid virtchannel request the driver would return uninitialized data to the VF from the PF stack which is a bug. Fix by initializing the stack variable earlier in the function before any return paths can be taken. Fixes: 1071a8358a28 ("ice: Implement virtchnl commands for AVF support") Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index fd419230a6c0..f8d26674cf5a 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -1886,8 +1886,8 @@ static int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg) enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; struct virtchnl_queue_select *vqs = (struct virtchnl_queue_select *)msg; + struct ice_eth_stats stats = { 0 }; struct ice_pf *pf = vf->pf; - struct ice_eth_stats stats; struct ice_vsi *vsi; if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { @@ -1906,7 +1906,6 @@ static int ice_vc_get_stats_msg(struct ice_vf *vf, u8 *msg) goto error_param; } - memset(&stats, 0, sizeof(struct ice_eth_stats)); ice_update_eth_stats(vsi); stats = vsi->eth_stats; -- cgit v1.2.3-59-g8ed1b From 1f9639d2fb9188a59acafae9dea626391c442a8d Mon Sep 17 00:00:00 2001 From: Akeem G Abodunrin Date: Fri, 8 Nov 2019 06:23:22 -0800 Subject: ice: Only disable VF state when freeing each VF resources It is wrong to set PF disable state flag for all VFs when freeing VF resources - Instead, we should set VF disable state flag for each VF with its resources being returned to the device. Right now, all VF opcodes, mailbox communication to clear its resources as well fails - since we already indicate that PF is in disable state, with all VFs not active. In addition, we don't need to notify VF that PF is intending to reset it, if it is already in disabled state. Signed-off-by: Akeem G Abodunrin Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index f8d26674cf5a..869111a45d61 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -318,8 +318,9 @@ void ice_free_vfs(struct ice_pf *pf) pf->num_alloc_vfs = 0; for (i = 0; i < tmp; i++) { if (test_bit(ICE_VF_STATE_INIT, pf->vf[i].vf_states)) { - /* disable VF qp mappings */ + /* disable VF qp mappings and set VF disable state */ ice_dis_vf_mappings(&pf->vf[i]); + set_bit(ICE_VF_STATE_DIS, pf->vf[i].vf_states); ice_free_vf_res(&pf->vf[i]); } } @@ -1303,9 +1304,12 @@ static void ice_vc_notify_vf_reset(struct ice_vf *vf) if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) return; - /* verify if the VF is in either init or active before proceeding */ - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && - !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) + /* Bail out if VF is in disabled state, neither initialized, nor active + * state - otherwise proceed with notifications + */ + if ((!test_bit(ICE_VF_STATE_INIT, vf->vf_states) && + !test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) || + test_bit(ICE_VF_STATE_DIS, vf->vf_states)) return; pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; -- cgit v1.2.3-59-g8ed1b From e25f9152bc07de534b2b590ce6c052ea25dd8900 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Nov 2019 06:23:23 -0800 Subject: ice: Fix setting coalesce to handle DCB configuration Currently there can be a case where a DCB map is applied and there are more interrupt vectors (vsi->num_q_vectors) than Rx queues (vsi->num_rxq) and Tx queues (vsi->num_txq). If we try to set coalesce settings in this case it will report a false failure. Fix this by checking if vector index is valid with respect to the number of Tx and Rx queues configured. Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 1f00091f7906..6c796c5c8edf 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3420,10 +3420,17 @@ __ice_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, struct ice_vsi *vsi = np->vsi; if (q_num < 0) { - int i; + int v_idx; + + ice_for_each_q_vector(vsi, v_idx) { + /* In some cases if DCB is configured the num_[rx|tx]q + * can be less than vsi->num_q_vectors. This check + * accounts for that so we don't report a false failure + */ + if (v_idx >= vsi->num_rxq && v_idx >= vsi->num_txq) + goto set_complete; - ice_for_each_q_vector(vsi, i) { - if (ice_set_q_coalesce(vsi, ec, i)) + if (ice_set_q_coalesce(vsi, ec, v_idx)) return -EINVAL; } goto set_complete; -- cgit v1.2.3-59-g8ed1b From 1bc7a4ab85ba0d874b193f2812a5e14e1ec6e9af Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Nov 2019 06:23:24 -0800 Subject: ice: Refactor removal of VLAN promiscuous rules Currently ice_clear_vsi_promisc() detects if the VLAN ID sent is not 0 and sets the recipe_id to ICE_SW_LKUP_PROMISC_VLAN in that case and ICE_SW_LKUP_PROMISC if the VLAN_ID is 0. However this doesn't allow VLAN 0 promiscuous rules to be removed, but they can be added. Fix this by checking if the promisc_mask contains ICE_PROMISC_VLAN_RX or ICE_PROMISC_VLAN_TX. This change was made to match what is being done for ice_set_vsi_promisc(). Signed-off-by: Brett Creeley Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_switch.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index 77d211ea3aae..b5a53f862a83 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -2428,7 +2428,7 @@ ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, if (!ice_is_vsi_valid(hw, vsi_handle)) return ICE_ERR_PARAM; - if (vid) + if (promisc_mask & (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX)) recipe_id = ICE_SW_LKUP_PROMISC_VLAN; else recipe_id = ICE_SW_LKUP_PROMISC; @@ -2440,13 +2440,18 @@ ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, mutex_lock(rule_lock); list_for_each_entry(itr, rule_head, list_entry) { + struct ice_fltr_info *fltr_info; u8 fltr_promisc_mask = 0; if (!ice_vsi_uses_fltr(itr, vsi_handle)) continue; + fltr_info = &itr->fltr_info; + + if (recipe_id == ICE_SW_LKUP_PROMISC_VLAN && + vid != fltr_info->l_data.mac_vlan.vlan_id) + continue; - fltr_promisc_mask |= - ice_determine_promisc_mask(&itr->fltr_info); + fltr_promisc_mask |= ice_determine_promisc_mask(fltr_info); /* Skip if filter is not completely specified by given mask */ if (fltr_promisc_mask & ~promisc_mask) @@ -2454,7 +2459,7 @@ ice_clear_vsi_promisc(struct ice_hw *hw, u16 vsi_handle, u8 promisc_mask, status = ice_add_entry_to_vsi_fltr_list(hw, vsi_handle, &remove_list_head, - &itr->fltr_info); + fltr_info); if (status) { mutex_unlock(rule_lock); goto free_fltr_list; -- cgit v1.2.3-59-g8ed1b From 9efe35d0db84cb7189e4a2c3d6a50eefd4380ff9 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Date: Fri, 8 Nov 2019 06:23:25 -0800 Subject: ice: Do not use devm* functions for local uses In situations where we alloc and free memory within the same function do not use the devm_* variants; use regular alloc and free functions. Remove any unused vars if there are no usages after these changes. Also, replace an allocate and copy with kmemdup() and remove an unnecessary memset() to 0 after a kzalloc(). Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 25 ++++++----- drivers/net/ethernet/intel/ice/ice_ethtool.c | 50 ++++++++++------------ drivers/net/ethernet/intel/ice/ice_lib.c | 54 ++++++++++++------------ drivers/net/ethernet/intel/ice/ice_main.c | 24 +++++------ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 15 +++---- 5 files changed, 80 insertions(+), 88 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 1150dbd98d0b..06736709968e 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -345,8 +345,7 @@ void ice_dcb_rebuild(struct ice_pf *pf) } /* Retrieve DCB config and ensure same as current in SW */ - prev_cfg = devm_kmemdup(&pf->pdev->dev, local_dcbx_cfg, - sizeof(*prev_cfg), GFP_KERNEL); + prev_cfg = kmemdup(local_dcbx_cfg, sizeof(*prev_cfg), GFP_KERNEL); if (!prev_cfg) { dev_err(&pf->pdev->dev, "Failed to alloc space for DCB cfg\n"); goto dcb_error; @@ -361,11 +360,12 @@ void ice_dcb_rebuild(struct ice_pf *pf) if (ice_dcb_need_recfg(pf, prev_cfg, local_dcbx_cfg)) { /* difference in cfg detected - disable DCB till next MIB */ dev_err(&pf->pdev->dev, "Set local MIB not accurate\n"); + kfree(prev_cfg); goto dcb_error; } /* fetched config congruent to previous configuration */ - devm_kfree(&pf->pdev->dev, prev_cfg); + kfree(prev_cfg); /* Set the local desired config */ if (local_dcbx_cfg->dcbx_mode == ICE_DCBX_MODE_CEE) @@ -389,13 +389,16 @@ void ice_dcb_rebuild(struct ice_pf *pf) dcb_error: dev_err(&pf->pdev->dev, "Disabling DCB until new settings occur\n"); - prev_cfg = devm_kzalloc(&pf->pdev->dev, sizeof(*prev_cfg), GFP_KERNEL); + prev_cfg = kzalloc(sizeof(*prev_cfg), GFP_KERNEL); + if (!prev_cfg) + return; + prev_cfg->etscfg.willing = true; prev_cfg->etscfg.tcbwtable[0] = ICE_TC_MAX_BW; prev_cfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS; memcpy(&prev_cfg->etsrec, &prev_cfg->etscfg, sizeof(prev_cfg->etsrec)); ice_pf_dcb_cfg(pf, prev_cfg, false); - devm_kfree(&pf->pdev->dev, prev_cfg); + kfree(prev_cfg); } /** @@ -410,18 +413,17 @@ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked) int ret = 0; pi = pf->hw.port_info; - newcfg = devm_kzalloc(&pf->pdev->dev, sizeof(*newcfg), GFP_KERNEL); + newcfg = kmemdup(&pi->local_dcbx_cfg, sizeof(*newcfg), GFP_KERNEL); if (!newcfg) return -ENOMEM; - memcpy(newcfg, &pi->local_dcbx_cfg, sizeof(*newcfg)); memset(&pi->local_dcbx_cfg, 0, sizeof(*newcfg)); dev_info(&pf->pdev->dev, "Configuring initial DCB values\n"); if (ice_pf_dcb_cfg(pf, newcfg, locked)) ret = -EINVAL; - devm_kfree(&pf->pdev->dev, newcfg); + kfree(newcfg); return ret; } @@ -442,9 +444,10 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool ets_willing, bool locked) hw = &pf->hw; pi = hw->port_info; - dcbcfg = devm_kzalloc(&pf->pdev->dev, sizeof(*dcbcfg), GFP_KERNEL); + dcbcfg = kzalloc(sizeof(*dcbcfg), GFP_KERNEL); + if (!dcbcfg) + return -ENOMEM; - memset(dcbcfg, 0, sizeof(*dcbcfg)); memset(&pi->local_dcbx_cfg, 0, sizeof(*dcbcfg)); dcbcfg->etscfg.willing = ets_willing ? 1 : 0; @@ -465,7 +468,7 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool ets_willing, bool locked) dcbcfg->app[0].prot_id = ICE_APP_PROT_ID_FCOE; ret = ice_pf_dcb_cfg(pf, dcbcfg, locked); - devm_kfree(&pf->pdev->dev, dcbcfg); + kfree(dcbcfg); if (ret) return ret; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 6c796c5c8edf..0ee78fd1bdfb 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -962,7 +962,7 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) } /* Get last SW configuration */ - caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (!caps) return -ENOMEM; @@ -1007,7 +1007,7 @@ static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec) } done: - devm_kfree(&vsi->back->pdev->dev, caps); + kfree(caps); return err; } @@ -1083,7 +1083,7 @@ ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) break; } - caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (!caps) return -ENOMEM; @@ -1110,7 +1110,7 @@ ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam) fecparam->fec |= ETHTOOL_FEC_OFF; done: - devm_kfree(&vsi->back->pdev->dev, caps); + kfree(caps); return err; } @@ -2141,7 +2141,7 @@ ice_get_link_ksettings(struct net_device *netdev, /* flow control is symmetric and always supported */ ethtool_link_ksettings_add_link_mode(ks, supported, Pause); - caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (!caps) return -ENOMEM; @@ -2199,7 +2199,7 @@ ice_get_link_ksettings(struct net_device *netdev, ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); done: - devm_kfree(&vsi->back->pdev->dev, caps); + kfree(caps); return err; } @@ -2428,8 +2428,7 @@ ice_set_link_ksettings(struct net_device *netdev, usleep_range(TEST_SET_BITS_SLEEP_MIN, TEST_SET_BITS_SLEEP_MAX); } - abilities = devm_kzalloc(&pf->pdev->dev, sizeof(*abilities), - GFP_KERNEL); + abilities = kzalloc(sizeof(*abilities), GFP_KERNEL); if (!abilities) return -ENOMEM; @@ -2521,7 +2520,7 @@ ice_set_link_ksettings(struct net_device *netdev, } done: - devm_kfree(&pf->pdev->dev, abilities); + kfree(abilities); clear_bit(__ICE_CFG_BUSY, pf->state); return err; @@ -2649,8 +2648,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) netdev_info(netdev, "Changing Tx descriptor count from %d to %d\n", vsi->tx_rings[0]->count, new_tx_cnt); - tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_txq, - sizeof(*tx_rings), GFP_KERNEL); + tx_rings = kcalloc(vsi->num_txq, sizeof(*tx_rings), GFP_KERNEL); if (!tx_rings) { err = -ENOMEM; goto done; @@ -2666,7 +2664,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) if (err) { while (i--) ice_clean_tx_ring(&tx_rings[i]); - devm_kfree(&pf->pdev->dev, tx_rings); + kfree(tx_rings); goto done; } } @@ -2678,8 +2676,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) netdev_info(netdev, "Changing XDP descriptor count from %d to %d\n", vsi->xdp_rings[0]->count, new_tx_cnt); - xdp_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_xdp_txq, - sizeof(*xdp_rings), GFP_KERNEL); + xdp_rings = kcalloc(vsi->num_xdp_txq, sizeof(*xdp_rings), GFP_KERNEL); if (!xdp_rings) { err = -ENOMEM; goto free_tx; @@ -2695,7 +2692,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) if (err) { while (i--) ice_clean_tx_ring(&xdp_rings[i]); - devm_kfree(&pf->pdev->dev, xdp_rings); + kfree(xdp_rings); goto free_tx; } ice_set_ring_xdp(&xdp_rings[i]); @@ -2709,8 +2706,7 @@ process_rx: netdev_info(netdev, "Changing Rx descriptor count from %d to %d\n", vsi->rx_rings[0]->count, new_rx_cnt); - rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_rxq, - sizeof(*rx_rings), GFP_KERNEL); + rx_rings = kcalloc(vsi->num_rxq, sizeof(*rx_rings), GFP_KERNEL); if (!rx_rings) { err = -ENOMEM; goto done; @@ -2740,7 +2736,7 @@ rx_unwind: i--; ice_free_rx_ring(&rx_rings[i]); } - devm_kfree(&pf->pdev->dev, rx_rings); + kfree(rx_rings); err = -ENOMEM; goto free_tx; } @@ -2758,7 +2754,7 @@ process_link: ice_free_tx_ring(vsi->tx_rings[i]); *vsi->tx_rings[i] = tx_rings[i]; } - devm_kfree(&pf->pdev->dev, tx_rings); + kfree(tx_rings); } if (rx_rings) { @@ -2776,7 +2772,7 @@ process_link: rx_rings[i].next_to_alloc = 0; *vsi->rx_rings[i] = rx_rings[i]; } - devm_kfree(&pf->pdev->dev, rx_rings); + kfree(rx_rings); } if (xdp_rings) { @@ -2784,7 +2780,7 @@ process_link: ice_free_tx_ring(vsi->xdp_rings[i]); *vsi->xdp_rings[i] = xdp_rings[i]; } - devm_kfree(&pf->pdev->dev, xdp_rings); + kfree(xdp_rings); } vsi->num_tx_desc = new_tx_cnt; @@ -2798,7 +2794,7 @@ free_tx: if (tx_rings) { ice_for_each_txq(vsi, i) ice_free_tx_ring(&tx_rings[i]); - devm_kfree(&pf->pdev->dev, tx_rings); + kfree(tx_rings); } done: @@ -2846,7 +2842,6 @@ ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_port_info *pi = np->vsi->port_info; struct ice_aqc_get_phy_caps_data *pcaps; - struct ice_vsi *vsi = np->vsi; struct ice_dcbx_cfg *dcbx_cfg; enum ice_status status; @@ -2856,8 +2851,7 @@ ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) dcbx_cfg = &pi->local_dcbx_cfg; - pcaps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*pcaps), - GFP_KERNEL); + pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return; @@ -2880,7 +2874,7 @@ ice_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) pause->rx_pause = 1; out: - devm_kfree(&vsi->back->pdev->dev, pcaps); + kfree(pcaps); } /** @@ -3061,7 +3055,7 @@ ice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) return -EIO; } - lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL); + lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); if (!lut) return -ENOMEM; @@ -3074,7 +3068,7 @@ ice_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, u8 *hfunc) indir[i] = (u32)(lut[i]); out: - devm_kfree(&pf->pdev->dev, lut); + kfree(lut); return ret; } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index d71f7ce0a265..de9f616b163e 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -215,7 +215,7 @@ void ice_vsi_delete(struct ice_vsi *vsi) struct ice_vsi_ctx *ctxt; enum ice_status status; - ctxt = devm_kzalloc(&pf->pdev->dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return; @@ -230,7 +230,7 @@ void ice_vsi_delete(struct ice_vsi *vsi) dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", vsi->vsi_num); - devm_kfree(&pf->pdev->dev, ctxt); + kfree(ctxt); } /** @@ -746,7 +746,7 @@ static int ice_vsi_init(struct ice_vsi *vsi) struct ice_vsi_ctx *ctxt; int ret = 0; - ctxt = devm_kzalloc(&pf->pdev->dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -763,7 +763,8 @@ static int ice_vsi_init(struct ice_vsi *vsi) ctxt->vf_num = vsi->vf_id + hw->func_caps.vf_base_id; break; default: - return -ENODEV; + ret = -ENODEV; + goto out; } ice_set_dflt_vsi_ctx(ctxt); @@ -797,7 +798,8 @@ static int ice_vsi_init(struct ice_vsi *vsi) if (ret) { dev_err(&pf->pdev->dev, "Add VSI failed, err %d\n", ret); - return -EIO; + ret = -EIO; + goto out; } /* keep context for update VSI operations */ @@ -806,7 +808,8 @@ static int ice_vsi_init(struct ice_vsi *vsi) /* record VSI number returned */ vsi->vsi_num = ctxt->vsi_num; - devm_kfree(&pf->pdev->dev, ctxt); +out: + kfree(ctxt); return ret; } @@ -944,8 +947,7 @@ int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) int err = 0; u8 *lut; - lut = devm_kzalloc(&vsi->back->pdev->dev, vsi->rss_table_size, - GFP_KERNEL); + lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); if (!lut) return -ENOMEM; @@ -958,7 +960,7 @@ int ice_vsi_manage_rss_lut(struct ice_vsi *vsi, bool ena) } err = ice_set_rss(vsi, NULL, lut, vsi->rss_table_size); - devm_kfree(&vsi->back->pdev->dev, lut); + kfree(lut); return err; } @@ -976,7 +978,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq); - lut = devm_kzalloc(&pf->pdev->dev, vsi->rss_table_size, GFP_KERNEL); + lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); if (!lut) return -ENOMEM; @@ -995,7 +997,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) goto ice_vsi_cfg_rss_exit; } - key = devm_kzalloc(&pf->pdev->dev, sizeof(*key), GFP_KERNEL); + key = kzalloc(sizeof(*key), GFP_KERNEL); if (!key) { err = -ENOMEM; goto ice_vsi_cfg_rss_exit; @@ -1017,9 +1019,9 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) err = -EIO; } - devm_kfree(&pf->pdev->dev, key); + kfree(key); ice_vsi_cfg_rss_exit: - devm_kfree(&pf->pdev->dev, lut); + kfree(lut); return err; } @@ -1397,13 +1399,12 @@ void ice_vsi_cfg_msix(struct ice_vsi *vsi) */ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) { - struct device *dev = &vsi->back->pdev->dev; struct ice_hw *hw = &vsi->back->hw; struct ice_vsi_ctx *ctxt; enum ice_status status; int ret = 0; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -1421,7 +1422,7 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { - dev_err(dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", + dev_err(&vsi->back->pdev->dev, "update VSI for VLAN insert failed, err %d aq_err %d\n", status, hw->adminq.sq_last_status); ret = -EIO; goto out; @@ -1429,7 +1430,7 @@ int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) vsi->info.vlan_flags = ctxt->info.vlan_flags; out: - devm_kfree(dev, ctxt); + kfree(ctxt); return ret; } @@ -1440,13 +1441,12 @@ out: */ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) { - struct device *dev = &vsi->back->pdev->dev; struct ice_hw *hw = &vsi->back->hw; struct ice_vsi_ctx *ctxt; enum ice_status status; int ret = 0; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -1468,7 +1468,7 @@ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { - dev_err(dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", + dev_err(&vsi->back->pdev->dev, "update VSI for VLAN strip failed, ena = %d err %d aq_err %d\n", ena, status, hw->adminq.sq_last_status); ret = -EIO; goto out; @@ -1476,7 +1476,7 @@ int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) vsi->info.vlan_flags = ctxt->info.vlan_flags; out: - devm_kfree(dev, ctxt); + kfree(ctxt); return ret; } @@ -1569,7 +1569,6 @@ int ice_vsi_stop_xdp_tx_rings(struct ice_vsi *vsi) int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) { struct ice_vsi_ctx *ctxt; - struct device *dev; struct ice_pf *pf; int status; @@ -1577,8 +1576,7 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) return -EINVAL; pf = vsi->back; - dev = &pf->pdev->dev; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -1612,11 +1610,11 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc) vsi->info.sec_flags = ctxt->info.sec_flags; vsi->info.sw_flags2 = ctxt->info.sw_flags2; - devm_kfree(dev, ctxt); + kfree(ctxt); return 0; err_out: - devm_kfree(dev, ctxt); + kfree(ctxt); return -EIO; } @@ -2548,7 +2546,7 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) vsi->tc_cfg.ena_tc = ena_tc; vsi->tc_cfg.numtc = num_tc; - ctx = devm_kzalloc(&pf->pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -2581,7 +2579,7 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) ice_vsi_cfg_netdev_tc(vsi, ena_tc); out: - devm_kfree(&pf->pdev->dev, ctx); + kfree(ctx); return ret; } #endif /* CONFIG_DCB */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 5681e3be81f2..0f68910ba87d 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -724,7 +724,7 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup) an = "False"; /* Get FEC mode requested based on PHY caps last SW configuration */ - caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL); + caps = kzalloc(sizeof(*caps), GFP_KERNEL); if (!caps) { fec_req = "Unknown"; goto done; @@ -744,7 +744,7 @@ void ice_print_link_msg(struct ice_vsi *vsi, bool isup) else fec_req = "NONE"; - devm_kfree(&vsi->back->pdev->dev, caps); + kfree(caps); done: netdev_info(vsi->netdev, "NIC Link is up %sbps, Requested FEC: %s, FEC: %s, Autoneg: %s, Flow Control: %s\n", @@ -1011,8 +1011,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) } event.buf_len = cq->rq_buf_size; - event.msg_buf = devm_kzalloc(&pf->pdev->dev, event.buf_len, - GFP_KERNEL); + event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); if (!event.msg_buf) return 0; @@ -1055,7 +1054,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) } } while (pending && (i++ < ICE_DFLT_IRQ_WORK)); - devm_kfree(&pf->pdev->dev, event.msg_buf); + kfree(event.msg_buf); return pending && (i == ICE_DFLT_IRQ_WORK); } @@ -1370,7 +1369,7 @@ static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) pi = vsi->port_info; - pcaps = devm_kzalloc(dev, sizeof(*pcaps), GFP_KERNEL); + pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); if (!pcaps) return -ENOMEM; @@ -1389,7 +1388,7 @@ static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP)) goto out; - cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL); + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) { retcode = -ENOMEM; goto out; @@ -1414,9 +1413,9 @@ static int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) retcode = -EIO; } - devm_kfree(dev, cfg); + kfree(cfg); out: - devm_kfree(dev, pcaps); + kfree(pcaps); return retcode; } @@ -4866,7 +4865,6 @@ ice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, */ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) { - struct device *dev = &vsi->back->pdev->dev; struct ice_aqc_vsi_props *vsi_props; struct ice_hw *hw = &vsi->back->hw; struct ice_vsi_ctx *ctxt; @@ -4875,7 +4873,7 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) vsi_props = &vsi->info; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -4891,7 +4889,7 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { - dev_err(dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n", + dev_err(&vsi->back->pdev->dev, "update VSI for bridge mode failed, bmode = %d err %d aq_err %d\n", bmode, status, hw->adminq.sq_last_status); ret = -EIO; goto out; @@ -4900,7 +4898,7 @@ static int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) vsi_props->sw_flags = ctxt->info.sw_flags; out: - devm_kfree(dev, ctxt); + kfree(ctxt); return ret; } diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 869111a45d61..565fc9780ebe 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -459,13 +459,12 @@ static void ice_vsi_kill_pvid_fill_ctxt(struct ice_vsi_ctx *ctxt) */ static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 vid, bool enable) { - struct device *dev = &vsi->back->pdev->dev; struct ice_hw *hw = &vsi->back->hw; struct ice_vsi_ctx *ctxt; enum ice_status status; int ret = 0; - ctxt = devm_kzalloc(dev, sizeof(*ctxt), GFP_KERNEL); + ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -477,7 +476,7 @@ static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 vid, bool enable) status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); if (status) { - dev_info(dev, "update VSI for port VLAN failed, err %d aq_err %d\n", + dev_info(&vsi->back->pdev->dev, "update VSI for port VLAN failed, err %d aq_err %d\n", status, hw->adminq.sq_last_status); ret = -EIO; goto out; @@ -485,7 +484,7 @@ static int ice_vsi_manage_pvid(struct ice_vsi *vsi, u16 vid, bool enable) vsi->info = ctxt->info; out: - devm_kfree(dev, ctxt); + kfree(ctxt); return ret; } @@ -1624,7 +1623,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) len = sizeof(struct virtchnl_vf_resource); - vfres = devm_kzalloc(&pf->pdev->dev, len, GFP_KERNEL); + vfres = kzalloc(len, GFP_KERNEL); if (!vfres) { v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; len = 0; @@ -1700,7 +1699,7 @@ err: ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES, v_ret, (u8 *)vfres, len); - devm_kfree(&pf->pdev->dev, vfres); + kfree(vfres); return ret; } @@ -3167,7 +3166,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) return 0; } - ctx = devm_kzalloc(&pf->pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -3190,7 +3189,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) vsi->info.sec_flags = ctx->info.sec_flags; vsi->info.sw_flags2 = ctx->info.sw_flags2; out: - devm_kfree(&pf->pdev->dev, ctx); + kfree(ctx); return ret; } -- cgit v1.2.3-59-g8ed1b From 4015d11e4b9720718de7df28d25c04d08d8b6226 Mon Sep 17 00:00:00 2001 From: Brett Creeley Date: Fri, 8 Nov 2019 06:23:26 -0800 Subject: ice: Add ice_pf_to_dev(pf) macro We use &pf->dev->pdev all over the code. Add a simple macro to do this for us. When multiple de-references like this are being done add a local struct device variable. Signed-off-by: Brett Creeley Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 2 + drivers/net/ethernet/intel/ice/ice_base.c | 22 +-- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 112 +++++++------ drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 2 +- drivers/net/ethernet/intel/ice/ice_dcb_nl.c | 14 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 57 ++++--- drivers/net/ethernet/intel/ice/ice_lib.c | 155 ++++++++++-------- drivers/net/ethernet/intel/ice/ice_main.c | 171 ++++++++++---------- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 191 +++++++++++++---------- drivers/net/ethernet/intel/ice/ice_xsk.c | 4 +- 10 files changed, 389 insertions(+), 341 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 8d7e8fc55585..cb7259c27353 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -130,6 +130,8 @@ extern const char ice_drv_ver[]; ICE_PROMISC_VLAN_TX | \ ICE_PROMISC_VLAN_RX) +#define ice_pf_to_dev(pf) (&((pf)->pdev->dev)) + struct ice_txq_meta { u32 q_teid; /* Tx-scheduler element identifier */ u16 q_id; /* Entry in VSI's txq_map bitmap */ diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c index 69d2da14fe5c..77d6a0291e97 100644 --- a/drivers/net/ethernet/intel/ice/ice_base.c +++ b/drivers/net/ethernet/intel/ice/ice_base.c @@ -101,7 +101,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, int v_idx) struct ice_q_vector *q_vector; /* allocate q_vector */ - q_vector = devm_kzalloc(&pf->pdev->dev, sizeof(*q_vector), GFP_KERNEL); + q_vector = devm_kzalloc(ice_pf_to_dev(pf), sizeof(*q_vector), + GFP_KERNEL); if (!q_vector) return -ENOMEM; @@ -138,10 +139,11 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) struct ice_q_vector *q_vector; struct ice_pf *pf = vsi->back; struct ice_ring *ring; + struct device *dev; + dev = ice_pf_to_dev(pf); if (!vsi->q_vectors[v_idx]) { - dev_dbg(&pf->pdev->dev, "Queue vector at index %d not found\n", - v_idx); + dev_dbg(dev, "Queue vector at index %d not found\n", v_idx); return; } q_vector = vsi->q_vectors[v_idx]; @@ -155,7 +157,7 @@ static void ice_free_q_vector(struct ice_vsi *vsi, int v_idx) if (vsi->netdev) netif_napi_del(&q_vector->napi); - devm_kfree(&pf->pdev->dev, q_vector); + devm_kfree(dev, q_vector); vsi->q_vectors[v_idx] = NULL; } @@ -482,7 +484,7 @@ int ice_vsi_ctrl_rx_ring(struct ice_vsi *vsi, bool ena, u16 rxq_idx) /* wait for the change to finish */ ret = ice_pf_rxq_wait(pf, pf_q, ena); if (ret) - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "VSI idx %d Rx ring %d %sable timeout\n", vsi->idx, pf_q, (ena ? "en" : "dis")); @@ -500,11 +502,12 @@ int ice_vsi_alloc_q_vectors(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; int v_idx = 0, num_q_vectors; + struct device *dev; int err; + dev = ice_pf_to_dev(pf); if (vsi->q_vectors[0]) { - dev_dbg(&pf->pdev->dev, "VSI %d has existing q_vectors\n", - vsi->vsi_num); + dev_dbg(dev, "VSI %d has existing q_vectors\n", vsi->vsi_num); return -EEXIST; } @@ -522,8 +525,7 @@ err_out: while (v_idx--) ice_free_q_vector(vsi, v_idx); - dev_err(&pf->pdev->dev, - "Failed to allocate %d q_vector for VSI %d, ret=%d\n", + dev_err(dev, "Failed to allocate %d q_vector for VSI %d, ret=%d\n", vsi->num_q_vectors, vsi->vsi_num, err); vsi->num_q_vectors = 0; return err; @@ -640,7 +642,7 @@ ice_vsi_cfg_txq(struct ice_vsi *vsi, struct ice_ring *ring, status = ice_ena_vsi_txq(vsi->port_info, vsi->idx, tc, ring->q_handle, 1, qg_buf, buf_len, NULL); if (status) { - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "Failed to set LAN Tx queue context, error: %d\n", status); return -ENODEV; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 06736709968e..20b63443237c 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -160,6 +160,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) { struct ice_aqc_port_ets_elem buf = { 0 }; struct ice_dcbx_cfg *old_cfg, *curr_cfg; + struct device *dev = ice_pf_to_dev(pf); int ret = ICE_DCB_NO_HW_CHG; struct ice_vsi *pf_vsi; @@ -171,15 +172,15 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) /* Enable DCB tagging only when more than one TC */ if (ice_dcb_get_num_tc(new_cfg) > 1) { - dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n"); + dev_dbg(dev, "DCB tagging enabled (num TC > 1)\n"); set_bit(ICE_FLAG_DCB_ENA, pf->flags); } else { - dev_dbg(&pf->pdev->dev, "DCB tagging disabled (num TC = 1)\n"); + dev_dbg(dev, "DCB tagging disabled (num TC = 1)\n"); clear_bit(ICE_FLAG_DCB_ENA, pf->flags); } if (!memcmp(new_cfg, curr_cfg, sizeof(*new_cfg))) { - dev_dbg(&pf->pdev->dev, "No change in DCB config required\n"); + dev_dbg(dev, "No change in DCB config required\n"); return ret; } @@ -188,10 +189,10 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) if (!old_cfg) return -ENOMEM; - dev_info(&pf->pdev->dev, "Commit DCB Configuration to the hardware\n"); + dev_info(dev, "Commit DCB Configuration to the hardware\n"); pf_vsi = ice_get_main_vsi(pf); if (!pf_vsi) { - dev_dbg(&pf->pdev->dev, "PF VSI doesn't exist\n"); + dev_dbg(dev, "PF VSI doesn't exist\n"); ret = -EINVAL; goto free_cfg; } @@ -213,7 +214,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) if (pf->hw.port_info->is_sw_lldp) { ret = ice_set_dcb_cfg(pf->hw.port_info); if (ret) { - dev_err(&pf->pdev->dev, "Set DCB Config failed\n"); + dev_err(dev, "Set DCB Config failed\n"); /* Restore previous settings to local config */ memcpy(curr_cfg, old_cfg, sizeof(*curr_cfg)); goto out; @@ -222,7 +223,7 @@ int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked) ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); if (ret) { - dev_err(&pf->pdev->dev, "Query Port ETS failed\n"); + dev_err(dev, "Query Port ETS failed\n"); goto out; } @@ -269,6 +270,7 @@ static bool ice_dcb_need_recfg(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg, struct ice_dcbx_cfg *new_cfg) { + struct device *dev = ice_pf_to_dev(pf); bool need_reconfig = false; /* Check if ETS configuration has changed */ @@ -279,33 +281,33 @@ ice_dcb_need_recfg(struct ice_pf *pf, struct ice_dcbx_cfg *old_cfg, &old_cfg->etscfg.prio_table, sizeof(new_cfg->etscfg.prio_table))) { need_reconfig = true; - dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n"); + dev_dbg(dev, "ETS UP2TC changed.\n"); } if (memcmp(&new_cfg->etscfg.tcbwtable, &old_cfg->etscfg.tcbwtable, sizeof(new_cfg->etscfg.tcbwtable))) - dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n"); + dev_dbg(dev, "ETS TC BW Table changed.\n"); if (memcmp(&new_cfg->etscfg.tsatable, &old_cfg->etscfg.tsatable, sizeof(new_cfg->etscfg.tsatable))) - dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n"); + dev_dbg(dev, "ETS TSA Table changed.\n"); } /* Check if PFC configuration has changed */ if (memcmp(&new_cfg->pfc, &old_cfg->pfc, sizeof(new_cfg->pfc))) { need_reconfig = true; - dev_dbg(&pf->pdev->dev, "PFC config change detected.\n"); + dev_dbg(dev, "PFC config change detected.\n"); } /* Check if APP Table has changed */ if (memcmp(&new_cfg->app, &old_cfg->app, sizeof(new_cfg->app))) { need_reconfig = true; - dev_dbg(&pf->pdev->dev, "APP Table change detected.\n"); + dev_dbg(dev, "APP Table change detected.\n"); } - dev_dbg(&pf->pdev->dev, "dcb need_reconfig=%d\n", need_reconfig); + dev_dbg(dev, "dcb need_reconfig=%d\n", need_reconfig); return need_reconfig; } @@ -317,11 +319,12 @@ void ice_dcb_rebuild(struct ice_pf *pf) { struct ice_dcbx_cfg *local_dcbx_cfg, *desired_dcbx_cfg, *prev_cfg; struct ice_aqc_port_ets_elem buf = { 0 }; + struct device *dev = ice_pf_to_dev(pf); enum ice_status ret; ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); if (ret) { - dev_err(&pf->pdev->dev, "Query Port ETS failed\n"); + dev_err(dev, "Query Port ETS failed\n"); goto dcb_error; } @@ -340,16 +343,14 @@ void ice_dcb_rebuild(struct ice_pf *pf) ice_cfg_etsrec_defaults(pf->hw.port_info); ret = ice_set_dcb_cfg(pf->hw.port_info); if (ret) { - dev_err(&pf->pdev->dev, "Failed to set DCB to unwilling\n"); + dev_err(dev, "Failed to set DCB to unwilling\n"); goto dcb_error; } /* Retrieve DCB config and ensure same as current in SW */ prev_cfg = kmemdup(local_dcbx_cfg, sizeof(*prev_cfg), GFP_KERNEL); - if (!prev_cfg) { - dev_err(&pf->pdev->dev, "Failed to alloc space for DCB cfg\n"); + if (!prev_cfg) goto dcb_error; - } ice_init_dcb(&pf->hw, true); if (pf->hw.port_info->dcbx_status == ICE_DCBX_STATUS_DIS) @@ -359,7 +360,7 @@ void ice_dcb_rebuild(struct ice_pf *pf) if (ice_dcb_need_recfg(pf, prev_cfg, local_dcbx_cfg)) { /* difference in cfg detected - disable DCB till next MIB */ - dev_err(&pf->pdev->dev, "Set local MIB not accurate\n"); + dev_err(dev, "Set local MIB not accurate\n"); kfree(prev_cfg); goto dcb_error; } @@ -375,20 +376,20 @@ void ice_dcb_rebuild(struct ice_pf *pf) ice_cfg_etsrec_defaults(pf->hw.port_info); ret = ice_set_dcb_cfg(pf->hw.port_info); if (ret) { - dev_err(&pf->pdev->dev, "Failed to set desired config\n"); + dev_err(dev, "Failed to set desired config\n"); goto dcb_error; } - dev_info(&pf->pdev->dev, "DCB restored after reset\n"); + dev_info(dev, "DCB restored after reset\n"); ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); if (ret) { - dev_err(&pf->pdev->dev, "Query Port ETS failed\n"); + dev_err(dev, "Query Port ETS failed\n"); goto dcb_error; } return; dcb_error: - dev_err(&pf->pdev->dev, "Disabling DCB until new settings occur\n"); + dev_err(dev, "Disabling DCB until new settings occur\n"); prev_cfg = kzalloc(sizeof(*prev_cfg), GFP_KERNEL); if (!prev_cfg) return; @@ -419,7 +420,7 @@ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked) memset(&pi->local_dcbx_cfg, 0, sizeof(*newcfg)); - dev_info(&pf->pdev->dev, "Configuring initial DCB values\n"); + dev_info(ice_pf_to_dev(pf), "Configuring initial DCB values\n"); if (ice_pf_dcb_cfg(pf, newcfg, locked)) ret = -EINVAL; @@ -507,13 +508,13 @@ static bool ice_dcb_tc_contig(u8 *prio_table) static int ice_dcb_noncontig_cfg(struct ice_pf *pf) { struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; + struct device *dev = ice_pf_to_dev(pf); int ret; /* Configure SW DCB default with ETS non-willing */ ret = ice_dcb_sw_dflt_cfg(pf, false, true); if (ret) { - dev_err(&pf->pdev->dev, - "Failed to set local DCB config %d\n", ret); + dev_err(dev, "Failed to set local DCB config %d\n", ret); return ret; } @@ -521,7 +522,7 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf) dcbcfg->etscfg.willing = 1; ret = ice_set_dcb_cfg(pf->hw.port_info); if (ret) - dev_err(&pf->pdev->dev, "Failed to set DCB to unwilling\n"); + dev_err(dev, "Failed to set DCB to unwilling\n"); return ret; } @@ -542,10 +543,12 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf) /* Update each VSI */ ice_for_each_vsi(pf, v) { - if (!pf->vsi[v]) + struct ice_vsi *vsi = pf->vsi[v]; + + if (!vsi) continue; - if (pf->vsi[v]->type == ICE_VSI_PF) { + if (vsi->type == ICE_VSI_PF) { tc_map = ice_dcb_get_ena_tc(dcbcfg); /* If DCBX request non-contiguous TC, then configure @@ -559,17 +562,16 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf) tc_map = ICE_DFLT_TRAFFIC_CLASS; } - ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map); + ret = ice_vsi_cfg_tc(vsi, tc_map); if (ret) { - dev_err(&pf->pdev->dev, - "Failed to config TC for VSI index: %d\n", - pf->vsi[v]->idx); + dev_err(ice_pf_to_dev(pf), "Failed to config TC for VSI index: %d\n", + vsi->idx); continue; } - ice_vsi_map_rings_to_vectors(pf->vsi[v]); - if (pf->vsi[v]->type == ICE_VSI_PF) - ice_dcbnl_set_all(pf->vsi[v]); + ice_vsi_map_rings_to_vectors(vsi); + if (vsi->type == ICE_VSI_PF) + ice_dcbnl_set_all(vsi); } } @@ -580,7 +582,7 @@ static void ice_pf_dcb_recfg(struct ice_pf *pf) */ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) { - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); struct ice_port_info *port_info; struct ice_hw *hw = &pf->hw; int err; @@ -589,23 +591,22 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) err = ice_init_dcb(hw, false); if (err && !port_info->is_sw_lldp) { - dev_err(&pf->pdev->dev, "Error initializing DCB %d\n", err); + dev_err(dev, "Error initializing DCB %d\n", err); goto dcb_init_err; } - dev_info(&pf->pdev->dev, + dev_info(dev, "DCB is enabled in the hardware, max number of TCs supported on this port are %d\n", pf->hw.func_caps.common_cap.maxtc); if (err) { struct ice_vsi *pf_vsi; /* FW LLDP is disabled, activate SW DCBX/LLDP mode */ - dev_info(&pf->pdev->dev, - "FW LLDP is disabled, DCBx/LLDP in SW mode.\n"); + dev_info(dev, "FW LLDP is disabled, DCBx/LLDP in SW mode.\n"); clear_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags); err = ice_dcb_sw_dflt_cfg(pf, true, locked); if (err) { - dev_err(&pf->pdev->dev, + dev_err(dev, "Failed to set local DCB config %d\n", err); err = -EIO; goto dcb_init_err; @@ -616,8 +617,7 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked) */ pf_vsi = ice_get_main_vsi(pf); if (!pf_vsi) { - dev_err(&pf->pdev->dev, - "Failed to set local DCB config\n"); + dev_err(dev, "Failed to set local DCB config\n"); err = -EIO; goto dcb_init_err; } @@ -732,6 +732,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, struct ice_rq_event_info *event) { struct ice_aqc_port_ets_elem buf = { 0 }; + struct device *dev = ice_pf_to_dev(pf); struct ice_aqc_lldp_get_mib *mib; struct ice_dcbx_cfg tmp_dcbx_cfg; bool need_reconfig = false; @@ -745,8 +746,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, return; if (pf->dcbx_cap & DCB_CAP_DCBX_HOST) { - dev_dbg(&pf->pdev->dev, - "MIB Change Event in HOST mode\n"); + dev_dbg(dev, "MIB Change Event in HOST mode\n"); return; } @@ -755,21 +755,20 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* Ignore if event is not for Nearest Bridge */ type = ((mib->type >> ICE_AQ_LLDP_BRID_TYPE_S) & ICE_AQ_LLDP_BRID_TYPE_M); - dev_dbg(&pf->pdev->dev, "LLDP event MIB bridge type 0x%x\n", type); + dev_dbg(dev, "LLDP event MIB bridge type 0x%x\n", type); if (type != ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID) return; /* Check MIB Type and return if event for Remote MIB update */ type = mib->type & ICE_AQ_LLDP_MIB_TYPE_M; - dev_dbg(&pf->pdev->dev, - "LLDP event mib type %s\n", type ? "remote" : "local"); + dev_dbg(dev, "LLDP event mib type %s\n", type ? "remote" : "local"); if (type == ICE_AQ_LLDP_MIB_REMOTE) { /* Update the remote cached instance and return */ ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE, ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, &pi->remote_dcbx_cfg); if (ret) { - dev_err(&pf->pdev->dev, "Failed to get remote DCB config\n"); + dev_err(dev, "Failed to get remote DCB config\n"); return; } } @@ -783,14 +782,13 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* Get updated DCBX data from firmware */ ret = ice_get_dcb_cfg(pf->hw.port_info); if (ret) { - dev_err(&pf->pdev->dev, "Failed to get DCB config\n"); + dev_err(dev, "Failed to get DCB config\n"); return; } /* No change detected in DCBX configs */ if (!memcmp(&tmp_dcbx_cfg, &pi->local_dcbx_cfg, sizeof(tmp_dcbx_cfg))) { - dev_dbg(&pf->pdev->dev, - "No change detected in DCBX configuration.\n"); + dev_dbg(dev, "No change detected in DCBX configuration.\n"); return; } @@ -802,16 +800,16 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, /* Enable DCB tagging only when more than one TC */ if (ice_dcb_get_num_tc(&pi->local_dcbx_cfg) > 1) { - dev_dbg(&pf->pdev->dev, "DCB tagging enabled (num TC > 1)\n"); + dev_dbg(dev, "DCB tagging enabled (num TC > 1)\n"); set_bit(ICE_FLAG_DCB_ENA, pf->flags); } else { - dev_dbg(&pf->pdev->dev, "DCB tagging disabled (num TC = 1)\n"); + dev_dbg(dev, "DCB tagging disabled (num TC = 1)\n"); clear_bit(ICE_FLAG_DCB_ENA, pf->flags); } pf_vsi = ice_get_main_vsi(pf); if (!pf_vsi) { - dev_dbg(&pf->pdev->dev, "PF VSI doesn't exist\n"); + dev_dbg(dev, "PF VSI doesn't exist\n"); return; } @@ -820,7 +818,7 @@ ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf, ret = ice_query_port_ets(pf->hw.port_info, &buf, sizeof(buf), NULL); if (ret) { - dev_err(&pf->pdev->dev, "Query Port ETS failed\n"); + dev_err(dev, "Query Port ETS failed\n"); rtnl_unlock(); return; } diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index e90e25b7da77..c81d7f69d5c4 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -58,7 +58,7 @@ ice_dcb_get_tc(struct ice_vsi __always_unused *vsi, static inline int ice_init_pf_dcb(struct ice_pf *pf, bool __always_unused locked) { - dev_dbg(&pf->pdev->dev, "DCB not supported\n"); + dev_dbg(ice_pf_to_dev(pf), "DCB not supported\n"); return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c index 3c90fc0a3feb..d870c1aedc17 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_nl.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_nl.c @@ -179,7 +179,7 @@ static u8 ice_dcbnl_setdcbx(struct net_device *netdev, u8 mode) else pf->hw.port_info->local_dcbx_cfg.dcbx_mode = ICE_DCBX_MODE_IEEE; - dev_info(&pf->pdev->dev, "DCBx mode = 0x%x\n", mode); + dev_info(ice_pf_to_dev(pf), "DCBx mode = 0x%x\n", mode); return ICE_DCB_HW_CHG_RST; } @@ -297,7 +297,7 @@ ice_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, u8 *setting) return; *setting = (pi->local_dcbx_cfg.pfc.pfcena >> prio) & 0x1; - dev_dbg(&pf->pdev->dev, + dev_dbg(ice_pf_to_dev(pf), "Get PFC Config up=%d, setting=%d, pfcenable=0x%x\n", prio, *setting, pi->local_dcbx_cfg.pfc.pfcena); } @@ -328,7 +328,7 @@ static void ice_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, u8 set) else new_cfg->pfc.pfcena &= ~BIT(prio); - dev_dbg(&pf->pdev->dev, "Set PFC config UP:%d set:%d pfcena:0x%x\n", + dev_dbg(ice_pf_to_dev(pf), "Set PFC config UP:%d set:%d pfcena:0x%x\n", prio, set, new_cfg->pfc.pfcena); } @@ -359,7 +359,7 @@ static u8 ice_dcbnl_getstate(struct net_device *netdev) state = test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); - dev_dbg(&pf->pdev->dev, "DCB enabled state = %d\n", state); + dev_dbg(ice_pf_to_dev(pf), "DCB enabled state = %d\n", state); return state; } @@ -418,7 +418,7 @@ ice_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int prio, return; *pgid = pi->local_dcbx_cfg.etscfg.prio_table[prio]; - dev_dbg(&pf->pdev->dev, + dev_dbg(ice_pf_to_dev(pf), "Get PG config prio=%d tc=%d\n", prio, *pgid); } @@ -479,7 +479,7 @@ ice_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, u8 *bw_pct) return; *bw_pct = pi->local_dcbx_cfg.etscfg.tcbwtable[pgid]; - dev_dbg(&pf->pdev->dev, "Get PG BW config tc=%d bw_pct=%d\n", + dev_dbg(ice_pf_to_dev(pf), "Get PG BW config tc=%d bw_pct=%d\n", pgid, *bw_pct); } @@ -597,7 +597,7 @@ static u8 ice_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) break; } - dev_dbg(&pf->pdev->dev, "DCBX Get Capability cap=%d capval=0x%x\n", + dev_dbg(ice_pf_to_dev(pf), "DCBX Get Capability cap=%d capval=0x%x\n", capid, *cap); return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 0ee78fd1bdfb..5b229f3703b5 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -248,7 +248,7 @@ ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, int ret = 0; u16 *buf; - dev = &pf->pdev->dev; + dev = ice_pf_to_dev(pf); eeprom->magic = hw->vendor_id | (hw->device_id << 16); @@ -343,6 +343,7 @@ static u64 ice_eeprom_test(struct net_device *netdev) static int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask) { struct ice_pf *pf = (struct ice_pf *)hw->back; + struct device *dev = ice_pf_to_dev(pf); static const u32 patterns[] = { 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF @@ -358,7 +359,7 @@ static int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask) val = rd32(hw, reg); if (val == pattern) continue; - dev_err(&pf->pdev->dev, + dev_err(dev, "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n" , __func__, reg, pattern, val); return 1; @@ -367,7 +368,7 @@ static int ice_reg_pattern_test(struct ice_hw *hw, u32 reg, u32 mask) wr32(hw, reg, orig_val); val = rd32(hw, reg); if (val != orig_val) { - dev_err(&pf->pdev->dev, + dev_err(dev, "%s: reg restore test failed - reg 0x%08x orig 0x%08x val 0x%08x\n" , __func__, reg, orig_val, val); return 1; @@ -507,7 +508,7 @@ static int ice_lbtest_create_frame(struct ice_pf *pf, u8 **ret_data, u16 size) if (!pf) return -EINVAL; - data = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL); + data = devm_kzalloc(ice_pf_to_dev(pf), size, GFP_KERNEL); if (!data) return -ENOMEM; @@ -649,9 +650,11 @@ static u64 ice_loopback_test(struct net_device *netdev) u8 broadcast[ETH_ALEN], ret = 0; int num_frames, valid_frames; LIST_HEAD(tmp_list); + struct device *dev; u8 *tx_frame; int i; + dev = ice_pf_to_dev(pf); netdev_info(netdev, "loopback test\n"); test_vsi = ice_lb_vsi_setup(pf, pf->hw.port_info); @@ -712,12 +715,12 @@ static u64 ice_loopback_test(struct net_device *netdev) ret = 10; lbtest_free_frame: - devm_kfree(&pf->pdev->dev, tx_frame); + devm_kfree(dev, tx_frame); remove_mac_filters: if (ice_remove_mac(&pf->hw, &tmp_list)) netdev_err(netdev, "Could not remove MAC filter for the test VSI"); free_mac_list: - ice_free_fltr_list(&pf->pdev->dev, &tmp_list); + ice_free_fltr_list(dev, &tmp_list); lbtest_mac_dis: /* Disable MAC loopback after the test is completed. */ if (ice_aq_set_mac_loopback(&pf->hw, false, NULL)) @@ -774,6 +777,9 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, struct ice_netdev_priv *np = netdev_priv(netdev); bool if_running = netif_running(netdev); struct ice_pf *pf = np->vsi->back; + struct device *dev; + + dev = ice_pf_to_dev(pf); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { netdev_info(netdev, "offline testing starting\n"); @@ -781,7 +787,7 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, set_bit(__ICE_TESTING, pf->state); if (ice_active_vfs(pf)) { - dev_warn(&pf->pdev->dev, + dev_warn(dev, "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n"); data[ICE_ETH_TEST_REG] = 1; data[ICE_ETH_TEST_EEPROM] = 1; @@ -816,8 +822,7 @@ ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, int status = ice_open(netdev); if (status) { - dev_err(&pf->pdev->dev, - "Could not open device %s, err %d", + dev_err(dev, "Could not open device %s, err %d", pf->int_name, status); } } @@ -1155,12 +1160,14 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) DECLARE_BITMAP(orig_flags, ICE_PF_FLAGS_NBITS); struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; + struct device *dev; int ret = 0; u32 i; if (flags > BIT(ICE_PRIV_FLAG_ARRAY_SIZE)) return -EINVAL; + dev = ice_pf_to_dev(pf); set_bit(ICE_FLAG_ETHTOOL_CTXT, pf->flags); bitmap_copy(orig_flags, pf->flags, ICE_PF_FLAGS_NBITS); @@ -1189,7 +1196,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) * events to respond to. */ if (status) - dev_info(&pf->pdev->dev, + dev_info(dev, "Failed to unreg for LLDP events\n"); /* The AQ call to stop the FW LLDP agent will generate @@ -1197,15 +1204,14 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) */ status = ice_aq_stop_lldp(&pf->hw, true, true, NULL); if (status) - dev_warn(&pf->pdev->dev, - "Fail to stop LLDP agent\n"); + dev_warn(dev, "Fail to stop LLDP agent\n"); /* Use case for having the FW LLDP agent stopped * will likely not need DCB, so failure to init is * not a concern of ethtool */ status = ice_init_pf_dcb(pf, true); if (status) - dev_warn(&pf->pdev->dev, "Fail to init DCB\n"); + dev_warn(dev, "Fail to init DCB\n"); } else { enum ice_status status; bool dcbx_agent_status; @@ -1215,8 +1221,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) */ status = ice_aq_start_lldp(&pf->hw, true, NULL); if (status) - dev_warn(&pf->pdev->dev, - "Fail to start LLDP Agent\n"); + dev_warn(dev, "Fail to start LLDP Agent\n"); /* AQ command to start FW DCBX agent will fail if * the agent is already started @@ -1225,10 +1230,9 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) &dcbx_agent_status, NULL); if (status) - dev_dbg(&pf->pdev->dev, - "Failed to start FW DCBX\n"); + dev_dbg(dev, "Failed to start FW DCBX\n"); - dev_info(&pf->pdev->dev, "FW DCBX agent is %s\n", + dev_info(dev, "FW DCBX agent is %s\n", dcbx_agent_status ? "ACTIVE" : "DISABLED"); /* Failure to configure MIB change or init DCB is not @@ -1238,7 +1242,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) */ status = ice_init_pf_dcb(pf, true); if (status) - dev_dbg(&pf->pdev->dev, "Fail to init DCB\n"); + dev_dbg(dev, "Fail to init DCB\n"); /* Remove rule to direct LLDP packets to default VSI. * The FW LLDP engine will now be consuming them. @@ -1248,7 +1252,7 @@ static int ice_set_priv_flags(struct net_device *netdev, u32 flags) /* Register for MIB change events */ status = ice_cfg_lldp_mib_change(&pf->hw, true); if (status) - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "Fail to enable MIB change events\n"); } } @@ -3089,8 +3093,10 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; + struct device *dev; u8 *seed = NULL; + dev = ice_pf_to_dev(pf); if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; @@ -3103,8 +3109,7 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, if (key) { if (!vsi->rss_hkey_user) { vsi->rss_hkey_user = - devm_kzalloc(&pf->pdev->dev, - ICE_VSIQF_HKEY_ARRAY_SIZE, + devm_kzalloc(dev, ICE_VSIQF_HKEY_ARRAY_SIZE, GFP_KERNEL); if (!vsi->rss_hkey_user) return -ENOMEM; @@ -3114,8 +3119,7 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, } if (!vsi->rss_lut_user) { - vsi->rss_lut_user = devm_kzalloc(&pf->pdev->dev, - vsi->rss_table_size, + vsi->rss_lut_user = devm_kzalloc(dev, vsi->rss_table_size, GFP_KERNEL); if (!vsi->rss_lut_user) return -ENOMEM; @@ -3177,7 +3181,7 @@ ice_get_rc_coalesce(struct ethtool_coalesce *ec, enum ice_container_type c_type, ec->tx_coalesce_usecs = rc->itr_setting & ~ICE_ITR_DYNAMIC; break; default: - dev_dbg(&pf->pdev->dev, "Invalid c_type %d\n", c_type); + dev_dbg(ice_pf_to_dev(pf), "Invalid c_type %d\n", c_type); return -EINVAL; } @@ -3317,7 +3321,8 @@ ice_set_rc_coalesce(enum ice_container_type c_type, struct ethtool_coalesce *ec, break; default: - dev_dbg(&pf->pdev->dev, "Invalid container type %d\n", c_type); + dev_dbg(ice_pf_to_dev(pf), "Invalid container type %d\n", + c_type); return -EINVAL; } diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index de9f616b163e..b546c69a4bbc 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -52,26 +52,29 @@ static int ice_vsi_ctrl_rx_rings(struct ice_vsi *vsi, bool ena) static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + struct device *dev; + + dev = ice_pf_to_dev(pf); /* allocate memory for both Tx and Rx ring pointers */ - vsi->tx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_txq, + vsi->tx_rings = devm_kcalloc(dev, vsi->alloc_txq, sizeof(*vsi->tx_rings), GFP_KERNEL); if (!vsi->tx_rings) return -ENOMEM; - vsi->rx_rings = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, + vsi->rx_rings = devm_kcalloc(dev, vsi->alloc_rxq, sizeof(*vsi->rx_rings), GFP_KERNEL); if (!vsi->rx_rings) goto err_rings; /* XDP will have vsi->alloc_txq Tx queues as well, so double the size */ - vsi->txq_map = devm_kcalloc(&pf->pdev->dev, (2 * vsi->alloc_txq), + vsi->txq_map = devm_kcalloc(dev, (2 * vsi->alloc_txq), sizeof(*vsi->txq_map), GFP_KERNEL); if (!vsi->txq_map) goto err_txq_map; - vsi->rxq_map = devm_kcalloc(&pf->pdev->dev, vsi->alloc_rxq, + vsi->rxq_map = devm_kcalloc(dev, vsi->alloc_rxq, sizeof(*vsi->rxq_map), GFP_KERNEL); if (!vsi->rxq_map) goto err_rxq_map; @@ -81,7 +84,7 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) return 0; /* allocate memory for q_vector pointers */ - vsi->q_vectors = devm_kcalloc(&pf->pdev->dev, vsi->num_q_vectors, + vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors, sizeof(*vsi->q_vectors), GFP_KERNEL); if (!vsi->q_vectors) goto err_vectors; @@ -89,13 +92,13 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi) return 0; err_vectors: - devm_kfree(&pf->pdev->dev, vsi->rxq_map); + devm_kfree(dev, vsi->rxq_map); err_rxq_map: - devm_kfree(&pf->pdev->dev, vsi->txq_map); + devm_kfree(dev, vsi->txq_map); err_txq_map: - devm_kfree(&pf->pdev->dev, vsi->rx_rings); + devm_kfree(dev, vsi->rx_rings); err_rings: - devm_kfree(&pf->pdev->dev, vsi->tx_rings); + devm_kfree(dev, vsi->tx_rings); return -ENOMEM; } @@ -169,7 +172,7 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) vsi->alloc_rxq = 1; break; default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); + dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi->type); break; } @@ -227,8 +230,8 @@ void ice_vsi_delete(struct ice_vsi *vsi) status = ice_free_vsi(&pf->hw, vsi->idx, ctxt, false, NULL); if (status) - dev_err(&pf->pdev->dev, "Failed to delete VSI %i in FW\n", - vsi->vsi_num); + dev_err(ice_pf_to_dev(pf), "Failed to delete VSI %i in FW - error: %d\n", + vsi->vsi_num, status); kfree(ctxt); } @@ -240,26 +243,29 @@ void ice_vsi_delete(struct ice_vsi *vsi) static void ice_vsi_free_arrays(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + struct device *dev; + + dev = ice_pf_to_dev(pf); /* free the ring and vector containers */ if (vsi->q_vectors) { - devm_kfree(&pf->pdev->dev, vsi->q_vectors); + devm_kfree(dev, vsi->q_vectors); vsi->q_vectors = NULL; } if (vsi->tx_rings) { - devm_kfree(&pf->pdev->dev, vsi->tx_rings); + devm_kfree(dev, vsi->tx_rings); vsi->tx_rings = NULL; } if (vsi->rx_rings) { - devm_kfree(&pf->pdev->dev, vsi->rx_rings); + devm_kfree(dev, vsi->rx_rings); vsi->rx_rings = NULL; } if (vsi->txq_map) { - devm_kfree(&pf->pdev->dev, vsi->txq_map); + devm_kfree(dev, vsi->txq_map); vsi->txq_map = NULL; } if (vsi->rxq_map) { - devm_kfree(&pf->pdev->dev, vsi->rxq_map); + devm_kfree(dev, vsi->rxq_map); vsi->rxq_map = NULL; } } @@ -276,6 +282,7 @@ static void ice_vsi_free_arrays(struct ice_vsi *vsi) int ice_vsi_clear(struct ice_vsi *vsi) { struct ice_pf *pf = NULL; + struct device *dev; if (!vsi) return 0; @@ -284,10 +291,10 @@ int ice_vsi_clear(struct ice_vsi *vsi) return -EINVAL; pf = vsi->back; + dev = ice_pf_to_dev(pf); if (!pf->vsi[vsi->idx] || pf->vsi[vsi->idx] != vsi) { - dev_dbg(&pf->pdev->dev, "vsi does not exist at pf->vsi[%d]\n", - vsi->idx); + dev_dbg(dev, "vsi does not exist at pf->vsi[%d]\n", vsi->idx); return -EINVAL; } @@ -300,7 +307,7 @@ int ice_vsi_clear(struct ice_vsi *vsi) ice_vsi_free_arrays(vsi); mutex_unlock(&pf->sw_mutex); - devm_kfree(&pf->pdev->dev, vsi); + devm_kfree(dev, vsi); return 0; } @@ -333,6 +340,7 @@ static irqreturn_t ice_msix_clean_rings(int __always_unused irq, void *data) static struct ice_vsi * ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id) { + struct device *dev = ice_pf_to_dev(pf); struct ice_vsi *vsi = NULL; /* Need to protect the allocation of the VSIs at the PF level */ @@ -343,11 +351,11 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id) * is available to be populated */ if (pf->next_vsi == ICE_NO_VSI) { - dev_dbg(&pf->pdev->dev, "out of VSI slots!\n"); + dev_dbg(dev, "out of VSI slots!\n"); goto unlock_pf; } - vsi = devm_kzalloc(&pf->pdev->dev, sizeof(*vsi), GFP_KERNEL); + vsi = devm_kzalloc(dev, sizeof(*vsi), GFP_KERNEL); if (!vsi) goto unlock_pf; @@ -379,7 +387,7 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id) goto err_rings; break; default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); + dev_warn(dev, "Unknown VSI type %d\n", vsi->type); goto unlock_pf; } @@ -392,7 +400,7 @@ ice_vsi_alloc(struct ice_pf *pf, enum ice_vsi_type type, u16 vf_id) goto unlock_pf; err_rings: - devm_kfree(&pf->pdev->dev, vsi); + devm_kfree(dev, vsi); vsi = NULL; unlock_pf: mutex_unlock(&pf->sw_mutex); @@ -481,14 +489,15 @@ bool ice_is_safe_mode(struct ice_pf *pf) */ static void ice_rss_clean(struct ice_vsi *vsi) { - struct ice_pf *pf; + struct ice_pf *pf = vsi->back; + struct device *dev; - pf = vsi->back; + dev = ice_pf_to_dev(pf); if (vsi->rss_hkey_user) - devm_kfree(&pf->pdev->dev, vsi->rss_hkey_user); + devm_kfree(dev, vsi->rss_hkey_user); if (vsi->rss_lut_user) - devm_kfree(&pf->pdev->dev, vsi->rss_lut_user); + devm_kfree(dev, vsi->rss_lut_user); } /** @@ -526,7 +535,7 @@ static void ice_vsi_set_rss_params(struct ice_vsi *vsi) case ICE_VSI_LB: break; default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", + dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi->type); break; } @@ -702,9 +711,11 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) { u8 lut_type, hash_type; + struct device *dev; struct ice_pf *pf; pf = vsi->back; + dev = ice_pf_to_dev(pf); switch (vsi->type) { case ICE_VSI_PF: @@ -718,11 +729,11 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) hash_type = ICE_AQ_VSI_Q_OPT_RSS_TPLZ; break; case ICE_VSI_LB: - dev_dbg(&pf->pdev->dev, "Unsupported VSI type %s\n", + dev_dbg(dev, "Unsupported VSI type %s\n", ice_vsi_type_str(vsi->type)); return; default: - dev_warn(&pf->pdev->dev, "Unknown VSI type %d\n", vsi->type); + dev_warn(dev, "Unknown VSI type %d\n", vsi->type); return; } @@ -796,8 +807,7 @@ static int ice_vsi_init(struct ice_vsi *vsi) ret = ice_add_vsi(hw, vsi->idx, ctxt, NULL); if (ret) { - dev_err(&pf->pdev->dev, - "Add VSI failed, err %d\n", ret); + dev_err(ice_pf_to_dev(pf), "Add VSI failed, err %d\n", ret); ret = -EIO; goto out; } @@ -826,14 +836,16 @@ out: static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + struct device *dev; u16 num_q_vectors; + 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->base_vector) { - dev_dbg(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n", + dev_dbg(dev, "VSI %d has non-zero base vector %d\n", vsi->vsi_num, vsi->base_vector); return -EEXIST; } @@ -843,7 +855,7 @@ static int ice_vsi_setup_vector_base(struct ice_vsi *vsi) vsi->base_vector = ice_get_res(pf, pf->irq_tracker, num_q_vectors, vsi->idx); if (vsi->base_vector < 0) { - dev_err(&pf->pdev->dev, + dev_err(dev, "Failed to get tracking for %d vectors for VSI %d, err=%d\n", num_q_vectors, vsi->vsi_num, vsi->base_vector); return -ENOENT; @@ -886,8 +898,10 @@ static void ice_vsi_clear_rings(struct ice_vsi *vsi) static int ice_vsi_alloc_rings(struct ice_vsi *vsi) { struct ice_pf *pf = vsi->back; + struct device *dev; int i; + dev = ice_pf_to_dev(pf); /* Allocate Tx rings */ for (i = 0; i < vsi->alloc_txq; i++) { struct ice_ring *ring; @@ -902,7 +916,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->reg_idx = vsi->txq_map[i]; ring->ring_active = false; ring->vsi = vsi; - ring->dev = &pf->pdev->dev; + ring->dev = dev; ring->count = vsi->num_tx_desc; vsi->tx_rings[i] = ring; } @@ -921,7 +935,7 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->ring_active = false; ring->vsi = vsi; ring->netdev = vsi->netdev; - ring->dev = &pf->pdev->dev; + ring->dev = dev; ring->count = vsi->num_rx_desc; vsi->rx_rings[i] = ring; } @@ -973,9 +987,11 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) struct ice_aqc_get_set_rss_keys *key; struct ice_pf *pf = vsi->back; enum ice_status status; + struct device *dev; int err = 0; u8 *lut; + dev = ice_pf_to_dev(pf); vsi->rss_size = min_t(int, vsi->rss_size, vsi->num_rxq); lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); @@ -991,8 +1007,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) vsi->rss_table_size); if (status) { - dev_err(&pf->pdev->dev, - "set_rss_lut failed, error %d\n", status); + dev_err(dev, "set_rss_lut failed, error %d\n", status); err = -EIO; goto ice_vsi_cfg_rss_exit; } @@ -1014,8 +1029,7 @@ static int ice_vsi_cfg_rss_lut_key(struct ice_vsi *vsi) status = ice_aq_set_rss_key(&pf->hw, vsi->idx, key); if (status) { - dev_err(&pf->pdev->dev, "set_rss_key failed, error %d\n", - status); + dev_err(dev, "set_rss_key failed, error %d\n", status); err = -EIO; } @@ -1041,7 +1055,7 @@ int ice_add_mac_to_list(struct ice_vsi *vsi, struct list_head *add_list, struct ice_fltr_list_entry *tmp; struct ice_pf *pf = vsi->back; - tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_ATOMIC); + tmp = devm_kzalloc(ice_pf_to_dev(pf), sizeof(*tmp), GFP_ATOMIC); if (!tmp) return -ENOMEM; @@ -1133,9 +1147,11 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) struct ice_pf *pf = vsi->back; LIST_HEAD(tmp_add_list); enum ice_status status; + struct device *dev; int err = 0; - tmp = devm_kzalloc(&pf->pdev->dev, sizeof(*tmp), GFP_KERNEL); + dev = ice_pf_to_dev(pf); + tmp = devm_kzalloc(dev, sizeof(*tmp), GFP_KERNEL); if (!tmp) return -ENOMEM; @@ -1152,11 +1168,11 @@ int ice_vsi_add_vlan(struct ice_vsi *vsi, u16 vid) status = ice_add_vlan(&pf->hw, &tmp_add_list); if (status) { err = -ENODEV; - dev_err(&pf->pdev->dev, "Failure Adding VLAN %d on VSI %i\n", - vid, vsi->vsi_num); + dev_err(dev, "Failure Adding VLAN %d on VSI %i\n", vid, + vsi->vsi_num); } - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + ice_free_fltr_list(dev, &tmp_add_list); return err; } @@ -1173,9 +1189,11 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) struct ice_pf *pf = vsi->back; LIST_HEAD(tmp_add_list); enum ice_status status; + struct device *dev; int err = 0; - list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); + dev = ice_pf_to_dev(pf); + list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL); if (!list) return -ENOMEM; @@ -1191,17 +1209,17 @@ int ice_vsi_kill_vlan(struct ice_vsi *vsi, u16 vid) status = ice_remove_vlan(&pf->hw, &tmp_add_list); if (status == ICE_ERR_DOES_NOT_EXIST) { - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "Failed to remove VLAN %d on VSI %i, it does not exist, status: %d\n", vid, vsi->vsi_num, status); } else if (status) { - dev_err(&pf->pdev->dev, + dev_err(dev, "Error removing VLAN %d on vsi %i error: %d\n", vid, vsi->vsi_num, status); err = -EIO; } - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + ice_free_fltr_list(dev, &tmp_add_list); return err; } @@ -1683,8 +1701,10 @@ ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule) struct ice_pf *pf = vsi->back; LIST_HEAD(tmp_add_list); enum ice_status status; + struct device *dev; - list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); + dev = ice_pf_to_dev(pf); + list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL); if (!list) return; @@ -1704,11 +1724,11 @@ ice_vsi_add_rem_eth_mac(struct ice_vsi *vsi, bool add_rule) status = ice_remove_eth_mac(&pf->hw, &tmp_add_list); if (status) - dev_err(&pf->pdev->dev, + dev_err(dev, "Failure Adding or Removing Ethertype on VSI %i error: %d\n", vsi->vsi_num, status); - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + ice_free_fltr_list(dev, &tmp_add_list); } /** @@ -1723,8 +1743,10 @@ void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create) struct ice_pf *pf = vsi->back; LIST_HEAD(tmp_add_list); enum ice_status status; + struct device *dev; - list = devm_kzalloc(&pf->pdev->dev, sizeof(*list), GFP_KERNEL); + dev = ice_pf_to_dev(pf); + list = devm_kzalloc(dev, sizeof(*list), GFP_KERNEL); if (!list) return; @@ -1751,12 +1773,11 @@ void ice_cfg_sw_lldp(struct ice_vsi *vsi, bool tx, bool create) status = ice_remove_eth_mac(&pf->hw, &tmp_add_list); if (status) - dev_err(&pf->pdev->dev, - "Fail %s %s LLDP rule on VSI %i error: %d\n", + dev_err(dev, "Fail %s %s LLDP rule on VSI %i error: %d\n", create ? "adding" : "removing", tx ? "TX" : "RX", vsi->vsi_num, status); - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + ice_free_fltr_list(dev, &tmp_add_list); } /** @@ -1778,7 +1799,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, enum ice_vsi_type type, u16 vf_id) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); enum ice_status status; struct ice_vsi *vsi; int ret, i; @@ -1887,8 +1908,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, max_txqs); if (status) { - dev_err(&pf->pdev->dev, - "VSI %d failed lan queue config, error %d\n", + dev_err(dev, "VSI %d failed lan queue config, error %d\n", vsi->vsi_num, status); goto unroll_vector_base; } @@ -2000,8 +2020,7 @@ void ice_vsi_free_irq(struct ice_vsi *vsi) /* clear the affinity_mask in the IRQ descriptor */ irq_set_affinity_hint(irq_num, NULL); synchronize_irq(irq_num); - devm_free_irq(&pf->pdev->dev, irq_num, - vsi->q_vectors[i]); + devm_free_irq(ice_pf_to_dev(pf), irq_num, vsi->q_vectors[i]); } } @@ -2187,7 +2206,7 @@ ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id) return -EINVAL; if (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) { - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "param err: needed=%d, num_entries = %d id=0x%04x\n", needed, res->num_entries, id); return -EINVAL; @@ -2469,7 +2488,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, max_txqs); if (status) { - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "VSI %d failed lan queue config, error %d\n", vsi->vsi_num, status); goto err_vectors; @@ -2532,9 +2551,12 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) struct ice_vsi_ctx *ctx; struct ice_pf *pf = vsi->back; enum ice_status status; + struct device *dev; int i, ret = 0; u8 num_tc = 0; + dev = ice_pf_to_dev(pf); + ice_for_each_traffic_class(i) { /* build bitmap of enabled TCs */ if (ena_tc & BIT(i)) @@ -2559,7 +2581,7 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); status = ice_update_vsi(&pf->hw, vsi->idx, ctx, NULL); if (status) { - dev_info(&pf->pdev->dev, "Failed VSI Update\n"); + dev_info(dev, "Failed VSI Update\n"); ret = -EIO; goto out; } @@ -2568,8 +2590,7 @@ int ice_vsi_cfg_tc(struct ice_vsi *vsi, u8 ena_tc) max_txqs); if (status) { - dev_err(&pf->pdev->dev, - "VSI %d failed TC config, error %d\n", + dev_err(dev, "VSI %d failed TC config, error %d\n", vsi->vsi_num, status); ret = -EIO; goto out; diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0f68910ba87d..ea577588b274 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -161,7 +161,7 @@ unregister: * had an error */ if (status && vsi->netdev->reg_state == NETREG_REGISTERED) { - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "Could not add MAC filters error %d. Unregistering device\n", status); unregister_netdev(vsi->netdev); @@ -495,7 +495,7 @@ ice_prepare_for_reset(struct ice_pf *pf) */ static void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) { - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; dev_dbg(dev, "reset_type 0x%x requested\n", reset_type); @@ -792,6 +792,7 @@ static int ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, u16 link_speed) { + struct device *dev = ice_pf_to_dev(pf); struct ice_phy_info *phy_info; struct ice_vsi *vsi; u16 old_link_speed; @@ -809,7 +810,7 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, */ result = ice_update_link_info(pi); if (result) - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "Failed to update link status and re-enable link events for port %d\n", pi->lport); @@ -828,7 +829,7 @@ ice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, result = ice_aq_set_link_restart_an(pi, false, NULL); if (result) { - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "Failed to set link down, VSI %d error %d\n", vsi->vsi_num, result); return result; @@ -924,7 +925,7 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event) !!(link_data->link_info & ICE_AQ_LINK_UP), le16_to_cpu(link_data->link_speed)); if (status) - dev_dbg(&pf->pdev->dev, + dev_dbg(ice_pf_to_dev(pf), "Could not process link event, error %d\n", status); return status; @@ -937,6 +938,7 @@ ice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event) */ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) { + struct device *dev = ice_pf_to_dev(pf); struct ice_rq_event_info event; struct ice_hw *hw = &pf->hw; struct ice_ctl_q_info *cq; @@ -958,8 +960,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) qtype = "Mailbox"; break; default: - dev_warn(&pf->pdev->dev, "Unknown control queue type 0x%x\n", - q_type); + dev_warn(dev, "Unknown control queue type 0x%x\n", q_type); return 0; } @@ -971,15 +972,15 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) PF_FW_ARQLEN_ARQCRIT_M)) { oldval = val; if (val & PF_FW_ARQLEN_ARQVFE_M) - dev_dbg(&pf->pdev->dev, - "%s Receive Queue VF Error detected\n", qtype); + dev_dbg(dev, "%s Receive Queue VF Error detected\n", + qtype); if (val & PF_FW_ARQLEN_ARQOVFL_M) { - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "%s Receive Queue Overflow Error detected\n", qtype); } if (val & PF_FW_ARQLEN_ARQCRIT_M) - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "%s Receive Queue Critical Error detected\n", qtype); val &= ~(PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M | @@ -993,16 +994,14 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) PF_FW_ATQLEN_ATQCRIT_M)) { oldval = val; if (val & PF_FW_ATQLEN_ATQVFE_M) - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "%s Send Queue VF Error detected\n", qtype); if (val & PF_FW_ATQLEN_ATQOVFL_M) { - dev_dbg(&pf->pdev->dev, - "%s Send Queue Overflow Error detected\n", + dev_dbg(dev, "%s Send Queue Overflow Error detected\n", qtype); } if (val & PF_FW_ATQLEN_ATQCRIT_M) - dev_dbg(&pf->pdev->dev, - "%s Send Queue Critical Error detected\n", + dev_dbg(dev, "%s Send Queue Critical Error detected\n", qtype); val &= ~(PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M | PF_FW_ATQLEN_ATQCRIT_M); @@ -1023,8 +1022,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) if (ret == ICE_ERR_AQ_NO_WORK) break; if (ret) { - dev_err(&pf->pdev->dev, - "%s Receive Queue event error %d\n", qtype, + dev_err(dev, "%s Receive Queue event error %d\n", qtype, ret); break; } @@ -1034,8 +1032,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) switch (opcode) { case ice_aqc_opc_get_link_status: if (ice_handle_link_event(pf, &event)) - dev_err(&pf->pdev->dev, - "Could not handle link event\n"); + dev_err(dev, "Could not handle link event\n"); break; case ice_mbx_opc_send_msg_to_pf: ice_vc_process_vf_msg(pf, &event); @@ -1047,7 +1044,7 @@ static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) ice_dcb_process_lldp_set_mib_change(pf, &event); break; default: - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "%s Receive Queue unknown event 0x%04x ignored\n", qtype, opcode); break; @@ -1198,6 +1195,7 @@ static void ice_service_timer(struct timer_list *t) */ static void ice_handle_mdd_event(struct ice_pf *pf) { + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; bool mdd_detected = false; u32 reg; @@ -1219,7 +1217,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) GL_MDET_TX_PQM_QNUM_S); if (netif_msg_tx_err(pf)) - dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", + dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_TX_PQM, 0xffffffff); mdd_detected = true; @@ -1237,7 +1235,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) GL_MDET_TX_TCLAN_QNUM_S); if (netif_msg_rx_err(pf)) - dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", + dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff); mdd_detected = true; @@ -1255,7 +1253,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) GL_MDET_RX_QNUM_S); if (netif_msg_rx_err(pf)) - dev_info(&pf->pdev->dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n", + dev_info(dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n", event, queue, pf_num, vf_num); wr32(hw, GL_MDET_RX, 0xffffffff); mdd_detected = true; @@ -1267,21 +1265,21 @@ static void ice_handle_mdd_event(struct ice_pf *pf) reg = rd32(hw, PF_MDET_TX_PQM); if (reg & PF_MDET_TX_PQM_VALID_M) { wr32(hw, PF_MDET_TX_PQM, 0xFFFF); - dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n"); + dev_info(dev, "TX driver issue detected, PF reset issued\n"); pf_mdd_detected = true; } reg = rd32(hw, PF_MDET_TX_TCLAN); if (reg & PF_MDET_TX_TCLAN_VALID_M) { wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF); - dev_info(&pf->pdev->dev, "TX driver issue detected, PF reset issued\n"); + dev_info(dev, "TX driver issue detected, PF reset issued\n"); pf_mdd_detected = true; } reg = rd32(hw, PF_MDET_RX); if (reg & PF_MDET_RX_VALID_M) { wr32(hw, PF_MDET_RX, 0xFFFF); - dev_info(&pf->pdev->dev, "RX driver issue detected, PF reset issued\n"); + dev_info(dev, "RX driver issue detected, PF reset issued\n"); pf_mdd_detected = true; } /* Queue belongs to the PF initiate a reset */ @@ -1301,7 +1299,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) if (reg & VP_MDET_TX_PQM_VALID_M) { wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF); vf_mdd_detected = true; - dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + dev_info(dev, "TX driver issue detected on VF %d\n", i); } @@ -1309,7 +1307,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) if (reg & VP_MDET_TX_TCLAN_VALID_M) { wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF); vf_mdd_detected = true; - dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + dev_info(dev, "TX driver issue detected on VF %d\n", i); } @@ -1317,7 +1315,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) if (reg & VP_MDET_TX_TDPU_VALID_M) { wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF); vf_mdd_detected = true; - dev_info(&pf->pdev->dev, "TX driver issue detected on VF %d\n", + dev_info(dev, "TX driver issue detected on VF %d\n", i); } @@ -1325,7 +1323,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) if (reg & VP_MDET_RX_VALID_M) { wr32(hw, VP_MDET_RX(i), 0xFFFF); vf_mdd_detected = true; - dev_info(&pf->pdev->dev, "RX driver issue detected on VF %d\n", + dev_info(dev, "RX driver issue detected on VF %d\n", i); } @@ -1333,7 +1331,7 @@ static void ice_handle_mdd_event(struct ice_pf *pf) vf->num_mdd_events++; if (vf->num_mdd_events && vf->num_mdd_events <= ICE_MDD_EVENTS_THRESHOLD) - dev_info(&pf->pdev->dev, + dev_info(dev, "VF %d has had %llu MDD events since last boot, Admin might need to reload AVF driver with this number of events\n", i, vf->num_mdd_events); } @@ -1580,11 +1578,13 @@ 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; int vector, err; int irq_num; + dev = ice_pf_to_dev(pf); for (vector = 0; vector < q_vectors; vector++) { struct ice_q_vector *q_vector = vsi->q_vectors[vector]; @@ -1604,8 +1604,7 @@ static int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) /* skip this unused q_vector */ continue; } - err = devm_request_irq(&pf->pdev->dev, irq_num, - vsi->irq_handler, 0, + err = devm_request_irq(dev, irq_num, vsi->irq_handler, 0, q_vector->name, q_vector); if (err) { netdev_err(vsi->netdev, @@ -1631,7 +1630,7 @@ free_q_irqs: irq_num = pf->msix_entries[base + vector].vector, irq_set_affinity_notifier(irq_num, NULL); irq_set_affinity_hint(irq_num, NULL); - devm_free_irq(&pf->pdev->dev, irq_num, &vsi->q_vectors[vector]); + devm_free_irq(dev, irq_num, &vsi->q_vectors[vector]); } return err; } @@ -1720,9 +1719,11 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog) .mapping_mode = ICE_VSI_MAP_CONTIG }; enum ice_status status; + struct device *dev; int i, v_idx; - vsi->xdp_rings = devm_kcalloc(&pf->pdev->dev, vsi->num_xdp_txq, + dev = ice_pf_to_dev(pf); + vsi->xdp_rings = devm_kcalloc(dev, vsi->num_xdp_txq, sizeof(*vsi->xdp_rings), GFP_KERNEL); if (!vsi->xdp_rings) return -ENOMEM; @@ -1769,8 +1770,7 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog) status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, max_txqs); if (status) { - dev_err(&pf->pdev->dev, - "Failed VSI LAN queue config for XDP, error:%d\n", + dev_err(dev, "Failed VSI LAN queue config for XDP, error:%d\n", status); goto clear_xdp_rings; } @@ -1792,7 +1792,7 @@ err_map_xdp: } mutex_unlock(&pf->avail_q_mutex); - devm_kfree(&pf->pdev->dev, vsi->xdp_rings); + devm_kfree(dev, vsi->xdp_rings); return -ENOMEM; } @@ -1845,7 +1845,7 @@ free_qmap: vsi->xdp_rings[i] = NULL; } - devm_kfree(&pf->pdev->dev, vsi->xdp_rings); + devm_kfree(ice_pf_to_dev(pf), vsi->xdp_rings); vsi->xdp_rings = NULL; if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0]) @@ -1992,8 +1992,10 @@ 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; + dev = ice_pf_to_dev(pf); set_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); set_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state); @@ -2029,8 +2031,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) else if (reset == ICE_RESET_EMPR) pf->empr_count++; else - dev_dbg(&pf->pdev->dev, "Invalid reset type %d\n", - reset); + dev_dbg(dev, "Invalid reset type %d\n", reset); /* If a reset cycle isn't already in progress, we set a bit in * pf->state so that the service task can start a reset/rebuild. @@ -2064,8 +2065,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) if (oicr & PFINT_OICR_HMC_ERR_M) { ena_mask &= ~PFINT_OICR_HMC_ERR_M; - dev_dbg(&pf->pdev->dev, - "HMC Error interrupt - info 0x%x, data 0x%x\n", + dev_dbg(dev, "HMC Error interrupt - info 0x%x, data 0x%x\n", rd32(hw, PFHMC_ERRORINFO), rd32(hw, PFHMC_ERRORDATA)); } @@ -2073,8 +2073,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data) /* Report any remaining unexpected interrupts */ oicr &= ena_mask; if (oicr) { - dev_dbg(&pf->pdev->dev, "unhandled interrupt oicr=0x%08x\n", - oicr); + dev_dbg(dev, "unhandled interrupt oicr=0x%08x\n", oicr); /* If a critical error is pending there is no choice but to * reset the device. */ @@ -2132,7 +2131,7 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf) if (pf->msix_entries) { synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); - devm_free_irq(&pf->pdev->dev, + devm_free_irq(ice_pf_to_dev(pf), pf->msix_entries[pf->oicr_idx].vector, pf); } @@ -2176,13 +2175,13 @@ static void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx) */ 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; if (!pf->int_name[0]) snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", - dev_driver_string(&pf->pdev->dev), - dev_name(&pf->pdev->dev)); + dev_driver_string(dev), dev_name(dev)); /* Do not request IRQ but do enable OICR interrupt since settings are * lost during reset. Note that this function is called only during @@ -2199,12 +2198,10 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf) pf->num_avail_sw_msix -= 1; pf->oicr_idx = oicr_idx; - err = devm_request_irq(&pf->pdev->dev, - pf->msix_entries[pf->oicr_idx].vector, + err = devm_request_irq(dev, pf->msix_entries[pf->oicr_idx].vector, ice_misc_intr, 0, pf->int_name, pf); if (err) { - dev_err(&pf->pdev->dev, - "devm_request_irq for %s failed: %d\n", + dev_err(dev, "devm_request_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; @@ -2337,7 +2334,7 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) ice_set_ops(netdev); if (vsi->type == ICE_VSI_PF) { - SET_NETDEV_DEV(netdev, &pf->pdev->dev); + SET_NETDEV_DEV(netdev, ice_pf_to_dev(pf)); ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr); ether_addr_copy(netdev->dev_addr, mac_addr); ether_addr_copy(netdev->perm_addr, mac_addr); @@ -2664,7 +2661,7 @@ static int ice_init_pf(struct ice_pf *pf) pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL); if (!pf->avail_rxqs) { - devm_kfree(&pf->pdev->dev, pf->avail_txqs); + devm_kfree(ice_pf_to_dev(pf), pf->avail_txqs); pf->avail_txqs = NULL; return -ENOMEM; } @@ -2681,6 +2678,7 @@ static int ice_init_pf(struct ice_pf *pf) */ static int ice_ena_msix_range(struct ice_pf *pf) { + struct device *dev = ice_pf_to_dev(pf); int v_left, v_actual, v_budget = 0; int needed, err, i; @@ -2701,7 +2699,7 @@ static int ice_ena_msix_range(struct ice_pf *pf) v_budget += needed; v_left -= needed; - pf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget, + pf->msix_entries = devm_kcalloc(dev, v_budget, sizeof(*pf->msix_entries), GFP_KERNEL); if (!pf->msix_entries) { @@ -2717,13 +2715,13 @@ static int ice_ena_msix_range(struct ice_pf *pf) ICE_MIN_MSIX, v_budget); if (v_actual < 0) { - dev_err(&pf->pdev->dev, "unable to reserve MSI-X vectors\n"); + dev_err(dev, "unable to reserve MSI-X vectors\n"); err = v_actual; goto msix_err; } if (v_actual < v_budget) { - dev_warn(&pf->pdev->dev, + dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n", v_budget, v_actual); /* 2 vectors for LAN (traffic + OICR) */ @@ -2742,11 +2740,11 @@ static int ice_ena_msix_range(struct ice_pf *pf) return v_actual; msix_err: - devm_kfree(&pf->pdev->dev, pf->msix_entries); + devm_kfree(dev, pf->msix_entries); goto exit_err; no_hw_vecs_left_err: - dev_err(&pf->pdev->dev, + dev_err(dev, "not enough device MSI-X vectors. requested = %d, available = %d\n", needed, v_left); err = -ERANGE; @@ -2762,7 +2760,7 @@ exit_err: static void ice_dis_msix(struct ice_pf *pf) { pci_disable_msix(pf->pdev); - devm_kfree(&pf->pdev->dev, pf->msix_entries); + devm_kfree(ice_pf_to_dev(pf), pf->msix_entries); pf->msix_entries = NULL; } @@ -2775,7 +2773,7 @@ static void ice_clear_interrupt_scheme(struct ice_pf *pf) ice_dis_msix(pf); if (pf->irq_tracker) { - devm_kfree(&pf->pdev->dev, pf->irq_tracker); + devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); pf->irq_tracker = NULL; } } @@ -2795,7 +2793,7 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf) /* set up vector assignment tracking */ pf->irq_tracker = - devm_kzalloc(&pf->pdev->dev, sizeof(*pf->irq_tracker) + + devm_kzalloc(ice_pf_to_dev(pf), sizeof(*pf->irq_tracker) + (sizeof(u16) * vectors), GFP_KERNEL); if (!pf->irq_tracker) { ice_dis_msix(pf); @@ -2819,7 +2817,7 @@ static void ice_log_pkg_init(struct ice_hw *hw, enum ice_status *status) { struct ice_pf *pf = (struct ice_pf *)hw->back; - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); switch (*status) { case ICE_SUCCESS: @@ -2938,7 +2936,7 @@ static void ice_load_pkg(const struct firmware *firmware, struct ice_pf *pf) { enum ice_status status = ICE_ERR_PARAM; - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; /* Load DDP Package */ @@ -2978,7 +2976,7 @@ ice_load_pkg(const struct firmware *firmware, struct ice_pf *pf) static void ice_verify_cacheline_size(struct ice_pf *pf) { if (rd32(&pf->hw, GLPCI_CNF2) & GLPCI_CNF2_CACHELINE_SIZE_M) - dev_warn(&pf->pdev->dev, + dev_warn(ice_pf_to_dev(pf), "%d Byte cache line assumption is invalid, driver may have Tx timeouts!\n", ICE_CACHE_LINE_BYTES); } @@ -3048,7 +3046,7 @@ static void ice_request_fw(struct ice_pf *pf) { char *opt_fw_filename = ice_get_opt_fw_name(pf); const struct firmware *firmware = NULL; - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); int err = 0; /* optional device-specific DDP (if present) overrides the default DDP @@ -3239,7 +3237,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) err = ice_setup_pf_sw(pf); if (err) { - dev_err(dev, "probe failed due to setup PF switch:%d\n", err); + dev_err(dev, "probe failed due to setup PF switch: %d\n", err); goto err_alloc_sw_unroll; } @@ -3287,7 +3285,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) err_alloc_sw_unroll: set_bit(__ICE_SERVICE_DIS, pf->state); set_bit(__ICE_DOWN, pf->state); - devm_kfree(&pf->pdev->dev, pf->first_sw); + devm_kfree(dev, pf->first_sw); err_msix_misc_unroll: ice_free_irq_msix_misc(pf); err_init_interrupt_unroll: @@ -4409,7 +4407,7 @@ static int ice_vsi_open(struct ice_vsi *vsi) goto err_setup_rx; snprintf(int_name, sizeof(int_name) - 1, "%s-%s", - dev_driver_string(&pf->pdev->dev), vsi->netdev->name); + dev_driver_string(ice_pf_to_dev(pf)), vsi->netdev->name); err = ice_vsi_req_irq_msix(vsi, int_name); if (err) goto err_setup_rx; @@ -4458,7 +4456,7 @@ static void ice_vsi_release_all(struct ice_pf *pf) err = ice_vsi_release(pf->vsi[i]); if (err) - dev_dbg(&pf->pdev->dev, + dev_dbg(ice_pf_to_dev(pf), "Failed to release pf->vsi[%d], err %d, vsi_num = %d\n", i, err, pf->vsi[i]->vsi_num); } @@ -4473,6 +4471,7 @@ static void ice_vsi_release_all(struct ice_pf *pf) */ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) { + struct device *dev = ice_pf_to_dev(pf); enum ice_status status; int i, err; @@ -4485,7 +4484,7 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) /* rebuild the VSI */ err = ice_vsi_rebuild(vsi); if (err) { - dev_err(&pf->pdev->dev, + dev_err(dev, "rebuild VSI failed, err %d, VSI index %d, type %s\n", err, vsi->idx, ice_vsi_type_str(type)); return err; @@ -4494,7 +4493,7 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) /* replay filters for the VSI */ status = ice_replay_vsi(&pf->hw, vsi->idx); if (status) { - dev_err(&pf->pdev->dev, + dev_err(dev, "replay VSI failed, status %d, VSI index %d, type %s\n", status, vsi->idx, ice_vsi_type_str(type)); return -EIO; @@ -4508,14 +4507,14 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) /* enable the VSI */ err = ice_ena_vsi(vsi, false); if (err) { - dev_err(&pf->pdev->dev, + dev_err(dev, "enable VSI failed, err %d, VSI index %d, type %s\n", err, vsi->idx, ice_vsi_type_str(type)); return err; } - dev_info(&pf->pdev->dev, "VSI rebuilt. VSI index %d, type %s\n", - vsi->idx, ice_vsi_type_str(type)); + dev_info(dev, "VSI rebuilt. VSI index %d, type %s\n", vsi->idx, + ice_vsi_type_str(type)); } return 0; @@ -4554,7 +4553,7 @@ static void ice_update_pf_netdev_link(struct ice_pf *pf) */ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) { - struct device *dev = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; enum ice_status ret; int err; @@ -4600,7 +4599,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) err = ice_update_link_info(hw->port_info); if (err) - dev_err(&pf->pdev->dev, "Get link status error %d\n", err); + dev_err(dev, "Get link status error %d\n", err); /* start misc vector */ err = ice_req_irq_msix_misc(pf); @@ -4759,7 +4758,9 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; enum ice_status status; + struct device *dev; + dev = ice_pf_to_dev(pf); if (seed) { struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; @@ -4767,8 +4768,7 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) status = ice_aq_set_rss_key(hw, vsi->idx, buf); if (status) { - dev_err(&pf->pdev->dev, - "Cannot set RSS key, err %d aq_err %d\n", + dev_err(dev, "Cannot set RSS key, err %d aq_err %d\n", status, hw->adminq.rq_last_status); return -EIO; } @@ -4778,8 +4778,7 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, lut, lut_size); if (status) { - dev_err(&pf->pdev->dev, - "Cannot set RSS lut, err %d aq_err %d\n", + dev_err(dev, "Cannot set RSS lut, err %d aq_err %d\n", status, hw->adminq.rq_last_status); return -EIO; } @@ -4802,15 +4801,16 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; enum ice_status status; + struct device *dev; + dev = ice_pf_to_dev(pf); if (seed) { struct ice_aqc_get_set_rss_keys *buf = (struct ice_aqc_get_set_rss_keys *)seed; status = ice_aq_get_rss_key(hw, vsi->idx, buf); if (status) { - dev_err(&pf->pdev->dev, - "Cannot get RSS key, err %d aq_err %d\n", + dev_err(dev, "Cannot get RSS key, err %d aq_err %d\n", status, hw->adminq.rq_last_status); return -EIO; } @@ -4820,8 +4820,7 @@ int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) status = ice_aq_get_rss_lut(hw, vsi->idx, vsi->rss_lut_type, lut, lut_size); if (status) { - dev_err(&pf->pdev->dev, - "Cannot get RSS lut, err %d aq_err %d\n", + dev_err(dev, "Cannot get RSS lut, err %d aq_err %d\n", status, hw->adminq.rq_last_status); return -EIO; } diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 565fc9780ebe..269204ca0b1d 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -185,12 +185,14 @@ static void ice_dis_vf_mappings(struct ice_vf *vf) { struct ice_pf *pf = vf->pf; struct ice_vsi *vsi; + struct device *dev; int first, last, v; struct ice_hw *hw; hw = &pf->hw; vsi = pf->vsi[vf->lan_vsi_idx]; + dev = ice_pf_to_dev(pf); wr32(hw, VPINT_ALLOC(vf->vf_id), 0); wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), 0); @@ -209,13 +211,12 @@ static void ice_dis_vf_mappings(struct ice_vf *vf) if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG) wr32(hw, VPLAN_TX_QBASE(vf->vf_id), 0); else - dev_err(&pf->pdev->dev, - "Scattered mode for VF Tx queues is not yet implemented\n"); + dev_err(dev, "Scattered mode for VF Tx queues is not yet implemented\n"); if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG) wr32(hw, VPLAN_RX_QBASE(vf->vf_id), 0); else - dev_err(&pf->pdev->dev, + dev_err(dev, "Scattered mode for VF Rx queues is not yet implemented\n"); } @@ -290,6 +291,7 @@ static void ice_dis_vf_qs(struct ice_vf *vf) */ void ice_free_vfs(struct ice_pf *pf) { + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; int tmp, i; @@ -311,7 +313,7 @@ void ice_free_vfs(struct ice_pf *pf) if (!pci_vfs_assigned(pf->pdev)) pci_disable_sriov(pf->pdev); else - dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n"); + dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n"); tmp = pf->num_alloc_vfs; pf->num_vf_qps = 0; @@ -326,10 +328,9 @@ void ice_free_vfs(struct ice_pf *pf) } if (ice_sriov_free_msix_res(pf)) - dev_err(&pf->pdev->dev, - "Failed to free MSIX resources used by SR-IOV\n"); + dev_err(dev, "Failed to free MSIX resources used by SR-IOV\n"); - devm_kfree(&pf->pdev->dev, pf->vf); + devm_kfree(dev, pf->vf); pf->vf = NULL; /* This check is for when the driver is unloaded while VFs are @@ -368,9 +369,11 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr) { struct ice_pf *pf = vf->pf; u32 reg, reg_idx, bit_idx; + struct device *dev; struct ice_hw *hw; int vf_abs_id, i; + dev = ice_pf_to_dev(pf); hw = &pf->hw; vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id; @@ -416,7 +419,7 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr) if ((reg & VF_TRANS_PENDING_M) == 0) break; - dev_err(&pf->pdev->dev, + dev_err(dev, "VF %d PCI transactions stuck\n", vf->vf_id); udelay(ICE_PCI_CIAD_WAIT_DELAY_US); } @@ -532,14 +535,16 @@ static int ice_alloc_vsi_res(struct ice_vf *vf) LIST_HEAD(tmp_add_list); u8 broadcast[ETH_ALEN]; struct ice_vsi *vsi; + struct device *dev; int status = 0; + dev = ice_pf_to_dev(pf); /* first vector index is the VFs OICR index */ vf->first_vector_idx = ice_calc_vf_first_vector_idx(pf, vf); vsi = ice_vf_vsi_setup(pf, pf->hw.port_info, vf->vf_id); if (!vsi) { - dev_err(&pf->pdev->dev, "Failed to create VF VSI\n"); + dev_err(dev, "Failed to create VF VSI\n"); return -ENOMEM; } @@ -567,8 +572,7 @@ static int ice_alloc_vsi_res(struct ice_vf *vf) status = ice_add_mac(&pf->hw, &tmp_add_list); if (status) - dev_err(&pf->pdev->dev, - "could not add mac filters error %d\n", status); + dev_err(dev, "could not add mac filters error %d\n", status); else vf->num_mac = 1; @@ -579,7 +583,7 @@ static int ice_alloc_vsi_res(struct ice_vf *vf) * more vectors. */ ice_alloc_vsi_res_exit: - ice_free_fltr_list(&pf->pdev->dev, &tmp_add_list); + ice_free_fltr_list(dev, &tmp_add_list); return status; } @@ -635,10 +639,12 @@ static void ice_ena_vf_mappings(struct ice_vf *vf) int abs_vf_id, abs_first, abs_last; struct ice_pf *pf = vf->pf; struct ice_vsi *vsi; + struct device *dev; int first, last, v; struct ice_hw *hw; u32 reg; + dev = ice_pf_to_dev(pf); hw = &pf->hw; vsi = pf->vsi[vf->lan_vsi_idx]; first = vf->first_vector_idx; @@ -686,8 +692,7 @@ static void ice_ena_vf_mappings(struct ice_vf *vf) VPLAN_TX_QBASE_VFNUMQ_M)); wr32(hw, VPLAN_TX_QBASE(vf->vf_id), reg); } else { - dev_err(&pf->pdev->dev, - "Scattered mode for VF Tx queues is not yet implemented\n"); + dev_err(dev, "Scattered mode for VF Tx queues is not yet implemented\n"); } /* set regardless of mapping mode */ @@ -705,8 +710,7 @@ static void ice_ena_vf_mappings(struct ice_vf *vf) VPLAN_RX_QBASE_VFNUMQ_M)); wr32(hw, VPLAN_RX_QBASE(vf->vf_id), reg); } else { - dev_err(&pf->pdev->dev, - "Scattered mode for VF Rx queues is not yet implemented\n"); + dev_err(dev, "Scattered mode for VF Rx queues is not yet implemented\n"); } } @@ -852,6 +856,7 @@ static int ice_check_avail_res(struct ice_pf *pf) { int max_valid_res_idx = ice_get_max_valid_res_idx(pf->irq_tracker); u16 num_msix, num_txq, num_rxq, num_avail_msix; + struct device *dev = ice_pf_to_dev(pf); if (!pf->num_alloc_vfs || max_valid_res_idx < 0) return -EINVAL; @@ -884,8 +889,7 @@ static int ice_check_avail_res(struct ice_pf *pf) ICE_DFLT_INTR_PER_VF, ICE_MIN_INTR_PER_VF); } else { - dev_err(&pf->pdev->dev, - "Number of VFs %d exceeds max VF count %d\n", + dev_err(dev, "Number of VFs %d exceeds max VF count %d\n", pf->num_alloc_vfs, ICE_MAX_VF_COUNT); return -EIO; } @@ -1023,12 +1027,12 @@ ice_vf_set_vsi_promisc(struct ice_vf *vf, struct ice_vsi *vsi, u8 promisc_m, */ static bool ice_config_res_vfs(struct ice_pf *pf) { + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; int v; if (ice_check_avail_res(pf)) { - dev_err(&pf->pdev->dev, - "Cannot allocate VF resources, try with fewer number of VFs\n"); + dev_err(dev, "Cannot allocate VF resources, try with fewer number of VFs\n"); return false; } @@ -1041,9 +1045,8 @@ static bool ice_config_res_vfs(struct ice_pf *pf) struct ice_vf *vf = &pf->vf[v]; vf->num_vf_qs = pf->num_vf_qps; - dev_dbg(&pf->pdev->dev, - "VF-id %d has %d queues configured\n", - vf->vf_id, vf->num_vf_qs); + dev_dbg(dev, "VF-id %d has %d queues configured\n", vf->vf_id, + vf->num_vf_qs); ice_cleanup_and_realloc_vf(vf); } @@ -1067,6 +1070,7 @@ static bool ice_config_res_vfs(struct ice_pf *pf) */ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) { + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; struct ice_vf *vf; int v, i; @@ -1125,7 +1129,7 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) * time, but continue on with the operation. */ if (v < pf->num_alloc_vfs) - dev_warn(&pf->pdev->dev, "VF reset check timeout\n"); + dev_warn(dev, "VF reset check timeout\n"); /* free VF resources to begin resetting the VSI state */ for (v = 0; v < pf->num_alloc_vfs; v++) { @@ -1142,8 +1146,7 @@ bool ice_reset_all_vfs(struct ice_pf *pf, bool is_vflr) } if (ice_sriov_free_msix_res(pf)) - dev_err(&pf->pdev->dev, - "Failed to free MSIX resources used by SR-IOV\n"); + dev_err(dev, "Failed to free MSIX resources used by SR-IOV\n"); if (!ice_config_res_vfs(pf)) return false; @@ -1181,16 +1184,18 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) { struct ice_pf *pf = vf->pf; struct ice_vsi *vsi; + struct device *dev; struct ice_hw *hw; bool rsd = false; u8 promisc_m; u32 reg; int i; + dev = ice_pf_to_dev(pf); + if (ice_is_vf_disabled(vf)) { - dev_dbg(&pf->pdev->dev, - "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n", - vf->vf_id); + dev_dbg(dev, "VF is already disabled, there is no need for resetting it, telling VM, all is fine %d\n", + vf->vf_id); return true; } @@ -1232,8 +1237,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) * continue on with the operation. */ if (!rsd) - dev_warn(&pf->pdev->dev, "VF reset check timeout on VF %d\n", - vf->vf_id); + dev_warn(dev, "VF reset check timeout on VF %d\n", vf->vf_id); /* disable promiscuous modes in case they were enabled * ignore any error if disabling process failed @@ -1247,7 +1251,7 @@ static bool ice_reset_vf(struct ice_vf *vf, bool is_vflr) vsi = pf->vsi[vf->lan_vsi_idx]; if (ice_vf_set_vsi_promisc(vf, vsi, promisc_m, true)) - dev_err(&pf->pdev->dev, "disabling promiscuous mode failed\n"); + dev_err(dev, "disabling promiscuous mode failed\n"); } /* free VF resources to begin resetting the VSI state */ @@ -1325,6 +1329,7 @@ static void ice_vc_notify_vf_reset(struct ice_vf *vf) */ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs) { + struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; struct ice_vf *vfs; int i, ret; @@ -1341,8 +1346,7 @@ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs) goto err_unroll_intr; } /* allocate memory */ - vfs = devm_kcalloc(&pf->pdev->dev, num_alloc_vfs, sizeof(*vfs), - GFP_KERNEL); + vfs = devm_kcalloc(dev, num_alloc_vfs, sizeof(*vfs), GFP_KERNEL); if (!vfs) { ret = -ENOMEM; goto err_pci_disable_sriov; @@ -1371,7 +1375,7 @@ static int ice_alloc_vfs(struct ice_pf *pf, u16 num_alloc_vfs) err_unroll_sriov: pf->vf = NULL; - devm_kfree(&pf->pdev->dev, vfs); + devm_kfree(dev, vfs); vfs = NULL; pf->num_alloc_vfs = 0; err_pci_disable_sriov: @@ -1416,7 +1420,7 @@ static bool ice_pf_state_is_nominal(struct ice_pf *pf) 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 = &pf->pdev->dev; + struct device *dev = ice_pf_to_dev(pf); int err; if (!ice_pf_state_is_nominal(pf)) { @@ -1461,10 +1465,10 @@ static int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs) int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) { struct ice_pf *pf = pci_get_drvdata(pdev); + struct device *dev = ice_pf_to_dev(pf); if (ice_is_safe_mode(pf)) { - dev_err(&pf->pdev->dev, - "SR-IOV cannot be configured - Device is in Safe Mode\n"); + dev_err(dev, "SR-IOV cannot be configured - Device is in Safe Mode\n"); return -EOPNOTSUPP; } @@ -1474,8 +1478,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs) if (!pci_vfs_assigned(pdev)) { ice_free_vfs(pf); } else { - dev_err(&pf->pdev->dev, - "can't free VFs because some are assigned to VMs.\n"); + dev_err(dev, "can't free VFs because some are assigned to VMs.\n"); return -EBUSY; } @@ -1538,6 +1541,7 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, enum virtchnl_status_code v_retval, u8 *msg, u16 msglen) { enum ice_status aq_ret; + struct device *dev; struct ice_pf *pf; /* validate the request */ @@ -1546,16 +1550,18 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, pf = vf->pf; + dev = ice_pf_to_dev(pf); + /* single place to detect unsuccessful return values */ if (v_retval) { vf->num_inval_msgs++; - dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n", - vf->vf_id, v_opcode, v_retval); + dev_info(dev, "VF %d failed opcode %d, retval: %d\n", vf->vf_id, + v_opcode, v_retval); if (vf->num_inval_msgs > ICE_DFLT_NUM_INVAL_MSGS_ALLOWED) { - dev_err(&pf->pdev->dev, + dev_err(dev, "Number of invalid messages exceeded for VF %d\n", vf->vf_id); - dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n"); + dev_err(dev, "Use PF Control I/F to enable the VF\n"); set_bit(ICE_VF_STATE_DIS, vf->vf_states); return -EIO; } @@ -1568,7 +1574,7 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, aq_ret = ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, v_opcode, v_retval, msg, msglen, NULL); if (aq_ret && pf->hw.mailboxq.sq_last_status != ICE_AQ_RC_ENOSYS) { - dev_info(&pf->pdev->dev, + dev_info(dev, "Unable to send the message to VF %d ret %d aq_err %d\n", vf->vf_id, aq_ret, pf->hw.mailboxq.sq_last_status); return -EIO; @@ -2273,7 +2279,7 @@ static int ice_vc_cfg_qs_msg(struct ice_vf *vf, u8 *msg) if (qci->num_queue_pairs > ICE_MAX_BASE_QS_PER_VF || qci->num_queue_pairs > min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)) { - dev_err(&pf->pdev->dev, + dev_err(ice_pf_to_dev(pf), "VF-%d requesting more than supported number of queues: %d\n", vf->vf_id, min_t(u16, vsi->alloc_txq, vsi->alloc_rxq)); v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2386,9 +2392,12 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) enum virtchnl_ops vc_op; enum ice_status status; struct ice_vsi *vsi; + struct device *dev; int mac_count = 0; int i; + dev = ice_pf_to_dev(pf); + if (set) vc_op = VIRTCHNL_OP_ADD_ETH_ADDR; else @@ -2402,7 +2411,7 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) if (set && !ice_is_vf_trusted(vf) && (vf->num_mac + al->num_elements) > ICE_MAX_MACADDR_PER_VF) { - dev_err(&pf->pdev->dev, + dev_err(dev, "Can't add more MAC addresses, because VF-%d is not trusted, switch the VF to trusted mode in order to add more functionalities\n", vf->vf_id); /* There is no need to let VF know about not being trusted @@ -2427,13 +2436,13 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) /* VF is trying to add filters that the PF * already added. Just continue. */ - dev_info(&pf->pdev->dev, + dev_info(dev, "MAC %pM already set for VF %d\n", maddr, vf->vf_id); continue; } else { /* VF can't remove dflt_lan_addr/bcast MAC */ - dev_err(&pf->pdev->dev, + dev_err(dev, "VF can't remove default MAC address or MAC %pM programmed by PF for VF %d\n", maddr, vf->vf_id); continue; @@ -2442,7 +2451,7 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) /* check for the invalid cases and bail if necessary */ if (is_zero_ether_addr(maddr)) { - dev_err(&pf->pdev->dev, + dev_err(dev, "invalid MAC %pM provided for VF %d\n", maddr, vf->vf_id); v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2451,7 +2460,7 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) if (is_unicast_ether_addr(maddr) && !ice_can_vf_change_mac(vf)) { - dev_err(&pf->pdev->dev, + dev_err(dev, "can't change unicast MAC for untrusted VF %d\n", vf->vf_id); v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2462,12 +2471,12 @@ ice_vc_handle_mac_addr_msg(struct ice_vf *vf, u8 *msg, bool set) status = ice_vsi_cfg_mac_fltr(vsi, maddr, set); if (status == ICE_ERR_DOES_NOT_EXIST || status == ICE_ERR_ALREADY_EXISTS) { - dev_info(&pf->pdev->dev, + dev_info(dev, "can't %s MAC filters %pM for VF %d, error %d\n", set ? "add" : "remove", maddr, vf->vf_id, status); } else if (status) { - dev_err(&pf->pdev->dev, + dev_err(dev, "can't %s MAC filters for VF %d, error %d\n", set ? "add" : "remove", vf->vf_id, status); v_ret = ice_err_to_virt_err(status); @@ -2532,7 +2541,9 @@ static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) u16 max_allowed_vf_queues; u16 tx_rx_queue_left; u16 cur_queues; + struct device *dev; + dev = ice_pf_to_dev(pf); if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; @@ -2543,17 +2554,15 @@ static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) ice_get_avail_rxq_count(pf)); max_allowed_vf_queues = tx_rx_queue_left + cur_queues; if (!req_queues) { - dev_err(&pf->pdev->dev, - "VF %d tried to request 0 queues. Ignoring.\n", + dev_err(dev, "VF %d tried to request 0 queues. Ignoring.\n", vf->vf_id); } else if (req_queues > ICE_MAX_BASE_QS_PER_VF) { - dev_err(&pf->pdev->dev, - "VF %d tried to request more than %d queues.\n", + dev_err(dev, "VF %d tried to request more than %d queues.\n", vf->vf_id, ICE_MAX_BASE_QS_PER_VF); vfres->num_queue_pairs = ICE_MAX_BASE_QS_PER_VF; } else if (req_queues > cur_queues && req_queues - cur_queues > tx_rx_queue_left) { - dev_warn(&pf->pdev->dev, + dev_warn(dev, "VF %d requested %u more queues, but only %u left.\n", vf->vf_id, req_queues - cur_queues, tx_rx_queue_left); vfres->num_queue_pairs = min_t(u16, max_allowed_vf_queues, @@ -2562,8 +2571,7 @@ static int ice_vc_request_qs_msg(struct ice_vf *vf, u8 *msg) /* request is successful, then reset VF */ vf->num_req_qs = req_queues; ice_vc_reset_vf(vf); - dev_info(&pf->pdev->dev, - "VF %d granted request of %u queues.\n", + dev_info(dev, "VF %d granted request of %u queues.\n", vf->vf_id, req_queues); return 0; } @@ -2592,36 +2600,37 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_pf *pf = np->vsi->back; struct ice_vsi *vsi; + struct device *dev; struct ice_vf *vf; int ret = 0; + dev = ice_pf_to_dev(pf); /* validate the request */ if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id); + dev_err(dev, "invalid VF id: %d\n", vf_id); return -EINVAL; } if (vlan_id > ICE_MAX_VLANID || qos > 7) { - dev_err(&pf->pdev->dev, "Invalid VF Parameters\n"); + dev_err(dev, "Invalid VF Parameters\n"); return -EINVAL; } if (vlan_proto != htons(ETH_P_8021Q)) { - dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n"); + dev_err(dev, "VF VLAN protocol is not supported\n"); return -EPROTONOSUPPORT; } vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); + dev_err(dev, "VF %d in reset. Try again.\n", vf_id); return -EBUSY; } if (le16_to_cpu(vsi->info.pvid) == vlanprio) { /* duplicate request, so just return success */ - dev_info(&pf->pdev->dev, - "Duplicate pvid %d request\n", vlanprio); + dev_dbg(dev, "Duplicate pvid %d request\n", vlanprio); return ret; } @@ -2640,7 +2649,7 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, } if (vlan_id) { - dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n", + dev_info(dev, "Setting VLAN %d, QoS 0x%x on VF %d\n", vlan_id, qos, vf_id); /* add new VLAN filter for each MAC */ @@ -2685,11 +2694,13 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) struct ice_pf *pf = vf->pf; bool vlan_promisc = false; struct ice_vsi *vsi; + struct device *dev; struct ice_hw *hw; int status = 0; u8 promisc_m; int i; + dev = ice_pf_to_dev(pf); if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto error_param; @@ -2707,7 +2718,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) if (add_v && !ice_is_vf_trusted(vf) && vf->num_vlan >= ICE_MAX_VLAN_PER_VF) { - dev_info(&pf->pdev->dev, + dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", vf->vf_id); /* There is no need to let VF know about being not trusted, @@ -2719,7 +2730,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) for (i = 0; i < vfl->num_elements; i++) { if (vfl->vlan_id[i] > ICE_MAX_VLANID) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(&pf->pdev->dev, + dev_err(dev, "invalid VF VLAN id %d\n", vfl->vlan_id[i]); goto error_param; } @@ -2747,7 +2758,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) if (!ice_is_vf_trusted(vf) && vf->num_vlan >= ICE_MAX_VLAN_PER_VF) { - dev_info(&pf->pdev->dev, + dev_info(dev, "VF-%d is not trusted, switch the VF to trusted mode, in order to add more VLAN addresses\n", vf->vf_id); /* There is no need to let VF know about being @@ -2768,7 +2779,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) status = ice_cfg_vlan_pruning(vsi, true, false); if (status) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(&pf->pdev->dev, + dev_err(dev, "Enable VLAN pruning on VLAN ID: %d failed error-%d\n", vid, status); goto error_param; @@ -2782,7 +2793,7 @@ static int ice_vc_process_vlan_msg(struct ice_vf *vf, u8 *msg, bool add_v) promisc_m, vid); if (status) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; - dev_err(&pf->pdev->dev, + dev_err(dev, "Enable Unicast/multicast promiscuous mode on VLAN ID:%d failed error-%d\n", vid, status); } @@ -2969,8 +2980,10 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) u16 msglen = event->msg_len; u8 *msg = event->msg_buf; struct ice_vf *vf = NULL; + struct device *dev; int err = 0; + dev = ice_pf_to_dev(pf); if (vf_id >= pf->num_alloc_vfs) { err = -EINVAL; goto error_handler; @@ -2997,7 +3010,7 @@ error_handler: if (err) { ice_vc_send_msg_to_vf(vf, v_opcode, VIRTCHNL_STATUS_ERR_PARAM, NULL, 0); - dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n", + dev_err(dev, "Invalid message from VF %d, opcode %d, len %d, error %d\n", vf_id, v_opcode, msglen, err); return; } @@ -3009,7 +3022,7 @@ error_handler: case VIRTCHNL_OP_GET_VF_RESOURCES: err = ice_vc_get_vf_res_msg(vf, msg); if (ice_vf_init_vlan_stripping(vf)) - dev_err(&pf->pdev->dev, + dev_err(dev, "Failed to initialize VLAN stripping for VF %d\n", vf->vf_id); ice_vc_notify_vf_link_state(vf); @@ -3062,8 +3075,8 @@ error_handler: break; case VIRTCHNL_OP_UNKNOWN: default: - dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n", - v_opcode, vf_id); + dev_err(dev, "Unsupported opcode %d from VF %d\n", v_opcode, + vf_id); err = ice_vc_send_msg_to_vf(vf, v_opcode, VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, NULL, 0); @@ -3073,8 +3086,7 @@ error_handler: /* Helper function cares less about error return values here * as it is busy with pending work. */ - dev_info(&pf->pdev->dev, - "PF failed to honor VF %d, opcode %d, error %d\n", + dev_info(dev, "PF failed to honor VF %d, opcode %d, error %d\n", vf_id, v_opcode, err); } } @@ -3145,9 +3157,12 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) struct ice_pf *pf = vsi->back; struct ice_vsi_ctx *ctx; enum ice_status status; + struct device *dev; struct ice_vf *vf; int ret = 0; + dev = ice_pf_to_dev(pf); + /* validate the request */ if (vf_id >= pf->num_alloc_vfs) { netdev_err(netdev, "invalid VF id: %d\n", vf_id); @@ -3161,7 +3176,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) } if (ena == vf->spoofchk) { - dev_dbg(&pf->pdev->dev, "VF spoofchk already %s\n", + dev_dbg(dev, "VF spoofchk already %s\n", ena ? "ON" : "OFF"); return 0; } @@ -3179,7 +3194,7 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) status = ice_update_vsi(&pf->hw, vsi->idx, ctx, NULL); if (status) { - dev_dbg(&pf->pdev->dev, + dev_dbg(dev, "Error %d, failed to update VSI* parameters\n", status); ret = -EIO; goto out; @@ -3280,11 +3295,14 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) struct ice_netdev_priv *np = netdev_priv(netdev); struct ice_vsi *vsi = np->vsi; struct ice_pf *pf = vsi->back; + struct device *dev; struct ice_vf *vf; + dev = ice_pf_to_dev(pf); + /* validate the request */ if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "invalid VF id: %d\n", vf_id); + dev_err(dev, "invalid VF id: %d\n", vf_id); return -EINVAL; } @@ -3299,7 +3317,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) ice_wait_on_vf_reset(vf); if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(&pf->pdev->dev, "VF %d in reset. Try again.\n", vf_id); + dev_err(dev, "VF %d in reset. Try again.\n", vf_id); return -EBUSY; } @@ -3309,7 +3327,7 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) vf->trusted = trusted; ice_vc_reset_vf(vf); - dev_info(&pf->pdev->dev, "VF %u is now %strusted\n", + dev_info(dev, "VF %u is now %strusted\n", vf_id, trusted ? "" : "un"); return 0; @@ -3329,11 +3347,14 @@ int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state) struct ice_pf *pf = np->vsi->back; struct virtchnl_pf_event pfe = { 0 }; struct ice_link_status *ls; + struct device *dev; struct ice_vf *vf; struct ice_hw *hw; + dev = ice_pf_to_dev(pf); + if (vf_id >= pf->num_alloc_vfs) { - dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id); + dev_err(dev, "Invalid VF Identifier %d\n", vf_id); return -EINVAL; } @@ -3342,7 +3363,7 @@ int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state) ls = &pf->hw.port_info->phy.link_info; if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(&pf->pdev->dev, "vf %d in reset. Try again.\n", vf_id); + dev_err(dev, "vf %d in reset. Try again.\n", vf_id); return -EBUSY; } diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c index fcffad0069d6..cf9b8b22d24f 100644 --- a/drivers/net/ethernet/intel/ice/ice_xsk.c +++ b/drivers/net/ethernet/intel/ice/ice_xsk.c @@ -331,7 +331,7 @@ static int ice_xsk_umem_dma_map(struct ice_vsi *vsi, struct xdp_umem *umem) struct device *dev; unsigned int i; - dev = &pf->pdev->dev; + dev = ice_pf_to_dev(pf); for (i = 0; i < umem->npgs; i++) { dma_addr_t dma = dma_map_page_attrs(dev, umem->pgs[i], 0, PAGE_SIZE, @@ -369,7 +369,7 @@ static void ice_xsk_umem_dma_unmap(struct ice_vsi *vsi, struct xdp_umem *umem) struct device *dev; unsigned int i; - dev = &pf->pdev->dev; + dev = ice_pf_to_dev(pf); for (i = 0; i < umem->npgs; i++) { dma_unmap_page_attrs(dev, umem->pages[i].dma, PAGE_SIZE, DMA_BIDIRECTIONAL, ICE_RX_DMA_ATTR); -- cgit v1.2.3-59-g8ed1b From 4c66d227e424c23af2c1c90f397909394f782c02 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 8 Nov 2019 06:23:27 -0800 Subject: ice: add helpers for virtchnl The virtchannel interface was repeating a lot of strings and wasting storage space in the kernel. There was also inconsistent messages for the same thing. Consolidate all those messages and bit checks into a couple of helper functions. Also, reduce stack space usage by simplifying getting the pointer to the pf using a helper. Signed-off-by: Jesse Brandeburg Co-developed-by: Brett Creeley Signed-off-by: Brett Creeley Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 134 +++++++++++------------ 1 file changed, 63 insertions(+), 71 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index 269204ca0b1d..aa99d7cb7d8e 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -5,6 +5,35 @@ #include "ice_base.h" #include "ice_lib.h" +/** + * ice_validate_vf_id - helper to check if VF ID is valid + * @pf: pointer to the PF structure + * @vf_id: the ID of the VF to check + */ +static int ice_validate_vf_id(struct ice_pf *pf, int vf_id) +{ + if (vf_id >= pf->num_alloc_vfs) { + dev_err(ice_pf_to_dev(pf), "Invalid VF ID: %d\n", vf_id); + return -EINVAL; + } + return 0; +} + +/** + * ice_check_vf_init - helper to check if VF init complete + * @pf: pointer to the PF structure + * @vf: the pointer to the VF to check + */ +static int ice_check_vf_init(struct ice_pf *pf, struct ice_vf *vf) +{ + if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + dev_err(ice_pf_to_dev(pf), "VF ID: %d in reset. Try again.\n", + vf->vf_id); + return -EBUSY; + } + return 0; +} + /** * ice_err_to_virt err - translate errors for VF return code * @ice_err: error return code @@ -1302,9 +1331,13 @@ void ice_vc_notify_reset(struct ice_pf *pf) static void ice_vc_notify_vf_reset(struct ice_vf *vf) { struct virtchnl_pf_event pfe; + struct ice_pf *pf; - /* validate the request */ - if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + if (!vf) + return; + + pf = vf->pf; + if (ice_validate_vf_id(pf, vf->vf_id)) return; /* Bail out if VF is in disabled state, neither initialized, nor active @@ -1317,7 +1350,7 @@ static void ice_vc_notify_vf_reset(struct ice_vf *vf) pfe.event = VIRTCHNL_EVENT_RESET_IMPENDING; pfe.severity = PF_EVENT_SEVERITY_CERTAIN_DOOM; - ice_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, VIRTCHNL_OP_EVENT, + ice_aq_send_msg_to_vf(&pf->hw, vf->vf_id, VIRTCHNL_OP_EVENT, VIRTCHNL_STATUS_SUCCESS, (u8 *)&pfe, sizeof(pfe), NULL); } @@ -1544,11 +1577,12 @@ ice_vc_send_msg_to_vf(struct ice_vf *vf, u32 v_opcode, struct device *dev; struct ice_pf *pf; - /* validate the request */ - if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs) + if (!vf) return -EINVAL; pf = vf->pf; + if (ice_validate_vf_id(pf, vf->vf_id)) + return -EINVAL; dev = ice_pf_to_dev(pf); @@ -1622,7 +1656,7 @@ static int ice_vc_get_vf_res_msg(struct ice_vf *vf, u8 *msg) int len = 0; int ret; - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { + if (ice_check_vf_init(pf, vf)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; goto err; } @@ -1801,7 +1835,7 @@ static int ice_vc_config_rss_key(struct ice_vf *vf, u8 *msg) struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg; struct ice_pf *pf = vf->pf; - struct ice_vsi *vsi = NULL; + struct ice_vsi *vsi; if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -1848,7 +1882,7 @@ static int ice_vc_config_rss_lut(struct ice_vf *vf, u8 *msg) struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg; enum virtchnl_status_code v_ret = VIRTCHNL_STATUS_SUCCESS; struct ice_pf *pf = vf->pf; - struct ice_vsi *vsi = NULL; + struct ice_vsi *vsi; if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) { v_ret = VIRTCHNL_STATUS_ERR_PARAM; @@ -2597,19 +2631,15 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, __be16 vlan_proto) { u16 vlanprio = vlan_id | (qos << ICE_VLAN_PRIORITY_S); - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_vsi *vsi; struct device *dev; struct ice_vf *vf; int ret = 0; dev = ice_pf_to_dev(pf); - /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(dev, "invalid VF id: %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } if (vlan_id > ICE_MAX_VLANID || qos > 7) { dev_err(dev, "Invalid VF Parameters\n"); @@ -2623,10 +2653,8 @@ ice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos, vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(dev, "VF %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } if (le16_to_cpu(vsi->info.pvid) == vlanprio) { /* duplicate request, so just return success */ @@ -2984,7 +3012,7 @@ void ice_vc_process_vf_msg(struct ice_pf *pf, struct ice_rq_event_info *event) int err = 0; dev = ice_pf_to_dev(pf); - if (vf_id >= pf->num_alloc_vfs) { + if (ice_validate_vf_id(pf, vf_id)) { err = -EINVAL; goto error_handler; } @@ -3102,24 +3130,18 @@ error_handler: int ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_vsi *vsi; struct ice_vf *vf; - /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - netdev_err(netdev, "invalid VF id: %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } vf = &pf->vf[vf_id]; vsi = pf->vsi[vf->lan_vsi_idx]; - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } ivi->vf = vf_id; ether_addr_copy(ivi->mac, vf->dflt_lan_addr.addr); @@ -3152,9 +3174,8 @@ ice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi) */ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_vsi *vsi = pf->vsi[0]; struct ice_vsi_ctx *ctx; enum ice_status status; struct device *dev; @@ -3162,18 +3183,12 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) int ret = 0; dev = ice_pf_to_dev(pf); - - /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - netdev_err(netdev, "invalid VF id: %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } vf = &pf->vf[vf_id]; - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } if (ena == vf->spoofchk) { dev_dbg(dev, "VF spoofchk already %s\n", @@ -3235,17 +3250,12 @@ static void ice_wait_on_vf_reset(struct ice_vf *vf) */ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_vf *vf; int ret = 0; - /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - netdev_err(netdev, "invalid VF id: %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } vf = &pf->vf[vf_id]; /* Don't set MAC on disabled VF */ @@ -3257,10 +3267,8 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) */ ice_wait_on_vf_reset(vf); - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - netdev_err(netdev, "VF %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } if (is_zero_ether_addr(mac) || is_multicast_ether_addr(mac)) { netdev_err(netdev, "%pM not a valid unicast address\n", mac); @@ -3292,19 +3300,13 @@ int ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) */ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct device *dev; struct ice_vf *vf; dev = ice_pf_to_dev(pf); - - /* validate the request */ - if (vf_id >= pf->num_alloc_vfs) { - dev_err(dev, "invalid VF id: %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } vf = &pf->vf[vf_id]; /* Don't set Trusted Mode on disabled VF */ @@ -3316,10 +3318,8 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) */ ice_wait_on_vf_reset(vf); - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(dev, "VF %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } /* Check if already trusted */ if (trusted == vf->trusted) @@ -3343,29 +3343,21 @@ int ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted) */ int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct virtchnl_pf_event pfe = { 0 }; struct ice_link_status *ls; - struct device *dev; struct ice_vf *vf; struct ice_hw *hw; - dev = ice_pf_to_dev(pf); - - if (vf_id >= pf->num_alloc_vfs) { - dev_err(dev, "Invalid VF Identifier %d\n", vf_id); + if (ice_validate_vf_id(pf, vf_id)) return -EINVAL; - } vf = &pf->vf[vf_id]; hw = &pf->hw; ls = &pf->hw.port_info->phy.link_info; - if (!test_bit(ICE_VF_STATE_INIT, vf->vf_states)) { - dev_err(dev, "vf %d in reset. Try again.\n", vf_id); + if (ice_check_vf_init(pf, vf)) return -EBUSY; - } pfe.event = VIRTCHNL_EVENT_LINK_CHANGE; pfe.severity = PF_EVENT_SEVERITY_INFO; -- cgit v1.2.3-59-g8ed1b From 730fdea40beffbc47b5d03d8d6205e6f9a226adc Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 8 Nov 2019 06:23:28 -0800 Subject: ice: implement VF stats NDO Implement the VF stats gathering via the kernel via ndo_get_vf_stats(). The driver will show per-VF stats in the output of the ip -s link show dev command. Signed-off-by: Jesse Brandeburg Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_main.c | 1 + drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c | 45 ++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h | 11 ++++++ 3 files changed, 57 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index ea577588b274..d282eb05c2e0 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5219,6 +5219,7 @@ static const struct net_device_ops ice_netdev_ops = { .ndo_set_vf_trust = ice_set_vf_trust, .ndo_set_vf_vlan = ice_set_vf_port_vlan, .ndo_set_vf_link_state = ice_set_vf_link_state, + .ndo_get_vf_stats = ice_get_vf_stats, .ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid, .ndo_set_features = ice_set_features, diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c index aa99d7cb7d8e..edb374296d1f 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c @@ -3391,3 +3391,48 @@ int ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state) return 0; } + +/** + * ice_get_vf_stats - populate some stats for the VF + * @netdev: the netdev of the PF + * @vf_id: the host OS identifier (0-255) + * @vf_stats: pointer to the OS memory to be initialized + */ +int ice_get_vf_stats(struct net_device *netdev, int vf_id, + struct ifla_vf_stats *vf_stats) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_eth_stats *stats; + struct ice_vsi *vsi; + struct ice_vf *vf; + + if (ice_validate_vf_id(pf, vf_id)) + return -EINVAL; + + vf = &pf->vf[vf_id]; + + if (ice_check_vf_init(pf, vf)) + return -EBUSY; + + vsi = pf->vsi[vf->lan_vsi_idx]; + if (!vsi) + return -EINVAL; + + ice_update_eth_stats(vsi); + stats = &vsi->eth_stats; + + memset(vf_stats, 0, sizeof(*vf_stats)); + + vf_stats->rx_packets = stats->rx_unicast + stats->rx_broadcast + + stats->rx_multicast; + vf_stats->tx_packets = stats->tx_unicast + stats->tx_broadcast + + stats->tx_multicast; + vf_stats->rx_bytes = stats->rx_bytes; + vf_stats->tx_bytes = stats->tx_bytes; + vf_stats->broadcast = stats->rx_broadcast; + vf_stats->multicast = stats->rx_multicast; + vf_stats->rx_dropped = stats->rx_discards; + vf_stats->tx_dropped = stats->tx_discards; + + return 0; +} diff --git a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h index 2e867ad2e81d..88aa65d5cb31 100644 --- a/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h @@ -122,6 +122,9 @@ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena); int ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector); void ice_set_vf_state_qs_dis(struct ice_vf *vf); +int +ice_get_vf_stats(struct net_device *netdev, int vf_id, + struct ifla_vf_stats *vf_stats); #else /* CONFIG_PCI_IOV */ #define ice_process_vflr_event(pf) do {} while (0) #define ice_free_vfs(pf) do {} while (0) @@ -194,5 +197,13 @@ ice_calc_vf_reg_idx(struct ice_vf __always_unused *vf, { return 0; } + +static inline int +ice_get_vf_stats(struct net_device __always_unused *netdev, + int __always_unused vf_id, + struct ifla_vf_stats __always_unused *vf_stats) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_PCI_IOV */ #endif /* _ICE_VIRTCHNL_PF_H_ */ -- cgit v1.2.3-59-g8ed1b From ab118da4c10a70b8437f5c90ab77adae1835963e Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 13 Nov 2019 12:03:47 +0200 Subject: net/mlx5: Don't write read-only fields in MODIFY_HCA_VPORT_CONTEXT command The MODIFY_HCA_VPORT_CONTEXT uses field_selector to mask fields needed to be written, other fields are required to be zero according to the HW specification. The supported fields are controlled by bitfield and limited to vport state, node and port GUIDs. Signed-off-by: Leon Romanovsky Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/vport.c | 27 +++++++------------------ 1 file changed, 7 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 30f7848a6f88..1faac31f74d0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -1064,26 +1064,13 @@ int mlx5_core_modify_hca_vport_context(struct mlx5_core_dev *dev, ctx = MLX5_ADDR_OF(modify_hca_vport_context_in, in, hca_vport_context); MLX5_SET(hca_vport_context, ctx, field_select, req->field_select); - MLX5_SET(hca_vport_context, ctx, sm_virt_aware, req->sm_virt_aware); - MLX5_SET(hca_vport_context, ctx, has_smi, req->has_smi); - MLX5_SET(hca_vport_context, ctx, has_raw, req->has_raw); - MLX5_SET(hca_vport_context, ctx, vport_state_policy, req->policy); - MLX5_SET(hca_vport_context, ctx, port_physical_state, req->phys_state); - MLX5_SET(hca_vport_context, ctx, vport_state, req->vport_state); - MLX5_SET64(hca_vport_context, ctx, port_guid, req->port_guid); - MLX5_SET64(hca_vport_context, ctx, node_guid, req->node_guid); - MLX5_SET(hca_vport_context, ctx, cap_mask1, req->cap_mask1); - MLX5_SET(hca_vport_context, ctx, cap_mask1_field_select, req->cap_mask1_perm); - MLX5_SET(hca_vport_context, ctx, cap_mask2, req->cap_mask2); - MLX5_SET(hca_vport_context, ctx, cap_mask2_field_select, req->cap_mask2_perm); - MLX5_SET(hca_vport_context, ctx, lid, req->lid); - MLX5_SET(hca_vport_context, ctx, init_type_reply, req->init_type_reply); - MLX5_SET(hca_vport_context, ctx, lmc, req->lmc); - MLX5_SET(hca_vport_context, ctx, subnet_timeout, req->subnet_timeout); - MLX5_SET(hca_vport_context, ctx, sm_lid, req->sm_lid); - MLX5_SET(hca_vport_context, ctx, sm_sl, req->sm_sl); - MLX5_SET(hca_vport_context, ctx, qkey_violation_counter, req->qkey_violation_counter); - MLX5_SET(hca_vport_context, ctx, pkey_violation_counter, req->pkey_violation_counter); + if (req->field_select & MLX5_HCA_VPORT_SEL_STATE_POLICY) + MLX5_SET(hca_vport_context, ctx, vport_state_policy, + req->policy); + if (req->field_select & MLX5_HCA_VPORT_SEL_PORT_GUID) + MLX5_SET64(hca_vport_context, ctx, port_guid, req->port_guid); + if (req->field_select & MLX5_HCA_VPORT_SEL_NODE_GUID) + MLX5_SET64(hca_vport_context, ctx, node_guid, req->node_guid); err = mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out)); ex: kfree(in); -- cgit v1.2.3-59-g8ed1b From 6e9e286e4ad53311b51b28fdc4b952ab7d2520c4 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Mon, 28 Oct 2019 16:30:27 +0200 Subject: net/mlx5: DR, Refactor VXLAN GPE flex parser tunnel code for SW steering Refactor flex parser tunnel code: - Add definition for flex parser tunneling header for VXLAN-GPE - Use macros for VXLAN-GPE SW steering when building STE - Refactor the code to reflect that this is a VXLAN GPE only code and not a general flex parser code. This also significantly simplifies addition of more flex parser protocols, such as Geneve. Signed-off-by: Yevgeny Kliteynik Reviewed-by: Alex Vesker Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/steering/dr_matcher.c | 33 ++++++---- .../ethernet/mellanox/mlx5/core/steering/dr_ste.c | 73 +++++++++------------- .../mellanox/mlx5/core/steering/dr_types.h | 6 +- .../mellanox/mlx5/core/steering/mlx5_ifc_dr.h | 11 ++++ 4 files changed, 66 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c index c6548980daf0..f177c468b740 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c @@ -102,13 +102,29 @@ static bool dr_mask_is_gre_set(struct mlx5dr_match_misc *misc) DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), gre) || \ DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), udp)) -static bool dr_mask_is_flex_parser_tnl_set(struct mlx5dr_match_misc3 *misc3) +static bool +dr_mask_is_misc3_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3) { return (misc3->outer_vxlan_gpe_vni || misc3->outer_vxlan_gpe_next_protocol || misc3->outer_vxlan_gpe_flags); } +static bool +dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & + MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; +} + +static bool +dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_misc3_vxlan_gpe_set(&mask->misc3) && + dr_matcher_supp_flex_parser_vxlan_gpe(&dmn->info.caps); +} + static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3) { return (misc3->icmpv6_type || misc3->icmpv6_code || @@ -137,13 +153,6 @@ static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc) return (misc->source_sqn || misc->source_port); } -static bool -dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_domain *dmn) -{ - return dmn->info.caps.flex_protocols & - MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED; -} - int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher, struct mlx5dr_matcher_rx_tx *nic_matcher, enum mlx5dr_ipv outer_ipv, @@ -262,10 +271,10 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, inner, rx); } - if (dr_mask_is_flex_parser_tnl_set(&mask.misc3) && - dr_matcher_supp_flex_parser_vxlan_gpe(dmn)) - mlx5dr_ste_build_flex_parser_tnl(&sb[idx++], &mask, - inner, rx); + if (dr_mask_is_flex_parser_tnl_vxlan_gpe_set(&mask, dmn)) + mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++], + &mask, + inner, rx); if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c index 7e9d6cfc356f..7a906938ceb9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c @@ -2103,68 +2103,57 @@ void mlx5dr_ste_build_eth_l4_misc(struct mlx5dr_ste_build *sb, sb->ste_build_tag_func = &dr_ste_build_eth_l4_misc_tag; } -static void dr_ste_build_flex_parser_tnl_bit_mask(struct mlx5dr_match_param *value, - bool inner, u8 *bit_mask) +static void +dr_ste_build_flex_parser_tnl_vxlan_gpe_bit_mask(struct mlx5dr_match_param *value, + bool inner, u8 *bit_mask) { struct mlx5dr_match_misc3 *misc_3_mask = &value->misc3; - if (misc_3_mask->outer_vxlan_gpe_flags || - misc_3_mask->outer_vxlan_gpe_next_protocol) { - MLX5_SET(ste_flex_parser_tnl, bit_mask, - flex_parser_tunneling_header_63_32, - (misc_3_mask->outer_vxlan_gpe_flags << 24) | - (misc_3_mask->outer_vxlan_gpe_next_protocol)); - misc_3_mask->outer_vxlan_gpe_flags = 0; - misc_3_mask->outer_vxlan_gpe_next_protocol = 0; - } - - if (misc_3_mask->outer_vxlan_gpe_vni) { - MLX5_SET(ste_flex_parser_tnl, bit_mask, - flex_parser_tunneling_header_31_0, - misc_3_mask->outer_vxlan_gpe_vni << 8); - misc_3_mask->outer_vxlan_gpe_vni = 0; - } + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_flags, + misc_3_mask, outer_vxlan_gpe_flags); + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_next_protocol, + misc_3_mask, outer_vxlan_gpe_next_protocol); + DR_STE_SET_MASK_V(flex_parser_tnl_vxlan_gpe, bit_mask, + outer_vxlan_gpe_vni, + misc_3_mask, outer_vxlan_gpe_vni); } -static int dr_ste_build_flex_parser_tnl_tag(struct mlx5dr_match_param *value, - struct mlx5dr_ste_build *sb, - u8 *hw_ste_p) +static int +dr_ste_build_flex_parser_tnl_vxlan_gpe_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *hw_ste_p) { struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; struct mlx5dr_match_misc3 *misc3 = &value->misc3; u8 *tag = hw_ste->tag; - if (misc3->outer_vxlan_gpe_flags || - misc3->outer_vxlan_gpe_next_protocol) { - MLX5_SET(ste_flex_parser_tnl, tag, - flex_parser_tunneling_header_63_32, - (misc3->outer_vxlan_gpe_flags << 24) | - (misc3->outer_vxlan_gpe_next_protocol)); - misc3->outer_vxlan_gpe_flags = 0; - misc3->outer_vxlan_gpe_next_protocol = 0; - } - - if (misc3->outer_vxlan_gpe_vni) { - MLX5_SET(ste_flex_parser_tnl, tag, - flex_parser_tunneling_header_31_0, - misc3->outer_vxlan_gpe_vni << 8); - misc3->outer_vxlan_gpe_vni = 0; - } + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_flags, misc3, + outer_vxlan_gpe_flags); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_next_protocol, misc3, + outer_vxlan_gpe_next_protocol); + DR_STE_SET_TAG(flex_parser_tnl_vxlan_gpe, tag, + outer_vxlan_gpe_vni, misc3, + outer_vxlan_gpe_vni); return 0; } -void mlx5dr_ste_build_flex_parser_tnl(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx) +void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) { - dr_ste_build_flex_parser_tnl_bit_mask(mask, inner, sb->bit_mask); + dr_ste_build_flex_parser_tnl_vxlan_gpe_bit_mask(mask, inner, + sb->bit_mask); sb->rx = rx; sb->inner = inner; sb->lu_type = MLX5DR_STE_LU_TYPE_FLEX_PARSER_TNL_HEADER; sb->byte_mask = dr_ste_conv_bit_to_byte_mask(sb->bit_mask); - sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_tag; + sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_vxlan_gpe_tag; } static void dr_ste_build_register_0_bit_mask(struct mlx5dr_match_param *value, 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 c1f45a60ee6b..a64af56b825f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -325,9 +325,9 @@ int mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, struct mlx5dr_cmd_caps *caps, bool inner, bool rx); -void mlx5dr_ste_build_flex_parser_tnl(struct mlx5dr_ste_build *sb, - struct mlx5dr_match_param *mask, - bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, bool inner, bool rx); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h index 596c927220d9..6d78b027fe56 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h @@ -548,6 +548,17 @@ struct mlx5_ifc_ste_flex_parser_tnl_bits { u8 reserved_at_40[0x40]; }; +struct mlx5_ifc_ste_flex_parser_tnl_vxlan_gpe_bits { + u8 outer_vxlan_gpe_flags[0x8]; + u8 reserved_at_8[0x10]; + u8 outer_vxlan_gpe_next_protocol[0x8]; + + u8 outer_vxlan_gpe_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + struct mlx5_ifc_ste_general_purpose_bits { u8 general_purpose_lookup_field[0x20]; -- cgit v1.2.3-59-g8ed1b From a18fab48dbacbb7ff104a13e987778b7995bec07 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Mon, 28 Oct 2019 16:58:53 +0200 Subject: net/mlx5: DR, Add HW bits and definitions for Geneve flex parser Add definition for flex parser tunneling header for Geneve. Signed-off-by: Yevgeny Kliteynik Reviewed-by: Alex Vesker Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h | 13 +++++++++++++ include/linux/mlx5/mlx5_ifc.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h index 6d78b027fe56..1722f4668269 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/mlx5_ifc_dr.h @@ -559,6 +559,19 @@ struct mlx5_ifc_ste_flex_parser_tnl_vxlan_gpe_bits { u8 reserved_at_40[0x40]; }; +struct mlx5_ifc_ste_flex_parser_tnl_geneve_bits { + u8 reserved_at_0[0x2]; + u8 geneve_opt_len[0x6]; + u8 geneve_oam[0x1]; + u8 reserved_at_9[0x7]; + u8 geneve_protocol_type[0x10]; + + u8 geneve_vni[0x18]; + u8 reserved_at_38[0x8]; + + u8 reserved_at_40[0x40]; +}; + struct mlx5_ifc_ste_general_purpose_bits { u8 general_purpose_lookup_field[0x20]; diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 4f912d4e67bc..5d54fccf87fc 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1110,6 +1110,7 @@ enum { }; enum { + MLX5_FLEX_PARSER_GENEVE_ENABLED = 1 << 3, MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED = 1 << 7, MLX5_FLEX_PARSER_ICMP_V4_ENABLED = 1 << 8, MLX5_FLEX_PARSER_ICMP_V6_ENABLED = 1 << 9, -- cgit v1.2.3-59-g8ed1b From b6d12238459d2f3c1140689c8fbb1bf1e0fe1927 Mon Sep 17 00:00:00 2001 From: Yevgeny Kliteynik Date: Mon, 28 Oct 2019 17:22:06 +0200 Subject: net/mlx5: DR, Add support for Geneve packets SW steering Add support for SW steering matching on Geneve header fields: - VNI - OAM - protocol type - options length Signed-off-by: Yevgeny Kliteynik Reviewed-by: Alex Vesker Signed-off-by: Saeed Mahameed --- .../mellanox/mlx5/core/steering/dr_matcher.c | 27 +++++++++++ .../ethernet/mellanox/mlx5/core/steering/dr_ste.c | 53 ++++++++++++++++++++++ .../mellanox/mlx5/core/steering/dr_types.h | 3 ++ 3 files changed, 83 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c index f177c468b740..c6dbd856df94 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c @@ -125,6 +125,29 @@ dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param *mask, dr_matcher_supp_flex_parser_vxlan_gpe(&dmn->info.caps); } +static bool dr_mask_is_misc_geneve_set(struct mlx5dr_match_misc *misc) +{ + return misc->geneve_vni || + misc->geneve_oam || + misc->geneve_protocol_type || + misc->geneve_opt_len; +} + +static bool +dr_matcher_supp_flex_parser_geneve(struct mlx5dr_cmd_caps *caps) +{ + return caps->flex_protocols & + MLX5_FLEX_PARSER_GENEVE_ENABLED; +} + +static bool +dr_mask_is_flex_parser_tnl_geneve_set(struct mlx5dr_match_param *mask, + struct mlx5dr_domain *dmn) +{ + return dr_mask_is_misc_geneve_set(&mask->misc) && + dr_matcher_supp_flex_parser_geneve(&dmn->info.caps); +} + static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3) { return (misc3->icmpv6_type || misc3->icmpv6_code || @@ -275,6 +298,10 @@ static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher, mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++], &mask, inner, rx); + else if (dr_mask_is_flex_parser_tnl_geneve_set(&mask, dmn)) + mlx5dr_ste_build_flex_parser_tnl_geneve(&sb[idx++], + &mask, + inner, rx); if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer)) mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c index 7a906938ceb9..53068d508b21 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ste.c @@ -2156,6 +2156,59 @@ void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_vxlan_gpe_tag; } +static void +dr_ste_build_flex_parser_tnl_geneve_bit_mask(struct mlx5dr_match_param *value, + u8 *bit_mask) +{ + struct mlx5dr_match_misc *misc_mask = &value->misc; + + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_protocol_type, + misc_mask, geneve_protocol_type); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_oam, + misc_mask, geneve_oam); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_opt_len, + misc_mask, geneve_opt_len); + DR_STE_SET_MASK_V(flex_parser_tnl_geneve, bit_mask, + geneve_vni, + misc_mask, geneve_vni); +} + +static int +dr_ste_build_flex_parser_tnl_geneve_tag(struct mlx5dr_match_param *value, + struct mlx5dr_ste_build *sb, + u8 *hw_ste_p) +{ + struct dr_hw_ste_format *hw_ste = (struct dr_hw_ste_format *)hw_ste_p; + struct mlx5dr_match_misc *misc = &value->misc; + u8 *tag = hw_ste->tag; + + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_protocol_type, misc, geneve_protocol_type); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_oam, misc, geneve_oam); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_opt_len, misc, geneve_opt_len); + DR_STE_SET_TAG(flex_parser_tnl_geneve, tag, + geneve_vni, misc, geneve_vni); + + return 0; +} + +void mlx5dr_ste_build_flex_parser_tnl_geneve(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx) +{ + dr_ste_build_flex_parser_tnl_geneve_bit_mask(mask, sb->bit_mask); + sb->rx = rx; + sb->inner = inner; + sb->lu_type = MLX5DR_STE_LU_TYPE_FLEX_PARSER_TNL_HEADER; + sb->byte_mask = dr_ste_conv_bit_to_byte_mask(sb->bit_mask); + sb->ste_build_tag_func = &dr_ste_build_flex_parser_tnl_geneve_tag; +} + static void dr_ste_build_register_0_bit_mask(struct mlx5dr_match_param *value, u8 *bit_mask) { 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 a64af56b825f..290fe61c33d0 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/dr_types.h @@ -328,6 +328,9 @@ int mlx5dr_ste_build_flex_parser_1(struct mlx5dr_ste_build *sb, void mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, bool inner, bool rx); +void mlx5dr_ste_build_flex_parser_tnl_geneve(struct mlx5dr_ste_build *sb, + struct mlx5dr_match_param *mask, + bool inner, bool rx); void mlx5dr_ste_build_general_purpose(struct mlx5dr_ste_build *sb, struct mlx5dr_match_param *mask, bool inner, bool rx); -- cgit v1.2.3-59-g8ed1b From e689e998e102100bdf7991763d4c244704846f2d Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Fri, 1 Nov 2019 15:38:30 -0700 Subject: net/mlx5e: TC, Stub out ipv6 tun create header function Improve mlx5e_route_lookup_ipv6 function structure by avoiding #ifdef then return -EOPNOTSUPP in the middle of the function code. To do so, we stub out mlx5e_tc_tun_create_header_ipv6 which is the only caller of this helper function to avoid calling it altogether when ipv6 is compiled out, which should also cleanup some compiler warnings of unused variables. Signed-off-by: Saeed Mahameed Reviewed-by: Eli Cohen Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 4 ---- drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index 5316cedd78bf..fe227713fe94 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -141,7 +141,6 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, struct dst_entry *dst; struct neighbour *n; -#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) int ret; ret = ipv6_stub->ipv6_dst_lookup(dev_net(mirred_dev), NULL, &dst, @@ -157,9 +156,6 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv, dst_release(dst); return ret; } -#else - return -EOPNOTSUPP; -#endif n = dst_neigh_lookup(dst, &fl6->daddr); dst_release(dst); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h index c362b9225dc2..6f9a78c85ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h @@ -58,9 +58,16 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, struct net_device *mirred_dev, struct mlx5e_encap_entry *e); +#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6) int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, struct net_device *mirred_dev, struct mlx5e_encap_entry *e); +#else +static inline int +mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, + struct net_device *mirred_dev, + struct mlx5e_encap_entry *e) { return -EOPNOTSUPP; } +#endif bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv, struct net_device *netdev); -- cgit v1.2.3-59-g8ed1b From 90ac245814abc30d2423474310654d31e3908b2f Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 31 Oct 2019 09:12:18 +0200 Subject: net/mlx5e: Remove redundant pointer check When code reaches the "out" label, n is guaranteed to be valid so we can unconditionally call neigh_release. Also change the label to release_neigh to better reflect the fact that we unconditionally free the neighbour and also match other labels convention. Signed-off-by: Eli Cohen Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed --- .../net/ethernet/mellanox/mlx5/core/en/tc_tun.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c index fe227713fe94..784b1e26f414 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c @@ -236,13 +236,13 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv4_encap_size, max_encap_size); err = -EOPNOTSUPP; - goto out; + goto release_neigh; } encap_header = kzalloc(ipv4_encap_size, GFP_KERNEL); if (!encap_header) { err = -ENOMEM; - goto out; + goto release_neigh; } /* used by mlx5e_detach_encap to lookup a neigh hash table @@ -294,7 +294,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, e->reformat_type, @@ -314,9 +314,8 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } @@ -355,13 +354,13 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n", ipv6_encap_size, max_encap_size); err = -EOPNOTSUPP; - goto out; + goto release_neigh; } encap_header = kzalloc(ipv6_encap_size, GFP_KERNEL); if (!encap_header) { err = -ENOMEM; - goto out; + goto release_neigh; } /* used by mlx5e_detach_encap to lookup a neigh hash table @@ -412,7 +411,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv, /* the encap entry will be made valid on neigh update event * and not used before that. */ - goto out; + goto release_neigh; } e->pkt_reformat = mlx5_packet_reformat_alloc(priv->mdev, @@ -433,9 +432,8 @@ destroy_neigh_entry: mlx5e_rep_encap_entry_detach(netdev_priv(e->out_dev), e); free_encap: kfree(encap_header); -out: - if (n) - neigh_release(n); +release_neigh: + neigh_release(n); return err; } -- cgit v1.2.3-59-g8ed1b From 87324e747fde7693620f6d4c74aa11b7551e096d Mon Sep 17 00:00:00 2001 From: Henry Tieman Date: Fri, 8 Nov 2019 06:23:29 -0800 Subject: ice: Implement ethtool ops for channels Add code to query and set the number of channels on the primary VSI for a PF. This is accessed from the 'ethtool -l' and 'ethtool -L' commands, respectively. Though the ice driver supports asymmetric queues report an IRQ vector that has both Rx and Tx queues attached and is counted as a 'combined' channel. Signed-off-by: Henry Tieman Co-developed-by: Maciej Fijalkowski Signed-off-by: Maciej Fijalkowski Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice.h | 4 + drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 4 +- drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 2 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 185 +++++++++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_lib.c | 70 ++++++++-- drivers/net/ethernet/intel/ice/ice_lib.h | 2 +- drivers/net/ethernet/intel/ice/ice_main.c | 87 ++++++++++++- 7 files changed, 335 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index cb7259c27353..f972dce8aebb 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -285,6 +285,8 @@ struct ice_vsi { u16 num_txq; /* Used Tx queues */ u16 alloc_rxq; /* Allocated Rx queues */ u16 num_rxq; /* Used Rx queues */ + u16 req_txq; /* User requested Tx queues */ + u16 req_rxq; /* User requested Rx queues */ u16 num_rx_desc; u16 num_tx_desc; struct ice_tc_cfg tc_cfg; @@ -491,6 +493,7 @@ void ice_set_ethtool_ops(struct net_device *netdev); void ice_set_ethtool_safe_mode_ops(struct net_device *netdev); u16 ice_get_avail_txq_count(struct ice_pf *pf); u16 ice_get_avail_rxq_count(struct ice_pf *pf); +int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx); void ice_update_vsi_stats(struct ice_vsi *vsi); void ice_update_pf_stats(struct ice_pf *pf); int ice_up(struct ice_vsi *vsi); @@ -505,6 +508,7 @@ ice_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames, int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size); void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size); +int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset); void ice_print_link_msg(struct ice_vsi *vsi, bool isup); int ice_open(struct net_device *netdev); int ice_stop(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c index 20b63443237c..d3d3ec29def9 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c @@ -4,8 +4,6 @@ #include "ice_dcb_lib.h" #include "ice_dcb_nl.h" -static void ice_pf_dcb_recfg(struct ice_pf *pf); - /** * ice_vsi_cfg_netdev_tc - Setup the netdev TC configuration * @vsi: the VSI being configured @@ -535,7 +533,7 @@ static int ice_dcb_noncontig_cfg(struct ice_pf *pf) * calling this function. Reconfiguring DCB based on * local_dcbx_cfg. */ -static void ice_pf_dcb_recfg(struct ice_pf *pf) +void ice_pf_dcb_recfg(struct ice_pf *pf) { struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg; u8 tc_map = 0; diff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h index c81d7f69d5c4..f15e5776f287 100644 --- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h @@ -20,6 +20,7 @@ u8 ice_dcb_get_num_tc(struct ice_dcbx_cfg *dcbcfg); u8 ice_dcb_get_tc(struct ice_vsi *vsi, int queue_index); int ice_pf_dcb_cfg(struct ice_pf *pf, struct ice_dcbx_cfg *new_cfg, bool locked); +void ice_pf_dcb_recfg(struct ice_pf *pf); void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi); int ice_init_pf_dcb(struct ice_pf *pf, bool locked); void ice_update_dcb_stats(struct ice_pf *pf); @@ -78,6 +79,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_ring __always_unused *tx_ring, } #define ice_update_dcb_stats(pf) do {} while (0) +#define ice_pf_dcb_recfg(pf) do {} while (0) #define ice_vsi_cfg_dcb_rings(vsi) do {} while (0) #define ice_dcb_process_lldp_set_mib_change(pf, event) do {} while (0) #define ice_set_cgd_num(tlan_ctx, ring) do {} while (0) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 5b229f3703b5..aec3c6c379df 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3142,6 +3142,188 @@ ice_set_rxfh(struct net_device *netdev, const u32 *indir, const u8 *key, return 0; } +/** + * ice_get_max_txq - return the maximum number of Tx queues for in a PF + * @pf: PF structure + */ +static int ice_get_max_txq(struct ice_pf *pf) +{ + return min_t(int, num_online_cpus(), + pf->hw.func_caps.common_cap.num_txq); +} + +/** + * ice_get_max_rxq - return the maximum number of Rx queues for in a PF + * @pf: PF structure + */ +static int ice_get_max_rxq(struct ice_pf *pf) +{ + return min_t(int, num_online_cpus(), + pf->hw.func_caps.common_cap.num_rxq); +} + +/** + * ice_get_combined_cnt - return the current number of combined channels + * @vsi: PF VSI pointer + * + * Go through all queue vectors and count ones that have both Rx and Tx ring + * attached + */ +static u32 ice_get_combined_cnt(struct ice_vsi *vsi) +{ + u32 combined = 0; + int q_idx; + + ice_for_each_q_vector(vsi, q_idx) { + struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; + + if (q_vector->rx.ring && q_vector->tx.ring) + combined++; + } + + return combined; +} + +/** + * ice_get_channels - get the current and max supported channels + * @dev: network interface device structure + * @ch: ethtool channel data structure + */ +static void +ice_get_channels(struct net_device *dev, struct ethtool_channels *ch) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + + /* check to see if VSI is active */ + if (test_bit(__ICE_DOWN, vsi->state)) + return; + + /* report maximum channels */ + ch->max_rx = ice_get_max_rxq(pf); + ch->max_tx = ice_get_max_txq(pf); + ch->max_combined = min_t(int, ch->max_rx, ch->max_tx); + + /* report current channels */ + ch->combined_count = ice_get_combined_cnt(vsi); + ch->rx_count = vsi->num_rxq - ch->combined_count; + ch->tx_count = vsi->num_txq - ch->combined_count; +} + +/** + * ice_vsi_set_dflt_rss_lut - set default RSS LUT with requested RSS size + * @vsi: VSI to reconfigure RSS LUT on + * @req_rss_size: requested range of queue numbers for hashing + * + * Set the VSI's RSS parameters, configure the RSS LUT based on these. + */ +static int ice_vsi_set_dflt_rss_lut(struct ice_vsi *vsi, int req_rss_size) +{ + struct ice_pf *pf = vsi->back; + enum ice_status status; + struct device *dev; + struct ice_hw *hw; + int err = 0; + u8 *lut; + + dev = ice_pf_to_dev(pf); + hw = &pf->hw; + + if (!req_rss_size) + return -EINVAL; + + lut = kzalloc(vsi->rss_table_size, GFP_KERNEL); + if (!lut) + return -ENOMEM; + + /* set RSS LUT parameters */ + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { + vsi->rss_size = 1; + } else { + struct ice_hw_common_caps *caps = &hw->func_caps.common_cap; + + vsi->rss_size = min_t(int, req_rss_size, + BIT(caps->rss_table_entry_width)); + } + + /* create/set RSS LUT */ + ice_fill_rss_lut(lut, vsi->rss_table_size, vsi->rss_size); + status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, lut, + vsi->rss_table_size); + if (status) { + dev_err(dev, "Cannot set RSS lut, err %d aq_err %d\n", + status, hw->adminq.rq_last_status); + err = -EIO; + } + + kfree(lut); + return err; +} + +/** + * ice_set_channels - set the number channels + * @dev: network interface device structure + * @ch: ethtool channel data structure + */ +static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch) +{ + struct ice_netdev_priv *np = netdev_priv(dev); + struct ice_vsi *vsi = np->vsi; + struct ice_pf *pf = vsi->back; + int new_rx = 0, new_tx = 0; + u32 curr_combined; + + /* do not support changing channels in Safe Mode */ + if (ice_is_safe_mode(pf)) { + netdev_err(dev, "Changing channel in Safe Mode is not supported\n"); + return -EOPNOTSUPP; + } + /* do not support changing other_count */ + if (ch->other_count) + return -EINVAL; + + curr_combined = ice_get_combined_cnt(vsi); + + /* these checks are for cases where user didn't specify a particular + * value on cmd line but we get non-zero value anyway via + * get_channels(); look at ethtool.c in ethtool repository (the user + * space part), particularly, do_schannels() routine + */ + if (ch->rx_count == vsi->num_rxq - curr_combined) + ch->rx_count = 0; + if (ch->tx_count == vsi->num_txq - curr_combined) + ch->tx_count = 0; + if (ch->combined_count == curr_combined) + ch->combined_count = 0; + + if (!(ch->combined_count || (ch->rx_count && ch->tx_count))) { + netdev_err(dev, "Please specify at least 1 Rx and 1 Tx channel\n"); + return -EINVAL; + } + + new_rx = ch->combined_count + ch->rx_count; + new_tx = ch->combined_count + ch->tx_count; + + if (new_rx > ice_get_max_rxq(pf)) { + netdev_err(dev, "Maximum allowed Rx channels is %d\n", + ice_get_max_rxq(pf)); + return -EINVAL; + } + if (new_tx > ice_get_max_txq(pf)) { + netdev_err(dev, "Maximum allowed Tx channels is %d\n", + ice_get_max_txq(pf)); + return -EINVAL; + } + + ice_vsi_recfg_qs(vsi, new_rx, new_tx); + + if (new_rx && !netif_is_rxfh_configured(dev)) + return ice_vsi_set_dflt_rss_lut(vsi, new_rx); + + return 0; +} + enum ice_container_type { ICE_RX_CONTAINER, ICE_TX_CONTAINER, @@ -3631,6 +3813,8 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_rxfh_indir_size = ice_get_rxfh_indir_size, .get_rxfh = ice_get_rxfh, .set_rxfh = ice_set_rxfh, + .get_channels = ice_get_channels, + .set_channels = ice_set_channels, .get_ts_info = ethtool_op_get_ts_info, .get_per_queue_coalesce = ice_get_per_q_coalesce, .set_per_queue_coalesce = ice_set_per_q_coalesce, @@ -3656,6 +3840,7 @@ static const struct ethtool_ops ice_ethtool_safe_mode_ops = { .get_ringparam = ice_get_ringparam, .set_ringparam = ice_set_ringparam, .nway_reset = ice_nway_reset, + .get_channels = ice_get_channels, }; /** diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index b546c69a4bbc..e7449248fab4 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -142,15 +142,24 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi, u16 vf_id) case ICE_VSI_PF: vsi->alloc_txq = min_t(int, ice_get_avail_txq_count(pf), num_online_cpus()); + if (vsi->req_txq) { + vsi->alloc_txq = vsi->req_txq; + vsi->num_txq = vsi->req_txq; + } pf->num_lan_tx = vsi->alloc_txq; /* only 1 Rx queue unless RSS is enabled */ - if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + if (!test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { vsi->alloc_rxq = 1; - else + } else { vsi->alloc_rxq = min_t(int, ice_get_avail_rxq_count(pf), num_online_cpus()); + if (vsi->req_rxq) { + vsi->alloc_rxq = vsi->req_rxq; + vsi->num_rxq = vsi->req_rxq; + } + } pf->num_lan_rx = vsi->alloc_rxq; @@ -639,7 +648,9 @@ static void ice_vsi_setup_q_map(struct ice_vsi *vsi, struct ice_vsi_ctx *ctxt) else max_rss = ICE_MAX_SMALL_RSS_QS; qcount_rx = min_t(int, rx_numq_tc, max_rss); - qcount_rx = min_t(int, qcount_rx, vsi->rss_size); + if (!vsi->req_rxq) + qcount_rx = min_t(int, qcount_rx, + vsi->rss_size); } } @@ -746,17 +757,20 @@ static void ice_set_rss_vsi_ctx(struct ice_vsi_ctx *ctxt, struct ice_vsi *vsi) /** * ice_vsi_init - Create and initialize a VSI * @vsi: the VSI being configured + * @init_vsi: is this call creating a VSI * * This initializes a VSI context depending on the VSI type to be added and * passes it down to the add_vsi aq command to create a new VSI. */ -static int ice_vsi_init(struct ice_vsi *vsi) +static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi) { struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; struct ice_vsi_ctx *ctxt; + struct device *dev; int ret = 0; + dev = ice_pf_to_dev(pf); ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); if (!ctxt) return -ENOMEM; @@ -784,11 +798,24 @@ static int ice_vsi_init(struct ice_vsi *vsi) ctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; /* Set LUT type and HASH type if RSS is enabled */ - if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) + if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) { ice_set_rss_vsi_ctx(ctxt, vsi); + /* if updating VSI context, make sure to set valid_section: + * to indicate which section of VSI context being updated + */ + if (!init_vsi) + ctxt->info.valid_sections |= + cpu_to_le16(ICE_AQ_VSI_PROP_Q_OPT_VALID); + } ctxt->info.sw_id = vsi->port_info->sw_id; ice_vsi_setup_q_map(vsi, ctxt); + if (!init_vsi) /* means VSI being updated */ + /* must to indicate which section of VSI context are + * being modified + */ + ctxt->info.valid_sections |= + cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); /* Enable MAC Antispoof with new VSI being initialized or updated */ if (vsi->type == ICE_VSI_VF && pf->vf[vsi->vf_id].spoofchk) { @@ -805,11 +832,20 @@ static int ice_vsi_init(struct ice_vsi *vsi) cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); } - ret = ice_add_vsi(hw, vsi->idx, ctxt, NULL); - if (ret) { - dev_err(ice_pf_to_dev(pf), "Add VSI failed, err %d\n", ret); - ret = -EIO; - goto out; + if (init_vsi) { + ret = ice_add_vsi(hw, vsi->idx, ctxt, NULL); + if (ret) { + dev_err(dev, "Add VSI failed, err %d\n", ret); + ret = -EIO; + goto out; + } + } else { + ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL); + if (ret) { + dev_err(dev, "Update VSI failed, err %d\n", ret); + ret = -EIO; + goto out; + } } /* keep context for update VSI operations */ @@ -1835,7 +1871,7 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi, ice_vsi_set_tc_cfg(vsi); /* create the VSI */ - ret = ice_vsi_init(vsi); + ret = ice_vsi_init(vsi, true); if (ret) goto unroll_get_qs; @@ -2368,10 +2404,11 @@ int ice_vsi_release(struct ice_vsi *vsi) /** * ice_vsi_rebuild - Rebuild VSI after reset * @vsi: VSI to be rebuild + * @init_vsi: is this an initialization or a reconfigure of the VSI * * Returns 0 on success and negative value on failure */ -int ice_vsi_rebuild(struct ice_vsi *vsi) +int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi) { u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; struct ice_vf *vf = NULL; @@ -2423,7 +2460,7 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) ice_vsi_set_tc_cfg(vsi); /* Initialize VSI struct elements and create VSI in FW */ - ret = ice_vsi_init(vsi); + ret = ice_vsi_init(vsi, init_vsi); if (ret < 0) goto err_vsi; @@ -2491,7 +2528,12 @@ int ice_vsi_rebuild(struct ice_vsi *vsi) dev_err(ice_pf_to_dev(pf), "VSI %d failed lan queue config, error %d\n", vsi->vsi_num, status); - goto err_vectors; + if (init_vsi) { + ret = -EIO; + goto err_vectors; + } else { + return ice_schedule_reset(pf, ICE_RESET_PFR); + } } return 0; diff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h index e86aa60c0254..6e31e30aba39 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_lib.h @@ -73,7 +73,7 @@ int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id); int ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id); -int ice_vsi_rebuild(struct ice_vsi *vsi); +int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi); bool ice_is_reset_in_progress(unsigned long *state); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index d282eb05c2e0..69bff085acf7 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -44,6 +44,7 @@ MODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)"); static struct workqueue_struct *ice_wq; static const struct net_device_ops ice_netdev_safe_mode_ops; static const struct net_device_ops ice_netdev_ops; +static int ice_vsi_open(struct ice_vsi *vsi); static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type); @@ -1524,6 +1525,44 @@ static void ice_set_ctrlq_len(struct ice_hw *hw) hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN; } +/** + * ice_schedule_reset - schedule a reset + * @pf: board private structure + * @reset: reset being requested + */ +int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset) +{ + struct device *dev = ice_pf_to_dev(pf); + + /* bail out if earlier reset has failed */ + if (test_bit(__ICE_RESET_FAILED, pf->state)) { + dev_dbg(dev, "earlier reset has failed\n"); + return -EIO; + } + /* bail if reset/recovery already in progress */ + if (ice_is_reset_in_progress(pf->state)) { + dev_dbg(dev, "Reset already in progress\n"); + return -EBUSY; + } + + switch (reset) { + case ICE_RESET_PFR: + set_bit(__ICE_PFR_REQ, pf->state); + break; + case ICE_RESET_CORER: + set_bit(__ICE_CORER_REQ, pf->state); + break; + case ICE_RESET_GLOBR: + set_bit(__ICE_GLOBR_REQ, pf->state); + break; + default: + return -EINVAL; + } + + ice_service_task_schedule(pf); + return 0; +} + /** * ice_irq_affinity_notify - Callback for affinity changes * @notify: context as to what irq was changed @@ -2808,6 +2847,52 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf) return 0; } +/** + * ice_vsi_recfg_qs - Change the number of queues on a VSI + * @vsi: VSI being changed + * @new_rx: new number of Rx queues + * @new_tx: new number of Tx queues + * + * Only change the number of queues if new_tx, or new_rx is non-0. + * + * Returns 0 on success. + */ +int ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx) +{ + struct ice_pf *pf = vsi->back; + int err = 0, timeout = 50; + + if (!new_rx && !new_tx) + return -EINVAL; + + while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { + timeout--; + if (!timeout) + return -EBUSY; + usleep_range(1000, 2000); + } + + if (new_tx) + vsi->req_txq = new_tx; + if (new_rx) + vsi->req_rxq = new_rx; + + /* set for the next time the netdev is started */ + if (!netif_running(vsi->netdev)) { + ice_vsi_rebuild(vsi, false); + dev_dbg(ice_pf_to_dev(pf), "Link is down, queue count change happens when link is brought up\n"); + goto done; + } + + ice_vsi_close(vsi); + ice_vsi_rebuild(vsi, false); + ice_pf_dcb_recfg(pf); + ice_vsi_open(vsi); +done: + clear_bit(__ICE_CFG_BUSY, pf->state); + return err; +} + /** * ice_log_pkg_init - log result of DDP package load * @hw: pointer to hardware info @@ -4482,7 +4567,7 @@ static int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) continue; /* rebuild the VSI */ - err = ice_vsi_rebuild(vsi); + err = ice_vsi_rebuild(vsi, true); if (err) { dev_err(dev, "rebuild VSI failed, err %d, VSI index %d, type %s\n", -- cgit v1.2.3-59-g8ed1b From 1748ce80e0a3d4a66667fd154623aa1c33a44875 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 8 Nov 2019 06:23:30 -0800 Subject: ice: remove pointless NULL check of port_info The code in ice_sched_cleanup_all checks whether the port info is NULL prior to calling ice_sched_clear_port. However, ice_sched_clear_port already checks whether port info is non-NULL. More importantly, it also checks whether the port structure has been initialized by checking its port_state field as well. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_sched.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_sched.c b/drivers/net/ethernet/intel/ice/ice_sched.c index 84f609996ed5..eae707ddf8e8 100644 --- a/drivers/net/ethernet/intel/ice/ice_sched.c +++ b/drivers/net/ethernet/intel/ice/ice_sched.c @@ -798,8 +798,7 @@ void ice_sched_cleanup_all(struct ice_hw *hw) hw->layer_info = NULL; } - if (hw->port_info) - ice_sched_clear_port(hw->port_info); + ice_sched_clear_port(hw->port_info); hw->num_tx_sched_layers = 0; hw->num_tx_sched_phys_layers = 0; -- cgit v1.2.3-59-g8ed1b From ed960c1d36f5db38a8038fcca83e1f6495f468fb Mon Sep 17 00:00:00 2001 From: Kevin Scott Date: Fri, 8 Nov 2019 06:23:31 -0800 Subject: ice: Update FW API minor version Update FW API minor version to align to current value advertised by FW in new NVM images. Signed-off-by: Kevin Scott Signed-off-by: Tony Nguyen Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ice/ice_controlq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h index 4df9da359135..bf0ebe6149e8 100644 --- a/drivers/net/ethernet/intel/ice/ice_controlq.h +++ b/drivers/net/ethernet/intel/ice/ice_controlq.h @@ -22,7 +22,7 @@ */ #define EXP_FW_API_VER_BRANCH 0x00 #define EXP_FW_API_VER_MAJOR 0x01 -#define EXP_FW_API_VER_MINOR 0x03 +#define EXP_FW_API_VER_MINOR 0x05 /* Different control queue types: These are mainly for SW consumption. */ enum ice_ctl_q { -- cgit v1.2.3-59-g8ed1b From 0ed96b46c0ac26ebcdd2ee95c2479ef8cf94bbd6 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Fri, 22 Nov 2019 06:30:01 +0530 Subject: cxgb4/chcr: update SGL DMA unmap for USO The FW_ETH_TX_EO_WR used for sending UDP Segmentation Offload (USO) requests expects the headers to be part of the descriptor and the payload to be part of the SGL containing the DMA mapped addresses. Hence, the DMA address in the first entry of the SGL can start after the packet headers. Currently, unmap_sgl() tries to unmap from this wrong offset, instead of the originally mapped DMA address. So, use existing unmap_skb() instead, which takes originally saved DMA addresses as input. Update all necessary Tx paths to save the original DMA addresses, so that unmap_skb() can unmap them properly. v2: - No change. Signed-off-by: Rahul Lakkireddy Signed-off-by: Jakub Kicinski --- drivers/crypto/chelsio/chcr_ipsec.c | 27 +++-- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 19 ++-- .../net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 119 ++++++--------------- 4 files changed, 52 insertions(+), 115 deletions(-) (limited to 'drivers/net') diff --git a/drivers/crypto/chelsio/chcr_ipsec.c b/drivers/crypto/chelsio/chcr_ipsec.c index 24355680f30a..9da0f93a330b 100644 --- a/drivers/crypto/chelsio/chcr_ipsec.c +++ b/drivers/crypto/chelsio/chcr_ipsec.c @@ -673,16 +673,16 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n) int chcr_ipsec_xmit(struct sk_buff *skb, struct net_device *dev) { struct xfrm_state *x = xfrm_input_state(skb); + unsigned int last_desc, ndesc, flits = 0; struct ipsec_sa_entry *sa_entry; u64 *pos, *end, *before, *sgl; + struct tx_sw_desc *sgl_sdesc; int qidx, left, credits; - unsigned int flits = 0, ndesc; - struct adapter *adap; + bool immediate = false; struct sge_eth_txq *q; + struct adapter *adap; struct port_info *pi; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; struct sec_path *sp; - bool immediate = false; if (!x->xso.offload_handle) return NETDEV_TX_BUSY; @@ -715,8 +715,14 @@ out_free: dev_kfree_skb_any(skb); return NETDEV_TX_BUSY; } + last_desc = q->q.pidx + ndesc - 1; + if (last_desc >= q->q.size) + last_desc -= q->q.size; + sgl_sdesc = &q->q.sdesc[last_desc]; + if (!immediate && - unlikely(cxgb4_map_skb(adap->pdev_dev, skb, addr) < 0)) { + unlikely(cxgb4_map_skb(adap->pdev_dev, skb, sgl_sdesc->addr) < 0)) { + memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr)); q->mapping_err++; goto out_free; } @@ -742,17 +748,10 @@ out_free: dev_kfree_skb_any(skb); cxgb4_inline_tx_skb(skb, &q->q, sgl); dev_consume_skb_any(skb); } else { - int last_desc; - cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, - 0, addr); + 0, sgl_sdesc->addr); skb_orphan(skb); - - last_desc = q->q.pidx + ndesc - 1; - if (last_desc >= q->q.size) - last_desc -= q->q.size; - q->q.sdesc[last_desc].skb = skb; - q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)sgl; + sgl_sdesc->skb = skb; } txq_advance(&q->q, ndesc); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 3121ed83d8e2..61a2cf62f694 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -735,7 +735,12 @@ struct tx_desc { __be64 flit[8]; }; -struct tx_sw_desc; +struct ulptx_sgl; + +struct tx_sw_desc { + struct sk_buff *skb; /* SKB to free after getting completion */ + dma_addr_t addr[MAX_SKB_FRAGS + 1]; /* DMA mapped addresses */ +}; struct sge_txq { unsigned int in_use; /* # of in-use Tx descriptors */ @@ -814,15 +819,10 @@ enum sge_eosw_state { CXGB4_EO_STATE_FLOWC_CLOSE_REPLY, /* Waiting for FLOWC close reply */ }; -struct sge_eosw_desc { - struct sk_buff *skb; /* SKB to free after getting completion */ - dma_addr_t addr[MAX_SKB_FRAGS + 1]; /* DMA mapped addresses */ -}; - struct sge_eosw_txq { spinlock_t lock; /* Per queue lock to synchronize completions */ enum sge_eosw_state state; /* Current ETHOFLD State */ - struct sge_eosw_desc *desc; /* Descriptor ring to hold packets */ + struct tx_sw_desc *desc; /* Descriptor ring to hold packets */ u32 ndesc; /* Number of descriptors */ u32 pidx; /* Current Producer Index */ u32 last_pidx; /* Last successfully transmitted Producer Index */ @@ -1151,11 +1151,6 @@ enum { SCHED_CLASS_RATEMODE_ABS = 1, /* Kb/s */ }; -struct tx_sw_desc { /* SW state per Tx descriptor */ - struct sk_buff *skb; - struct ulptx_sgl *sgl; -}; - /* Support for "sched_queue" command to allow one or more NIC TX Queues * to be bound to a TX Scheduling Class. */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c index db55673b77bd..477973d2e341 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_mqprio.c @@ -70,7 +70,7 @@ static int cxgb4_init_eosw_txq(struct net_device *dev, u32 eotid, u32 hwqid) { struct adapter *adap = netdev2adap(dev); - struct sge_eosw_desc *ring; + struct tx_sw_desc *ring; memset(eosw_txq, 0, sizeof(*eosw_txq)); diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index a0400b9a11e9..5ad54493f825 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -300,65 +300,6 @@ static void deferred_unmap_destructor(struct sk_buff *skb) } #endif -static void unmap_sgl(struct device *dev, const struct sk_buff *skb, - const struct ulptx_sgl *sgl, const struct sge_txq *q) -{ - const struct ulptx_sge_pair *p; - unsigned int nfrags = skb_shinfo(skb)->nr_frags; - - if (likely(skb_headlen(skb))) - dma_unmap_single(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), - DMA_TO_DEVICE); - else { - dma_unmap_page(dev, be64_to_cpu(sgl->addr0), ntohl(sgl->len0), - DMA_TO_DEVICE); - nfrags--; - } - - /* - * the complexity below is because of the possibility of a wrap-around - * in the middle of an SGL - */ - for (p = sgl->sge; nfrags >= 2; nfrags -= 2) { - if (likely((u8 *)(p + 1) <= (u8 *)q->stat)) { -unmap: dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(p->addr[1]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p++; - } else if ((u8 *)p == (u8 *)q->stat) { - p = (const struct ulptx_sge_pair *)q->desc; - goto unmap; - } else if ((u8 *)p + 8 == (u8 *)q->stat) { - const __be64 *addr = (const __be64 *)q->desc; - - dma_unmap_page(dev, be64_to_cpu(addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[1]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[2]; - } else { - const __be64 *addr = (const __be64 *)q->desc; - - dma_unmap_page(dev, be64_to_cpu(p->addr[0]), - ntohl(p->len[0]), DMA_TO_DEVICE); - dma_unmap_page(dev, be64_to_cpu(addr[0]), - ntohl(p->len[1]), DMA_TO_DEVICE); - p = (const struct ulptx_sge_pair *)&addr[1]; - } - } - if (nfrags) { - __be64 addr; - - if ((u8 *)p == (u8 *)q->stat) - p = (const struct ulptx_sge_pair *)q->desc; - addr = (u8 *)p + 16 <= (u8 *)q->stat ? p->addr[0] : - *(const __be64 *)q->desc; - dma_unmap_page(dev, be64_to_cpu(addr), ntohl(p->len[0]), - DMA_TO_DEVICE); - } -} - /** * free_tx_desc - reclaims Tx descriptors and their buffers * @adapter: the adapter @@ -372,15 +313,16 @@ unmap: dma_unmap_page(dev, be64_to_cpu(p->addr[0]), void free_tx_desc(struct adapter *adap, struct sge_txq *q, unsigned int n, bool unmap) { - struct tx_sw_desc *d; unsigned int cidx = q->cidx; - struct device *dev = adap->pdev_dev; + struct tx_sw_desc *d; d = &q->sdesc[cidx]; while (n--) { if (d->skb) { /* an SGL is present */ - if (unmap) - unmap_sgl(dev, d->skb, d->sgl, q); + if (unmap && d->addr[0]) { + unmap_skb(adap->pdev_dev, d->skb, d->addr); + memset(d->addr, 0, sizeof(d->addr)); + } dev_consume_skb_any(d->skb); d->skb = NULL; } @@ -1414,13 +1356,13 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; bool ptp_enabled = is_ptp_enabled(skb, dev); - dma_addr_t addr[MAX_SKB_FRAGS + 1]; + unsigned int last_desc, flits, ndesc; const struct skb_shared_info *ssi; + struct tx_sw_desc *sgl_sdesc; struct fw_eth_tx_pkt_wr *wr; struct cpl_tx_pkt_core *cpl; int len, qidx, credits, ret; const struct port_info *pi; - unsigned int flits, ndesc; bool immediate = false; u32 wr_mid, ctrl0, op; u64 cntrl, *end, *sgl; @@ -1489,8 +1431,14 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->encapsulation && chip_ver > CHELSIO_T5) tnl_type = cxgb_encap_offload_supported(skb); + last_desc = q->q.pidx + ndesc - 1; + if (last_desc >= q->q.size) + last_desc -= q->q.size; + sgl_sdesc = &q->q.sdesc[last_desc]; + if (!immediate && - unlikely(cxgb4_map_skb(adap->pdev_dev, skb, addr) < 0)) { + unlikely(cxgb4_map_skb(adap->pdev_dev, skb, sgl_sdesc->addr) < 0)) { + memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr)); q->mapping_err++; if (ptp_enabled) spin_unlock(&adap->ptp_lock); @@ -1618,16 +1566,10 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) cxgb4_inline_tx_skb(skb, &q->q, sgl); dev_consume_skb_any(skb); } else { - int last_desc; - - cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, 0, addr); + cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, 0, + sgl_sdesc->addr); skb_orphan(skb); - - last_desc = q->q.pidx + ndesc - 1; - if (last_desc >= q->q.size) - last_desc -= q->q.size; - q->q.sdesc[last_desc].skb = skb; - q->q.sdesc[last_desc].sgl = (struct ulptx_sgl *)sgl; + sgl_sdesc->skb = skb; } txq_advance(&q->q, ndesc); @@ -1725,12 +1667,12 @@ static inline unsigned int t4vf_calc_tx_flits(const struct sk_buff *skb) static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - dma_addr_t addr[MAX_SKB_FRAGS + 1]; + unsigned int last_desc, flits, ndesc; const struct skb_shared_info *ssi; struct fw_eth_tx_pkt_vm_wr *wr; + struct tx_sw_desc *sgl_sdesc; struct cpl_tx_pkt_core *cpl; const struct port_info *pi; - unsigned int flits, ndesc; struct sge_eth_txq *txq; struct adapter *adapter; int qidx, credits, ret; @@ -1782,12 +1724,19 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } + last_desc = txq->q.pidx + ndesc - 1; + if (last_desc >= txq->q.size) + last_desc -= txq->q.size; + sgl_sdesc = &txq->q.sdesc[last_desc]; + if (!t4vf_is_eth_imm(skb) && - unlikely(cxgb4_map_skb(adapter->pdev_dev, skb, addr) < 0)) { + unlikely(cxgb4_map_skb(adapter->pdev_dev, skb, + sgl_sdesc->addr) < 0)) { /* We need to map the skb into PCI DMA space (because it can't * be in-lined directly into the Work Request) and the mapping * operation failed. Record the error and drop the packet. */ + memset(sgl_sdesc->addr, 0, sizeof(sgl_sdesc->addr)); txq->mapping_err++; goto out_free; } @@ -1962,7 +1911,6 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, */ struct ulptx_sgl *sgl = (struct ulptx_sgl *)(cpl + 1); struct sge_txq *tq = &txq->q; - int last_desc; /* If the Work Request header was an exact multiple of our TX * Descriptor length, then it's possible that the starting SGL @@ -1976,14 +1924,9 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb, ((void *)end - (void *)tq->stat)); } - cxgb4_write_sgl(skb, tq, sgl, end, 0, addr); + cxgb4_write_sgl(skb, tq, sgl, end, 0, sgl_sdesc->addr); skb_orphan(skb); - - last_desc = tq->pidx + ndesc - 1; - if (last_desc >= tq->size) - last_desc -= tq->size; - tq->sdesc[last_desc].skb = skb; - tq->sdesc[last_desc].sgl = sgl; + sgl_sdesc->skb = skb; } /* Advance our internal TX Queue state, tell the hardware about @@ -2035,7 +1978,7 @@ static inline void eosw_txq_advance_index(u32 *idx, u32 n, u32 max) void cxgb4_eosw_txq_free_desc(struct adapter *adap, struct sge_eosw_txq *eosw_txq, u32 ndesc) { - struct sge_eosw_desc *d; + struct tx_sw_desc *d; d = &eosw_txq->desc[eosw_txq->last_cidx]; while (ndesc--) { @@ -2167,7 +2110,7 @@ static void ethofld_hard_xmit(struct net_device *dev, struct cpl_tx_pkt_core *cpl; struct fw_eth_tx_eo_wr *wr; bool skip_eotx_wr = false; - struct sge_eosw_desc *d; + struct tx_sw_desc *d; struct sk_buff *skb; u8 flits, ndesc; int left; -- cgit v1.2.3-59-g8ed1b From 1a2a14fbc7e7df35aebb929ed6cdb1fcf238e9d2 Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Fri, 22 Nov 2019 06:30:02 +0530 Subject: cxgb4: add UDP segmentation offload support Implement and export UDP segmentation offload (USO) support for both NIC and MQPRIO QoS offload Tx path. Update appropriate logic in Tx to parse GSO info in skb and configure FW_ETH_TX_EO_WR request needed to perform USO. v2: - Remove inline keyword from write_eo_udp_wr() in sge.c. Let the compiler decide. Signed-off-by: Rahul Lakkireddy Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 3 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 11 +- drivers/net/ethernet/chelsio/cxgb4/sge.c | 159 +++++++++++++++------ drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 14 +- 6 files changed, 139 insertions(+), 50 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 61a2cf62f694..04cb8909feeb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -772,6 +772,7 @@ struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */ u8 dbqt; /* SGE Doorbell Queue Timer in use */ unsigned int dbqtimerix; /* SGE Doorbell Queue Timer Index */ unsigned long tso; /* # of TSO requests */ + unsigned long uso; /* # of USO requests */ unsigned long tx_cso; /* # of Tx checksum offloads */ unsigned long vlan_ins; /* # of Tx VLAN insertions */ unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a13b03f771cc..fa229d0f1016 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2748,6 +2748,7 @@ do { \ RL("RxDrops:", stats.rx_drops); RL("RxBadPkts:", stats.bad_rx_pkts); TL("TSO:", tso); + TL("USO:", uso); TL("TxCSO:", tx_cso); TL("VLANins:", vlan_ins); TL("TxQFull:", q.stops); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index 76538f4cd595..f57457453561 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -91,6 +91,7 @@ static const char stats_strings[][ETH_GSTRING_LEN] = { "rx_bg3_frames_trunc ", "tso ", + "uso ", "tx_csum_offload ", "rx_csum_good ", "vlan_extractions ", @@ -220,6 +221,7 @@ static void get_strings(struct net_device *dev, u32 stringset, u8 *data) */ struct queue_port_stats { u64 tso; + u64 uso; u64 tx_csum; u64 rx_csum; u64 vlan_ex; @@ -247,6 +249,7 @@ static void collect_sge_port_stats(const struct adapter *adap, memset(s, 0, sizeof(*s)); for (i = 0; i < p->nqsets; i++, rx++, tx++) { s->tso += tx->tso; + s->uso += tx->uso; s->tx_csum += tx->tx_cso; s->rx_csum += rx->stats.rx_cso; s->vlan_ex += rx->stats.vlan_ex; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index e8a1826a1e90..12ff69b3ba91 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1136,11 +1136,17 @@ static u16 cxgb_select_queue(struct net_device *dev, struct sk_buff *skb, if (dev->num_tc) { struct port_info *pi = netdev2pinfo(dev); + u8 ver, proto; + + ver = ip_hdr(skb)->version; + proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : + ip_hdr(skb)->protocol; /* Send unsupported traffic pattern to normal NIC queues. */ txq = netdev_pick_tx(dev, skb, sb_dev); if (xfrm_offload(skb) || is_ptp_enabled(skb, dev) || - ip_hdr(skb)->protocol != IPPROTO_TCP) + skb->encapsulation || + (proto != IPPROTO_TCP && proto != IPPROTO_UDP)) txq = txq % pi->nqsets; return txq; @@ -5838,7 +5844,8 @@ static void free_some_resources(struct adapter *adapter) t4_fw_bye(adapter, adapter->pf); } -#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | \ + NETIF_F_GSO_UDP_L4) #define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \ NETIF_F_GRO | NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA) #define SEGMENT_SIZE 128 diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 5ad54493f825..53f9a821c29f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -734,6 +734,8 @@ static inline int is_eth_imm(const struct sk_buff *skb, unsigned int chip_ver) chip_ver > CHELSIO_T5) { hdrlen = sizeof(struct cpl_tx_tnl_lso); hdrlen += sizeof(struct cpl_tx_pkt_core); + } else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { + return 0; } else { hdrlen = skb_shinfo(skb)->gso_size ? sizeof(struct cpl_tx_pkt_lso_core) : 0; @@ -775,12 +777,20 @@ static inline unsigned int calc_tx_flits(const struct sk_buff *skb, */ flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); if (skb_shinfo(skb)->gso_size) { - if (skb->encapsulation && chip_ver > CHELSIO_T5) + if (skb->encapsulation && chip_ver > CHELSIO_T5) { hdrlen = sizeof(struct fw_eth_tx_pkt_wr) + sizeof(struct cpl_tx_tnl_lso); - else + } else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) { + u32 pkt_hdrlen; + + pkt_hdrlen = eth_get_headlen(skb->dev, skb->data, + skb_headlen(skb)); + hdrlen = sizeof(struct fw_eth_tx_eo_wr) + + round_up(pkt_hdrlen, 16); + } else { hdrlen = sizeof(struct fw_eth_tx_pkt_wr) + sizeof(struct cpl_tx_pkt_lso_core); + } hdrlen += sizeof(struct cpl_tx_pkt_core); flits += (hdrlen / sizeof(__be64)); @@ -1345,6 +1355,25 @@ static inline int cxgb4_validate_skb(struct sk_buff *skb, return 0; } +static void *write_eo_udp_wr(struct sk_buff *skb, struct fw_eth_tx_eo_wr *wr, + u32 hdr_len) +{ + wr->u.udpseg.type = FW_ETH_TX_EO_TYPE_UDPSEG; + wr->u.udpseg.ethlen = skb_network_offset(skb); + wr->u.udpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); + wr->u.udpseg.udplen = sizeof(struct udphdr); + wr->u.udpseg.rtplen = 0; + wr->u.udpseg.r4 = 0; + if (skb_shinfo(skb)->gso_size) + wr->u.udpseg.mss = cpu_to_be16(skb_shinfo(skb)->gso_size); + else + wr->u.udpseg.mss = cpu_to_be16(skb->len - hdr_len); + wr->u.udpseg.schedpktsize = wr->u.udpseg.mss; + wr->u.udpseg.plen = cpu_to_be32(skb->len - hdr_len); + + return (void *)(wr + 1); +} + /** * cxgb4_eth_xmit - add a packet to an Ethernet Tx queue * @skb: the packet @@ -1357,14 +1386,15 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) enum cpl_tx_tnl_lso_type tnl_type = TX_TNL_TYPE_OPAQUE; bool ptp_enabled = is_ptp_enabled(skb, dev); unsigned int last_desc, flits, ndesc; + u32 wr_mid, ctrl0, op, sgl_off = 0; const struct skb_shared_info *ssi; + int len, qidx, credits, ret, left; struct tx_sw_desc *sgl_sdesc; + struct fw_eth_tx_eo_wr *eowr; struct fw_eth_tx_pkt_wr *wr; struct cpl_tx_pkt_core *cpl; - int len, qidx, credits, ret; const struct port_info *pi; bool immediate = false; - u32 wr_mid, ctrl0, op; u64 cntrl, *end, *sgl; struct sge_eth_txq *q; unsigned int chip_ver; @@ -1469,13 +1499,17 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) } wr = (void *)&q->q.desc[q->q.pidx]; + eowr = (void *)&q->q.desc[q->q.pidx]; wr->equiq_to_len16 = htonl(wr_mid); wr->r3 = cpu_to_be64(0); - end = (u64 *)wr + flits; + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) + end = (u64 *)eowr + flits; + else + end = (u64 *)wr + flits; len = immediate ? skb->len : 0; len += sizeof(*cpl); - if (ssi->gso_size) { + if (ssi->gso_size && !(ssi->gso_type & SKB_GSO_UDP_L4)) { struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); struct cpl_tx_tnl_lso *tnl_lso = (void *)(wr + 1); @@ -1507,20 +1541,29 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) cntrl = hwcsum(adap->params.chip, skb); } sgl = (u64 *)(cpl + 1); /* sgl start here */ - if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) { - /* If current position is already at the end of the - * txq, reset the current to point to start of the queue - * and update the end ptr as well. - */ - if (sgl == (u64 *)q->q.stat) { - int left = (u8 *)end - (u8 *)q->q.stat; - - end = (void *)q->q.desc + left; - sgl = (void *)q->q.desc; - } - } q->tso++; q->tx_cso += ssi->gso_segs; + } else if (ssi->gso_size) { + u64 *start; + u32 hdrlen; + + hdrlen = eth_get_headlen(dev, skb->data, skb_headlen(skb)); + len += hdrlen; + wr->op_immdlen = cpu_to_be32(FW_WR_OP_V(FW_ETH_TX_EO_WR) | + FW_ETH_TX_EO_WR_IMMDLEN_V(len)); + cpl = write_eo_udp_wr(skb, eowr, hdrlen); + cntrl = hwcsum(adap->params.chip, skb); + + start = (u64 *)(cpl + 1); + sgl = (u64 *)inline_tx_skb_header(skb, &q->q, (void *)start, + hdrlen); + if (unlikely(start > sgl)) { + left = (u8 *)end - (u8 *)q->q.stat; + end = (void *)q->q.desc + left; + } + sgl_off = hdrlen; + q->uso++; + q->tx_cso += ssi->gso_segs; } else { if (ptp_enabled) op = FW_PTP_TX_PKT_WR; @@ -1537,6 +1580,16 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) } } + if (unlikely((u8 *)sgl >= (u8 *)q->q.stat)) { + /* If current position is already at the end of the + * txq, reset the current to point to start of the queue + * and update the end ptr as well. + */ + left = (u8 *)end - (u8 *)q->q.stat; + end = (void *)q->q.desc + left; + sgl = (void *)q->q.desc; + } + if (skb_vlan_tag_present(skb)) { q->vlan_ins++; cntrl |= TXPKT_VLAN_VLD_F | TXPKT_VLAN_V(skb_vlan_tag_get(skb)); @@ -1566,7 +1619,7 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev) cxgb4_inline_tx_skb(skb, &q->q, sgl); dev_consume_skb_any(skb); } else { - cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, 0, + cxgb4_write_sgl(skb, &q->q, (void *)sgl, end, sgl_off, sgl_sdesc->addr); skb_orphan(skb); sgl_sdesc->skb = skb; @@ -2024,7 +2077,8 @@ static inline u8 ethofld_calc_tx_flits(struct adapter *adap, u32 wrlen; wrlen = sizeof(struct fw_eth_tx_eo_wr) + sizeof(struct cpl_tx_pkt_core); - if (skb_shinfo(skb)->gso_size) + if (skb_shinfo(skb)->gso_size && + !(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)) wrlen += sizeof(struct cpl_tx_pkt_lso_core); wrlen += roundup(hdr_len, 16); @@ -2032,10 +2086,14 @@ static inline u8 ethofld_calc_tx_flits(struct adapter *adap, /* Packet headers + WR + CPLs */ flits = DIV_ROUND_UP(wrlen, 8); - if (skb_shinfo(skb)->nr_frags > 0) - nsgl = sgl_len(skb_shinfo(skb)->nr_frags); - else if (skb->len - hdr_len) + if (skb_shinfo(skb)->nr_frags > 0) { + if (skb_headlen(skb) - hdr_len) + nsgl = sgl_len(skb_shinfo(skb)->nr_frags + 1); + else + nsgl = sgl_len(skb_shinfo(skb)->nr_frags); + } else if (skb->len - hdr_len) { nsgl = sgl_len(1); + } return flits + nsgl; } @@ -2049,16 +2107,16 @@ static inline void *write_eo_wr(struct adapter *adap, struct cpl_tx_pkt_core *cpl; u32 immd_len, wrlen16; bool compl = false; + u8 ver, proto; + + ver = ip_hdr(skb)->version; + proto = (ver == 6) ? ipv6_hdr(skb)->nexthdr : ip_hdr(skb)->protocol; wrlen16 = DIV_ROUND_UP(wrlen, 16); immd_len = sizeof(struct cpl_tx_pkt_core); - if (skb_shinfo(skb)->gso_size) { - if (skb->encapsulation && - CHELSIO_CHIP_VERSION(adap->params.chip) > CHELSIO_T5) - immd_len += sizeof(struct cpl_tx_tnl_lso); - else - immd_len += sizeof(struct cpl_tx_pkt_lso_core); - } + if (skb_shinfo(skb)->gso_size && + !(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4)) + immd_len += sizeof(struct cpl_tx_pkt_lso_core); immd_len += hdr_len; if (!eosw_txq->ncompl || @@ -2074,23 +2132,27 @@ static inline void *write_eo_wr(struct adapter *adap, wr->equiq_to_len16 = cpu_to_be32(FW_WR_LEN16_V(wrlen16) | FW_WR_FLOWID_V(eosw_txq->hwtid)); wr->r3 = 0; - wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG; - wr->u.tcpseg.ethlen = skb_network_offset(skb); - wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); - wr->u.tcpseg.tcplen = tcp_hdrlen(skb); - wr->u.tcpseg.tsclk_tsoff = 0; - wr->u.tcpseg.r4 = 0; - wr->u.tcpseg.r5 = 0; - wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len); - - if (ssi->gso_size) { - struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); - - wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size); - cpl = write_tso_wr(adap, skb, lso); + if (proto == IPPROTO_UDP) { + cpl = write_eo_udp_wr(skb, wr, hdr_len); } else { - wr->u.tcpseg.mss = cpu_to_be16(0xffff); - cpl = (void *)(wr + 1); + wr->u.tcpseg.type = FW_ETH_TX_EO_TYPE_TCPSEG; + wr->u.tcpseg.ethlen = skb_network_offset(skb); + wr->u.tcpseg.iplen = cpu_to_be16(skb_network_header_len(skb)); + wr->u.tcpseg.tcplen = tcp_hdrlen(skb); + wr->u.tcpseg.tsclk_tsoff = 0; + wr->u.tcpseg.r4 = 0; + wr->u.tcpseg.r5 = 0; + wr->u.tcpseg.plen = cpu_to_be32(skb->len - hdr_len); + + if (ssi->gso_size) { + struct cpl_tx_pkt_lso_core *lso = (void *)(wr + 1); + + wr->u.tcpseg.mss = cpu_to_be16(ssi->gso_size); + cpl = write_tso_wr(adap, skb, lso); + } else { + wr->u.tcpseg.mss = cpu_to_be16(0xffff); + cpl = (void *)(wr + 1); + } } eosw_txq->cred -= wrlen16; @@ -4312,7 +4374,10 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq, txq->q.q_type = CXGB4_TXQ_ETH; init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_G(ntohl(c.eqid_pkd))); txq->txq = netdevq; - txq->tso = txq->tx_cso = txq->vlan_ins = 0; + txq->tso = 0; + txq->uso = 0; + txq->tx_cso = 0; + txq->vlan_ins = 0; txq->mapping_err = 0; txq->dbqt = dbqt; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 414e5cca293e..ac4fb43bdec6 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -536,7 +536,8 @@ struct fw_eth_tx_pkt_wr { }; enum fw_eth_tx_eo_type { - FW_ETH_TX_EO_TYPE_TCPSEG = 1, + FW_ETH_TX_EO_TYPE_UDPSEG = 0, + FW_ETH_TX_EO_TYPE_TCPSEG, }; struct fw_eth_tx_eo_wr { @@ -544,6 +545,17 @@ struct fw_eth_tx_eo_wr { __be32 equiq_to_len16; __be64 r3; union fw_eth_tx_eo { + struct fw_eth_tx_eo_udpseg { + __u8 type; + __u8 ethlen; + __be16 iplen; + __u8 udplen; + __u8 rtplen; + __be16 r4; + __be16 mss; + __be16 schedpktsize; + __be32 plen; + } udpseg; struct fw_eth_tx_eo_tcpseg { __u8 type; __u8 ethlen; -- cgit v1.2.3-59-g8ed1b From 8311f0be9763386556d7b698f5e101c688f9c2eb Mon Sep 17 00:00:00 2001 From: Rahul Lakkireddy Date: Fri, 22 Nov 2019 06:30:03 +0530 Subject: cxgb4: add stats for MQPRIO QoS offload Tx path Export necessary stats for traffic flowing through MQPRIO QoS offload Tx path. v2: - No change. Signed-off-by: Rahul Lakkireddy Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 1 + drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 13 ++++++++++++- drivers/net/ethernet/chelsio/cxgb4/sge.c | 14 ++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 04cb8909feeb..a70ac2097892 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -850,6 +850,7 @@ struct sge_eohw_txq { struct sge_txq q; /* HW Txq */ struct adapter *adap; /* Backpointer to adapter */ unsigned long tso; /* # of TSO requests */ + unsigned long uso; /* # of USO requests */ unsigned long tx_cso; /* # of Tx checksum offloads */ unsigned long vlan_ins; /* # of Tx VLAN insertions */ unsigned long mapping_err; /* # of I/O MMU packet mapping errors */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index fa229d0f1016..93868dca186a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2797,6 +2797,7 @@ do { \ RL("RxAN", stats.an); RL("RxNoMem", stats.nomem); TL("TSO:", tso); + TL("USO:", uso); TL("TxCSO:", tx_cso); TL("VLANins:", vlan_ins); TL("TxQFull:", q.stops); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index f57457453561..20ab3b6285a2 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -242,9 +242,10 @@ static void collect_sge_port_stats(const struct adapter *adap, const struct port_info *p, struct queue_port_stats *s) { - int i; const struct sge_eth_txq *tx = &adap->sge.ethtxq[p->first_qset]; const struct sge_eth_rxq *rx = &adap->sge.ethrxq[p->first_qset]; + struct sge_eohw_txq *eohw_tx; + unsigned int i; memset(s, 0, sizeof(*s)); for (i = 0; i < p->nqsets; i++, rx++, tx++) { @@ -257,6 +258,16 @@ static void collect_sge_port_stats(const struct adapter *adap, s->gro_pkts += rx->stats.lro_pkts; s->gro_merged += rx->stats.lro_merged; } + + if (adap->sge.eohw_txq) { + eohw_tx = &adap->sge.eohw_txq[p->first_qset]; + for (i = 0; i < p->nqsets; i++, eohw_tx++) { + s->tso += eohw_tx->tso; + s->uso += eohw_tx->uso; + s->tx_csum += eohw_tx->tx_cso; + s->vlan_ins += eohw_tx->vlan_ins; + } + } } static void collect_adapter_stats(struct adapter *adap, struct adapter_stats *s) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 53f9a821c29f..97cda501e7e8 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -2262,6 +2262,19 @@ write_wr_headers: d->addr); } + if (skb_shinfo(skb)->gso_size) { + if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) + eohw_txq->uso++; + else + eohw_txq->tso++; + eohw_txq->tx_cso += skb_shinfo(skb)->gso_segs; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + eohw_txq->tx_cso++; + } + + if (skb_vlan_tag_present(skb)) + eohw_txq->vlan_ins++; + txq_advance(&eohw_txq->q, ndesc); cxgb4_ring_tx_db(adap, &eohw_txq->q, ndesc); eosw_txq_advance_index(&eosw_txq->last_pidx, 1, eosw_txq->ndesc); @@ -4546,6 +4559,7 @@ int t4_sge_alloc_ethofld_txq(struct adapter *adap, struct sge_eohw_txq *txq, spin_lock_init(&txq->lock); txq->adap = adap; txq->tso = 0; + txq->uso = 0; txq->tx_cso = 0; txq->vlan_ins = 0; txq->mapping_err = 0; -- cgit v1.2.3-59-g8ed1b From 8490e75cdbb734829d3b324c3a52492c2edbfbd6 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 22 Nov 2019 17:57:03 +0000 Subject: sfc: change ARFS expiry mechanism The old rfs_filters_added method for determining the quota could potentially allow the NIC to become filled with old filters, which never get tested for expiry. Instead, explicitly make expiry check work depend on the number of filters installed, and don't count checking slots without filters in as doing work. This guarantees that each filter will be checked for expiry at least once every thirty seconds (assuming the channel to which it belongs is NAPI polling actively) regardless of fill level. Signed-off-by: Edward Cree Tested-by: David Ahern Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/efx.c | 8 +++--- drivers/net/ethernet/sfc/efx.h | 9 ++++--- drivers/net/ethernet/sfc/net_driver.h | 14 ++++++----- drivers/net/ethernet/sfc/rx.c | 46 ++++++++++++++++++++--------------- 4 files changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 0fa9972027db..38d186b949be 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -1969,6 +1969,8 @@ static int efx_probe_filters(struct efx_nic *efx) ++i) channel->rps_flow_id[i] = RPS_FLOW_ID_INVALID; + channel->rfs_expire_index = 0; + channel->rfs_filter_count = 0; } if (!success) { @@ -1978,8 +1980,6 @@ static int efx_probe_filters(struct efx_nic *efx) rc = -ENOMEM; goto out_unlock; } - - efx->rps_expire_index = efx->rps_expire_channel = 0; } #endif out_unlock: @@ -1993,8 +1993,10 @@ static void efx_remove_filters(struct efx_nic *efx) #ifdef CONFIG_RFS_ACCEL struct efx_channel *channel; - efx_for_each_channel(channel, efx) + efx_for_each_channel(channel, efx) { + flush_work(&channel->filter_work); kfree(channel->rps_flow_id); + } #endif down_write(&efx->filter_sem); efx->type->filter_table_remove(efx); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index 45c7ae4114ec..e58c2b6d64d9 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -166,15 +166,16 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx, #ifdef CONFIG_RFS_ACCEL int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id); -bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota); +bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota); static inline void efx_filter_rfs_expire(struct work_struct *data) { struct efx_channel *channel = container_of(data, struct efx_channel, filter_work); + unsigned int time = jiffies - channel->rfs_last_expiry, quota; - if (channel->rfs_filters_added >= 60 && - __efx_filter_rfs_expire(channel->efx, 100)) - channel->rfs_filters_added -= 60; + quota = channel->rfs_filter_count * time / (30 * HZ); + if (quota > 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota))) + channel->rfs_last_expiry += time; } #define efx_filter_rfs_enabled() 1 #else diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 04e49eac7327..5b1b882f6c67 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -439,6 +439,11 @@ enum efx_sync_events_state { * @event_test_cpu: Last CPU to handle interrupt or test event for this channel * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score + * @rfs_filter_count: number of accelerated RFS filters currently in place; + * equals the count of @rps_flow_id slots filled + * @rfs_last_expiry: value of jiffies last time some accelerated RFS filters + * were checked for expiry + * @rfs_expire_index: next accelerated RFS filter ID to check for expiry * @filter_work: Work item for efx_filter_rfs_expire() * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS, * indexed by filter ID @@ -489,7 +494,9 @@ struct efx_channel { unsigned int irq_count; unsigned int irq_mod_score; #ifdef CONFIG_RFS_ACCEL - unsigned int rfs_filters_added; + unsigned int rfs_filter_count; + unsigned int rfs_last_expiry; + unsigned int rfs_expire_index; struct work_struct filter_work; #define RPS_FLOW_ID_INVALID 0xFFFFFFFF u32 *rps_flow_id; @@ -923,9 +930,6 @@ struct efx_async_filter_insertion { * @filter_sem: Filter table rw_semaphore, protects existence of @filter_state * @filter_state: Architecture-dependent filter table state * @rps_mutex: Protects RPS state of all channels - * @rps_expire_channel: Next channel to check for expiry - * @rps_expire_index: Next index to check for expiry in - * @rps_expire_channel's @rps_flow_id * @rps_slot_map: bitmap of in-flight entries in @rps_slot * @rps_slot: array of ARFS insertion requests for efx_filter_rfs_work() * @rps_hash_lock: Protects ARFS filter mapping state (@rps_hash_table and @@ -1096,8 +1100,6 @@ struct efx_nic { void *filter_state; #ifdef CONFIG_RFS_ACCEL struct mutex rps_mutex; - unsigned int rps_expire_channel; - unsigned int rps_expire_index; unsigned long rps_slot_map; struct efx_async_filter_insertion rps_slot[EFX_RPS_MAX_IN_FLIGHT]; spinlock_t rps_hash_lock; diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index bec261905530..bbf2393f7599 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -988,6 +988,7 @@ static void efx_filter_rfs_work(struct work_struct *data) rc = efx->type->filter_insert(efx, &req->spec, true); if (rc >= 0) + /* Discard 'priority' part of EF10+ filter ID (mcdi_filters) */ rc %= efx->type->max_rx_ip_filters; if (efx->rps_hash_table) { spin_lock_bh(&efx->rps_hash_lock); @@ -1012,8 +1013,9 @@ static void efx_filter_rfs_work(struct work_struct *data) * later. */ mutex_lock(&efx->rps_mutex); + if (channel->rps_flow_id[rc] == RPS_FLOW_ID_INVALID) + channel->rfs_filter_count++; channel->rps_flow_id[rc] = req->flow_id; - ++channel->rfs_filters_added; mutex_unlock(&efx->rps_mutex); if (req->spec.ether_type == htons(ETH_P_IP)) @@ -1139,38 +1141,44 @@ out_clear: return rc; } -bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned int quota) +bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota) { bool (*expire_one)(struct efx_nic *efx, u32 flow_id, unsigned int index); - unsigned int channel_idx, index, size; + struct efx_nic *efx = channel->efx; + unsigned int index, size, start; u32 flow_id; if (!mutex_trylock(&efx->rps_mutex)) return false; expire_one = efx->type->filter_rfs_expire_one; - channel_idx = efx->rps_expire_channel; - index = efx->rps_expire_index; + index = channel->rfs_expire_index; + start = index; size = efx->type->max_rx_ip_filters; - while (quota--) { - struct efx_channel *channel = efx_get_channel(efx, channel_idx); + while (quota) { flow_id = channel->rps_flow_id[index]; - if (flow_id != RPS_FLOW_ID_INVALID && - expire_one(efx, flow_id, index)) { - netif_info(efx, rx_status, efx->net_dev, - "expired filter %d [queue %u flow %u]\n", - index, channel_idx, flow_id); - channel->rps_flow_id[index] = RPS_FLOW_ID_INVALID; + if (flow_id != RPS_FLOW_ID_INVALID) { + quota--; + if (expire_one(efx, flow_id, index)) { + netif_info(efx, rx_status, efx->net_dev, + "expired filter %d [channel %u flow %u]\n", + index, channel->channel, flow_id); + channel->rps_flow_id[index] = RPS_FLOW_ID_INVALID; + channel->rfs_filter_count--; + } } - if (++index == size) { - if (++channel_idx == efx->n_channels) - channel_idx = 0; + if (++index == size) index = 0; - } + /* If we were called with a quota that exceeds the total number + * of filters in the table (which should never happen), ensure + * that we don't loop forever - stop when we've examined every + * row of the table. + */ + if (WARN_ON(index == start && quota)) + break; } - efx->rps_expire_channel = channel_idx; - efx->rps_expire_index = index; + channel->rfs_expire_index = index; mutex_unlock(&efx->rps_mutex); return true; } -- cgit v1.2.3-59-g8ed1b From 0aa6608daec5d19275809d30df6a02529eb66c7d Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 22 Nov 2019 17:57:19 +0000 Subject: sfc: suppress MCDI errors from ARFS In high connection count usage, the NIC's filter table may be filled with sufficiently many ARFS filters that further insertions fail. As this does not represent a correctness issue, do not log the resulting MCDI errors. Add a debug-level message under the (by default disabled) rx_status category instead; and take the opportunity to do a little extra expiry work. Since there are now multiple workitems able to call __efx_filter_rfs_expire on a given channel, it is possible for them to race and thus pass quotas which, combined, exceed rfs_filter_count. Thus, don't WARN_ON if we loop all the way around the table with quota left over. Signed-off-by: Edward Cree Tested-by: David Ahern Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/ef10.c | 8 ++++++-- drivers/net/ethernet/sfc/rx.c | 28 ++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index ad68eb0cb8fd..4d9bbccc6f89 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -4202,11 +4202,15 @@ static int efx_ef10_filter_push(struct efx_nic *efx, { MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN); + size_t outlen; int rc; efx_ef10_filter_push_prep(efx, spec, inbuf, *handle, ctx, replacing); - rc = efx_mcdi_rpc(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf), - outbuf, sizeof(outbuf), NULL); + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc && spec->priority != EFX_FILTER_PRI_HINT) + efx_mcdi_display_error(efx, MC_CMD_FILTER_OP, sizeof(inbuf), + outbuf, outlen, rc); if (rc == 0) *handle = MCDI_QWORD(outbuf, FILTER_OP_OUT_HANDLE); if (rc == -ENOSPC) diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index bbf2393f7599..252a5f10596d 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -1032,6 +1032,26 @@ static void efx_filter_rfs_work(struct work_struct *data) req->spec.rem_host, ntohs(req->spec.rem_port), req->spec.loc_host, ntohs(req->spec.loc_port), req->rxq_index, req->flow_id, rc, arfs_id); + } else { + if (req->spec.ether_type == htons(ETH_P_IP)) + netif_dbg(efx, rx_status, efx->net_dev, + "failed to steer %s %pI4:%u:%pI4:%u to queue %u [flow %u rc %d id %u]\n", + (req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", + req->spec.rem_host, ntohs(req->spec.rem_port), + req->spec.loc_host, ntohs(req->spec.loc_port), + req->rxq_index, req->flow_id, rc, arfs_id); + else + netif_dbg(efx, rx_status, efx->net_dev, + "failed to steer %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u rc %d id %u]\n", + (req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP", + req->spec.rem_host, ntohs(req->spec.rem_port), + req->spec.loc_host, ntohs(req->spec.loc_port), + req->rxq_index, req->flow_id, rc, arfs_id); + /* We're overloading the NIC's filter tables, so let's do a + * chunk of extra expiry work. + */ + __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, + 100u)); } /* Release references */ @@ -1170,11 +1190,11 @@ bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota) if (++index == size) index = 0; /* If we were called with a quota that exceeds the total number - * of filters in the table (which should never happen), ensure - * that we don't loop forever - stop when we've examined every - * row of the table. + * of filters in the table (which shouldn't happen, but could + * if two callers race), ensure that we don't loop forever - + * stop when we've examined every row of the table. */ - if (WARN_ON(index == start && quota)) + if (index == start) break; } -- cgit v1.2.3-59-g8ed1b From ca70bd423f10b004f1bf7b2424d34025a9408e54 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 22 Nov 2019 17:57:27 +0000 Subject: sfc: add statistics for ARFS Report the number of successful and failed insertions, and also the current count of filters, to aid in tuning e.g. rps_flow_cnt. Signed-off-by: Edward Cree Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/ethtool.c | 6 ++++++ drivers/net/ethernet/sfc/net_driver.h | 4 ++++ drivers/net/ethernet/sfc/rx.c | 2 ++ 3 files changed, 12 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 8db593fb9699..6a9347cd67f3 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -56,6 +56,9 @@ static u64 efx_get_atomic_stat(void *field) #define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \ EFX_ETHTOOL_STAT(field, channel, n_##field, \ unsigned int, efx_get_uint_stat) +#define EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(field) \ + EFX_ETHTOOL_STAT(field, channel, field, \ + unsigned int, efx_get_uint_stat) #define EFX_ETHTOOL_UINT_TXQ_STAT(field) \ EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \ @@ -87,6 +90,9 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect), + EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(rfs_filter_count), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_succeeded), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_failed), }; #define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 5b1b882f6c67..ccd480e699d3 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -444,6 +444,8 @@ enum efx_sync_events_state { * @rfs_last_expiry: value of jiffies last time some accelerated RFS filters * were checked for expiry * @rfs_expire_index: next accelerated RFS filter ID to check for expiry + * @n_rfs_succeeded: number of successful accelerated RFS filter insertions + * @n_rfs_failed; number of failed accelerated RFS filter insertions * @filter_work: Work item for efx_filter_rfs_expire() * @rps_flow_id: Flow IDs of filters allocated for accelerated RFS, * indexed by filter ID @@ -497,6 +499,8 @@ struct efx_channel { unsigned int rfs_filter_count; unsigned int rfs_last_expiry; unsigned int rfs_expire_index; + unsigned int n_rfs_succeeded; + unsigned int n_rfs_failed; struct work_struct filter_work; #define RPS_FLOW_ID_INVALID 0xFFFFFFFF u32 *rps_flow_id; diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c index 252a5f10596d..ef52b24ad9e7 100644 --- a/drivers/net/ethernet/sfc/rx.c +++ b/drivers/net/ethernet/sfc/rx.c @@ -1032,6 +1032,7 @@ static void efx_filter_rfs_work(struct work_struct *data) req->spec.rem_host, ntohs(req->spec.rem_port), req->spec.loc_host, ntohs(req->spec.loc_port), req->rxq_index, req->flow_id, rc, arfs_id); + channel->n_rfs_succeeded++; } else { if (req->spec.ether_type == htons(ETH_P_IP)) netif_dbg(efx, rx_status, efx->net_dev, @@ -1047,6 +1048,7 @@ static void efx_filter_rfs_work(struct work_struct *data) req->spec.rem_host, ntohs(req->spec.rem_port), req->spec.loc_host, ntohs(req->spec.loc_port), req->rxq_index, req->flow_id, rc, arfs_id); + channel->n_rfs_failed++; /* We're overloading the NIC's filter tables, so let's do a * chunk of extra expiry work. */ -- cgit v1.2.3-59-g8ed1b From 6fbc05e59163e66795a2bbdb4068abd7f7ae3510 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 22 Nov 2019 17:57:40 +0000 Subject: sfc: do ARFS expiry work occasionally even without NAPI poll If there's no traffic on a channel, its ARFS expiry work will never get scheduled by efx_poll() as that isn't being run. So make efx_filter_rfs_expire() reschedule itself to run after 30 seconds. Signed-off-by: Edward Cree Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/efx.c | 8 ++++---- drivers/net/ethernet/sfc/efx.h | 10 +++++++--- drivers/net/ethernet/sfc/net_driver.h | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 38d186b949be..992c773620ec 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -355,7 +355,7 @@ static int efx_poll(struct napi_struct *napi, int budget) #ifdef CONFIG_RFS_ACCEL /* Perhaps expire some ARFS filters */ - schedule_work(&channel->filter_work); + mod_delayed_work(system_wq, &channel->filter_work, 0); #endif /* There is no race here; although napi_disable() will @@ -487,7 +487,7 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) } #ifdef CONFIG_RFS_ACCEL - INIT_WORK(&channel->filter_work, efx_filter_rfs_expire); + INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire); #endif rx_queue = &channel->rx_queue; @@ -533,7 +533,7 @@ efx_copy_channel(const struct efx_channel *old_channel) memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); timer_setup(&rx_queue->slow_fill, efx_rx_slow_fill, 0); #ifdef CONFIG_RFS_ACCEL - INIT_WORK(&channel->filter_work, efx_filter_rfs_expire); + INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire); #endif return channel; @@ -1994,7 +1994,7 @@ static void efx_remove_filters(struct efx_nic *efx) struct efx_channel *channel; efx_for_each_channel(channel, efx) { - flush_work(&channel->filter_work); + cancel_delayed_work_sync(&channel->filter_work); kfree(channel->rps_flow_id); } #endif diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index e58c2b6d64d9..2dd8d5002315 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -169,13 +169,17 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota); static inline void efx_filter_rfs_expire(struct work_struct *data) { - struct efx_channel *channel = container_of(data, struct efx_channel, - filter_work); - unsigned int time = jiffies - channel->rfs_last_expiry, quota; + struct delayed_work *dwork = to_delayed_work(data); + struct efx_channel *channel; + unsigned int time, quota; + channel = container_of(dwork, struct efx_channel, filter_work); + time = jiffies - channel->rfs_last_expiry; quota = channel->rfs_filter_count * time / (30 * HZ); if (quota > 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota))) channel->rfs_last_expiry += time; + /* Ensure we do more work eventually even if NAPI poll is not happening */ + schedule_delayed_work(dwork, 30 * HZ); } #define efx_filter_rfs_enabled() 1 #else diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index ccd480e699d3..1f88212be085 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -501,7 +501,7 @@ struct efx_channel { unsigned int rfs_expire_index; unsigned int n_rfs_succeeded; unsigned int n_rfs_failed; - struct work_struct filter_work; + struct delayed_work filter_work; #define RPS_FLOW_ID_INVALID 0xFFFFFFFF u32 *rps_flow_id; #endif -- cgit v1.2.3-59-g8ed1b From e3cf8b3668a808c1d252269ffc34a5723cfb9a7b Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 22 Nov 2019 12:37:08 +0000 Subject: net: phy: remove phy_ethtool_sset() There are no users of phy_ethtool_sset() in the kernel anymore, and as of commit 3c1bcc8614db ("net: ethernet: Convert phydev advertize and supported from u32 to link mode"), the implementation is slightly buggy - it doesn't correctly check the masked advertising mask as it used to. Remove it, and update the phy documentation to refer to its replacement function. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Signed-off-by: Jakub Kicinski --- Documentation/networking/phy.rst | 3 +- drivers/net/phy/phy.c | 60 ---------------------------------------- include/linux/phy.h | 1 - 3 files changed, 2 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/Documentation/networking/phy.rst b/Documentation/networking/phy.rst index a689966bc4be..cda1c0a0492a 100644 --- a/Documentation/networking/phy.rst +++ b/Documentation/networking/phy.rst @@ -352,7 +352,8 @@ Fills the phydev structure with up-to-date information about the current settings in the PHY. :: - int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); + int phy_ethtool_ksettings_set(struct phy_device *phydev, + const struct ethtool_link_ksettings *cmd); Ethtool convenience functions. :: diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36d4ffe1cd3f..80be4d691e5b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -253,66 +253,6 @@ static void phy_sanitize_settings(struct phy_device *phydev) } } -/** - * phy_ethtool_sset - generic ethtool sset function, handles all the details - * @phydev: target phy_device struct - * @cmd: ethtool_cmd - * - * A few notes about parameter checking: - * - * - We don't set port or transceiver, so we don't care what they - * were set to. - * - phy_start_aneg() will make sure forced settings are sane, and - * choose the next best ones from the ones selected, so we don't - * care if ethtool tries to give us bad values. - */ -int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) -{ - __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); - u32 speed = ethtool_cmd_speed(cmd); - - if (cmd->phy_address != phydev->mdio.addr) - return -EINVAL; - - /* We make sure that we don't pass unsupported values in to the PHY */ - ethtool_convert_legacy_u32_to_link_mode(advertising, cmd->advertising); - linkmode_and(advertising, advertising, phydev->supported); - - /* Verify the settings we care about. */ - if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - - if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) - return -EINVAL; - - if (cmd->autoneg == AUTONEG_DISABLE && - ((speed != SPEED_1000 && - speed != SPEED_100 && - speed != SPEED_10) || - (cmd->duplex != DUPLEX_HALF && - cmd->duplex != DUPLEX_FULL))) - return -EINVAL; - - phydev->autoneg = cmd->autoneg; - - phydev->speed = speed; - - linkmode_copy(phydev->advertising, advertising); - - linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, - phydev->advertising, AUTONEG_ENABLE == cmd->autoneg); - - phydev->duplex = cmd->duplex; - - phydev->mdix_ctrl = cmd->eth_tp_mdix_ctrl; - - /* Restart the PHY */ - phy_start_aneg(phydev); - - return 0; -} -EXPORT_SYMBOL(phy_ethtool_sset); - int phy_ethtool_ksettings_set(struct phy_device *phydev, const struct ethtool_link_ksettings *cmd) { diff --git a/include/linux/phy.h b/include/linux/phy.h index 124516fe2763..f5cdfb206097 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1160,7 +1160,6 @@ void phy_queue_state_machine(struct phy_device *phydev, unsigned long jiffies); void phy_mac_interrupt(struct phy_device *phydev); void phy_start_machine(struct phy_device *phydev); void phy_stop_machine(struct phy_device *phydev); -int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); void phy_ethtool_ksettings_get(struct phy_device *phydev, struct ethtool_link_ksettings *cmd); int phy_ethtool_ksettings_set(struct phy_device *phydev, -- cgit v1.2.3-59-g8ed1b From a5d66f810061e2dd70fb7a108dcd14e535bc639f Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 22 Nov 2019 15:23:23 +0000 Subject: net: phy: initialise phydev speed and duplex sanely When a phydev is created, the speed and duplex are set to zero and -1 respectively, rather than using the predefined SPEED_UNKNOWN and DUPLEX_UNKNOWN constants. There is a window at initialisation time where we may report link down using the 0/-1 values. Tidy this up and use the predefined constants, so debug doesn't complain with: "Unsupported (update phy-core.c)/Unsupported (update phy-core.c)" when the speed and duplex settings are printed. Signed-off-by: Russell King Signed-off-by: Jakub Kicinski --- drivers/net/phy/phy_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 990f22eb6ce7..0887ed2bb050 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -597,8 +597,8 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, mdiodev->device_free = phy_mdio_device_free; mdiodev->device_remove = phy_mdio_device_remove; - dev->speed = 0; - dev->duplex = -1; + dev->speed = SPEED_UNKNOWN; + dev->duplex = DUPLEX_UNKNOWN; dev->pause = 0; dev->asym_pause = 0; dev->link = 0; -- cgit v1.2.3-59-g8ed1b From ab818362c9054beb950b97a09ce7b0d56f5a32a1 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Fri, 22 Nov 2019 08:15:19 +0000 Subject: net: use rhashtable_lookup() instead of rhashtable_lookup_fast() rhashtable_lookup_fast() internally calls rcu_read_lock() then, calls rhashtable_lookup(). So if rcu_read_lock() is already held, rhashtable_lookup() is enough. Signed-off-by: Taehee Yoo Signed-off-by: Jakub Kicinski --- drivers/infiniband/hw/hfi1/sdma.c | 4 ++-- drivers/net/ethernet/mellanox/mlx5/core/en_tc.c | 2 +- drivers/net/ethernet/netronome/nfp/bpf/offload.c | 4 ++-- net/tipc/socket.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index c61b6022575e..5774dfc22e18 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -881,8 +881,8 @@ struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd, cpu_id = smp_processor_id(); rcu_read_lock(); - rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu_id, - sdma_rht_params); + rht_node = rhashtable_lookup(dd->sdma_rht, &cpu_id, + sdma_rht_params); if (rht_node && rht_node->map[vl]) { struct sdma_rht_map_elem *map = rht_node->map[vl]; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index 761fc35c4aab..0d5d84b5fa23 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -3876,7 +3876,7 @@ int mlx5e_delete_flower(struct net_device *dev, struct mlx5e_priv *priv, int err; rcu_read_lock(); - flow = rhashtable_lookup_fast(tc_ht, &f->cookie, tc_ht_params); + flow = rhashtable_lookup(tc_ht, &f->cookie, tc_ht_params); if (!flow || !same_flow_direction(flow, flags)) { err = -EINVAL; goto errout; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 06927ba5a3ae..95a0d3910e31 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -458,8 +458,8 @@ int nfp_bpf_event_output(struct nfp_app_bpf *bpf, const void *data, return -EINVAL; rcu_read_lock(); - record = rhashtable_lookup_fast(&bpf->maps_neutral, &map_id, - nfp_bpf_maps_neutral_params); + record = rhashtable_lookup(&bpf->maps_neutral, &map_id, + nfp_bpf_maps_neutral_params); if (!record || map_id_full > U32_MAX) { rcu_read_unlock(); cmsg_warn(bpf, "perf event: map id %lld (0x%llx) not recognized, dropping event\n", diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5d7859aac78e..a1c8d722ca20 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -2880,7 +2880,7 @@ static struct tipc_sock *tipc_sk_lookup(struct net *net, u32 portid) struct tipc_sock *tsk; rcu_read_lock(); - tsk = rhashtable_lookup_fast(&tn->sk_rht, &portid, tsk_rht_params); + tsk = rhashtable_lookup(&tn->sk_rht, &portid, tsk_rht_params); if (tsk) sock_hold(&tsk->sk); rcu_read_unlock(); -- cgit v1.2.3-59-g8ed1b From d46b7e4fb06037a61415f5b6964fcf632ee1dc34 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 21 Nov 2019 00:36:22 +0000 Subject: net: phylink: rename mac_link_state() op to mac_pcs_get_state() Rename the mac_link_state() method to mac_pcs_get_state() to make it clear that it should be returning the MACs PCS current state, which is used for inband negotiation rather than just reading back what the MAC has been configured for. Update the documentation to explicitly mention that this is for inband. We drop the return value as well; most of phylink doesn't check the return value and it is not clear what it should do on error - instead arrange for state->link to be false. Signed-off-by: Russell King Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/cadence/macb_main.c | 8 ++++---- drivers/net/ethernet/marvell/mvneta.c | 8 +++----- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 21 +++++++++---------- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +++----- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++---- drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 8 +++----- drivers/net/phy/phylink.c | 15 ++++++-------- include/linux/phylink.h | 25 ++++++++++++----------- net/dsa/dsa_priv.h | 4 ++-- net/dsa/port.c | 19 +++++++++-------- 10 files changed, 59 insertions(+), 65 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 8fc2e21f0bb1..d5ae2e1e0b0e 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -505,10 +505,10 @@ static void macb_validate(struct phylink_config *config, __ETHTOOL_LINK_MODE_MASK_NBITS); } -static int macb_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void macb_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { - return -EOPNOTSUPP; + state->link = 0; } static void macb_mac_an_restart(struct phylink_config *config) @@ -604,7 +604,7 @@ static void macb_mac_link_up(struct phylink_config *config, unsigned int mode, static const struct phylink_mac_ops macb_phylink_ops = { .validate = macb_validate, - .mac_link_state = macb_mac_link_state, + .mac_pcs_get_state = macb_mac_pcs_get_state, .mac_an_restart = macb_mac_an_restart, .mac_config = macb_mac_config, .mac_link_down = macb_mac_link_down, diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a06d109c9e80..71a872d46bc4 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3694,8 +3694,8 @@ static void mvneta_validate(struct phylink_config *config, phylink_helper_basex_speed(state); } -static int mvneta_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void mvneta_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { struct net_device *ndev = to_net_dev(config->dev); struct mvneta_port *pp = netdev_priv(ndev); @@ -3721,8 +3721,6 @@ static int mvneta_mac_link_state(struct phylink_config *config, state->pause |= MLO_PAUSE_RX; if (gmac_stat & MVNETA_GMAC_TX_FLOW_CTRL_ENABLE) state->pause |= MLO_PAUSE_TX; - - return 1; } static void mvneta_mac_an_restart(struct phylink_config *config) @@ -3915,7 +3913,7 @@ static void mvneta_mac_link_up(struct phylink_config *config, unsigned int mode, static const struct phylink_mac_ops mvneta_phylink_ops = { .validate = mvneta_validate, - .mac_link_state = mvneta_mac_link_state, + .mac_pcs_get_state = mvneta_mac_pcs_get_state, .mac_an_restart = mvneta_mac_an_restart, .mac_config = mvneta_mac_config, .mac_link_down = mvneta_mac_link_down, diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 17e24c1e1c2b..62dc2f362a16 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -4823,8 +4823,8 @@ empty_set: bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); } -static void mvpp22_xlg_link_state(struct mvpp2_port *port, - struct phylink_link_state *state) +static void mvpp22_xlg_pcs_get_state(struct mvpp2_port *port, + struct phylink_link_state *state) { u32 val; @@ -4843,8 +4843,8 @@ static void mvpp22_xlg_link_state(struct mvpp2_port *port, state->pause |= MLO_PAUSE_RX; } -static void mvpp2_gmac_link_state(struct mvpp2_port *port, - struct phylink_link_state *state) +static void mvpp2_gmac_pcs_get_state(struct mvpp2_port *port, + struct phylink_link_state *state) { u32 val; @@ -4877,8 +4877,8 @@ static void mvpp2_gmac_link_state(struct mvpp2_port *port, state->pause |= MLO_PAUSE_TX; } -static int mvpp2_phylink_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void mvpp2_phylink_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { struct mvpp2_port *port = container_of(config, struct mvpp2_port, phylink_config); @@ -4888,13 +4888,12 @@ static int mvpp2_phylink_mac_link_state(struct phylink_config *config, mode &= MVPP22_XLG_CTRL3_MACMODESELECT_MASK; if (mode == MVPP22_XLG_CTRL3_MACMODESELECT_10G) { - mvpp22_xlg_link_state(port, state); - return 1; + mvpp22_xlg_pcs_get_state(port, state); + return; } } - mvpp2_gmac_link_state(port, state); - return 1; + mvpp2_gmac_pcs_get_state(port, state); } static void mvpp2_mac_an_restart(struct phylink_config *config) @@ -5186,7 +5185,7 @@ static void mvpp2_mac_link_down(struct phylink_config *config, static const struct phylink_mac_ops mvpp2_phylink_ops = { .validate = mvpp2_phylink_validate, - .mac_link_state = mvpp2_phylink_mac_link_state, + .mac_pcs_get_state = mvpp2_phylink_mac_pcs_get_state, .mac_an_restart = mvpp2_mac_an_restart, .mac_config = mvpp2_mac_config, .mac_link_up = mvpp2_mac_link_up, diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 1923ba76a1ec..527ad2aadcca 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -361,8 +361,8 @@ init_err: mac->id, phy_modes(state->interface), err); } -static int mtk_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void mtk_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { struct mtk_mac *mac = container_of(config, struct mtk_mac, phylink_config); @@ -391,8 +391,6 @@ static int mtk_mac_link_state(struct phylink_config *config, state->pause |= MLO_PAUSE_RX; if (pmsr & MAC_MSR_TX_FC) state->pause |= MLO_PAUSE_TX; - - return 1; } static void mtk_mac_an_restart(struct phylink_config *config) @@ -514,7 +512,7 @@ static void mtk_validate(struct phylink_config *config, static const struct phylink_mac_ops mtk_phylink_ops = { .validate = mtk_validate, - .mac_link_state = mtk_mac_link_state, + .mac_pcs_get_state = mtk_mac_pcs_get_state, .mac_an_restart = mtk_mac_an_restart, .mac_config = mtk_mac_config, .mac_link_down = mtk_mac_link_down, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 8cc4cd0cc515..644cb5d1fd4f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -868,10 +868,10 @@ static void stmmac_validate(struct phylink_config *config, __ETHTOOL_LINK_MODE_MASK_NBITS); } -static int stmmac_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void stmmac_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { - return -EOPNOTSUPP; + state->link = 0; } static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, @@ -965,7 +965,7 @@ static void stmmac_mac_link_up(struct phylink_config *config, static const struct phylink_mac_ops stmmac_phylink_mac_ops = { .validate = stmmac_validate, - .mac_link_state = stmmac_mac_link_state, + .mac_pcs_get_state = stmmac_mac_pcs_get_state, .mac_config = stmmac_mac_config, .mac_an_restart = stmmac_mac_an_restart, .mac_link_down = stmmac_mac_link_down, diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 8f32db6d2c45..20746b801959 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -1405,8 +1405,8 @@ static void axienet_validate(struct phylink_config *config, __ETHTOOL_LINK_MODE_MASK_NBITS); } -static int axienet_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +static void axienet_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { struct net_device *ndev = to_net_dev(config->dev); struct axienet_local *lp = netdev_priv(ndev); @@ -1431,8 +1431,6 @@ static int axienet_mac_link_state(struct phylink_config *config, state->an_complete = 0; state->duplex = 1; - - return 1; } static void axienet_mac_an_restart(struct phylink_config *config) @@ -1497,7 +1495,7 @@ static void axienet_mac_link_up(struct phylink_config *config, static const struct phylink_mac_ops axienet_phylink_ops = { .validate = axienet_validate, - .mac_link_state = axienet_mac_link_state, + .mac_pcs_get_state = axienet_mac_pcs_get_state, .mac_an_restart = axienet_mac_an_restart, .mac_config = axienet_mac_config, .mac_link_down = axienet_mac_link_down, diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 8e2a12885789..9a616d6bc4eb 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -357,9 +357,9 @@ static void phylink_mac_an_restart(struct phylink *pl) pl->ops->mac_an_restart(pl->config); } -static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *state) +static void phylink_mac_pcs_get_state(struct phylink *pl, + struct phylink_link_state *state) { - linkmode_copy(state->advertising, pl->link_config.advertising); linkmode_zero(state->lp_advertising); state->interface = pl->link_config.interface; @@ -370,7 +370,7 @@ static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state * state->an_complete = 0; state->link = 1; - return pl->ops->mac_link_state(pl->config, state); + pl->ops->mac_pcs_get_state(pl->config, state); } /* The fixed state is... fixed except for the link state, @@ -493,7 +493,7 @@ static void phylink_resolve(struct work_struct *w) break; case MLO_AN_INBAND: - phylink_get_mac_state(pl, &link_state); + phylink_mac_pcs_get_state(pl, &link_state); /* If we have a phy, the "up" state is the union of * both the PHY and the MAC */ @@ -1142,7 +1142,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl, if (pl->phydev) break; - phylink_get_mac_state(pl, &link_state); + phylink_mac_pcs_get_state(pl, &link_state); /* The MAC is reporting the link results from its own PCS * layer via in-band status. Report these as the current @@ -1561,10 +1561,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id, case MLO_AN_INBAND: if (phy_id == 0) { - val = phylink_get_mac_state(pl, &state); - if (val < 0) - return val; - + phylink_mac_pcs_get_state(pl, &state); val = phylink_mii_emul_read(reg, &state); } break; diff --git a/include/linux/phylink.h b/include/linux/phylink.h index 300ecdb6790a..fed5488e3c75 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -72,7 +72,7 @@ struct phylink_config { /** * struct phylink_mac_ops - MAC operations structure. * @validate: Validate and update the link configuration. - * @mac_link_state: Read the current link state from the hardware. + * @mac_pcs_get_state: Read the current link state from the hardware. * @mac_config: configure the MAC for the selected mode and state. * @mac_an_restart: restart 802.3z BaseX autonegotiation. * @mac_link_down: take the link down. @@ -84,8 +84,8 @@ struct phylink_mac_ops { void (*validate)(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); - int (*mac_link_state)(struct phylink_config *config, - struct phylink_link_state *state); + void (*mac_pcs_get_state)(struct phylink_config *config, + struct phylink_link_state *state); void (*mac_config)(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state); void (*mac_an_restart)(struct phylink_config *config); @@ -127,18 +127,19 @@ void validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); /** - * mac_link_state() - Read the current link state from the hardware + * mac_pcs_get_state() - Read the current inband link state from the hardware * @config: a pointer to a &struct phylink_config. * @state: a pointer to a &struct phylink_link_state. * - * Read the current link state from the MAC, reporting the current - * speed in @state->speed, duplex mode in @state->duplex, pause mode - * in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits, - * negotiation completion state in @state->an_complete, and link - * up state in @state->link. + * Read the current inband link state from the MAC PCS, reporting the + * current speed in @state->speed, duplex mode in @state->duplex, pause + * mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits, + * negotiation completion state in @state->an_complete, and link up state + * in @state->link. If possible, @state->lp_advertising should also be + * populated. */ -int mac_link_state(struct phylink_config *config, - struct phylink_link_state *state); +void mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state); /** * mac_config() - configure the MAC for the selected mode and state @@ -166,7 +167,7 @@ int mac_link_state(struct phylink_config *config, * 1000base-X or Cisco SGMII mode depending on the @state->interface * mode). In both cases, link state management (whether the link * is up or not) is performed by the MAC, and reported via the - * mac_link_state() callback. Changes in link state must be made + * mac_pcs_get_state() callback. Changes in link state must be made * by calling phylink_mac_change(). * * If in 802.3z mode, the link speed is fixed, dependent on the diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 53e7577896b6..2dd86d9bcda9 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -153,8 +153,8 @@ void dsa_port_link_unregister_of(struct dsa_port *dp); void dsa_port_phylink_validate(struct phylink_config *config, unsigned long *supported, struct phylink_link_state *state); -int dsa_port_phylink_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state); +void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state); void dsa_port_phylink_mac_config(struct phylink_config *config, unsigned int mode, const struct phylink_link_state *state); diff --git a/net/dsa/port.c b/net/dsa/port.c index 6e93c36bf0c0..46ac9ba21987 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -429,19 +429,22 @@ void dsa_port_phylink_validate(struct phylink_config *config, } EXPORT_SYMBOL_GPL(dsa_port_phylink_validate); -int dsa_port_phylink_mac_link_state(struct phylink_config *config, - struct phylink_link_state *state) +void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) { struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); struct dsa_switch *ds = dp->ds; - /* Only called for SGMII and 802.3z */ - if (!ds->ops->phylink_mac_link_state) - return -EOPNOTSUPP; + /* Only called for inband modes */ + if (!ds->ops->phylink_mac_link_state) { + state->link = 0; + return; + } - return ds->ops->phylink_mac_link_state(ds, dp->index, state); + if (ds->ops->phylink_mac_link_state(ds, dp->index, state) < 0) + state->link = 0; } -EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_state); +EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_pcs_get_state); void dsa_port_phylink_mac_config(struct phylink_config *config, unsigned int mode, @@ -510,7 +513,7 @@ EXPORT_SYMBOL_GPL(dsa_port_phylink_mac_link_up); const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .validate = dsa_port_phylink_validate, - .mac_link_state = dsa_port_phylink_mac_link_state, + .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, .mac_config = dsa_port_phylink_mac_config, .mac_an_restart = dsa_port_phylink_mac_an_restart, .mac_link_down = dsa_port_phylink_mac_link_down, -- cgit v1.2.3-59-g8ed1b From 6f3aeb1ba05d41320e6cf9a60f698d9c4e44348e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 23 Nov 2019 15:50:17 -0800 Subject: hv_netvsc: make recording RSS hash depend on feature flag The recording of RSS hash should be controlled by NETIF_F_RXHASH. Fixes: 1fac7ca4e63b ("hv_netvsc: record hardware hash in skb") Suggested-by: Eric Dumazet Signed-off-by: Stephen Hemminger Signed-off-by: Haiyang Zhang Reviewed-by: Michael Kelley Signed-off-by: Jakub Kicinski --- drivers/net/hyperv/hyperv_net.h | 3 ++- drivers/net/hyperv/netvsc_drv.c | 2 +- drivers/net/hyperv/rndis_filter.c | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 034dbab7aa80..250bd90627a5 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -823,7 +823,8 @@ struct nvsp_message { #define NETVSC_SUPPORTED_HW_FEATURES (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | \ NETIF_F_TSO | NETIF_F_IPV6_CSUM | \ - NETIF_F_TSO6 | NETIF_F_LRO | NETIF_F_SG) + NETIF_F_TSO6 | NETIF_F_LRO | \ + NETIF_F_SG | NETIF_F_RXHASH) #define VRSS_SEND_TAB_SIZE 16 /* must be power of 2 */ #define VRSS_CHANNEL_MAX 64 diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 5fa5c49e481b..868e22e286ca 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -803,7 +803,7 @@ static struct sk_buff *netvsc_alloc_recv_skb(struct net_device *net, skb->ip_summed = CHECKSUM_UNNECESSARY; } - if (hash_info) + if (hash_info && (net->features & NETIF_F_RXHASH)) skb_set_hash(skb, *hash_info, PKT_HASH_TYPE_L4); if (vlan) { diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index c06178380ac8..206b4e77eaf0 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1214,6 +1214,7 @@ static int rndis_netdev_set_hwcaps(struct rndis_device *rndis_device, /* Compute tx offload settings based on hw capabilities */ net->hw_features |= NETIF_F_RXCSUM; net->hw_features |= NETIF_F_SG; + net->hw_features |= NETIF_F_RXHASH; if ((hwcaps.csum.ip4_txcsum & NDIS_TXCSUM_ALL_TCP4) == NDIS_TXCSUM_ALL_TCP4) { /* Can checksum TCP */ -- cgit v1.2.3-59-g8ed1b From ab44081fef9b5d31ea5641494c9a379b0ebe1839 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Sat, 23 Nov 2019 09:45:42 -0800 Subject: sfc: fix build without CONFIG_RFS_ACCEL The rfs members of struct efx_channel are under CONFIG_RFS_ACCEL. Ethtool stats which access those need to be as well. Reported-by: kbuild test robot Fixes: ca70bd423f10 ("sfc: add statistics for ARFS") Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/sfc/ethtool.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 6a9347cd67f3..b31032da4bcb 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -90,9 +90,11 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect), +#ifdef CONFIG_RFS_ACCEL EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(rfs_filter_count), EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_succeeded), EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_failed), +#endif }; #define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc) -- cgit v1.2.3-59-g8ed1b From fb4cd81e4c03efa54b82e81e2a4afc092c061384 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:38 -0500 Subject: bnxt_en: Add chip IDs for 57452 and 57454 chips. Fix BNXT_CHIP_NUM_5645X() to include 57452 and 56454 chip IDs, so that these chips will be properly classified as P4 chips to take advantage of the P4 fixes and features. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 37549cac3de6..e07311e36792 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1443,6 +1443,8 @@ struct bnxt { #define CHIP_NUM_57414L 0x16db #define CHIP_NUM_5745X 0xd730 +#define CHIP_NUM_57452 0xc452 +#define CHIP_NUM_57454 0xc454 #define CHIP_NUM_57508 0x1750 #define CHIP_NUM_57504 0x1751 @@ -1475,7 +1477,10 @@ struct bnxt { ((chip_num) == CHIP_NUM_58700) #define BNXT_CHIP_NUM_5745X(chip_num) \ - ((chip_num) == CHIP_NUM_5745X) + ((chip_num) == CHIP_NUM_5745X || \ + (chip_num) == CHIP_NUM_57452 || \ + (chip_num) == CHIP_NUM_57454) + #define BNXT_CHIP_NUM_57X0X(chip_num) \ (BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num)) -- cgit v1.2.3-59-g8ed1b From ef02af8c8ece3d6fb01fe267c1c7622399bc34f6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:39 -0500 Subject: bnxt_en: Disable/enable Bus master during suspend/resume. Disable Bus master during suspend to prevent DMAs after the device goes into D3hot state. The new 57500 devices may continue to DMA from context memory after the system goes into D3hot state. This may cause some PCIe errors on some system. Re-enable it during resume. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 35bc579d594a..14b610451331 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -11921,6 +11921,7 @@ static int bnxt_suspend(struct device *device) rc = bnxt_close(dev); } bnxt_hwrm_func_drv_unrgtr(bp); + pci_disable_device(bp->pdev); rtnl_unlock(); return rc; } @@ -11932,6 +11933,13 @@ static int bnxt_resume(struct device *device) int rc = 0; rtnl_lock(); + rc = pci_enable_device(bp->pdev); + if (rc) { + netdev_err(dev, "Cannot re-enable PCI device during resume, err = %d\n", + rc); + goto resume_exit; + } + pci_set_master(bp->pdev); if (bnxt_hwrm_ver_get(bp) || bnxt_hwrm_func_drv_rgtr(bp)) { rc = -ENODEV; goto resume_exit; -- cgit v1.2.3-59-g8ed1b From bdb3860236b3ec8bb0f55ddef6d62666a8b3b23e Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 23 Nov 2019 22:30:40 -0500 Subject: bnxt_en: Do driver unregister cleanup in bnxt_init_one() failure path. In the bnxt_init_one() failure path, if the driver has already called firmware to register the driver, it is not undoing the driver registration. Add this missing step to unregister for correctness, so that the firmware knows that the driver has unloaded. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 ++++++++++--- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 14b610451331..464e8bd14365 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4483,9 +4483,12 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp) mutex_lock(&bp->hwrm_cmd_lock); rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); - if (!rc && (resp->flags & - cpu_to_le32(FUNC_DRV_RGTR_RESP_FLAGS_IF_CHANGE_SUPPORTED))) - bp->fw_cap |= BNXT_FW_CAP_IF_CHANGE; + if (!rc) { + set_bit(BNXT_STATE_DRV_REGISTERED, &bp->state); + if (resp->flags & + cpu_to_le32(FUNC_DRV_RGTR_RESP_FLAGS_IF_CHANGE_SUPPORTED)) + bp->fw_cap |= BNXT_FW_CAP_IF_CHANGE; + } mutex_unlock(&bp->hwrm_cmd_lock); return rc; } @@ -4494,6 +4497,9 @@ static int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp) { struct hwrm_func_drv_unrgtr_input req = {0}; + if (!test_and_clear_bit(BNXT_STATE_DRV_REGISTERED, &bp->state)) + return 0; + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_DRV_UNRGTR, -1, -1); return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } @@ -11864,6 +11870,7 @@ init_err_cleanup_tc: bnxt_clear_int_mode(bp); init_err_pci_clean: + bnxt_hwrm_func_drv_unrgtr(bp); bnxt_free_hwrm_short_cmd_req(bp); bnxt_free_hwrm_resources(bp); bnxt_free_ctx_mem(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index e07311e36792..a38664eef614 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1646,6 +1646,7 @@ struct bnxt { #define BNXT_STATE_IN_FW_RESET 4 #define BNXT_STATE_ABORT_ERR 5 #define BNXT_STATE_FW_FATAL_COND 6 +#define BNXT_STATE_DRV_REGISTERED 7 struct bnxt_irq *irq_tbl; int total_irqs; -- cgit v1.2.3-59-g8ed1b From 2e882468fce263afef4a77ea4fe40808baaddae7 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 23 Nov 2019 22:30:41 -0500 Subject: bnxt_en: Combine 2 functions calling the same HWRM_DRV_RGTR fw command. Everytime driver registers with firmware, driver is required to register for async event notifications as well. These 2 calls are done using the same firmware command and can be combined. We are also missing the 2nd step to register for async events in the suspend/resume path and this will fix it. Prior to this, we were getting only default notifications. ULP can register for additional async events for the RDMA driver, so we add a parameter to the new function to only do step 2 when it is called from ULP. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 74 +++++++++++---------------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +- drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 4 +- 3 files changed, 35 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 464e8bd14365..f627741ef585 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4394,53 +4394,22 @@ int hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len, return rc; } -int bnxt_hwrm_func_rgtr_async_events(struct bnxt *bp, unsigned long *bmap, - int bmap_size) +int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, + bool async_only) { + struct hwrm_func_drv_rgtr_output *resp = bp->hwrm_cmd_resp_addr; struct hwrm_func_drv_rgtr_input req = {0}; DECLARE_BITMAP(async_events_bmap, 256); u32 *events = (u32 *)async_events_bmap; - int i; - - bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_DRV_RGTR, -1, -1); - - req.enables = - cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD); - - memset(async_events_bmap, 0, sizeof(async_events_bmap)); - for (i = 0; i < ARRAY_SIZE(bnxt_async_events_arr); i++) { - u16 event_id = bnxt_async_events_arr[i]; - - if (event_id == ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY && - !(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)) - continue; - __set_bit(bnxt_async_events_arr[i], async_events_bmap); - } - if (bmap && bmap_size) { - for (i = 0; i < bmap_size; i++) { - if (test_bit(i, bmap)) - __set_bit(i, async_events_bmap); - } - } - - for (i = 0; i < 8; i++) - req.async_event_fwd[i] |= cpu_to_le32(events[i]); - - return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); -} - -static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp) -{ - struct hwrm_func_drv_rgtr_output *resp = bp->hwrm_cmd_resp_addr; - struct hwrm_func_drv_rgtr_input req = {0}; u32 flags; - int rc; + int rc, i; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_DRV_RGTR, -1, -1); req.enables = cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_OS_TYPE | - FUNC_DRV_RGTR_REQ_ENABLES_VER); + FUNC_DRV_RGTR_REQ_ENABLES_VER | + FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD); req.os_type = cpu_to_le16(FUNC_DRV_RGTR_REQ_OS_TYPE_LINUX); flags = FUNC_DRV_RGTR_REQ_FLAGS_16BIT_VER_MODE | @@ -4481,6 +4450,28 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp) req.flags |= cpu_to_le32( FUNC_DRV_RGTR_REQ_FLAGS_FLOW_HANDLE_64BIT_MODE); + memset(async_events_bmap, 0, sizeof(async_events_bmap)); + for (i = 0; i < ARRAY_SIZE(bnxt_async_events_arr); i++) { + u16 event_id = bnxt_async_events_arr[i]; + + if (event_id == ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY && + !(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)) + continue; + __set_bit(bnxt_async_events_arr[i], async_events_bmap); + } + if (bmap && bmap_size) { + for (i = 0; i < bmap_size; i++) { + if (test_bit(i, bmap)) + __set_bit(i, async_events_bmap); + } + } + for (i = 0; i < 8; i++) + req.async_event_fwd[i] |= cpu_to_le32(events[i]); + + if (async_only) + req.enables = + cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD); + mutex_lock(&bp->hwrm_cmd_lock); rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); if (!rc) { @@ -10490,11 +10481,7 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp) netdev_warn(bp->dev, "hwrm query error recovery failure rc: %d\n", rc); - rc = bnxt_hwrm_func_drv_rgtr(bp); - if (rc) - return -ENODEV; - - rc = bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0); + rc = bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, false); if (rc) return -ENODEV; @@ -11947,7 +11934,8 @@ static int bnxt_resume(struct device *device) goto resume_exit; } pci_set_master(bp->pdev); - if (bnxt_hwrm_ver_get(bp) || bnxt_hwrm_func_drv_rgtr(bp)) { + if (bnxt_hwrm_ver_get(bp) || + bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, false)) { rc = -ENODEV; goto resume_exit; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a38664eef614..35c483b9db67 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1996,8 +1996,8 @@ int _hwrm_send_message(struct bnxt *, void *, u32, int); int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 len, int timeout); int hwrm_send_message(struct bnxt *, void *, u32, int); int hwrm_send_message_silent(struct bnxt *, void *, u32, int); -int bnxt_hwrm_func_rgtr_async_events(struct bnxt *bp, unsigned long *bmap, - int bmap_size); +int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, + int bmap_size, bool async_only); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); int bnxt_nq_rings_in_use(struct bnxt *bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c index 077fd101be60..c601ff7b8f61 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c @@ -81,7 +81,7 @@ static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id) edev->en_ops->bnxt_free_msix(edev, ulp_id); if (ulp->max_async_event_id) - bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0); + bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true); RCU_INIT_POINTER(ulp->ulp_ops, NULL); synchronize_rcu(); @@ -441,7 +441,7 @@ static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id, /* Make sure bnxt_ulp_async_events() sees this order */ smp_wmb(); ulp->max_async_event_id = max_id; - bnxt_hwrm_func_rgtr_async_events(bp, events_bmap, max_id + 1); + bnxt_hwrm_func_drv_rgtr(bp, events_bmap, max_id + 1, true); return 0; } -- cgit v1.2.3-59-g8ed1b From f92335d830059f3f9db950f0af49405d287924d5 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 23 Nov 2019 22:30:42 -0500 Subject: bnxt_en: Send FUNC_RESOURCE_QCAPS command in bnxt_resume() After driver unregister, firmware is erasing the information that driver supports new resource management. Send FUNC_RESOURCE_QCAPS command to inform the firmware that driver supports new resource management while resuming from hibernation. Otherwise, we fallback to the older resource allocation scheme. Also, move driver register after sending FUNC_RESOURCE_QCAPS command to be consistent with the normal initialization sequence. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index f627741ef585..69d7ab1d01db 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -11934,8 +11934,7 @@ static int bnxt_resume(struct device *device) goto resume_exit; } pci_set_master(bp->pdev); - if (bnxt_hwrm_ver_get(bp) || - bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, false)) { + if (bnxt_hwrm_ver_get(bp)) { rc = -ENODEV; goto resume_exit; } @@ -11944,6 +11943,15 @@ static int bnxt_resume(struct device *device) rc = -EBUSY; goto resume_exit; } + + if (BNXT_NEW_RM(bp)) + bnxt_hwrm_func_resc_qcaps(bp, false); + + if (bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, false)) { + rc = -ENODEV; + goto resume_exit; + } + bnxt_get_wol_settings(bp); if (netif_running(dev)) { rc = bnxt_open(dev); -- cgit v1.2.3-59-g8ed1b From f9b69d7f62796b33657c98e0d3ca3be763f70fa4 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 23 Nov 2019 22:30:43 -0500 Subject: bnxt_en: Fix suspend/resume path on 57500 chips Driver calls HWRM_FUNC_RESET firmware call while resuming the device which clears the context memory backing store. Because of which allocating firmware resources would eventually fail. Fix it by freeing all context memory during suspend and reallocate the memory during resume. Call bnxt_hwrm_queue_qportcfg() in resume path. This firmware call is needed on the 57500 chips so that firmware will set up the proper queue mapping in relation to the context memory. Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 69d7ab1d01db..6a12ab5b8830 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -11916,6 +11916,9 @@ static int bnxt_suspend(struct device *device) } bnxt_hwrm_func_drv_unrgtr(bp); pci_disable_device(bp->pdev); + bnxt_free_ctx_mem(bp); + kfree(bp->ctx); + bp->ctx = NULL; rtnl_unlock(); return rc; } @@ -11944,6 +11947,17 @@ static int bnxt_resume(struct device *device) goto resume_exit; } + if (bnxt_hwrm_queue_qportcfg(bp)) { + rc = -ENODEV; + goto resume_exit; + } + + if (bp->hwrm_spec_code >= 0x10803) { + if (bnxt_alloc_ctx_mem(bp)) { + rc = -ENODEV; + goto resume_exit; + } + } if (BNXT_NEW_RM(bp)) bnxt_hwrm_func_resc_qcaps(bp, false); -- cgit v1.2.3-59-g8ed1b From 3be8136ce14ea12c7b40f7ad20a5ff8aec339289 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:44 -0500 Subject: bnxt_en: Initialize context memory to the value specified by firmware. Some chips that need host context memory as a backing store requires the memory to be initialized to a non-zero value. Query the value from firmware and initialize the context memory accordingly. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 +++++++++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 ++ 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 6a12ab5b8830..0e384c578aa0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2688,6 +2688,9 @@ static int bnxt_alloc_ring(struct bnxt *bp, struct bnxt_ring_mem_info *rmem) if (!rmem->pg_arr[i]) return -ENOMEM; + if (rmem->init_val) + memset(rmem->pg_arr[i], rmem->init_val, + rmem->page_size); if (rmem->nr_pages > 1 || rmem->depth > 0) { if (i == rmem->nr_pages - 2 && (rmem->flags & BNXT_RMEM_RING_PTE_FLAG)) @@ -6487,6 +6490,7 @@ static int bnxt_hwrm_func_backing_store_qcaps(struct bnxt *bp) le16_to_cpu(resp->mrav_num_entries_units); ctx->tim_entry_size = le16_to_cpu(resp->tim_entry_size); ctx->tim_max_entries = le32_to_cpu(resp->tim_max_entries); + ctx->ctx_kind_initializer = resp->ctx_kind_initializer; } else { rc = 0; } @@ -6641,7 +6645,7 @@ static int bnxt_alloc_ctx_mem_blk(struct bnxt *bp, static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, struct bnxt_ctx_pg_info *ctx_pg, u32 mem_size, - u8 depth) + u8 depth, bool use_init_val) { struct bnxt_ring_mem_info *rmem = &ctx_pg->ring_mem; int rc; @@ -6679,6 +6683,8 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, rmem->pg_tbl_map = ctx_pg->ctx_dma_arr[i]; rmem->depth = 1; rmem->nr_pages = MAX_CTX_PAGES; + if (use_init_val) + rmem->init_val = bp->ctx->ctx_kind_initializer; if (i == (nr_tbls - 1)) { int rem = ctx_pg->nr_pages % MAX_CTX_PAGES; @@ -6693,6 +6699,8 @@ static int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp, rmem->nr_pages = DIV_ROUND_UP(mem_size, BNXT_PAGE_SIZE); if (rmem->nr_pages > 1 || depth) rmem->depth = 1; + if (use_init_val) + rmem->init_val = bp->ctx->ctx_kind_initializer; rc = bnxt_alloc_ctx_mem_blk(bp, ctx_pg); } return rc; @@ -6783,21 +6791,21 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ctx_pg->entries = ctx->qp_min_qp1_entries + ctx->qp_max_l2_entries + extra_qps; mem_size = ctx->qp_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, true); if (rc) return rc; ctx_pg = &ctx->srq_mem; ctx_pg->entries = ctx->srq_max_l2_entries + extra_srqs; mem_size = ctx->srq_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, true); if (rc) return rc; ctx_pg = &ctx->cq_mem; ctx_pg->entries = ctx->cq_max_l2_entries + extra_qps * 2; mem_size = ctx->cq_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, pg_lvl, true); if (rc) return rc; @@ -6805,14 +6813,14 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ctx_pg->entries = ctx->vnic_max_vnic_entries + ctx->vnic_max_ring_table_entries; mem_size = ctx->vnic_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, true); if (rc) return rc; ctx_pg = &ctx->stat_mem; ctx_pg->entries = ctx->stat_max_entries; mem_size = ctx->stat_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, true); if (rc) return rc; @@ -6828,7 +6836,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) num_ah = 1024 * 128; ctx_pg->entries = num_mr + num_ah; mem_size = ctx->mrav_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 2, true); if (rc) return rc; ena = FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV; @@ -6840,7 +6848,7 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp) ctx_pg = &ctx->tim_mem; ctx_pg->entries = ctx->qp_mem.entries; mem_size = ctx->tim_entry_size * ctx_pg->entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, false); if (rc) return rc; ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TIM; @@ -6854,7 +6862,7 @@ skip_rdma: ctx_pg = ctx->tqm_mem[i]; ctx_pg->entries = entries; mem_size = ctx->tqm_entry_size * entries; - rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1); + rc = bnxt_alloc_ctx_pg_tbls(bp, ctx_pg, mem_size, 1, false); if (rc) return rc; ena |= FUNC_BACKING_STORE_CFG_REQ_ENABLES_TQM_SP << i; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 35c483b9db67..dbdd09750d91 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -721,6 +721,7 @@ struct bnxt_ring_mem_info { #define BNXT_RMEM_USE_FULL_PAGE_FLAG 4 u16 depth; + u8 init_val; void **pg_arr; dma_addr_t *dma_arr; @@ -1352,6 +1353,7 @@ struct bnxt_ctx_mem_info { u32 tim_max_entries; u16 mrav_num_entries_units; u8 tqm_entries_multiple; + u8 ctx_kind_initializer; u32 flags; #define BNXT_CTX_FLAG_INITED 0x01 -- cgit v1.2.3-59-g8ed1b From 1acefc9aedb3179fc9add0a21fa62c0aca08efc4 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:45 -0500 Subject: bnxt_en: Assign more RSS context resources to the VFs. The driver currently only assignes 1 RSS context to each VF. This works for the Linux VF driver. But other drivers, such as DPDK, can make use of additional RSS contexts. Modify the code to divide up and assign RSS contexts to VFs just like other resources. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index f6f3454d6059..2aba1e02a8f4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -515,6 +515,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) struct bnxt_pf_info *pf = &bp->pf; int i, rc = 0, min = 1; u16 vf_msix = 0; + u16 vf_rss; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESOURCE_CFG, -1, -1); @@ -533,9 +534,9 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) vf_tx_rings = hw_resc->max_tx_rings - bp->tx_nr_rings; vf_vnics = hw_resc->max_vnics - bp->nr_vnics; vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); + vf_rss = hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs; req.min_rsscos_ctx = cpu_to_le16(BNXT_VF_MIN_RSS_CTX); - req.max_rsscos_ctx = cpu_to_le16(BNXT_VF_MAX_RSS_CTX); if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL_STATIC) { min = 0; req.min_rsscos_ctx = cpu_to_le16(min); @@ -557,6 +558,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) vf_vnics /= num_vfs; vf_stat_ctx /= num_vfs; vf_ring_grps /= num_vfs; + vf_rss /= num_vfs; req.min_cmpl_rings = cpu_to_le16(vf_cp_rings); req.min_tx_rings = cpu_to_le16(vf_tx_rings); @@ -565,6 +567,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) req.min_vnics = cpu_to_le16(vf_vnics); req.min_stat_ctx = cpu_to_le16(vf_stat_ctx); req.min_hw_ring_grps = cpu_to_le16(vf_ring_grps); + req.min_rsscos_ctx = cpu_to_le16(vf_rss); } req.max_cmpl_rings = cpu_to_le16(vf_cp_rings); req.max_tx_rings = cpu_to_le16(vf_tx_rings); @@ -573,6 +576,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) req.max_vnics = cpu_to_le16(vf_vnics); req.max_stat_ctx = cpu_to_le16(vf_stat_ctx); req.max_hw_ring_grps = cpu_to_le16(vf_ring_grps); + req.max_rsscos_ctx = cpu_to_le16(vf_rss); if (bp->flags & BNXT_FLAG_CHIP_P5) req.max_msix = cpu_to_le16(vf_msix / num_vfs); @@ -598,7 +602,7 @@ static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs, bool reset) hw_resc->max_hw_ring_grps -= le16_to_cpu(req.min_hw_ring_grps) * n; hw_resc->max_cp_rings -= le16_to_cpu(req.min_cmpl_rings) * n; - hw_resc->max_rsscos_ctxs -= pf->active_vfs; + hw_resc->max_rsscos_ctxs -= le16_to_cpu(req.min_rsscos_ctx) * n; hw_resc->max_stat_ctxs -= le16_to_cpu(req.min_stat_ctx) * n; hw_resc->max_vnics -= le16_to_cpu(req.min_vnics) * n; if (bp->flags & BNXT_FLAG_CHIP_P5) -- cgit v1.2.3-59-g8ed1b From 8a60efd1decbaf9ef71d4296b75ff262e653bd34 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:46 -0500 Subject: bnxt_en: Skip disabling autoneg before PHY loopback when appropriate. New firmware allows PHY loopback to be set without disabling autoneg first. Check this capability and skip disabling autoneg when it is supported by firmware. Using this scheme, loopback will always work even if the PHY only supports autoneg. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 7 ++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 ++- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0e384c578aa0..9d02232c3113 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8419,7 +8419,8 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) bp->flags &= ~BNXT_FLAG_EEE_CAP; if (bp->test_info) - bp->test_info->flags &= ~BNXT_TEST_FL_EXT_LPBK; + bp->test_info->flags &= ~(BNXT_TEST_FL_EXT_LPBK | + BNXT_TEST_FL_AN_PHY_LPBK); if (bp->hwrm_spec_code < 0x10201) return 0; @@ -8445,6 +8446,10 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) if (bp->test_info) bp->test_info->flags |= BNXT_TEST_FL_EXT_LPBK; } + if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_AUTONEG_LPBK_SUPPORTED) { + if (bp->test_info) + bp->test_info->flags |= BNXT_TEST_FL_AN_PHY_LPBK; + } if (resp->supported_speeds_auto_mode) link_info->support_auto_speeds = le16_to_cpu(resp->supported_speeds_auto_mode); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index dbdd09750d91..94c8a9276d3a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1226,7 +1226,8 @@ struct bnxt_led_info { struct bnxt_test_info { u8 offline_mask; u8 flags; -#define BNXT_TEST_FL_EXT_LPBK 0x1 +#define BNXT_TEST_FL_EXT_LPBK 0x1 +#define BNXT_TEST_FL_AN_PHY_LPBK 0x2 u16 timeout; char string[BNXT_MAX_TEST][ETH_GSTRING_LEN]; }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 0641020b56d5..62ef84741a55 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2698,7 +2698,8 @@ static int bnxt_disable_an_for_lpbk(struct bnxt *bp, u16 fw_speed; int rc; - if (!link_info->autoneg) + if (!link_info->autoneg || + (bp->test_info->flags & BNXT_TEST_FL_AN_PHY_LPBK)) return 0; rc = bnxt_query_force_speeds(bp, &fw_advertising); -- cgit v1.2.3-59-g8ed1b From 8119e49b68fa1ec778f9ec8be05b5492046100b2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:47 -0500 Subject: bnxt_en: Refactor the initialization of the ethtool link settings. Refactor this logic in bnxt_probe_phy() into a separate function bnxt_init_ethtool_link_settings(). It used to be that the settable link settings will never be changed without going through ethtool. So we only needed to do this once in bnxt_probe_phy(). Now, another function sharing the port may change it and we may need to re-initialize the ethtool settings again in run-time. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 46 +++++++++++++++++-------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9d02232c3113..1b86ba8d0be3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10249,6 +10249,31 @@ static void bnxt_chk_missed_irq(struct bnxt *bp) static void bnxt_cfg_ntp_filters(struct bnxt *); +static void bnxt_init_ethtool_link_settings(struct bnxt *bp) +{ + struct bnxt_link_info *link_info = &bp->link_info; + + if (BNXT_AUTO_MODE(link_info->auto_mode)) { + link_info->autoneg = BNXT_AUTONEG_SPEED; + if (bp->hwrm_spec_code >= 0x10201) { + if (link_info->auto_pause_setting & + PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE) + link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; + } else { + link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; + } + link_info->advertising = link_info->auto_link_speeds; + } else { + link_info->req_link_speed = link_info->force_link_speed; + link_info->req_duplex = link_info->duplex_setting; + } + if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) + link_info->req_flow_ctrl = + link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH; + else + link_info->req_flow_ctrl = link_info->force_pause_setting; +} + static void bnxt_sp_task(struct work_struct *work) { struct bnxt *bp = container_of(work, struct bnxt, sp_task); @@ -11411,26 +11436,7 @@ static int bnxt_probe_phy(struct bnxt *bp, bool fw_dflt) if (!fw_dflt) return 0; - /*initialize the ethool setting copy with NVM settings */ - if (BNXT_AUTO_MODE(link_info->auto_mode)) { - link_info->autoneg = BNXT_AUTONEG_SPEED; - if (bp->hwrm_spec_code >= 0x10201) { - if (link_info->auto_pause_setting & - PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE) - link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; - } else { - link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; - } - link_info->advertising = link_info->auto_link_speeds; - } else { - link_info->req_link_speed = link_info->force_link_speed; - link_info->req_duplex = link_info->duplex_setting; - } - if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) - link_info->req_flow_ctrl = - link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH; - else - link_info->req_flow_ctrl = link_info->force_pause_setting; + bnxt_init_ethtool_link_settings(bp); return 0; } -- cgit v1.2.3-59-g8ed1b From b1613e78e98d065fd3356d0b93df665b0740f652 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:48 -0500 Subject: bnxt_en: Add async. event logic for PHY configuration changes. If the link settings have been changed by another function sharing the port, firmware will send us an async. message. In response, we will call the new bnxt_init_ethtool_link_settings() function to update the current settings. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1b86ba8d0be3..4b0303ac307f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -250,10 +250,12 @@ static const u16 bnxt_vf_req_snif[] = { static const u16 bnxt_async_events_arr[] = { ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE, + ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD, ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED, ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE, ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE, + ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE, ASYNC_EVENT_CMPL_EVENT_ID_RESET_NOTIFY, ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY, }; @@ -1968,6 +1970,10 @@ static int bnxt_async_event_process(struct bnxt *bp, set_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, &bp->sp_event); } /* fall through */ + case ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CHANGE: + case ASYNC_EVENT_CMPL_EVENT_ID_PORT_PHY_CFG_CHANGE: + set_bit(BNXT_LINK_CFG_CHANGE_SP_EVENT, &bp->sp_event); + /* fall through */ case ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: set_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event); break; @@ -10324,6 +10330,10 @@ static void bnxt_sp_task(struct work_struct *work) &bp->sp_event)) bnxt_hwrm_phy_qcaps(bp); + if (test_and_clear_bit(BNXT_LINK_CFG_CHANGE_SP_EVENT, + &bp->sp_event)) + bnxt_init_ethtool_link_settings(bp); + rc = bnxt_update_link(bp, true); mutex_unlock(&bp->link_lock); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 94c8a9276d3a..cab1703dfcf7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1763,6 +1763,7 @@ struct bnxt { #define BNXT_RING_COAL_NOW_SP_EVENT 17 #define BNXT_FW_RESET_NOTIFY_SP_EVENT 18 #define BNXT_FW_EXCEPTION_SP_EVENT 19 +#define BNXT_LINK_CFG_CHANGE_SP_EVENT 21 struct delayed_work fw_reset_task; int fw_reset_state; -- cgit v1.2.3-59-g8ed1b From c7e457f42c02066e49a6e03028c889aefbb8999b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sat, 23 Nov 2019 22:30:49 -0500 Subject: bnxt_en: Allow PHY settings on multi-function or NPAR PFs if allowed by FW. Currently, the driver does not allow PHY settings on a multi-function or NPAR NIC whose port is shared by more than one function. Newer firmware now allows PHY settings on some of these NICs. Check for this new firmware setting and allow the user to set the PHY settings accordingly. Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 +++ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 8 ++++---- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4b0303ac307f..85983f0e3134 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8456,6 +8456,10 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) if (bp->test_info) bp->test_info->flags |= BNXT_TEST_FL_AN_PHY_LPBK; } + if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_SHARED_PHY_CFG_SUPPORTED) { + if (BNXT_PF(bp)) + bp->fw_cap |= BNXT_FW_CAP_SHARED_PORT_CFG; + } if (resp->supported_speeds_auto_mode) link_info->support_auto_speeds = le16_to_cpu(resp->supported_speeds_auto_mode); @@ -8570,7 +8574,7 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) } mutex_unlock(&bp->hwrm_cmd_lock); - if (!BNXT_SINGLE_PF(bp)) + if (!BNXT_PHY_CFG_ABLE(bp)) return 0; diff = link_info->support_auto_speeds ^ link_info->advertising; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index cab1703dfcf7..505af5cfb1bd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1548,6 +1548,8 @@ struct bnxt { #define BNXT_NPAR(bp) ((bp)->port_partition_type) #define BNXT_MH(bp) ((bp)->flags & BNXT_FLAG_MULTI_HOST) #define BNXT_SINGLE_PF(bp) (BNXT_PF(bp) && !BNXT_NPAR(bp) && !BNXT_MH(bp)) +#define BNXT_PHY_CFG_ABLE(bp) (BNXT_SINGLE_PF(bp) || \ + ((bp)->fw_cap & BNXT_FW_CAP_SHARED_PORT_CFG)) #define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0) #define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE) #define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_TYPE_NITRO_A0(bp) && \ @@ -1682,6 +1684,7 @@ struct bnxt { #define BNXT_FW_CAP_EXT_STATS_SUPPORTED 0x00040000 #define BNXT_FW_CAP_ERR_RECOVER_RELOAD 0x00100000 #define BNXT_FW_CAP_HOT_RESET 0x00200000 + #define BNXT_FW_CAP_SHARED_PORT_CFG 0x00400000 #define BNXT_NEW_RM(bp) ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM) u32 hwrm_spec_code; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 62ef84741a55..e455aaa50a64 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1590,7 +1590,7 @@ static int bnxt_set_link_ksettings(struct net_device *dev, u32 speed; int rc = 0; - if (!BNXT_SINGLE_PF(bp)) + if (!BNXT_PHY_CFG_ABLE(bp)) return -EOPNOTSUPP; mutex_lock(&bp->link_lock); @@ -1662,7 +1662,7 @@ static int bnxt_set_pauseparam(struct net_device *dev, struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; - if (!BNXT_SINGLE_PF(bp)) + if (!BNXT_PHY_CFG_ABLE(bp)) return -EOPNOTSUPP; if (epause->autoneg) { @@ -2399,7 +2399,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); int rc = 0; - if (!BNXT_SINGLE_PF(bp)) + if (!BNXT_PHY_CFG_ABLE(bp)) return -EOPNOTSUPP; if (!(bp->flags & BNXT_FLAG_EEE_CAP)) @@ -2586,7 +2586,7 @@ static int bnxt_nway_reset(struct net_device *dev) struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; - if (!BNXT_SINGLE_PF(bp)) + if (!BNXT_PHY_CFG_ABLE(bp)) return -EOPNOTSUPP; if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) -- cgit v1.2.3-59-g8ed1b From d168f328fecc9f401b54db18ff4ddd4bca7b161d Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Sat, 23 Nov 2019 22:30:50 -0500 Subject: bnxt_en: Add support for flashing the device via devlink Use the same bnxt_flash_package_from_file() function to support devlink flash operation. Cc: Jiri Pirko Signed-off-by: Vasundhara Volam Signed-off-by: Michael Chan Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 20 ++++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 4 ++-- drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 707827176231..acb2dd64c023 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -14,6 +14,25 @@ #include "bnxt.h" #include "bnxt_vfr.h" #include "bnxt_devlink.h" +#include "bnxt_ethtool.h" + +static int +bnxt_dl_flash_update(struct devlink *dl, const char *filename, + const char *region, struct netlink_ext_ack *extack) +{ + struct bnxt *bp = bnxt_get_bp_from_dl(dl); + + if (region) + return -EOPNOTSUPP; + + if (!BNXT_PF(bp)) { + NL_SET_ERR_MSG_MOD(extack, + "flash update not supported from a VF"); + return -EPERM; + } + + return bnxt_flash_package_from_file(bp->dev, filename, 0); +} static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, @@ -225,6 +244,7 @@ static const struct devlink_ops bnxt_dl_ops = { .eswitch_mode_set = bnxt_dl_eswitch_mode_set, .eswitch_mode_get = bnxt_dl_eswitch_mode_get, #endif /* CONFIG_BNXT_SRIOV */ + .flash_update = bnxt_dl_flash_update, }; enum bnxt_dl_param_id { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index e455aaa50a64..2ccf79cdcb1e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -2000,8 +2000,8 @@ static int bnxt_flash_firmware_from_file(struct net_device *dev, return rc; } -static int bnxt_flash_package_from_file(struct net_device *dev, - char *filename, u32 install_type) +int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, + u32 install_type) { struct bnxt *bp = netdev_priv(dev); struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index 01de7e79d14f..4428d0abcbc1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -81,6 +81,8 @@ extern const struct ethtool_ops bnxt_ethtool_ops; u32 _bnxt_fw_to_ethtool_adv_spds(u16, u8); u32 bnxt_fw_to_ethtool_speed(u16); u16 bnxt_get_fw_auto_link_speeds(u32); +int bnxt_flash_package_from_file(struct net_device *dev, const char *filename, + u32 install_type); void bnxt_ethtool_init(struct bnxt *bp); void bnxt_ethtool_free(struct bnxt *bp); -- cgit v1.2.3-59-g8ed1b From c5731cc5ebcbfdb0b34c7ce29d488c52d8af957b Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Sun, 24 Nov 2019 09:48:02 +0200 Subject: mlxsw: spectrum_router: After underlay moves, demote conflicting tunnels When a GRE tunnel is bound to an underlay netdevice and that netdevice is moved to a different VRF, that could cause two tunnels to have the same underlay local address in the same VRF. Linux in this situation dispatches the traffic according to the tunnel key (or lack thereof), but that cannot be offloaded to Spectrum devices. Detect this situation and unoffload the two impacted tunnels when it happens. Signed-off-by: Petr Machata Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- .../net/ethernet/mellanox/mlxsw/spectrum_router.c | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 86e25824fcd8..4c4d99ab15a0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1614,8 +1614,25 @@ static int mlxsw_sp_netdevice_ipip_ul_vrf_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_ipip_entry *ipip_entry, struct net_device *ul_dev, + bool *demote_this, struct netlink_ext_ack *extack) { + u32 ul_tb_id = l3mdev_fib_table(ul_dev) ? : RT_TABLE_MAIN; + enum mlxsw_sp_l3proto ul_proto; + union mlxsw_sp_l3addr saddr; + + /* Moving underlay to a different VRF might cause local address + * conflict, and the conflicting tunnels need to be demoted. + */ + ul_proto = mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto; + saddr = mlxsw_sp_ipip_netdev_saddr(ul_proto, ipip_entry->ol_dev); + if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, ul_proto, + saddr, ul_tb_id, + ipip_entry)) { + *demote_this = true; + return 0; + } + return __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, true, true, false, extack); } @@ -1766,6 +1783,7 @@ static int __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_ipip_entry *ipip_entry, struct net_device *ul_dev, + bool *demote_this, unsigned long event, struct netdev_notifier_info *info) { @@ -1780,6 +1798,7 @@ __mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, return mlxsw_sp_netdevice_ipip_ul_vrf_event(mlxsw_sp, ipip_entry, ul_dev, + demote_this, extack); break; @@ -1806,13 +1825,31 @@ mlxsw_sp_netdevice_ipip_ul_event(struct mlxsw_sp *mlxsw_sp, while ((ipip_entry = mlxsw_sp_ipip_entry_find_by_ul_dev(mlxsw_sp, ul_dev, ipip_entry))) { + struct mlxsw_sp_ipip_entry *prev; + bool demote_this = false; + err = __mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, ipip_entry, - ul_dev, event, info); + ul_dev, &demote_this, + event, info); if (err) { mlxsw_sp_ipip_demote_tunnel_by_ul_netdev(mlxsw_sp, ul_dev); return err; } + + if (demote_this) { + if (list_is_first(&ipip_entry->ipip_list_node, + &mlxsw_sp->router->ipip_list)) + prev = NULL; + else + /* This can't be cached from previous iteration, + * because that entry could be gone now. + */ + prev = list_prev_entry(ipip_entry, + ipip_list_node); + mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); + ipip_entry = prev; + } } return 0; -- cgit v1.2.3-59-g8ed1b From ed43cff065d7ca2ffa60a7a1ea62be4a574529f9 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Sun, 24 Nov 2019 09:48:03 +0200 Subject: mlxsw: spectrum_router: Fix use of uninitialized adjacency index When mlxsw_sp_adj_discard_write() is called for the first time, the value stored in 'mlxsw_sp->router->adj_discard_index' is invalid, as indicated by 'mlxsw_sp->router->adj_discard_index_valid' being set to 'false'. In this case, we should not use the value initially stored in 'mlxsw_sp->router->adj_discard_index' (0) and instead use the value allocated later in the function. Fixes: 983db6198f0d ("mlxsw: spectrum_router: Allocate discard adjacency entry when needed") Signed-off-by: Amit Cohen Acked-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 4c4d99ab15a0..30bfe3880faf 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -4221,7 +4221,6 @@ mlxsw_sp_fib_entry_ralue_pack(char *ralue_pl, static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) { - u32 adj_discard_index = mlxsw_sp->router->adj_discard_index; enum mlxsw_reg_ratr_trap_action trap_action; char ratr_pl[MLXSW_REG_RATR_LEN]; int err; @@ -4236,8 +4235,8 @@ static int mlxsw_sp_adj_discard_write(struct mlxsw_sp *mlxsw_sp, u16 rif_index) trap_action = MLXSW_REG_RATR_TRAP_ACTION_DISCARD_ERRORS; mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, true, - MLXSW_REG_RATR_TYPE_ETHERNET, adj_discard_index, - rif_index); + MLXSW_REG_RATR_TYPE_ETHERNET, + mlxsw_sp->router->adj_discard_index, rif_index); mlxsw_reg_ratr_trap_action_set(ratr_pl, trap_action); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); if (err) -- cgit v1.2.3-59-g8ed1b From dc83ef22cdb483027f1bf0892e466433ec5299bf Mon Sep 17 00:00:00 2001 From: "Andreas K. Besslein" Date: Sat, 23 Nov 2019 22:04:47 +0100 Subject: ax88179_178a: add ethtool_op_get_ts_info() This enables the use of SW timestamping. ax88179_178a uses the usbnet transmit function usbnet_start_xmit() which implements software timestamping. ax88179_178a overrides ethtool_ops but missed to set .get_ts_info. This caused SOF_TIMESTAMPING_TX_SOFTWARE capability to be not available. Signed-off-by: Andreas K. Besslein Signed-off-by: Jakub Kicinski --- drivers/net/usb/ax88179_178a.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index c5a6e75c24e3..93044cf1417a 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -827,6 +827,7 @@ static const struct ethtool_ops ax88179_ethtool_ops = { .nway_reset = usbnet_nway_reset, .get_link_ksettings = ax88179_get_link_ksettings, .set_link_ksettings = ax88179_set_link_ksettings, + .get_ts_info = ethtool_op_get_ts_info, }; static void ax88179_set_multicast(struct net_device *net) -- cgit v1.2.3-59-g8ed1b From 32085f25d7b68404055f3525c780142fc72e543f Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 22 Nov 2019 22:44:51 +0100 Subject: mdio_bus: don't use managed reset-controller Geert Uytterhoeven reported that using devm_reset_controller_get leads to a WARNING when probing a reset-controlled PHY. This is because the device devm_reset_controller_get gets supplied is not actually the one being probed. Acquire an unmanaged reset-control as well as free the reset_control on unregister to fix this. Reported-by: Geert Uytterhoeven CC: Andrew Lunn Signed-off-by: David Bauer Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index dbacb0031877..229e480179ff 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -62,8 +62,8 @@ static int mdiobus_register_reset(struct mdio_device *mdiodev) struct reset_control *reset = NULL; if (mdiodev->dev.of_node) - reset = devm_reset_control_get_exclusive(&mdiodev->dev, - "phy"); + reset = of_reset_control_get_exclusive(mdiodev->dev.of_node, + "phy"); if (IS_ERR(reset)) { if (PTR_ERR(reset) == -ENOENT || PTR_ERR(reset) == -ENOTSUPP) reset = NULL; @@ -107,6 +107,8 @@ int mdiobus_unregister_device(struct mdio_device *mdiodev) if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev) return -EINVAL; + reset_control_put(mdiodev->reset_ctrl); + mdiodev->bus->mdio_map[mdiodev->addr] = NULL; return 0; -- cgit v1.2.3-59-g8ed1b From bec170e55982c2d3b8e1beccadf16e288fe6fb5a Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Sat, 23 Nov 2019 17:28:37 +0100 Subject: net: phy: add helpers phy_(un)lock_mdio_bus Add helpers to make locking/unlocking the MDIO bus easier. Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller --- drivers/net/phy/phy-core.c | 28 ++++++++++++++-------------- include/linux/phy.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c index 5458ed1b87a8..769a076514b0 100644 --- a/drivers/net/phy/phy-core.c +++ b/drivers/net/phy/phy-core.c @@ -419,9 +419,9 @@ int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_read_mmd(phydev, devad, regnum); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -480,9 +480,9 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_write_mmd(phydev, devad, regnum, val); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -536,9 +536,9 @@ int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_modify_changed(phydev, regnum, mask, set); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -580,9 +580,9 @@ int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set) { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_modify(phydev, regnum, mask, set); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -639,9 +639,9 @@ int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -687,9 +687,9 @@ int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, { int ret; - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); ret = __phy_modify_mmd(phydev, devad, regnum, mask, set); - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } @@ -721,7 +721,7 @@ static int __phy_write_page(struct phy_device *phydev, int page) */ int phy_save_page(struct phy_device *phydev) { - mutex_lock(&phydev->mdio.bus->mdio_lock); + phy_lock_mdio_bus(phydev); return __phy_read_page(phydev); } EXPORT_SYMBOL_GPL(phy_save_page); @@ -788,7 +788,7 @@ int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) ret = oldpage; } - mutex_unlock(&phydev->mdio.bus->mdio_lock); + phy_unlock_mdio_bus(phydev); return ret; } diff --git a/include/linux/phy.h b/include/linux/phy.h index f5cdfb206097..5032d453ac66 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1076,6 +1076,16 @@ static inline const char *phydev_name(const struct phy_device *phydev) return dev_name(&phydev->mdio.dev); } +static inline void phy_lock_mdio_bus(struct phy_device *phydev) +{ + mutex_lock(&phydev->mdio.bus->mdio_lock); +} + +static inline void phy_unlock_mdio_bus(struct phy_device *phydev) +{ + mutex_unlock(&phydev->mdio.bus->mdio_lock); +} + void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) __printf(2, 3); void phy_attached_info(struct phy_device *phydev); -- cgit v1.2.3-59-g8ed1b From c431047c4efe7903fb1c5a23e0f3f8eb1efc89f9 Mon Sep 17 00:00:00 2001 From: Po Liu Date: Mon, 25 Nov 2019 05:56:56 +0000 Subject: enetc: add support Credit Based Shaper(CBS) for hardware offload The ENETC hardware support the Credit Based Shaper(CBS) which part of the IEEE-802.1Qav. The CBS driver was loaded by the sch_cbs interface when set in the QOS in the kernel. Here is an example command to set 20Mbits bandwidth in 1Gbits port for taffic class 7: tc qdisc add dev eth0 root handle 1: mqprio \ num_tc 8 map 0 1 2 3 4 5 6 7 hw 1 tc qdisc replace dev eth0 parent 1:8 cbs \ locredit -1470 hicredit 30 \ sendslope -980000 idleslope 20000 offload 1 Signed-off-by: Po Liu Reviewed-by: Claudiu Manoil Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/enetc/Kconfig | 4 +- drivers/net/ethernet/freescale/enetc/enetc.c | 2 + drivers/net/ethernet/freescale/enetc/enetc.h | 2 + drivers/net/ethernet/freescale/enetc/enetc_hw.h | 4 + drivers/net/ethernet/freescale/enetc/enetc_qos.c | 128 +++++++++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index 491659fe3e35..edad4ca46327 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -53,10 +53,10 @@ config FSL_ENETC_HW_TIMESTAMPING config FSL_ENETC_QOS bool "ENETC hardware Time-sensitive Network support" - depends on (FSL_ENETC || FSL_ENETC_VF) && NET_SCH_TAPRIO + depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS) help There are Time-Sensitive Network(TSN) capabilities(802.1Qbv/802.1Qci /802.1Qbu etc.) supported by ENETC. These TSN capabilities can be set enable/disable from user space via Qos commands(tc). In the kernel side, it can be loaded by Qos driver. Currently, it is only support - taprio(802.1Qbv). + taprio(802.1Qbv) and Credit Based Shaper(802.1Qbu). diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index 27f6fd1708f0..9db1b96ed9b9 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1496,6 +1496,8 @@ int enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type, return enetc_setup_tc_mqprio(ndev, type_data); case TC_SETUP_QDISC_TAPRIO: return enetc_setup_tc_taprio(ndev, type_data); + case TC_SETUP_QDISC_CBS: + return enetc_setup_tc_cbs(ndev, type_data); default: return -EOPNOTSUPP; } diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h index 89f23156f330..7ee0da6d0015 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.h +++ b/drivers/net/ethernet/freescale/enetc/enetc.h @@ -255,7 +255,9 @@ int enetc_send_cmd(struct enetc_si *si, struct enetc_cbd *cbd); #ifdef CONFIG_FSL_ENETC_QOS int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data); void enetc_sched_speed_set(struct net_device *ndev); +int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data); #else #define enetc_setup_tc_taprio(ndev, type_data) -EOPNOTSUPP #define enetc_sched_speed_set(ndev) (void)0 +#define enetc_setup_tc_cbs(ndev, type_data) -EOPNOTSUPP #endif diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 924ddb6d358a..51f543ef37a8 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -185,6 +185,8 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PSICFGR0_SIVC(bmp) (((bmp) & 0xff) << 24) /* VLAN_TYPE */ #define ENETC_PTCCBSR0(n) (0x1110 + (n) * 8) /* n = 0 to 7*/ +#define ENETC_CBSE BIT(31) +#define ENETC_CBS_BW_MASK GENMASK(6, 0) #define ENETC_PTCCBSR1(n) (0x1114 + (n) * 8) /* n = 0 to 7*/ #define ENETC_RSSHASH_KEY_SIZE 40 #define ENETC_PRSSK(n) (0x1410 + (n) * 4) /* n = [0..9] */ @@ -603,6 +605,8 @@ struct enetc_cbd { u8 status_flags; }; +#define ENETC_CLK 400000000ULL + /* port time gating control register */ #define ENETC_QBV_PTGCR_OFFSET 0x11a00 #define ENETC_QBV_TGE BIT(31) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c index 66a3da61ca16..2e99438cb1bf 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c @@ -4,6 +4,7 @@ #include "enetc.h" #include +#include static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) { @@ -170,3 +171,130 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) return err; } + +static u32 enetc_get_cbs_enable(struct enetc_hw *hw, u8 tc) +{ + return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBSE; +} + +static u8 enetc_get_cbs_bw(struct enetc_hw *hw, u8 tc) +{ + return enetc_port_rd(hw, ENETC_PTCCBSR0(tc)) & ENETC_CBS_BW_MASK; +} + +int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) +{ + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct tc_cbs_qopt_offload *cbs = type_data; + u32 port_transmit_rate = priv->speed; + u8 tc_nums = netdev_get_num_tc(ndev); + struct enetc_si *si = priv->si; + u32 hi_credit_bit, hi_credit_reg; + u32 max_interference_size; + u32 port_frame_max_size; + u32 tc_max_sized_frame; + u8 tc = cbs->queue; + u8 prio_top, prio_next; + int bw_sum = 0; + u8 bw; + + prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1); + prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2); + + /* Support highest prio and second prio tc in cbs mode */ + if (tc != prio_top && tc != prio_next) + return -EOPNOTSUPP; + + if (!cbs->enable) { + /* Make sure the other TC that are numerically + * lower than this TC have been disabled. + */ + if (tc == prio_top && + enetc_get_cbs_enable(&si->hw, prio_next)) { + dev_err(&ndev->dev, + "Disable TC%d before disable TC%d\n", + prio_next, tc); + return -EINVAL; + } + + enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0); + enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0); + + return 0; + } + + if (cbs->idleslope - cbs->sendslope != port_transmit_rate * 1000L || + cbs->idleslope < 0 || cbs->sendslope > 0) + return -EOPNOTSUPP; + + port_frame_max_size = ndev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN; + + bw = cbs->idleslope / (port_transmit_rate * 10UL); + + /* Make sure the other TC that are numerically + * higher than this TC have been enabled. + */ + if (tc == prio_next) { + if (!enetc_get_cbs_enable(&si->hw, prio_top)) { + dev_err(&ndev->dev, + "Enable TC%d first before enable TC%d\n", + prio_top, prio_next); + return -EINVAL; + } + bw_sum += enetc_get_cbs_bw(&si->hw, prio_top); + } + + if (bw_sum + bw >= 100) { + dev_err(&ndev->dev, + "The sum of all CBS Bandwidth can't exceed 100\n"); + return -EINVAL; + } + + tc_max_sized_frame = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc)); + + /* For top prio TC, the max_interfrence_size is maxSizedFrame. + * + * For next prio TC, the max_interfrence_size is calculated as below: + * + * max_interference_size = M0 + Ma + Ra * M0 / (R0 - Ra) + * + * - RA: idleSlope for AVB Class A + * - R0: port transmit rate + * - M0: maximum sized frame for the port + * - MA: maximum sized frame for AVB Class A + */ + + if (tc == prio_top) { + max_interference_size = port_frame_max_size * 8; + } else { + u32 m0, ma, r0, ra; + + m0 = port_frame_max_size * 8; + ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8; + ra = enetc_get_cbs_bw(&si->hw, prio_top) * + port_transmit_rate * 10000ULL; + r0 = port_transmit_rate * 1000000ULL; + max_interference_size = m0 + ma + + (u32)div_u64((u64)ra * m0, r0 - ra); + } + + /* hiCredit bits calculate by: + * + * maxSizedFrame * (idleSlope/portTxRate) + */ + hi_credit_bit = max_interference_size * bw / 100; + + /* hiCredit bits to hiCredit register need to calculated as: + * + * (enetClockFrequency / portTransmitRate) * 100 + */ + hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit, + port_transmit_rate * 1000000ULL); + + enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg); + + /* Set bw register and enable this traffic class */ + enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE); + + return 0; +} -- cgit v1.2.3-59-g8ed1b From 1d7ea55668878bb350979c377fc72509dd6f5b21 Mon Sep 17 00:00:00 2001 From: Menglong Dong Date: Mon, 25 Nov 2019 16:58:09 +0800 Subject: macvlan: schedule bc_work even if error While enqueueing a broadcast skb to port->bc_queue, schedule_work() is called to add port->bc_work, which processes the skbs in bc_queue, to "events" work queue. If port->bc_queue is full, the skb will be discarded and schedule_work(&port->bc_work) won't be called. However, if port->bc_queue is full and port->bc_work is not running or pending, port->bc_queue will keep full and schedule_work() won't be called any more, and all broadcast skbs to macvlan will be discarded. This case can happen: macvlan_process_broadcast() is the pending function of port->bc_work, it moves all the skbs in port->bc_queue to the queue "list", and processes the skbs in "list". During this, new skbs will keep being added to port->bc_queue in macvlan_broadcast_enqueue(), and port->bc_queue may already full when macvlan_process_broadcast() return. This may happen, especially when there are a lot of real-time threads and the process is preempted. Fix this by calling schedule_work(&port->bc_work) even if port->bc_work is full in macvlan_broadcast_enqueue(). Fixes: 412ca1550cbe ("macvlan: Move broadcasts into a work queue") Signed-off-by: Menglong Dong Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 34fc59bd1e20..05631d97eeb4 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -359,10 +359,11 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port, } spin_unlock(&port->bc_queue.lock); + schedule_work(&port->bc_work); + if (err) goto free_nskb; - schedule_work(&port->bc_work); return; free_nskb: -- cgit v1.2.3-59-g8ed1b From 9bca3a0a923fc3f0fb9e41391be1d0f291e86858 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Mon, 25 Nov 2019 12:43:51 +0100 Subject: net: dsa: sja1105: fix sja1105_parse_rgmii_delays() This function was using configuration of port 0 in devicetree for all ports. In case CPU port was not 0, the delay settings was ignored. This resulted not working communication between CPU and the switch. Fixes: f5b8631c293b ("net: dsa: sja1105: Error out if RGMII delays are requested in DT") Signed-off-by: Oleksij Rempel Reviewed-by: Vladimir Oltean Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 7687ddcae159..aa140662c7c2 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -594,15 +594,15 @@ static int sja1105_parse_rgmii_delays(struct sja1105_private *priv, int i; for (i = 0; i < SJA1105_NUM_PORTS; i++) { - if (ports->role == XMII_MAC) + if (ports[i].role == XMII_MAC) continue; - if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || - ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_RXID || + ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID) priv->rgmii_rx_delay[i] = true; - if (ports->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || - ports->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) + if (ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_TXID || + ports[i].phy_mode == PHY_INTERFACE_MODE_RGMII_ID) priv->rgmii_tx_delay[i] = true; if ((priv->rgmii_rx_delay[i] || priv->rgmii_tx_delay[i]) && -- cgit v1.2.3-59-g8ed1b From e58c1912418980f57ba2060017583067f5f71e52 Mon Sep 17 00:00:00 2001 From: Jouni Hogander Date: Mon, 25 Nov 2019 14:23:43 +0200 Subject: slip: Fix use-after-free Read in slip_open Slip_open doesn't clean-up device which registration failed from the slip_devs device list. On next open after failure this list is iterated and freed device is accessed. Fix this by calling sl_free_netdev in error path. Here is the trace from the Syzbot: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0x197/0x210 lib/dump_stack.c:118 print_address_description.constprop.0.cold+0xd4/0x30b mm/kasan/report.c:374 __kasan_report.cold+0x1b/0x41 mm/kasan/report.c:506 kasan_report+0x12/0x20 mm/kasan/common.c:634 __asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:132 sl_sync drivers/net/slip/slip.c:725 [inline] slip_open+0xecd/0x11b7 drivers/net/slip/slip.c:801 tty_ldisc_open.isra.0+0xa3/0x110 drivers/tty/tty_ldisc.c:469 tty_set_ldisc+0x30e/0x6b0 drivers/tty/tty_ldisc.c:596 tiocsetd drivers/tty/tty_io.c:2334 [inline] tty_ioctl+0xe8d/0x14f0 drivers/tty/tty_io.c:2594 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0xdb6/0x13e0 fs/ioctl.c:696 ksys_ioctl+0xab/0xd0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x73/0xb0 fs/ioctl.c:718 do_syscall_64+0xfa/0x760 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: 3b5a39979daf ("slip: Fix memory leak in slip_open error path") Reported-by: syzbot+4d5170758f3762109542@syzkaller.appspotmail.com Cc: David Miller Cc: Oliver Hartkopp Cc: Lukas Bulwahn Signed-off-by: Jouni Hogander Signed-off-by: David S. Miller --- drivers/net/slip/slip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 4d479e3c817d..2a91c192659f 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -855,6 +855,7 @@ err_free_chan: sl->tty = NULL; tty->disc_data = NULL; clear_bit(SLF_INUSE, &sl->flags); + sl_free_netdev(sl->dev); free_netdev(sl->dev); err_exit: -- cgit v1.2.3-59-g8ed1b