The following commit has been merged in the master branch: commit 68aaf4459556b1f9370c259fd486aecad2257552 Merge: d00ee466a07eb9182ad3caf6140c7ebb527b4c64 9e8312f5e160ade069e131d54ab8652cf0e86e1a Author: David S. Miller davem@davemloft.net Date: Tue Aug 27 14:23:31 2019 -0700
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Minor conflict in r8169, bug fix had two versions in net and net-next, take the net-next hunks.
Signed-off-by: David S. Miller davem@davemloft.net
diff --combined MAINTAINERS index 986085351d79,f7c84004187d..818f2a17699a --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -938,14 -938,6 +938,14 @@@ S: Supporte F: drivers/mux/adgs1408.c F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt
+ANALOG DEVICES INC ADIN DRIVER +M: Alexandru Ardelean alexaundru.ardelean@analog.com +L: netdev@vger.kernel.org +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/net/phy/adin.c +F: Documentation/devicetree/bindings/net/adi,adin.yaml + ANALOG DEVICES INC ADIS DRIVER LIBRARY M: Alexandru Ardelean alexandru.ardelean@analog.com S: Supported @@@ -3643,12 -3635,9 +3643,12 @@@ S: Maintaine F: Documentation/devicetree/bindings/net/can/ F: drivers/net/can/ F: include/linux/can/dev.h +F: include/linux/can/led.h +F: include/linux/can/rx-offload.h F: include/linux/can/platform/ F: include/uapi/linux/can/error.h F: include/uapi/linux/can/netlink.h +F: include/uapi/linux/can/vxcan.h
CAN NETWORK LAYER M: Oliver Hartkopp socketcan@hartkopp.net @@@ -3661,8 -3650,6 +3661,8 @@@ S: Maintaine F: Documentation/networking/can.rst F: net/can/ F: include/linux/can/core.h +F: include/linux/can/skb.h +F: include/net/netns/can.h F: include/uapi/linux/can.h F: include/uapi/linux/can/bcm.h F: include/uapi/linux/can/raw.h @@@ -7469,7 -7456,6 +7469,7 @@@ F: drivers/hid/hid-hyperv. F: drivers/hv/ F: drivers/input/serio/hyperv-keyboard.c F: drivers/pci/controller/pci-hyperv.c +F: drivers/pci/controller/pci-hyperv-intf.c F: drivers/net/hyperv/ F: drivers/scsi/storvsc_drv.c F: drivers/uio/uio_hv_generic.c @@@ -8468,11 -8454,6 +8468,6 @@@ S: Maintaine F: fs/io_uring.c F: include/uapi/linux/io_uring.h
- IP MASQUERADING - M: Juanjo Ciarlante jjciarla@raiz.uncu.edu.ar - S: Maintained - F: net/ipv4/netfilter/ipt_MASQUERADE.c - IPMI SUBSYSTEM M: Corey Minyard minyard@acm.org L: openipmi-developer@lists.sourceforge.net (moderated for non-subscribers) @@@ -8846,14 -8827,6 +8841,6 @@@ F: virt/kvm/ F: tools/kvm/ F: tools/testing/selftests/kvm/
- KERNEL VIRTUAL MACHINE FOR AMD-V (KVM/amd) - M: Joerg Roedel joro@8bytes.org - L: kvm@vger.kernel.org - W: http://www.linux-kvm.org/ - S: Maintained - F: arch/x86/include/asm/svm.h - F: arch/x86/kvm/svm.c - KERNEL VIRTUAL MACHINE FOR ARM/ARM64 (KVM/arm, KVM/arm64) M: Marc Zyngier maz@kernel.org R: James Morse james.morse@arm.com @@@ -8896,7 -8869,7 +8883,7 @@@ M: Christian Borntraeger <borntraeger@d M: Janosch Frank frankja@linux.ibm.com R: David Hildenbrand david@redhat.com R: Cornelia Huck cohuck@redhat.com - L: linux-s390@vger.kernel.org + L: kvm@vger.kernel.org W: http://www.ibm.com/developerworks/linux/linux390/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux.git S: Supported @@@ -8911,6 -8884,11 +8898,11 @@@ F: tools/testing/selftests/kvm/*/s390x KERNEL VIRTUAL MACHINE FOR X86 (KVM/x86) M: Paolo Bonzini pbonzini@redhat.com M: Radim Krčmář rkrcmar@redhat.com + R: Sean Christopherson sean.j.christopherson@intel.com + R: Vitaly Kuznetsov vkuznets@redhat.com + R: Wanpeng Li wanpengli@tencent.com + R: Jim Mattson jmattson@google.com + R: Joerg Roedel joro@8bytes.org L: kvm@vger.kernel.org W: http://www.linux-kvm.org T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git @@@ -8918,8 -8896,12 +8910,12 @@@ S: Supporte F: arch/x86/kvm/ F: arch/x86/kvm/*/ F: arch/x86/include/uapi/asm/kvm* + F: arch/x86/include/uapi/asm/vmx.h + F: arch/x86/include/uapi/asm/svm.h F: arch/x86/include/asm/kvm* F: arch/x86/include/asm/pvclock-abi.h + F: arch/x86/include/asm/svm.h + F: arch/x86/include/asm/vmx.h F: arch/x86/kernel/kvm.c F: arch/x86/kernel/kvmclock.c
@@@ -11099,7 -11081,7 +11095,7 @@@ NET_FAILOVER MODUL M: Sridhar Samudrala sridhar.samudrala@intel.com L: netdev@vger.kernel.org S: Supported - F: driver/net/net_failover.c + F: drivers/net/net_failover.c F: include/net/net_failover.h F: Documentation/networking/net_failover.rst
@@@ -11172,7 -11154,6 +11168,7 @@@ S: Maintaine W: https://fedorahosted.org/dropwatch/ F: net/core/drop_monitor.c F: include/uapi/linux/net_dropmon.h +F: include/net/drop_monitor.h
NETWORKING DRIVERS M: "David S. Miller" davem@davemloft.net @@@ -11352,6 -11333,7 +11348,6 @@@ F: include/net/nfc F: include/uapi/linux/nfc.h F: drivers/nfc/ F: include/linux/platform_data/nfcmrvl.h -F: include/linux/platform_data/nxp-nci.h F: Documentation/devicetree/bindings/net/nfc/
NFS, SUNRPC, AND LOCKD CLIENTS @@@ -13246,7 -13228,7 +13242,7 @@@ M: Manish Chopra <manishc@marvell.com M: GR-Linux-NIC-Dev@marvell.com L: netdev@vger.kernel.org S: Supported -F: drivers/net/ethernet/qlogic/qlge/ +F: drivers/staging/qlge/
QM1D1B0004 MEDIA DRIVER M: Akihiro Tsukada tskd08@gmail.com @@@ -14491,6 -14473,7 +14487,7 @@@ F: drivers/net/phy/phylink. F: drivers/net/phy/sfp* F: include/linux/phylink.h F: include/linux/sfp.h + K: phylink
SGI GRU DRIVER M: Dimitri Sivanich sivanich@sgi.com @@@ -14896,9 -14879,9 +14893,9 @@@ F: include/linux/arm_sdei. F: include/uapi/linux/arm_sdei.h
SOFTWARE RAID (Multiple Disks) SUPPORT - M: Shaohua Li shli@kernel.org + M: Song Liu song@kernel.org L: linux-raid@vger.kernel.org - T: git git://git.kernel.org/pub/scm/linux/kernel/git/shli/md.git + T: git git://git.kernel.org/pub/scm/linux/kernel/git/song/md.git S: Supported F: drivers/md/Makefile F: drivers/md/Kconfig diff --combined drivers/net/dsa/bcm_sf2.c index 4f839348011d,28c963a21dac..26509fa37a50 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@@ -157,9 -157,6 +157,9 @@@ static int bcm_sf2_port_setup(struct ds unsigned int i; u32 reg;
+ if (!dsa_is_user_port(ds, port)) + return 0; + /* Clear the memory power down */ reg = core_readl(priv, CORE_MEM_PSM_VDD_CTRL); reg &= ~P_TXQ_PSM_VDD(port); @@@ -481,6 -478,7 +481,7 @@@ static void bcm_sf2_sw_validate(struct unsigned long *supported, struct phylink_link_state *state) { + struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
if (!phy_interface_mode_is_rgmii(state->interface) && @@@ -490,8 -488,10 +491,10 @@@ state->interface != PHY_INTERFACE_MODE_INTERNAL && state->interface != PHY_INTERFACE_MODE_MOCA) { bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); - dev_err(ds->dev, - "Unsupported interface: %d\n", state->interface); + if (port != core_readl(priv, CORE_IMP0_PRT_ID)) + dev_err(ds->dev, + "Unsupported interface: %d for port %d\n", + state->interface, port); return; }
@@@ -529,6 -529,9 +532,9 @@@ static void bcm_sf2_sw_mac_config(struc u32 id_mode_dis = 0, port_mode; u32 reg, offset;
+ if (port == core_readl(priv, CORE_IMP0_PRT_ID)) + return; + if (priv->type == BCM7445_DEVICE_ID) offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); else @@@ -1044,6 -1047,7 +1050,6 @@@ static int bcm_sf2_sw_probe(struct plat struct b53_device *dev; struct dsa_switch *ds; void __iomem **base; - struct resource *r; unsigned int i; u32 reg, rev; int ret; @@@ -1109,7 -1113,8 +1115,7 @@@
base = &priv->core; for (i = 0; i < BCM_SF2_REGS_NUM; i++) { - r = platform_get_resource(pdev, IORESOURCE_MEM, i); - *base = devm_ioremap_resource(&pdev->dev, r); + *base = devm_platform_ioremap_resource(pdev, i); if (IS_ERR(*base)) { pr_err("unable to find register: %s\n", reg_names[i]); return PTR_ERR(*base); diff --combined drivers/net/ethernet/netronome/nfp/flower/offload.c index 3a4f4f042ae7,9917d64694c6..b0708460e342 --- a/drivers/net/ethernet/netronome/nfp/flower/offload.c +++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c @@@ -61,11 -61,6 +61,11 @@@ NFP_FLOWER_LAYER_IPV4 | \ NFP_FLOWER_LAYER_IPV6)
+#define NFP_FLOWER_PRE_TUN_RULE_FIELDS \ + (NFP_FLOWER_LAYER_PORT | \ + NFP_FLOWER_LAYER_MAC | \ + NFP_FLOWER_LAYER_IPV4) + struct nfp_flower_merge_check { union { struct { @@@ -494,7 -489,6 +494,7 @@@ nfp_flower_allocate_new(struct nfp_fl_k flow_pay->meta.flags = 0; INIT_LIST_HEAD(&flow_pay->linked_flows); flow_pay->in_hw = false; + flow_pay->pre_tun_rule.dev = NULL;
return flow_pay;
@@@ -738,62 -732,28 +738,62 @@@ nfp_flower_copy_pre_actions(char *act_d return act_off; }
-static int nfp_fl_verify_post_tun_acts(char *acts, int len) +static int +nfp_fl_verify_post_tun_acts(char *acts, int len, struct nfp_fl_push_vlan **vlan) { struct nfp_fl_act_head *a; unsigned int act_off = 0;
while (act_off < len) { a = (struct nfp_fl_act_head *)&acts[act_off]; - if (a->jump_id != NFP_FL_ACTION_OPCODE_OUTPUT) + + if (a->jump_id == NFP_FL_ACTION_OPCODE_PUSH_VLAN && !act_off) + *vlan = (struct nfp_fl_push_vlan *)a; + else if (a->jump_id != NFP_FL_ACTION_OPCODE_OUTPUT) return -EOPNOTSUPP;
act_off += a->len_lw << NFP_FL_LW_SIZ; }
+ /* Ensure any VLAN push also has an egress action. */ + if (*vlan && act_off <= sizeof(struct nfp_fl_push_vlan)) + return -EOPNOTSUPP; + return 0; }
static int +nfp_fl_push_vlan_after_tun(char *acts, int len, struct nfp_fl_push_vlan *vlan) +{ + struct nfp_fl_set_ipv4_tun *tun; + struct nfp_fl_act_head *a; + unsigned int act_off = 0; + + while (act_off < len) { + a = (struct nfp_fl_act_head *)&acts[act_off]; + + if (a->jump_id == NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL) { + tun = (struct nfp_fl_set_ipv4_tun *)a; + tun->outer_vlan_tpid = vlan->vlan_tpid; + tun->outer_vlan_tci = vlan->vlan_tci; + + return 0; + } + + act_off += a->len_lw << NFP_FL_LW_SIZ; + } + + /* Return error if no tunnel action is found. */ + return -EOPNOTSUPP; +} + +static int nfp_flower_merge_action(struct nfp_fl_payload *sub_flow1, struct nfp_fl_payload *sub_flow2, struct nfp_fl_payload *merge_flow) { unsigned int sub1_act_len, sub2_act_len, pre_off1, pre_off2; + struct nfp_fl_push_vlan *post_tun_push_vlan = NULL; bool tunnel_act = false; char *merge_act; int err; @@@ -830,36 -790,18 +830,36 @@@ sub2_act_len -= pre_off2;
/* FW does a tunnel push when egressing, therefore, if sub_flow 1 pushes - * a tunnel, sub_flow 2 can only have output actions for a valid merge. + * a tunnel, there are restrictions on what sub_flow 2 actions lead to a + * valid merge. */ if (tunnel_act) { char *post_tun_acts = &sub_flow2->action_data[pre_off2];
- err = nfp_fl_verify_post_tun_acts(post_tun_acts, sub2_act_len); + err = nfp_fl_verify_post_tun_acts(post_tun_acts, sub2_act_len, + &post_tun_push_vlan); if (err) return err; + + if (post_tun_push_vlan) { + pre_off2 += sizeof(*post_tun_push_vlan); + sub2_act_len -= sizeof(*post_tun_push_vlan); + } }
/* Copy remaining actions from sub_flows 1 and 2. */ memcpy(merge_act, sub_flow1->action_data + pre_off1, sub1_act_len); + + if (post_tun_push_vlan) { + /* Update tunnel action in merge to include VLAN push. */ + err = nfp_fl_push_vlan_after_tun(merge_act, sub1_act_len, + post_tun_push_vlan); + if (err) + return err; + + merge_flow->meta.act_len -= sizeof(*post_tun_push_vlan); + } + merge_act += sub1_act_len; memcpy(merge_act, sub_flow2->action_data + pre_off2, sub2_act_len);
@@@ -1003,106 -945,6 +1003,106 @@@ err_destroy_merge_flow }
/** + * nfp_flower_validate_pre_tun_rule() + * @app: Pointer to the APP handle + * @flow: Pointer to NFP flow representation of rule + * @extack: Netlink extended ACK report + * + * Verifies the flow as a pre-tunnel rule. + * + * Return: negative value on error, 0 if verified. + */ +static int +nfp_flower_validate_pre_tun_rule(struct nfp_app *app, + struct nfp_fl_payload *flow, + struct netlink_ext_ack *extack) +{ + struct nfp_flower_meta_tci *meta_tci; + struct nfp_flower_mac_mpls *mac; + struct nfp_fl_act_head *act; + u8 *mask = flow->mask_data; + bool vlan = false; + int act_offset; + u8 key_layer; + + meta_tci = (struct nfp_flower_meta_tci *)flow->unmasked_data; + if (meta_tci->tci & cpu_to_be16(NFP_FLOWER_MASK_VLAN_PRESENT)) { + u16 vlan_tci = be16_to_cpu(meta_tci->tci); + + vlan_tci &= ~NFP_FLOWER_MASK_VLAN_PRESENT; + flow->pre_tun_rule.vlan_tci = cpu_to_be16(vlan_tci); + vlan = true; + } else { + flow->pre_tun_rule.vlan_tci = cpu_to_be16(0xffff); + } + + key_layer = meta_tci->nfp_flow_key_layer; + if (key_layer & ~NFP_FLOWER_PRE_TUN_RULE_FIELDS) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: too many match fields"); + return -EOPNOTSUPP; + } + + if (!(key_layer & NFP_FLOWER_LAYER_MAC)) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: MAC fields match required"); + return -EOPNOTSUPP; + } + + /* Skip fields known to exist. */ + mask += sizeof(struct nfp_flower_meta_tci); + mask += sizeof(struct nfp_flower_in_port); + + /* Ensure destination MAC address is fully matched. */ + mac = (struct nfp_flower_mac_mpls *)mask; + if (!is_broadcast_ether_addr(&mac->mac_dst[0])) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: dest MAC field must not be masked"); + return -EOPNOTSUPP; + } + + if (key_layer & NFP_FLOWER_LAYER_IPV4) { + int ip_flags = offsetof(struct nfp_flower_ipv4, ip_ext.flags); + int ip_proto = offsetof(struct nfp_flower_ipv4, ip_ext.proto); + int i; + + mask += sizeof(struct nfp_flower_mac_mpls); + + /* Ensure proto and flags are the only IP layer fields. */ + for (i = 0; i < sizeof(struct nfp_flower_ipv4); i++) + if (mask[i] && i != ip_flags && i != ip_proto) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: only flags and proto can be matched in ip header"); + return -EOPNOTSUPP; + } + } + + /* Action must be a single egress or pop_vlan and egress. */ + act_offset = 0; + act = (struct nfp_fl_act_head *)&flow->action_data[act_offset]; + if (vlan) { + if (act->jump_id != NFP_FL_ACTION_OPCODE_POP_VLAN) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: match on VLAN must have VLAN pop as first action"); + return -EOPNOTSUPP; + } + + act_offset += act->len_lw << NFP_FL_LW_SIZ; + act = (struct nfp_fl_act_head *)&flow->action_data[act_offset]; + } + + if (act->jump_id != NFP_FL_ACTION_OPCODE_OUTPUT) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: non egress action detected where egress was expected"); + return -EOPNOTSUPP; + } + + act_offset += act->len_lw << NFP_FL_LW_SIZ; + + /* Ensure there are no more actions after egress. */ + if (act_offset != flow->meta.act_len) { + NL_SET_ERR_MSG_MOD(extack, "unsupported pre-tunnel rule: egress is not the last action"); + return -EOPNOTSUPP; + } + + return 0; +} + +/** * nfp_flower_add_offload() - Adds a new flow to hardware. * @app: Pointer to the APP handle * @netdev: netdev structure. @@@ -1152,12 -994,6 +1152,12 @@@ nfp_flower_add_offload(struct nfp_app * if (err) goto err_destroy_flow;
+ if (flow_pay->pre_tun_rule.dev) { + err = nfp_flower_validate_pre_tun_rule(app, flow_pay, extack); + if (err) + goto err_destroy_flow; + } + err = nfp_compile_flow_metadata(app, flow, flow_pay, netdev, extack); if (err) goto err_destroy_flow; @@@ -1170,11 -1006,8 +1170,11 @@@ goto err_release_metadata; }
- err = nfp_flower_xmit_flow(app, flow_pay, - NFP_FLOWER_CMSG_TYPE_FLOW_ADD); + if (flow_pay->pre_tun_rule.dev) + err = nfp_flower_xmit_pre_tun_flow(app, flow_pay); + else + err = nfp_flower_xmit_flow(app, flow_pay, + NFP_FLOWER_CMSG_TYPE_FLOW_ADD); if (err) goto err_remove_rhash;
@@@ -1316,11 -1149,8 +1316,11 @@@ nfp_flower_del_offload(struct nfp_app * goto err_free_merge_flow; }
- err = nfp_flower_xmit_flow(app, nfp_flow, - NFP_FLOWER_CMSG_TYPE_FLOW_DEL); + if (nfp_flow->pre_tun_rule.dev) + err = nfp_flower_xmit_pre_tun_del_flow(app, nfp_flow); + else + err = nfp_flower_xmit_flow(app, nfp_flow, + NFP_FLOWER_CMSG_TYPE_FLOW_DEL); /* Fall through on error. */
err_free_merge_flow: @@@ -1586,6 -1416,13 +1586,13 @@@ nfp_flower_setup_indr_tc_block(struct n
switch (f->command) { case FLOW_BLOCK_BIND: + cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev); + if (cb_priv && + flow_block_cb_is_busy(nfp_flower_setup_indr_block_cb, + cb_priv, + &nfp_block_cb_list)) + return -EBUSY; + cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL); if (!cb_priv) return -ENOMEM; @@@ -1649,17 -1486,16 +1656,17 @@@ int nfp_flower_reg_indir_block_handler( return NOTIFY_OK;
if (event == NETDEV_REGISTER) { - err = __tc_indr_block_cb_register(netdev, app, - nfp_flower_indr_setup_tc_cb, - app); + err = __flow_indr_block_cb_register(netdev, app, + nfp_flower_indr_setup_tc_cb, + app); if (err) nfp_flower_cmsg_warn(app, "Indirect block reg failed - %s\n", netdev->name); } else if (event == NETDEV_UNREGISTER) { - __tc_indr_block_cb_unregister(netdev, - nfp_flower_indr_setup_tc_cb, app); + __flow_indr_block_cb_unregister(netdev, + nfp_flower_indr_setup_tc_cb, + app); }
return NOTIFY_OK; diff --combined drivers/net/ethernet/qlogic/qed/qed_main.c index 0a7645937412,1efff7f68ef6..7891f8c5a1bc --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@@ -67,8 -67,6 +67,8 @@@ #define QED_ROCE_QPS (8192) #define QED_ROCE_DPIS (8) #define QED_RDMA_SRQS QED_ROCE_QPS +#define QED_NVM_CFG_SET_FLAGS 0xE +#define QED_NVM_CFG_SET_PF_FLAGS 0x1E
static char version[] = "QLogic FastLinQ 4xxxx Core Module qed " DRV_MODULE_VERSION "\n"; @@@ -1327,7 -1325,7 +1327,7 @@@ static int qed_slowpath_start(struct qe &drv_version); if (rc) { DP_NOTICE(cdev, "Failed sending drv version command\n"); - return rc; + goto err4; } }
@@@ -1335,6 -1333,8 +1335,8 @@@
return 0;
+ err4: + qed_ll2_dealloc_if(cdev); err3: qed_hw_stop(cdev); err2: @@@ -1690,7 -1690,6 +1692,7 @@@ static void qed_fill_link_capability(st
switch (media_type) { case MEDIA_DA_TWINAX: + *if_capability |= QED_LM_FIBRE_BIT; if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) *if_capability |= QED_LM_20000baseKR2_Full_BIT; /* For DAC media multiple speed capabilities are supported*/ @@@ -1710,7 -1709,6 +1712,7 @@@ *if_capability |= QED_LM_100000baseCR4_Full_BIT; break; case MEDIA_BASE_T: + *if_capability |= QED_LM_TP_BIT; if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_EXT_PHY) { if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { @@@ -1722,7 -1720,6 +1724,7 @@@ } } if (board_cfg & NVM_CFG1_PORT_PORT_TYPE_MODULE) { + *if_capability |= QED_LM_FIBRE_BIT; if (tcvr_type == ETH_TRANSCEIVER_TYPE_1000BASET) *if_capability |= QED_LM_1000baseT_Full_BIT; if (tcvr_type == ETH_TRANSCEIVER_TYPE_10G_BASET) @@@ -1733,7 -1730,6 +1735,7 @@@ case MEDIA_SFPP_10G_FIBER: case MEDIA_XFP_FIBER: case MEDIA_MODULE_FIBER: + *if_capability |= QED_LM_FIBRE_BIT; if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) { if ((tcvr_type == ETH_TRANSCEIVER_TYPE_1G_LX) || @@@ -1776,7 -1772,6 +1778,7 @@@
break; case MEDIA_KR: + *if_capability |= QED_LM_Backplane_BIT; if (capability & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G) *if_capability |= QED_LM_20000baseKR2_Full_BIT; if (capability & @@@ -1828,6 -1823,7 +1830,6 @@@ static void qed_fill_link(struct qed_hw if_link->link_up = true;
/* TODO - at the moment assume supported and advertised speed equal */ - if_link->supported_caps = QED_LM_FIBRE_BIT; if (link_caps.default_speed_autoneg) if_link->supported_caps |= QED_LM_Autoneg_BIT; if (params.pause.autoneg || @@@ -2233,69 -2229,6 +2235,69 @@@ static int qed_nvm_flash_image_validate return 0; }
+/* Binary file format - + * /----------------------------------------------------------------------\ + * 0B | 0x5 [command index] | + * 4B | Entity ID | Reserved | Number of config attributes | + * 8B | Config ID | Length | Value | + * | | + * ----------------------------------------------------------------------/ + * There can be several cfg_id-Length-Value sets as specified by 'Number of...'. + * Entity ID - A non zero entity value for which the config need to be updated. + * + * The API parses config attributes from the user provided buffer and flashes + * them to the respective NVM path using Management FW inerface. + */ +static int qed_nvm_flash_cfg_write(struct qed_dev *cdev, const u8 **data) +{ + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); + u8 entity_id, len, buf[32]; + struct qed_ptt *ptt; + u16 cfg_id, count; + int rc = 0, i; + u32 flags; + + ptt = qed_ptt_acquire(hwfn); + if (!ptt) + return -EAGAIN; + + /* NVM CFG ID attribute header */ + *data += 4; + entity_id = **data; + *data += 2; + count = *((u16 *)*data); + *data += 2; + + DP_VERBOSE(cdev, NETIF_MSG_DRV, + "Read config ids: entity id %02x num _attrs = %0d\n", + entity_id, count); + /* NVM CFG ID attributes */ + for (i = 0; i < count; i++) { + cfg_id = *((u16 *)*data); + *data += 2; + len = **data; + (*data)++; + memcpy(buf, *data, len); + *data += len; + + flags = entity_id ? QED_NVM_CFG_SET_PF_FLAGS : + QED_NVM_CFG_SET_FLAGS; + + DP_VERBOSE(cdev, NETIF_MSG_DRV, + "cfg_id = %d len = %d\n", cfg_id, len); + rc = qed_mcp_nvm_set_cfg(hwfn, ptt, cfg_id, entity_id, flags, + buf, len); + if (rc) { + DP_ERR(cdev, "Error %d configuring %d\n", rc, cfg_id); + break; + } + } + + qed_ptt_release(hwfn, ptt); + + return rc; +} + static int qed_nvm_flash(struct qed_dev *cdev, const char *name) { const struct firmware *image; @@@ -2337,9 -2270,6 +2339,9 @@@ rc = qed_nvm_flash_image_access(cdev, &data, &check_resp); break; + case QED_NVM_FLASH_CMD_NVM_CFG_ID: + rc = qed_nvm_flash_cfg_write(cdev, &data); + break; default: DP_ERR(cdev, "Unknown command %08x\n", cmd_type); rc = -EINVAL; diff --combined drivers/net/ethernet/ti/cpsw.c index 54010957da5c,a46b8b2e44e1..f298d714efd6 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@@ -2764,7 -2764,7 +2764,7 @@@ static int cpsw_probe(struct platform_d struct net_device *ndev; struct cpsw_priv *priv; void __iomem *ss_regs; - struct resource *res, *ss_res; + struct resource *ss_res; struct gpio_descs *mode; const struct soc_device_attribute *soc; struct cpsw_common *cpsw; @@@ -2775,6 -2775,7 +2775,7 @@@ if (!cpsw) return -ENOMEM;
+ platform_set_drvdata(pdev, cpsw); cpsw->dev = dev;
mode = devm_gpiod_get_array_optional(dev, "mode", GPIOD_OUT_LOW); @@@ -2798,7 -2799,8 +2799,7 @@@ return PTR_ERR(ss_regs); cpsw->regs = ss_regs;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - cpsw->wr_regs = devm_ioremap_resource(dev, res); + cpsw->wr_regs = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(cpsw->wr_regs)) return PTR_ERR(cpsw->wr_regs);
@@@ -2878,7 -2880,6 +2879,6 @@@ goto clean_cpts; }
- platform_set_drvdata(pdev, cpsw); priv = netdev_priv(ndev); priv->cpsw = cpsw; priv->ndev = ndev; diff --combined drivers/net/usb/r8152.c index 17f0e9e98697,eee0f5007ee3..c6fa0c17c13d --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@@ -22,11 -22,10 +22,11 @@@ #include <linux/mdio.h> #include <linux/usb/cdc.h> #include <linux/suspend.h> +#include <linux/atomic.h> #include <linux/acpi.h>
/* Information for net-next */ -#define NETNEXT_VERSION "09" +#define NETNEXT_VERSION "10"
/* Information for net */ #define NET_VERSION "10" @@@ -584,9 -583,6 +584,9 @@@ enum rtl_register_content #define TX_ALIGN 4 #define RX_ALIGN 8
+#define RTL8152_RX_MAX_PENDING 4096 +#define RTL8152_RXFG_HEADSZ 256 + #define INTR_LINK 0x0004
#define RTL8152_REQT_READ 0xc0 @@@ -619,7 -615,7 +619,7 @@@ enum rtl8152_flags RTL8152_LINK_CHG, SELECTIVE_SUSPEND, PHY_RESET, - SCHEDULE_NAPI, + SCHEDULE_TASKLET, GREEN_ETHERNET, DELL_TB_RX_AGG_BUG, }; @@@ -698,11 -694,11 +698,11 @@@ struct tx_desc struct r8152;
struct rx_agg { - struct list_head list; + struct list_head list, info_list; struct urb *urb; struct r8152 *context; + struct page *page; void *buffer; - void *head; };
struct tx_agg { @@@ -723,7 -719,7 +723,7 @@@ struct r8152 struct net_device *netdev; struct urb *intr_urb; struct tx_agg tx_info[RTL8152_MAX_TX]; - struct rx_agg rx_info[RTL8152_MAX_RX]; + struct list_head rx_info, rx_used; struct list_head rx_done, tx_free; struct sk_buff_head tx_queue, rx_queue; spinlock_t rx_lock, tx_lock; @@@ -733,7 -729,6 +733,7 @@@ #ifdef CONFIG_PM_SLEEP struct notifier_block pm_notifier; #endif + struct tasklet_struct tx_tl;
struct rtl_ops { void (*init)(struct r8152 *); @@@ -749,21 -744,13 +749,21 @@@ void (*autosuspend_en)(struct r8152 *tp, bool enable); } rtl_ops;
+ atomic_t rx_count; + + bool eee_en; int intr_interval; u32 saved_wolopts; u32 msg_enable; u32 tx_qlen; u32 coalesce; + u32 rx_buf_sz; + u32 rx_copybreak; + u32 rx_pending; + u16 ocp_base; u16 speed; + u16 eee_adv; u8 *intr_buff; u8 version; u8 duplex; @@@ -812,8 -799,11 +812,11 @@@ int get_registers(struct r8152 *tp, u1 ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0), RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, value, index, tmp, size, 500); + if (ret < 0) + memset(data, 0xff, size); + else + memcpy(data, tmp, size);
- memcpy(data, tmp, size); kfree(tmp);
return ret; @@@ -1404,7 -1394,7 +1407,7 @@@ static void write_bulk_callback(struct return;
if (!skb_queue_empty(&tp->tx_queue)) - napi_schedule(&tp->napi); + tasklet_schedule(&tp->tx_tl); }
static void intr_callback(struct urb *urb) @@@ -1480,72 -1470,18 +1483,72 @@@ static inline void *tx_agg_align(void * return (void *)ALIGN((uintptr_t)data, TX_ALIGN); }
+static void free_rx_agg(struct r8152 *tp, struct rx_agg *agg) +{ + list_del(&agg->info_list); + + usb_free_urb(agg->urb); + put_page(agg->page); + kfree(agg); + + atomic_dec(&tp->rx_count); +} + +static struct rx_agg *alloc_rx_agg(struct r8152 *tp, gfp_t mflags) +{ + struct net_device *netdev = tp->netdev; + int node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1; + unsigned int order = get_order(tp->rx_buf_sz); + struct rx_agg *rx_agg; + unsigned long flags; + + rx_agg = kmalloc_node(sizeof(*rx_agg), mflags, node); + if (!rx_agg) + return NULL; + + rx_agg->page = alloc_pages(mflags | __GFP_COMP, order); + if (!rx_agg->page) + goto free_rx; + + rx_agg->buffer = page_address(rx_agg->page); + + rx_agg->urb = usb_alloc_urb(0, mflags); + if (!rx_agg->urb) + goto free_buf; + + rx_agg->context = tp; + + INIT_LIST_HEAD(&rx_agg->list); + INIT_LIST_HEAD(&rx_agg->info_list); + spin_lock_irqsave(&tp->rx_lock, flags); + list_add_tail(&rx_agg->info_list, &tp->rx_info); + spin_unlock_irqrestore(&tp->rx_lock, flags); + + atomic_inc(&tp->rx_count); + + return rx_agg; + +free_buf: + __free_pages(rx_agg->page, order); +free_rx: + kfree(rx_agg); + return NULL; +} + static void free_all_mem(struct r8152 *tp) { + struct rx_agg *agg, *agg_next; + unsigned long flags; int i;
- for (i = 0; i < RTL8152_MAX_RX; i++) { - usb_free_urb(tp->rx_info[i].urb); - tp->rx_info[i].urb = NULL; + spin_lock_irqsave(&tp->rx_lock, flags);
- kfree(tp->rx_info[i].buffer); - tp->rx_info[i].buffer = NULL; - tp->rx_info[i].head = NULL; - } + list_for_each_entry_safe(agg, agg_next, &tp->rx_info, info_list) + free_rx_agg(tp, agg); + + spin_unlock_irqrestore(&tp->rx_lock, flags); + + WARN_ON(atomic_read(&tp->rx_count));
for (i = 0; i < RTL8152_MAX_TX; i++) { usb_free_urb(tp->tx_info[i].urb); @@@ -1569,28 -1505,46 +1572,28 @@@ static int alloc_all_mem(struct r8152 * struct usb_interface *intf = tp->intf; struct usb_host_interface *alt = intf->cur_altsetting; struct usb_host_endpoint *ep_intr = alt->endpoint + 2; - struct urb *urb; int node, i; - u8 *buf;
node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
spin_lock_init(&tp->rx_lock); spin_lock_init(&tp->tx_lock); + INIT_LIST_HEAD(&tp->rx_info); INIT_LIST_HEAD(&tp->tx_free); INIT_LIST_HEAD(&tp->rx_done); skb_queue_head_init(&tp->tx_queue); skb_queue_head_init(&tp->rx_queue); + atomic_set(&tp->rx_count, 0);
for (i = 0; i < RTL8152_MAX_RX; i++) { - buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); - if (!buf) + if (!alloc_rx_agg(tp, GFP_KERNEL)) goto err1; - - if (buf != rx_agg_align(buf)) { - kfree(buf); - buf = kmalloc_node(agg_buf_sz + RX_ALIGN, GFP_KERNEL, - node); - if (!buf) - goto err1; - } - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - kfree(buf); - goto err1; - } - - INIT_LIST_HEAD(&tp->rx_info[i].list); - tp->rx_info[i].context = tp; - tp->rx_info[i].urb = urb; - tp->rx_info[i].buffer = buf; - tp->rx_info[i].head = rx_agg_align(buf); }
for (i = 0; i < RTL8152_MAX_TX; i++) { + struct urb *urb; + u8 *buf; + buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node); if (!buf) goto err1; @@@ -1956,46 -1910,6 +1959,46 @@@ return_result return checksum; }
+static inline bool rx_count_exceed(struct r8152 *tp) +{ + return atomic_read(&tp->rx_count) > RTL8152_MAX_RX; +} + +static inline int agg_offset(struct rx_agg *agg, void *addr) +{ + return (int)(addr - agg->buffer); +} + +static struct rx_agg *rtl_get_free_rx(struct r8152 *tp, gfp_t mflags) +{ + struct rx_agg *agg, *agg_next, *agg_free = NULL; + unsigned long flags; + + spin_lock_irqsave(&tp->rx_lock, flags); + + list_for_each_entry_safe(agg, agg_next, &tp->rx_used, list) { + if (page_count(agg->page) == 1) { + if (!agg_free) { + list_del_init(&agg->list); + agg_free = agg; + continue; + } + if (rx_count_exceed(tp)) { + list_del_init(&agg->list); + free_rx_agg(tp, agg); + } + break; + } + } + + spin_unlock_irqrestore(&tp->rx_lock, flags); + + if (!agg_free && atomic_read(&tp->rx_count) < tp->rx_pending) + agg_free = alloc_rx_agg(tp, mflags); + + return agg_free; +} + static int rx_bottom(struct r8152 *tp, int budget) { unsigned long flags; @@@ -2031,7 -1945,7 +2034,7 @@@
list_for_each_safe(cursor, next, &rx_queue) { struct rx_desc *rx_desc; - struct rx_agg *agg; + struct rx_agg *agg, *agg_free; int len_used = 0; struct urb *urb; u8 *rx_data; @@@ -2043,16 -1957,14 +2046,16 @@@ if (urb->actual_length < ETH_ZLEN) goto submit;
- rx_desc = agg->head; - rx_data = agg->head; + agg_free = rtl_get_free_rx(tp, GFP_ATOMIC); + + rx_desc = agg->buffer; + rx_data = agg->buffer; len_used += sizeof(struct rx_desc);
while (urb->actual_length > len_used) { struct net_device *netdev = tp->netdev; struct net_device_stats *stats = &netdev->stats; - unsigned int pkt_len; + unsigned int pkt_len, rx_frag_head_sz; struct sk_buff *skb;
/* limite the skb numbers for rx_queue */ @@@ -2070,37 -1982,22 +2073,37 @@@ pkt_len -= ETH_FCS_LEN; rx_data += sizeof(struct rx_desc);
- skb = napi_alloc_skb(napi, pkt_len); + if (!agg_free || tp->rx_copybreak > pkt_len) + rx_frag_head_sz = pkt_len; + else + rx_frag_head_sz = tp->rx_copybreak; + + skb = napi_alloc_skb(napi, rx_frag_head_sz); if (!skb) { stats->rx_dropped++; goto find_next_rx; }
skb->ip_summed = r8152_rx_csum(tp, rx_desc); - memcpy(skb->data, rx_data, pkt_len); - skb_put(skb, pkt_len); + memcpy(skb->data, rx_data, rx_frag_head_sz); + skb_put(skb, rx_frag_head_sz); + pkt_len -= rx_frag_head_sz; + rx_data += rx_frag_head_sz; + if (pkt_len) { + skb_add_rx_frag(skb, 0, agg->page, + agg_offset(agg, rx_data), + pkt_len, + SKB_DATA_ALIGN(pkt_len)); + get_page(agg->page); + } + skb->protocol = eth_type_trans(skb, netdev); rtl_rx_vlan_tag(rx_desc, skb); if (work_done < budget) { - napi_gro_receive(napi, skb); work_done++; stats->rx_packets++; - stats->rx_bytes += pkt_len; + stats->rx_bytes += skb->len; + napi_gro_receive(napi, skb); } else { __skb_queue_tail(&tp->rx_queue, skb); } @@@ -2108,24 -2005,10 +2111,24 @@@ find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + ETH_FCS_LEN); rx_desc = (struct rx_desc *)rx_data; - len_used = (int)(rx_data - (u8 *)agg->head); + len_used = agg_offset(agg, rx_data); len_used += sizeof(struct rx_desc); }
+ WARN_ON(!agg_free && page_count(agg->page) > 1); + + if (agg_free) { + spin_lock_irqsave(&tp->rx_lock, flags); + if (page_count(agg->page) == 1) { + list_add(&agg_free->list, &tp->rx_used); + } else { + list_add_tail(&agg->list, &tp->rx_used); + agg = agg_free; + urb = agg->urb; + } + spin_unlock_irqrestore(&tp->rx_lock, flags); + } + submit: if (!ret) { ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); @@@ -2182,12 -2065,8 +2185,12 @@@ static void tx_bottom(struct r8152 *tp } while (res == 0); }
-static void bottom_half(struct r8152 *tp) +static void bottom_half(unsigned long data) { + struct r8152 *tp; + + tp = (struct r8152 *)data; + if (test_bit(RTL8152_UNPLUG, &tp->flags)) return;
@@@ -2199,7 -2078,7 +2202,7 @@@ if (!netif_carrier_ok(tp->netdev)) return;
- clear_bit(SCHEDULE_NAPI, &tp->flags); + clear_bit(SCHEDULE_TASKLET, &tp->flags);
tx_bottom(tp); } @@@ -2210,12 -2089,16 +2213,12 @@@ static int r8152_poll(struct napi_struc int work_done;
work_done = rx_bottom(tp, budget); - bottom_half(tp);
if (work_done < budget) { if (!napi_complete_done(napi, work_done)) goto out; if (!list_empty(&tp->rx_done)) napi_schedule(napi); - else if (!skb_queue_empty(&tp->tx_queue) && - !list_empty(&tp->tx_free)) - napi_schedule(napi); }
out: @@@ -2233,7 -2116,7 +2236,7 @@@ int r8152_submit_rx(struct r8152 *tp, s return 0;
usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1), - agg->head, agg_buf_sz, + agg->buffer, tp->rx_buf_sz, (usb_complete_t)read_bulk_callback, agg);
ret = usb_submit_urb(agg->urb, mem_flags); @@@ -2369,11 -2252,11 +2372,11 @@@ static netdev_tx_t rtl8152_start_xmit(s
if (!list_empty(&tp->tx_free)) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - set_bit(SCHEDULE_NAPI, &tp->flags); + set_bit(SCHEDULE_TASKLET, &tp->flags); schedule_delayed_work(&tp->schedule, 0); } else { usb_mark_last_busy(tp->udev); - napi_schedule(&tp->napi); + tasklet_schedule(&tp->tx_tl); } } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) { netif_stop_queue(netdev); @@@ -2450,80 -2333,44 +2453,80 @@@ static void rxdy_gated_en(struct r8152
static int rtl_start_rx(struct r8152 *tp) { - int i, ret = 0; + struct rx_agg *agg, *agg_next; + struct list_head tmp_list; + unsigned long flags; + int ret = 0, i = 0;
- INIT_LIST_HEAD(&tp->rx_done); - for (i = 0; i < RTL8152_MAX_RX; i++) { - INIT_LIST_HEAD(&tp->rx_info[i].list); - ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL); - if (ret) - break; - } + INIT_LIST_HEAD(&tmp_list);
- if (ret && ++i < RTL8152_MAX_RX) { - struct list_head rx_queue; - unsigned long flags; + spin_lock_irqsave(&tp->rx_lock, flags);
- INIT_LIST_HEAD(&rx_queue); + INIT_LIST_HEAD(&tp->rx_done); + INIT_LIST_HEAD(&tp->rx_used);
- do { - struct rx_agg *agg = &tp->rx_info[i++]; - struct urb *urb = agg->urb; + list_splice_init(&tp->rx_info, &tmp_list);
- urb->actual_length = 0; - list_add_tail(&agg->list, &rx_queue); - } while (i < RTL8152_MAX_RX); + spin_unlock_irqrestore(&tp->rx_lock, flags);
- spin_lock_irqsave(&tp->rx_lock, flags); - list_splice_tail(&rx_queue, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); + list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) { + INIT_LIST_HEAD(&agg->list); + + /* Only RTL8152_MAX_RX rx_agg need to be submitted. */ + if (++i > RTL8152_MAX_RX) { + spin_lock_irqsave(&tp->rx_lock, flags); + list_add_tail(&agg->list, &tp->rx_used); + spin_unlock_irqrestore(&tp->rx_lock, flags); + } else if (unlikely(ret < 0)) { + spin_lock_irqsave(&tp->rx_lock, flags); + list_add_tail(&agg->list, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); + } else { + ret = r8152_submit_rx(tp, agg, GFP_KERNEL); + } }
+ spin_lock_irqsave(&tp->rx_lock, flags); + WARN_ON(!list_empty(&tp->rx_info)); + list_splice(&tmp_list, &tp->rx_info); + spin_unlock_irqrestore(&tp->rx_lock, flags); + return ret; }
static int rtl_stop_rx(struct r8152 *tp) { - int i; + struct rx_agg *agg, *agg_next; + struct list_head tmp_list; + unsigned long flags; + + INIT_LIST_HEAD(&tmp_list); + + /* The usb_kill_urb() couldn't be used in atomic. + * Therefore, move the list of rx_info to a tmp one. + * Then, list_for_each_entry_safe could be used without + * spin lock. + */ + + spin_lock_irqsave(&tp->rx_lock, flags); + list_splice_init(&tp->rx_info, &tmp_list); + spin_unlock_irqrestore(&tp->rx_lock, flags); + + list_for_each_entry_safe(agg, agg_next, &tmp_list, info_list) { + /* At least RTL8152_MAX_RX rx_agg have the page_count being + * equal to 1, so the other ones could be freed safely. + */ + if (page_count(agg->page) > 1) + free_rx_agg(tp, agg); + else + usb_kill_urb(agg->urb); + }
- for (i = 0; i < RTL8152_MAX_RX; i++) - usb_kill_urb(tp->rx_info[i].urb); + /* Move back the list of temp to the rx_info */ + spin_lock_irqsave(&tp->rx_lock, flags); + WARN_ON(!list_empty(&tp->rx_info)); + list_splice(&tmp_list, &tp->rx_info); + spin_unlock_irqrestore(&tp->rx_lock, flags);
while (!skb_queue_empty(&tp->rx_queue)) dev_kfree_skb(__skb_dequeue(&tp->rx_queue)); @@@ -2603,7 -2450,7 +2606,7 @@@ static void r8153_set_rx_early_timeout(
static void r8153_set_rx_early_size(struct r8152 *tp) { - u32 ocp_data = agg_buf_sz - rx_reserved_size(tp->netdev->mtu); + u32 ocp_data = tp->rx_buf_sz - rx_reserved_size(tp->netdev->mtu);
switch (tp->version) { case RTL_VER_03: @@@ -3202,76 -3049,10 +3205,76 @@@ static void r8152_eee_en(struct r8152 * ocp_reg_write(tp, OCP_EEE_CONFIG3, config3); }
-static void r8152b_enable_eee(struct r8152 *tp) +static void r8153_eee_en(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + u16 config; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); + config = ocp_reg_read(tp, OCP_EEE_CFG); + + if (enable) { + ocp_data |= EEE_RX_EN | EEE_TX_EN; + config |= EEE10_EN; + } else { + ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); + config &= ~EEE10_EN; + } + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); + ocp_reg_write(tp, OCP_EEE_CFG, config); +} + +static void r8153b_eee_en(struct r8152 *tp, bool enable) { - r8152_eee_en(tp, true); - r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, MDIO_EEE_100TX); + r8153_eee_en(tp, enable); + + if (enable) + r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_EEE, 0); + else + r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_EEE); +} + +static void rtl_eee_enable(struct r8152 *tp, bool enable) +{ + switch (tp->version) { + case RTL_VER_01: + case RTL_VER_02: + case RTL_VER_07: + if (enable) { + r8152_eee_en(tp, true); + r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, + tp->eee_adv); + } else { + r8152_eee_en(tp, false); + r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0); + } + break; + case RTL_VER_03: + case RTL_VER_04: + case RTL_VER_05: + case RTL_VER_06: + if (enable) { + r8153_eee_en(tp, true); + ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv); + } else { + r8153_eee_en(tp, false); + ocp_reg_write(tp, OCP_EEE_ADV, 0); + } + break; + case RTL_VER_08: + case RTL_VER_09: + if (enable) { + r8153b_eee_en(tp, true); + ocp_reg_write(tp, OCP_EEE_ADV, tp->eee_adv); + } else { + r8153b_eee_en(tp, false); + ocp_reg_write(tp, OCP_EEE_ADV, 0); + } + break; + default: + break; + } }
static void r8152b_enable_fc(struct r8152 *tp) @@@ -3292,7 -3073,7 +3295,7 @@@ static void rtl8152_disable(struct r815
static void r8152b_hw_phy_cfg(struct r8152 *tp) { - r8152b_enable_eee(tp); + rtl_eee_enable(tp, tp->eee_en); r8152_aldps_en(tp, true); r8152b_enable_fc(tp);
@@@ -3486,6 -3267,36 +3489,6 @@@ static void r8153b_aldps_en(struct r815 r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_ALDPS); }
-static void r8153_eee_en(struct r8152 *tp, bool enable) -{ - u32 ocp_data; - u16 config; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - config = ocp_reg_read(tp, OCP_EEE_CFG); - - if (enable) { - ocp_data |= EEE_RX_EN | EEE_TX_EN; - config |= EEE10_EN; - } else { - ocp_data &= ~(EEE_RX_EN | EEE_TX_EN); - config &= ~EEE10_EN; - } - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); - ocp_reg_write(tp, OCP_EEE_CFG, config); -} - -static void r8153b_eee_en(struct r8152 *tp, bool enable) -{ - r8153_eee_en(tp, enable); - - if (enable) - r8153b_ups_flags_w1w0(tp, UPS_FLAGS_EN_EEE, 0); - else - r8153b_ups_flags_w1w0(tp, 0, UPS_FLAGS_EN_EEE); -} - static void r8153b_enable_fc(struct r8152 *tp) { r8152b_enable_fc(tp); @@@ -3501,7 -3312,8 +3504,7 @@@ static void r8153_hw_phy_cfg(struct r81 r8153_aldps_en(tp, false);
/* disable EEE before updating the PHY parameters */ - r8153_eee_en(tp, false); - ocp_reg_write(tp, OCP_EEE_ADV, 0); + rtl_eee_enable(tp, false);
if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); @@@ -3532,8 -3344,8 +3535,8 @@@ sram_write(tp, SRAM_10M_AMP1, 0x00af); sram_write(tp, SRAM_10M_AMP2, 0x0208);
- r8153_eee_en(tp, true); - ocp_reg_write(tp, OCP_EEE_ADV, MDIO_EEE_1000T | MDIO_EEE_100TX); + if (tp->eee_en) + rtl_eee_enable(tp, true);
r8153_aldps_en(tp, true); r8152b_enable_fc(tp); @@@ -3573,7 -3385,8 +3576,7 @@@ static void r8153b_hw_phy_cfg(struct r8 r8153b_aldps_en(tp, false);
/* disable EEE before updating the PHY parameters */ - r8153b_eee_en(tp, false); - ocp_reg_write(tp, OCP_EEE_ADV, 0); + rtl_eee_enable(tp, false);
r8153b_green_en(tp, test_bit(GREEN_ETHERNET, &tp->flags));
@@@ -3635,8 -3448,8 +3638,8 @@@
r8153b_ups_flags_w1w0(tp, ups_flags, 0);
- r8153b_eee_en(tp, true); - ocp_reg_write(tp, OCP_EEE_ADV, MDIO_EEE_1000T | MDIO_EEE_100TX); + if (tp->eee_en) + rtl_eee_enable(tp, true);
r8153b_aldps_en(tp, true); r8153b_enable_fc(tp); @@@ -4057,11 -3870,9 +4060,11 @@@ static void set_carrier(struct r8152 *t } else { if (netif_carrier_ok(netdev)) { netif_carrier_off(netdev); + tasklet_disable(&tp->tx_tl); napi_disable(napi); tp->rtl_ops.disable(tp); napi_enable(napi); + tasklet_enable(&tp->tx_tl); netif_info(tp, link, netdev, "carrier off\n"); } } @@@ -4094,10 -3905,10 +4097,10 @@@ static void rtl_work_func_t(struct work if (test_and_clear_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev);
- /* don't schedule napi before linking */ - if (test_and_clear_bit(SCHEDULE_NAPI, &tp->flags) && + /* don't schedule tasket before linking */ + if (test_and_clear_bit(SCHEDULE_TASKLET, &tp->flags) && netif_carrier_ok(tp->netdev)) - napi_schedule(&tp->napi); + tasklet_schedule(&tp->tx_tl);
mutex_unlock(&tp->control);
@@@ -4183,7 -3994,6 +4186,7 @@@ static int rtl8152_open(struct net_devi goto out_unlock; } napi_enable(&tp->napi); + tasklet_enable(&tp->tx_tl);
mutex_unlock(&tp->control);
@@@ -4211,7 -4021,6 +4214,7 @@@ static int rtl8152_close(struct net_dev #ifdef CONFIG_PM_SLEEP unregister_pm_notifier(&tp->pm_notifier); #endif + tasklet_disable(&tp->tx_tl); if (!test_bit(RTL8152_UNPLUG, &tp->flags)) napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); @@@ -4481,7 -4290,6 +4484,7 @@@ static int rtl8152_pre_reset(struct usb return 0;
netif_stop_queue(netdev); + tasklet_disable(&tp->tx_tl); napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); @@@ -4525,7 -4333,6 +4528,7 @@@ static int rtl8152_post_reset(struct us }
napi_enable(&tp->napi); + tasklet_enable(&tp->tx_tl); netif_wake_queue(netdev); usb_submit_urb(tp->intr_urb, GFP_KERNEL);
@@@ -4679,12 -4486,10 +4682,12 @@@ static int rtl8152_system_suspend(struc
clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); + tasklet_disable(&tp->tx_tl); napi_disable(napi); cancel_delayed_work_sync(&tp->schedule); tp->rtl_ops.down(tp); napi_enable(napi); + tasklet_enable(&tp->tx_tl); }
return 0; @@@ -4927,7 -4732,7 +4930,7 @@@ static void rtl8152_get_strings(struct
static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) { - u32 ocp_data, lp, adv, supported = 0; + u32 lp, adv, supported = 0; u16 val;
val = r8152_mmd_read(tp, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); @@@ -4939,10 -4744,13 +4942,10 @@@ val = r8152_mmd_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE); lp = mmd_eee_adv_to_ethtool_adv_t(val);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data &= EEE_RX_EN | EEE_TX_EN; - - eee->eee_enabled = !!ocp_data; + eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); eee->supported = supported; - eee->advertised = adv; + eee->advertised = tp->eee_adv; eee->lp_advertised = lp;
return 0; @@@ -4952,17 -4760,19 +4955,17 @@@ static int r8152_set_eee(struct r8152 * { u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised);
- r8152_eee_en(tp, eee->eee_enabled); + tp->eee_en = eee->eee_enabled; + tp->eee_adv = val;
- if (!eee->eee_enabled) - val = 0; - - r8152_mmd_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val); + rtl_eee_enable(tp, tp->eee_en);
return 0; }
static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) { - u32 ocp_data, lp, adv, supported = 0; + u32 lp, adv, supported = 0; u16 val;
val = ocp_reg_read(tp, OCP_EEE_ABLE); @@@ -4974,15 -4784,46 +4977,15 @@@ val = ocp_reg_read(tp, OCP_EEE_LPABLE); lp = mmd_eee_adv_to_ethtool_adv_t(val);
- ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); - ocp_data &= EEE_RX_EN | EEE_TX_EN; - - eee->eee_enabled = !!ocp_data; + eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); eee->supported = supported; - eee->advertised = adv; + eee->advertised = tp->eee_adv; eee->lp_advertised = lp;
return 0; }
-static int r8153_set_eee(struct r8152 *tp, struct ethtool_eee *eee) -{ - u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); - - r8153_eee_en(tp, eee->eee_enabled); - - if (!eee->eee_enabled) - val = 0; - - ocp_reg_write(tp, OCP_EEE_ADV, val); - - return 0; -} - -static int r8153b_set_eee(struct r8152 *tp, struct ethtool_eee *eee) -{ - u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); - - r8153b_eee_en(tp, eee->eee_enabled); - - if (!eee->eee_enabled) - val = 0; - - ocp_reg_write(tp, OCP_EEE_ADV, val); - - return 0; -} - static int rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) { @@@ -5116,77 -4957,6 +5119,77 @@@ static int rtl8152_set_coalesce(struct return ret; }
+static int rtl8152_get_tunable(struct net_device *netdev, + const struct ethtool_tunable *tunable, void *d) +{ + struct r8152 *tp = netdev_priv(netdev); + + switch (tunable->id) { + case ETHTOOL_RX_COPYBREAK: + *(u32 *)d = tp->rx_copybreak; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int rtl8152_set_tunable(struct net_device *netdev, + const struct ethtool_tunable *tunable, + const void *d) +{ + struct r8152 *tp = netdev_priv(netdev); + u32 val; + + switch (tunable->id) { + case ETHTOOL_RX_COPYBREAK: + val = *(u32 *)d; + if (val < ETH_ZLEN) { + netif_err(tp, rx_err, netdev, + "Invalid rx copy break value\n"); + return -EINVAL; + } + + if (tp->rx_copybreak != val) { + napi_disable(&tp->napi); + tp->rx_copybreak = val; + napi_enable(&tp->napi); + } + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static void rtl8152_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct r8152 *tp = netdev_priv(netdev); + + ring->rx_max_pending = RTL8152_RX_MAX_PENDING; + ring->rx_pending = tp->rx_pending; +} + +static int rtl8152_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct r8152 *tp = netdev_priv(netdev); + + if (ring->rx_pending < (RTL8152_MAX_RX * 2)) + return -EINVAL; + + if (tp->rx_pending != ring->rx_pending) { + napi_disable(&tp->napi); + tp->rx_pending = ring->rx_pending; + napi_enable(&tp->napi); + } + + return 0; +} + static const struct ethtool_ops ops = { .get_drvinfo = rtl8152_get_drvinfo, .get_link = ethtool_op_get_link, @@@ -5204,10 -4974,6 +5207,10 @@@ .set_eee = rtl_ethtool_set_eee, .get_link_ksettings = rtl8152_get_link_ksettings, .set_link_ksettings = rtl8152_set_link_ksettings, + .get_tunable = rtl8152_get_tunable, + .set_tunable = rtl8152_set_tunable, + .get_ringparam = rtl8152_get_ringparam, + .set_ringparam = rtl8152_set_ringparam, };
static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@@ -5352,9 -5118,6 +5355,9 @@@ static int rtl_ops_init(struct r8152 *t ops->in_nway = rtl8152_in_nway; ops->hw_phy_cfg = r8152b_hw_phy_cfg; ops->autosuspend_en = rtl_runtime_suspend_enable; + tp->rx_buf_sz = 16 * 1024; + tp->eee_en = true; + tp->eee_adv = MDIO_EEE_100TX; break;
case RTL_VER_03: @@@ -5368,13 -5131,10 +5371,13 @@@ ops->down = rtl8153_down; ops->unload = rtl8153_unload; ops->eee_get = r8153_get_eee; - ops->eee_set = r8153_set_eee; + ops->eee_set = r8152_set_eee; ops->in_nway = rtl8153_in_nway; ops->hw_phy_cfg = r8153_hw_phy_cfg; ops->autosuspend_en = rtl8153_runtime_enable; + tp->rx_buf_sz = 32 * 1024; + tp->eee_en = true; + tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX; break;
case RTL_VER_08: @@@ -5386,13 -5146,10 +5389,13 @@@ ops->down = rtl8153b_down; ops->unload = rtl8153b_unload; ops->eee_get = r8153_get_eee; - ops->eee_set = r8153b_set_eee; + ops->eee_set = r8152_set_eee; ops->in_nway = rtl8153_in_nway; ops->hw_phy_cfg = r8153b_hw_phy_cfg; ops->autosuspend_en = rtl8153b_runtime_enable; + tp->rx_buf_sz = 32 * 1024; + tp->eee_en = true; + tp->eee_adv = MDIO_EEE_1000T | MDIO_EEE_100TX; break;
default: @@@ -5514,8 -5271,6 +5517,8 @@@ static int rtl8152_probe(struct usb_int 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); + tasklet_init(&tp->tx_tl, bottom_half, (unsigned long)tp); + tasklet_disable(&tp->tx_tl);
netdev->netdev_ops = &rtl8152_netdev_ops; netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; @@@ -5569,9 -5324,6 +5572,9 @@@ tp->speed = tp->mii.supports_gmii ? SPEED_1000 : SPEED_100; tp->duplex = DUPLEX_FULL;
+ tp->rx_copybreak = RTL8152_RXFG_HEADSZ; + tp->rx_pending = 10 * RTL8152_MAX_RX; + intf->needs_remote_wakeup = 1;
tp->rtl_ops.init(tp); @@@ -5602,7 -5354,6 +5605,7 @@@
out1: netif_napi_del(&tp->napi); + tasklet_kill(&tp->tx_tl); usb_set_intfdata(intf, NULL); out: free_netdev(netdev); @@@ -5619,7 -5370,6 +5622,7 @@@ static void rtl8152_disconnect(struct u
netif_napi_del(&tp->napi); unregister_netdev(tp->netdev); + tasklet_kill(&tp->tx_tl); cancel_delayed_work_sync(&tp->hw_phy_work); tp->rtl_ops.unload(tp); free_netdev(tp->netdev); diff --combined drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index b74bd58f3f45,a7bc00d1296f..d6499763f0dd --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@@ -3327,10 -3327,20 +3327,20 @@@ static int iwl_mvm_mac_sta_state(struc /* enable beacon filtering */ WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
+ /* + * Now that the station is authorized, i.e., keys were already + * installed, need to indicate to the FW that + * multicast data frames can be forwarded to the driver + */ + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band, true); } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { + /* Multicast data frames are no longer allowed */ + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + /* disable beacon filtering */ ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); WARN_ON(ret && @@@ -4035,8 -4045,7 +4045,8 @@@ out_unlock return ret; }
-static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw) +static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
diff --combined drivers/s390/net/qeth_core_main.c index 8b4ea5f2832b,6502b148541e..a7868c8133ee --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@@ -63,16 -63,14 +63,16 @@@ static struct device *qeth_core_root_de static struct lock_class_key qdio_out_skb_queue_key;
static void qeth_issue_next_read_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob); + struct qeth_cmd_buffer *iob, + unsigned int data_length); static void qeth_free_buffer_pool(struct qeth_card *); static int qeth_qdio_establish(struct qeth_card *); static void qeth_free_qdio_queues(struct qeth_card *card); static void qeth_notify_skbs(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, enum iucv_tx_notify notification); -static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf); +static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error, + int budget); static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
static void qeth_close_dev_handler(struct work_struct *work) @@@ -412,7 -410,7 +412,7 @@@ static void qeth_cleanup_handled_pendin /* release here to avoid interleaving between outbound tasklet and inbound tasklet regarding notifications and lifecycle */ - qeth_release_skbs(c); + qeth_tx_complete_buf(c, forced_cleanup, 0);
c = f->next_pending; WARN_ON_ONCE(head->next_pending != f); @@@ -538,28 -536,50 +538,28 @@@ static int qeth_issue_next_read(struct return ret; }
-static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) -{ - struct qeth_reply *reply; - - reply = kzalloc(sizeof(*reply), GFP_KERNEL); - if (reply) { - refcount_set(&reply->refcnt, 1); - init_completion(&reply->received); - spin_lock_init(&reply->lock); - } - return reply; -} - -static void qeth_get_reply(struct qeth_reply *reply) -{ - refcount_inc(&reply->refcnt); -} - -static void qeth_put_reply(struct qeth_reply *reply) -{ - if (refcount_dec_and_test(&reply->refcnt)) - kfree(reply); -} - -static void qeth_enqueue_reply(struct qeth_card *card, struct qeth_reply *reply) +static void qeth_enqueue_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob) { spin_lock_irq(&card->lock); - list_add_tail(&reply->list, &card->cmd_waiter_list); + list_add_tail(&iob->list, &card->cmd_waiter_list); spin_unlock_irq(&card->lock); }
-static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply) +static void qeth_dequeue_cmd(struct qeth_card *card, + struct qeth_cmd_buffer *iob) { spin_lock_irq(&card->lock); - list_del(&reply->list); + list_del(&iob->list); spin_unlock_irq(&card->lock); }
-void qeth_notify_reply(struct qeth_reply *reply, int reason) +void qeth_notify_cmd(struct qeth_cmd_buffer *iob, int reason) { - reply->rc = reason; - complete(&reply->received); + iob->rc = reason; + complete(&iob->done); } -EXPORT_SYMBOL_GPL(qeth_notify_reply); +EXPORT_SYMBOL_GPL(qeth_notify_cmd);
static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, struct qeth_card *card) @@@ -637,14 -657,14 +637,14 @@@ static struct qeth_ipa_cmd *qeth_check_
void qeth_clear_ipacmd_list(struct qeth_card *card) { - struct qeth_reply *reply; + struct qeth_cmd_buffer *iob; unsigned long flags;
QETH_CARD_TEXT(card, 4, "clipalst");
spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(reply, &card->cmd_waiter_list, list) - qeth_notify_reply(reply, -EIO); + list_for_each_entry(iob, &card->cmd_waiter_list, list) + qeth_notify_cmd(iob, -EIO); spin_unlock_irqrestore(&card->lock, flags); } EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); @@@ -673,6 -693,8 +673,6 @@@ static int qeth_check_idx_response(stru void qeth_put_cmd(struct qeth_cmd_buffer *iob) { if (refcount_dec_and_test(&iob->ref_count)) { - if (iob->reply) - qeth_put_reply(iob->reply); kfree(iob->data); kfree(iob); } @@@ -680,15 -702,17 +680,15 @@@ EXPORT_SYMBOL_GPL(qeth_put_cmd);
static void qeth_release_buffer_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob, + unsigned int data_length) { qeth_put_cmd(iob); }
static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc) { - struct qeth_reply *reply = iob->reply; - - if (reply) - qeth_notify_reply(reply, rc); + qeth_notify_cmd(iob, rc); qeth_put_cmd(iob); }
@@@ -712,9 -736,6 +712,9 @@@ struct qeth_cmd_buffer *qeth_alloc_cmd( return NULL; }
+ init_completion(&iob->done); + spin_lock_init(&iob->lock); + INIT_LIST_HEAD(&iob->list); refcount_set(&iob->ref_count, 1); iob->channel = channel; iob->timeout = timeout; @@@ -724,13 -745,11 +724,13 @@@ EXPORT_SYMBOL_GPL(qeth_alloc_cmd);
static void qeth_issue_next_read_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob, + unsigned int data_length) { + struct qeth_cmd_buffer *request = NULL; struct qeth_ipa_cmd *cmd = NULL; struct qeth_reply *reply = NULL; - struct qeth_reply *r; + struct qeth_cmd_buffer *tmp; unsigned long flags; int rc = 0;
@@@ -765,39 -784,44 +765,39 @@@
/* match against pending cmd requests */ spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(r, &card->cmd_waiter_list, list) { - if ((r->seqno == QETH_IDX_COMMAND_SEQNO) || - (cmd && (r->seqno == cmd->hdr.seqno))) { - reply = r; + list_for_each_entry(tmp, &card->cmd_waiter_list, list) { + if (!IS_IPA(tmp->data) || + __ipa_cmd(tmp)->hdr.seqno == cmd->hdr.seqno) { + request = tmp; /* take the object outside the lock */ - qeth_get_reply(reply); + qeth_get_cmd(request); break; } } spin_unlock_irqrestore(&card->lock, flags);
- if (!reply) + if (!request) goto out;
+ reply = &request->reply; if (!reply->callback) { rc = 0; goto no_callback; }
- spin_lock_irqsave(&reply->lock, flags); - if (reply->rc) { + spin_lock_irqsave(&request->lock, flags); + if (request->rc) /* Bail out when the requestor has already left: */ - rc = reply->rc; - } else { - if (cmd) { - reply->offset = (u16)((char *)cmd - (char *)iob->data); - rc = reply->callback(card, reply, (unsigned long)cmd); - } else { - rc = reply->callback(card, reply, (unsigned long)iob); - } - } - spin_unlock_irqrestore(&reply->lock, flags); + rc = request->rc; + else + rc = reply->callback(card, reply, cmd ? (unsigned long)cmd : + (unsigned long)iob); + spin_unlock_irqrestore(&request->lock, flags);
no_callback: if (rc <= 0) - qeth_notify_reply(reply, rc); - qeth_put_reply(reply); - + qeth_notify_cmd(request, rc); + qeth_put_cmd(request); out: memcpy(&card->seqno.pdu_hdr_ack, QETH_PDU_HEADER_SEQ_NO(iob->data), @@@ -1048,16 -1072,8 +1048,16 @@@ static void qeth_irq(struct ccw_device } }
- if (iob && iob->callback) - iob->callback(card, iob); + if (iob) { + /* sanity check: */ + if (irb->scsw.cmd.count > iob->length) { + qeth_cancel_cmd(iob, -EIO); + goto out; + } + if (iob->callback) + iob->callback(card, iob, + iob->length - irb->scsw.cmd.count); + }
out: wake_up(&card->wait_q); @@@ -1078,52 -1094,22 +1078,52 @@@ static void qeth_notify_skbs(struct qet } }
-static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf) +static void qeth_tx_complete_buf(struct qeth_qdio_out_buffer *buf, bool error, + int budget) { + struct qeth_qdio_out_q *queue = buf->q; struct sk_buff *skb;
/* release may never happen from within CQ tasklet scope */ WARN_ON_ONCE(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ);
if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING) - qeth_notify_skbs(buf->q, buf, TX_NOTIFY_GENERALERROR); + qeth_notify_skbs(queue, buf, TX_NOTIFY_GENERALERROR);
- while ((skb = __skb_dequeue(&buf->skb_list)) != NULL) - consume_skb(skb); + /* Empty buffer? */ + if (buf->next_element_to_fill == 0) + return; + + QETH_TXQ_STAT_INC(queue, bufs); + QETH_TXQ_STAT_ADD(queue, buf_elements, buf->next_element_to_fill); + while ((skb = __skb_dequeue(&buf->skb_list)) != NULL) { + unsigned int bytes = qdisc_pkt_len(skb); + bool is_tso = skb_is_gso(skb); + unsigned int packets; + + packets = is_tso ? skb_shinfo(skb)->gso_segs : 1; + if (error) { + QETH_TXQ_STAT_ADD(queue, tx_errors, packets); + } else { + QETH_TXQ_STAT_ADD(queue, tx_packets, packets); + QETH_TXQ_STAT_ADD(queue, tx_bytes, bytes); + if (skb->ip_summed == CHECKSUM_PARTIAL) + QETH_TXQ_STAT_ADD(queue, skbs_csum, packets); + if (skb_is_nonlinear(skb)) + QETH_TXQ_STAT_INC(queue, skbs_sg); + if (is_tso) { + QETH_TXQ_STAT_INC(queue, skbs_tso); + QETH_TXQ_STAT_ADD(queue, tso_bytes, bytes); + } + } + + napi_consume_skb(skb, budget); + } }
static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf) + struct qeth_qdio_out_buffer *buf, + bool error, int budget) { int i;
@@@ -1131,7 -1117,7 +1131,7 @@@ if (buf->buffer->element[0].sflags & SBAL_SFLAGS0_PCI_REQ) atomic_dec(&queue->set_pci_flags_count);
- qeth_release_skbs(buf); + qeth_tx_complete_buf(buf, error, budget);
for (i = 0; i < queue->max_elements; ++i) { if (buf->buffer->element[i].addr && buf->is_header[i]) @@@ -1142,7 -1128,6 +1142,7 @@@
qeth_scrub_qdio_buffer(buf->buffer, queue->max_elements); buf->next_element_to_fill = 0; + buf->bytes = 0; atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); }
@@@ -1154,7 -1139,7 +1154,7 @@@ static void qeth_drain_output_queue(str if (!q->bufs[j]) continue; qeth_cleanup_handled_pending(q, j, 1); - qeth_clear_output_buffer(q, q->bufs[j]); + qeth_clear_output_buffer(q, q->bufs[j], true, 0); if (free) { kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]); q->bufs[j] = NULL; @@@ -1667,6 -1652,7 +1667,6 @@@ static void qeth_mpc_finalize_cmd(struc memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
- iob->reply->seqno = QETH_IDX_COMMAND_SEQNO; iob->callback = qeth_release_buffer_cb; }
@@@ -1717,19 -1703,29 +1717,19 @@@ static int qeth_send_control_data(struc void *reply_param) { struct qeth_channel *channel = iob->channel; + struct qeth_reply *reply = &iob->reply; long timeout = iob->timeout; int rc; - struct qeth_reply *reply = NULL;
QETH_CARD_TEXT(card, 2, "sendctl");
- reply = qeth_alloc_reply(card); - if (!reply) { - qeth_put_cmd(iob); - return -ENOMEM; - } reply->callback = reply_cb; reply->param = reply_param;
- /* pairs with qeth_put_cmd(): */ - qeth_get_reply(reply); - iob->reply = reply; - timeout = wait_event_interruptible_timeout(card->wait_q, qeth_trylock_channel(channel), timeout); if (timeout <= 0) { - qeth_put_reply(reply); qeth_put_cmd(iob); return (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; } @@@ -1738,10 -1734,7 +1738,10 @@@ iob->finalize(card, iob); QETH_DBF_HEX(CTRL, 2, iob->data, min(iob->length, QETH_DBF_CTRL_LEN));
- qeth_enqueue_reply(card, reply); + qeth_enqueue_cmd(card, iob); + + /* This pairs with iob->callback, and keeps the iob alive after IO: */ + qeth_get_cmd(iob);
QETH_CARD_TEXT(card, 6, "noirqpnd"); spin_lock_irq(get_ccwdev_lock(channel->ccwdev)); @@@ -1752,74 -1745,51 +1752,74 @@@ QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", CARD_DEVID(card), rc); QETH_CARD_TEXT_(card, 2, " err%d", rc); - qeth_dequeue_reply(card, reply); - qeth_put_reply(reply); + qeth_dequeue_cmd(card, iob); qeth_put_cmd(iob); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); - return rc; + goto out; }
- timeout = wait_for_completion_interruptible_timeout(&reply->received, + timeout = wait_for_completion_interruptible_timeout(&iob->done, timeout); if (timeout <= 0) rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME;
- qeth_dequeue_reply(card, reply); + qeth_dequeue_cmd(card, iob);
if (reply_cb) { /* Wait until the callback for a late reply has completed: */ - spin_lock_irq(&reply->lock); + spin_lock_irq(&iob->lock); if (rc) /* Zap any callback that's still pending: */ - reply->rc = rc; - spin_unlock_irq(&reply->lock); + iob->rc = rc; + spin_unlock_irq(&iob->lock); }
if (!rc) - rc = reply->rc; - qeth_put_reply(reply); + rc = iob->rc; + +out: + qeth_put_cmd(iob); return rc; }
+struct qeth_node_desc { + struct node_descriptor nd1; + struct node_descriptor nd2; + struct node_descriptor nd3; +}; + static void qeth_read_conf_data_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob, + unsigned int data_length) { - unsigned char *prcd = iob->data; + struct qeth_node_desc *nd = (struct qeth_node_desc *) iob->data; + int rc = 0; + u8 *tag;
QETH_CARD_TEXT(card, 2, "cfgunit"); - card->info.chpid = prcd[30]; - card->info.unit_addr2 = prcd[31]; - card->info.cula = prcd[63]; - card->info.is_vm_nic = ((prcd[0x10] == _ascebc['V']) && - (prcd[0x11] == _ascebc['M'])); - card->info.use_v1_blkt = prcd[74] == 0xF0 && prcd[75] == 0xF0 && - prcd[76] >= 0xF1 && prcd[76] <= 0xF4; - - qeth_notify_reply(iob->reply, 0); + + if (data_length < sizeof(*nd)) { + rc = -EINVAL; + goto out; + } + + card->info.is_vm_nic = nd->nd1.plant[0] == _ascebc['V'] && + nd->nd1.plant[1] == _ascebc['M']; + tag = (u8 *)&nd->nd1.tag; + card->info.chpid = tag[0]; + card->info.unit_addr2 = tag[1]; + + tag = (u8 *)&nd->nd2.tag; + card->info.cula = tag[1]; + + card->info.use_v1_blkt = nd->nd3.model[0] == 0xF0 && + nd->nd3.model[1] == 0xF0 && + nd->nd3.model[2] >= 0xF1 && + nd->nd3.model[2] <= 0xF4; + +out: + qeth_notify_cmd(iob, rc); qeth_put_cmd(iob); }
@@@ -1833,8 -1803,6 +1833,8 @@@ static int qeth_read_conf_data(struct q ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD); if (!ciw || ciw->cmd == 0) return -EOPNOTSUPP; + if (ciw->count < sizeof(struct qeth_node_desc)) + return -EINVAL;
iob = qeth_alloc_cmd(channel, ciw->count, 1, QETH_RCD_TIMEOUT); if (!iob) @@@ -1882,8 -1850,7 +1882,8 @@@ static int qeth_idx_check_activate_resp }
static void qeth_idx_activate_read_channel_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob, + unsigned int data_length) { struct qeth_channel *channel = iob->channel; u16 peer_level; @@@ -1911,13 -1878,12 +1911,13 @@@ QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH);
out: - qeth_notify_reply(iob->reply, rc); + qeth_notify_cmd(iob, rc); qeth_put_cmd(iob); }
static void qeth_idx_activate_write_channel_cb(struct qeth_card *card, - struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob, + unsigned int data_length) { struct qeth_channel *channel = iob->channel; u16 peer_level; @@@ -1939,7 -1905,7 +1939,7 @@@ }
out: - qeth_notify_reply(iob->reply, rc); + qeth_notify_cmd(iob, rc); qeth_put_cmd(iob); }
@@@ -2287,14 -2253,6 +2287,14 @@@ static struct qeth_qdio_out_q *qeth_all return q; }
+static void qeth_tx_completion_timer(struct timer_list *timer) +{ + struct qeth_qdio_out_q *queue = from_timer(queue, timer, timer); + + napi_schedule(&queue->napi); + QETH_TXQ_STAT_INC(queue, completion_timer); +} + static int qeth_alloc_qdio_queues(struct qeth_card *card) { int i, j; @@@ -2316,22 -2274,17 +2316,22 @@@
/* outbound */ for (i = 0; i < card->qdio.no_out_queues; ++i) { - card->qdio.out_qs[i] = qeth_alloc_output_queue(); - if (!card->qdio.out_qs[i]) + struct qeth_qdio_out_q *queue; + + queue = qeth_alloc_output_queue(); + if (!queue) goto out_freeoutq; QETH_CARD_TEXT_(card, 2, "outq %i", i); - QETH_CARD_HEX(card, 2, &card->qdio.out_qs[i], sizeof(void *)); - card->qdio.out_qs[i]->card = card; - card->qdio.out_qs[i]->queue_no = i; + QETH_CARD_HEX(card, 2, &queue, sizeof(void *)); + card->qdio.out_qs[i] = queue; + queue->card = card; + queue->queue_no = i; + timer_setup(&queue->timer, qeth_tx_completion_timer, 0); + /* give outbound qeth_qdio_buffers their qdio_buffers */ for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) { - WARN_ON(card->qdio.out_qs[i]->bufs[j] != NULL); - if (qeth_init_qdio_out_buf(card->qdio.out_qs[i], j)) + WARN_ON(queue->bufs[j]); + if (qeth_init_qdio_out_buf(queue, j)) goto out_freeoutqbufs; } } @@@ -2671,12 -2624,9 +2671,12 @@@ int qeth_init_qdio_queues(struct qeth_c queue->max_elements = QETH_MAX_BUFFER_ELEMENTS(card); queue->next_buf_to_fill = 0; queue->do_pack = 0; + queue->prev_hdr = NULL; + queue->bulk_start = 0; atomic_set(&queue->used_buffers, 0); atomic_set(&queue->set_pci_flags_count, 0); atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED); + netdev_tx_reset_queue(netdev_get_tx_queue(card->dev, i)); } return 0; } @@@ -2688,7 -2638,8 +2688,7 @@@ static void qeth_ipa_finalize_cmd(struc qeth_mpc_finalize_cmd(card, iob);
/* override with IPA-specific values: */ - __ipa_cmd(iob)->hdr.seqno = card->seqno.ipa; - iob->reply->seqno = card->seqno.ipa++; + __ipa_cmd(iob)->hdr.seqno = card->seqno.ipa++; }
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, @@@ -3245,7 -3196,6 +3245,7 @@@ static int qeth_switch_to_nonpacking_if static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int index, int count) { + struct qeth_card *card = queue->card; struct qeth_qdio_out_buffer *buf; int rc; int i; @@@ -3289,17 -3239,14 +3289,17 @@@ } }
- QETH_TXQ_STAT_ADD(queue, bufs, count); qdio_flags = QDIO_FLAG_SYNC_OUTPUT; if (atomic_read(&queue->set_pci_flags_count)) qdio_flags |= QDIO_FLAG_PCI_OUT; rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags, queue->queue_no, index, count); + + /* Fake the TX completion interrupt: */ + if (IS_IQD(card)) + napi_schedule(&queue->napi); + if (rc) { - QETH_TXQ_STAT_ADD(queue, tx_errors, count); /* ignore temporary SIGA errors without busy condition */ if (rc == -ENOBUFS) return; @@@ -3316,14 -3263,6 +3316,14 @@@ } }
+static void qeth_flush_queue(struct qeth_qdio_out_q *queue) +{ + qeth_flush_buffers(queue, queue->bulk_start, 1); + + queue->bulk_start = QDIO_BUFNR(queue->bulk_start + 1); + queue->prev_hdr = NULL; +} + static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) { int index; @@@ -3485,12 -3424,48 +3485,12 @@@ static void qeth_qdio_output_handler(st int bidx = i % QDIO_MAX_BUFFERS_PER_Q; buffer = queue->bufs[bidx]; qeth_handle_send_error(card, buffer, qdio_error); - - if (queue->bufstates && - (queue->bufstates[bidx].flags & - QDIO_OUTBUF_STATE_FLAG_PENDING) != 0) { - WARN_ON_ONCE(card->options.cq != QETH_CQ_ENABLED); - - if (atomic_cmpxchg(&buffer->state, - QETH_QDIO_BUF_PRIMED, - QETH_QDIO_BUF_PENDING) == - QETH_QDIO_BUF_PRIMED) { - qeth_notify_skbs(queue, buffer, - TX_NOTIFY_PENDING); - } - QETH_CARD_TEXT_(queue->card, 5, "pel%d", bidx); - - /* prepare the queue slot for re-use: */ - qeth_scrub_qdio_buffer(buffer->buffer, - queue->max_elements); - if (qeth_init_qdio_out_buf(queue, bidx)) { - QETH_CARD_TEXT(card, 2, "outofbuf"); - qeth_schedule_recovery(card); - } - } else { - if (card->options.cq == QETH_CQ_ENABLED) { - enum iucv_tx_notify n; - - n = qeth_compute_cq_notification( - buffer->buffer->element[15].sflags, 0); - qeth_notify_skbs(queue, buffer, n); - } - - qeth_clear_output_buffer(queue, buffer); - } - qeth_cleanup_handled_pending(queue, bidx, 0); + qeth_clear_output_buffer(queue, buffer, qdio_error, 0); } + atomic_sub(count, &queue->used_buffers); - /* check if we need to do something on this outbound queue */ - if (!IS_IQD(card)) - qeth_check_outbound_queue(queue); + qeth_check_outbound_queue(queue);
- if (IS_IQD(card)) - __queue = qeth_iqd_translate_txq(dev, __queue); txq = netdev_get_tx_queue(dev, __queue); /* xmit may have observed the full-condition, but not yet stopped the * txq. In which case the code below won't trigger. So before returning, @@@ -3560,7 -3535,7 +3560,7 @@@ static int qeth_get_elements_for_frags( int cnt, elements = 0;
for (cnt = 0; cnt < skb_shinfo(skb)->nr_frags; cnt++) { - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[cnt]; + skb_frag_t *frag = &skb_shinfo(skb)->frags[cnt];
elements += qeth_get_elements_for_range( (addr_t)skb_frag_address(frag), @@@ -3679,32 -3654,9 +3679,32 @@@ check_layout return 0; }
-static void __qeth_fill_buffer(struct sk_buff *skb, - struct qeth_qdio_out_buffer *buf, - bool is_first_elem, unsigned int offset) +static bool qeth_iqd_may_bulk(struct qeth_qdio_out_q *queue, + struct qeth_qdio_out_buffer *buffer, + struct sk_buff *curr_skb, + struct qeth_hdr *curr_hdr) +{ + struct qeth_hdr *prev_hdr = queue->prev_hdr; + + if (!prev_hdr) + return true; + + /* All packets must have the same target: */ + if (curr_hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) { + struct sk_buff *prev_skb = skb_peek(&buffer->skb_list); + + return ether_addr_equal(eth_hdr(prev_skb)->h_dest, + eth_hdr(curr_skb)->h_dest) && + qeth_l2_same_vlan(&prev_hdr->hdr.l2, &curr_hdr->hdr.l2); + } + + return qeth_l3_same_next_hop(&prev_hdr->hdr.l3, &curr_hdr->hdr.l3) && + qeth_l3_iqd_same_vlan(&prev_hdr->hdr.l3, &curr_hdr->hdr.l3); +} + +static unsigned int __qeth_fill_buffer(struct sk_buff *skb, + struct qeth_qdio_out_buffer *buf, + bool is_first_elem, unsigned int offset) { struct qdio_buffer *buffer = buf->buffer; int element = buf->next_element_to_fill; @@@ -3761,21 -3713,24 +3761,21 @@@ if (buffer->element[element - 1].eflags) buffer->element[element - 1].eflags = SBAL_EFLAGS_LAST_FRAG; buf->next_element_to_fill = element; + return element; }
/** * qeth_fill_buffer() - map skb into an output buffer - * @queue: QDIO queue to submit the buffer on * @buf: buffer to transport the skb * @skb: skb to map into the buffer * @hdr: qeth_hdr for this skb. Either at skb->data, or allocated * from qeth_core_header_cache. * @offset: when mapping the skb, start at skb->data + offset * @hd_len: if > 0, build a dedicated header element of this size - * flush: Prepare the buffer to be flushed, regardless of its fill level. */ -static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, - struct qeth_qdio_out_buffer *buf, - struct sk_buff *skb, struct qeth_hdr *hdr, - unsigned int offset, unsigned int hd_len, - bool flush) +static unsigned int qeth_fill_buffer(struct qeth_qdio_out_buffer *buf, + struct sk_buff *skb, struct qeth_hdr *hdr, + unsigned int offset, unsigned int hd_len) { struct qdio_buffer *buffer = buf->buffer; bool is_first_elem = true; @@@ -3795,22 -3750,35 +3795,22 @@@ buf->next_element_to_fill++; }
- __qeth_fill_buffer(skb, buf, is_first_elem, offset); - - if (!queue->do_pack) { - QETH_CARD_TEXT(queue->card, 6, "fillbfnp"); - } else { - QETH_CARD_TEXT(queue->card, 6, "fillbfpa"); - - QETH_TXQ_STAT_INC(queue, skbs_pack); - /* If the buffer still has free elements, keep using it. */ - if (!flush && - buf->next_element_to_fill < queue->max_elements) - return 0; - } - - /* flush out the buffer */ - atomic_set(&buf->state, QETH_QDIO_BUF_PRIMED); - queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % - QDIO_MAX_BUFFERS_PER_Q; - return 1; + return __qeth_fill_buffer(skb, buf, is_first_elem, offset); }
-static int qeth_do_send_packet_fast(struct qeth_qdio_out_q *queue, - struct sk_buff *skb, struct qeth_hdr *hdr, - unsigned int offset, unsigned int hd_len) +static int __qeth_xmit(struct qeth_card *card, struct qeth_qdio_out_q *queue, + struct sk_buff *skb, unsigned int elements, + struct qeth_hdr *hdr, unsigned int offset, + unsigned int hd_len) { - int index = queue->next_buf_to_fill; - struct qeth_qdio_out_buffer *buffer = queue->bufs[index]; + struct qeth_qdio_out_buffer *buffer = queue->bufs[queue->bulk_start]; + unsigned int bytes = qdisc_pkt_len(skb); + unsigned int next_element; struct netdev_queue *txq; bool stopped = false; + bool flush; + + txq = netdev_get_tx_queue(card->dev, skb_get_queue_mapping(skb));
/* Just a sanity check, the wake/stop logic should ensure that we always * get a free buffer. @@@ -3818,19 -3786,9 +3818,19 @@@ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) return -EBUSY;
- txq = netdev_get_tx_queue(queue->card->dev, skb_get_queue_mapping(skb)); + if ((buffer->next_element_to_fill + elements > queue->max_elements) || + !qeth_iqd_may_bulk(queue, buffer, skb, hdr)) { + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + qeth_flush_queue(queue); + buffer = queue->bufs[queue->bulk_start]; + + /* Sanity-check again: */ + if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) + return -EBUSY; + }
- if (atomic_inc_return(&queue->used_buffers) >= QDIO_MAX_BUFFERS_PER_Q) { + if (buffer->next_element_to_fill == 0 && + atomic_inc_return(&queue->used_buffers) >= QDIO_MAX_BUFFERS_PER_Q) { /* If a TX completion happens right _here_ and misses to wake * the txq, then our re-check below will catch the race. */ @@@ -3839,17 -3797,8 +3839,17 @@@ stopped = true; }
- qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len, stopped); - qeth_flush_buffers(queue, index, 1); + next_element = qeth_fill_buffer(buffer, skb, hdr, offset, hd_len); + buffer->bytes += bytes; + queue->prev_hdr = hdr; + + flush = __netdev_tx_sent_queue(txq, bytes, + !stopped && netdev_xmit_more()); + + if (flush || next_element >= queue->max_elements) { + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + qeth_flush_queue(queue); + }
if (stopped && !qeth_out_queue_is_full(queue)) netif_tx_start_queue(txq); @@@ -3862,7 -3811,6 +3862,7 @@@ int qeth_do_send_packet(struct qeth_car int elements_needed) { struct qeth_qdio_out_buffer *buffer; + unsigned int next_element; struct netdev_queue *txq; bool stopped = false; int start_index; @@@ -3925,17 -3873,8 +3925,17 @@@ stopped = true; }
- flush_count += qeth_fill_buffer(queue, buffer, skb, hdr, offset, hd_len, - stopped); + next_element = qeth_fill_buffer(buffer, skb, hdr, offset, hd_len); + + if (queue->do_pack) + QETH_TXQ_STAT_INC(queue, skbs_pack); + if (!queue->do_pack || stopped || next_element >= queue->max_elements) { + flush_count++; + atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED); + queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % + QDIO_MAX_BUFFERS_PER_Q; + } + if (flush_count) qeth_flush_buffers(queue, start_index, flush_count); else if (!atomic_read(&queue->set_pci_flags_count)) @@@ -4002,6 -3941,7 +4002,6 @@@ int qeth_xmit(struct qeth_card *card, s unsigned int hd_len = 0; unsigned int elements; int push_len, rc; - bool is_sg;
if (is_tso) { hw_hdr_len = sizeof(struct qeth_hdr_tso); @@@ -4030,9 -3970,10 +4030,9 @@@ qeth_fill_tso_ext((struct qeth_hdr_tso *) hdr, frame_len - proto_len, skb, proto_len);
- is_sg = skb_is_nonlinear(skb); if (IS_IQD(card)) { - rc = qeth_do_send_packet_fast(queue, skb, hdr, data_offset, - hd_len); + rc = __qeth_xmit(card, queue, skb, elements, hdr, data_offset, + hd_len); } else { /* TODO: drop skb_orphan() once TX completion is fast enough */ skb_orphan(skb); @@@ -4040,9 -3981,18 +4040,9 @@@ hd_len, elements); }
- if (!rc) { - QETH_TXQ_STAT_ADD(queue, buf_elements, elements); - if (is_sg) - QETH_TXQ_STAT_INC(queue, skbs_sg); - if (is_tso) { - QETH_TXQ_STAT_INC(queue, skbs_tso); - QETH_TXQ_STAT_ADD(queue, tso_bytes, frame_len); - } - } else { - if (!push_len) - kmem_cache_free(qeth_core_header_cache, hdr); - } + if (rc && !push_len) + kmem_cache_free(qeth_core_header_cache, hdr); + return rc; } EXPORT_SYMBOL_GPL(qeth_xmit); @@@ -4064,14 -4014,23 +4064,14 @@@ static int qeth_setadp_promisc_mode_cb( return (cmd->hdr.return_code) ? -EIO : 0; }
-void qeth_setadp_promisc_mode(struct qeth_card *card) +void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable) { - enum qeth_ipa_promisc_modes mode; - struct net_device *dev = card->dev; + enum qeth_ipa_promisc_modes mode = enable ? SET_PROMISC_MODE_ON : + SET_PROMISC_MODE_OFF; struct qeth_cmd_buffer *iob; struct qeth_ipa_cmd *cmd;
QETH_CARD_TEXT(card, 4, "setprom"); - - if (((dev->flags & IFF_PROMISC) && - (card->info.promisc_mode == SET_PROMISC_MODE_ON)) || - (!(dev->flags & IFF_PROMISC) && - (card->info.promisc_mode == SET_PROMISC_MODE_OFF))) - return; - mode = SET_PROMISC_MODE_OFF; - if (dev->flags & IFF_PROMISC) - mode = SET_PROMISC_MODE_ON; QETH_CARD_TEXT_(card, 4, "mode:%x", mode);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE, @@@ -4339,16 -4298,20 +4339,16 @@@ static int qeth_mdio_read(struct net_de }
static int qeth_snmp_command_cb(struct qeth_card *card, - struct qeth_reply *reply, unsigned long sdata) + struct qeth_reply *reply, unsigned long data) { - struct qeth_ipa_cmd *cmd; - struct qeth_arp_query_info *qinfo; - unsigned char *data; + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct qeth_arp_query_info *qinfo = reply->param; + struct qeth_ipacmd_setadpparms *adp_cmd; + unsigned int data_len; void *snmp_data; - __u16 data_len;
QETH_CARD_TEXT(card, 3, "snpcmdcb");
- cmd = (struct qeth_ipa_cmd *) sdata; - data = (unsigned char *)((char *)cmd - reply->offset); - qinfo = (struct qeth_arp_query_info *) reply->param; - if (cmd->hdr.return_code) { QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code); return -EIO; @@@ -4359,14 -4322,15 +4359,14 @@@ QETH_CARD_TEXT_(card, 4, "scer2%x", cmd->hdr.return_code); return -EIO; } - data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data)); - if (cmd->data.setadapterparms.hdr.seq_no == 1) { - snmp_data = &cmd->data.setadapterparms.data.snmp; - data_len -= offsetof(struct qeth_ipa_cmd, - data.setadapterparms.data.snmp); + + adp_cmd = &cmd->data.setadapterparms; + data_len = adp_cmd->hdr.cmdlength - sizeof(adp_cmd->hdr); + if (adp_cmd->hdr.seq_no == 1) { + snmp_data = &adp_cmd->data.snmp; } else { - snmp_data = &cmd->data.setadapterparms.data.snmp.request; - data_len -= offsetof(struct qeth_ipa_cmd, - data.setadapterparms.data.snmp.request); + snmp_data = &adp_cmd->data.snmp.request; + data_len -= offsetof(struct qeth_snmp_cmd, request); }
/* check if there is enough room in userspace */ @@@ -4410,6 -4374,10 +4410,10 @@@ static int qeth_snmp_command(struct qet get_user(req_len, &ureq->hdr.req_len)) return -EFAULT;
+ /* Sanitize user input, to avoid overflows in iob size calculation: */ + if (req_len > QETH_BUFSIZE) + return -EINVAL; + iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL, req_len); if (!iob) return -ENOMEM; @@@ -4773,7 -4741,7 +4777,7 @@@ static int qeth_qdio_establish(struct q init_data.input_sbal_addr_array = in_sbal_ptrs; init_data.output_sbal_addr_array = out_sbal_ptrs; init_data.output_sbal_state_array = card->qdio.out_bufstates; - init_data.scan_threshold = IS_IQD(card) ? 1 : 32; + init_data.scan_threshold = IS_IQD(card) ? 0 : 32;
if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { @@@ -5187,107 -5155,6 +5191,107 @@@ out } EXPORT_SYMBOL_GPL(qeth_poll);
+static void qeth_iqd_tx_complete(struct qeth_qdio_out_q *queue, + unsigned int bidx, bool error, int budget) +{ + struct qeth_qdio_out_buffer *buffer = queue->bufs[bidx]; + u8 sflags = buffer->buffer->element[15].sflags; + struct qeth_card *card = queue->card; + + if (queue->bufstates && (queue->bufstates[bidx].flags & + QDIO_OUTBUF_STATE_FLAG_PENDING)) { + WARN_ON_ONCE(card->options.cq != QETH_CQ_ENABLED); + + if (atomic_cmpxchg(&buffer->state, QETH_QDIO_BUF_PRIMED, + QETH_QDIO_BUF_PENDING) == + QETH_QDIO_BUF_PRIMED) + qeth_notify_skbs(queue, buffer, TX_NOTIFY_PENDING); + + QETH_CARD_TEXT_(card, 5, "pel%u", bidx); + + /* prepare the queue slot for re-use: */ + qeth_scrub_qdio_buffer(buffer->buffer, queue->max_elements); + if (qeth_init_qdio_out_buf(queue, bidx)) { + QETH_CARD_TEXT(card, 2, "outofbuf"); + qeth_schedule_recovery(card); + } + + return; + } + + if (card->options.cq == QETH_CQ_ENABLED) + qeth_notify_skbs(queue, buffer, + qeth_compute_cq_notification(sflags, 0)); + qeth_clear_output_buffer(queue, buffer, error, budget); +} + +static int qeth_tx_poll(struct napi_struct *napi, int budget) +{ + struct qeth_qdio_out_q *queue = qeth_napi_to_out_queue(napi); + unsigned int queue_no = queue->queue_no; + struct qeth_card *card = queue->card; + struct net_device *dev = card->dev; + unsigned int work_done = 0; + struct netdev_queue *txq; + + txq = netdev_get_tx_queue(dev, qeth_iqd_translate_txq(dev, queue_no)); + + while (1) { + unsigned int start, error, i; + unsigned int packets = 0; + unsigned int bytes = 0; + int completed; + + if (qeth_out_queue_is_empty(queue)) { + napi_complete(napi); + return 0; + } + + /* Give the CPU a breather: */ + if (work_done >= QDIO_MAX_BUFFERS_PER_Q) { + QETH_TXQ_STAT_INC(queue, completion_yield); + if (napi_complete_done(napi, 0)) + napi_schedule(napi); + return 0; + } + + completed = qdio_inspect_queue(CARD_DDEV(card), queue_no, false, + &start, &error); + if (completed <= 0) { + /* Ensure we see TX completion for pending work: */ + if (napi_complete_done(napi, 0)) + qeth_tx_arm_timer(queue); + return 0; + } + + for (i = start; i < start + completed; i++) { + struct qeth_qdio_out_buffer *buffer; + unsigned int bidx = QDIO_BUFNR(i); + + buffer = queue->bufs[bidx]; + packets += skb_queue_len(&buffer->skb_list); + bytes += buffer->bytes; + + qeth_handle_send_error(card, buffer, error); + qeth_iqd_tx_complete(queue, bidx, error, budget); + qeth_cleanup_handled_pending(queue, bidx, false); + } + + netdev_tx_completed_queue(txq, packets, bytes); + atomic_sub(completed, &queue->used_buffers); + work_done += completed; + + /* xmit may have observed the full-condition, but not yet + * stopped the txq. In which case the code below won't trigger. + * So before returning, xmit will re-check the txq's fill level + * and wake it up if needed. + */ + if (netif_tx_queue_stopped(txq) && + !qeth_out_queue_is_full(queue)) + netif_tx_wake_queue(txq); + } +} + static int qeth_setassparms_inspect_rc(struct qeth_ipa_cmd *cmd) { if (!cmd->hdr.return_code) @@@ -6234,17 -6101,6 +6238,17 @@@ int qeth_open(struct net_device *dev napi_enable(&card->napi); local_bh_disable(); napi_schedule(&card->napi); + if (IS_IQD(card)) { + struct qeth_qdio_out_q *queue; + unsigned int i; + + qeth_for_each_output_queue(card, queue, i) { + netif_tx_napi_add(dev, &queue->napi, qeth_tx_poll, + QETH_NAPI_WEIGHT); + napi_enable(&queue->napi); + napi_schedule(&queue->napi); + } + } /* kick-start the NAPI softirq: */ local_bh_enable(); return 0; @@@ -6256,26 -6112,7 +6260,26 @@@ int qeth_stop(struct net_device *dev struct qeth_card *card = dev->ml_priv;
QETH_CARD_TEXT(card, 4, "qethstop"); - netif_tx_disable(dev); + if (IS_IQD(card)) { + struct qeth_qdio_out_q *queue; + unsigned int i; + + /* Quiesce the NAPI instances: */ + qeth_for_each_output_queue(card, queue, i) { + napi_disable(&queue->napi); + del_timer_sync(&queue->timer); + } + + /* Stop .ndo_start_xmit, might still access queue->napi. */ + netif_tx_disable(dev); + + /* Queues may get re-allocated, so remove the NAPIs here. */ + qeth_for_each_output_queue(card, queue, i) + netif_napi_del(&queue->napi); + } else { + netif_tx_disable(dev); + } + napi_disable(&card->napi); return 0; } diff --combined kernel/bpf/verifier.c index 10c0ff93f52b,b5c14c9d7b98..16d66bd7af09 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@@ -985,9 -985,6 +985,6 @@@ static void __mark_reg_unbounded(struc reg->smax_value = S64_MAX; reg->umin_value = 0; reg->umax_value = U64_MAX; - - /* constant backtracking is enabled for root only for now */ - reg->precise = capable(CAP_SYS_ADMIN) ? false : true; }
/* Mark a register as having a completely unknown (scalar) value. */ @@@ -1014,7 -1011,11 +1011,11 @@@ static void mark_reg_unknown(struct bpf __mark_reg_not_init(regs + regno); return; } - __mark_reg_unknown(regs + regno); + regs += regno; + __mark_reg_unknown(regs); + /* constant backtracking is enabled for root without bpf2bpf calls */ + regs->precise = env->subprog_cnt > 1 || !env->allow_ptr_leaks ? + true : false; }
static void __mark_reg_not_init(struct bpf_reg_state *reg) @@@ -3457,7 -3458,6 +3458,7 @@@ static int check_map_func_compatibility goto error; break; case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_DEVMAP_HASH: if (func_id != BPF_FUNC_redirect_map && func_id != BPF_FUNC_map_lookup_elem) goto error; @@@ -3540,7 -3540,6 +3541,7 @@@ break; case BPF_FUNC_redirect_map: if (map->map_type != BPF_MAP_TYPE_DEVMAP && + map->map_type != BPF_MAP_TYPE_DEVMAP_HASH && map->map_type != BPF_MAP_TYPE_CPUMAP && map->map_type != BPF_MAP_TYPE_XSKMAP) goto error; diff --combined net/core/filter.c index 0c1059cdad3d,4c6a252d4212..b91988f8b94e --- a/net/core/filter.c +++ b/net/core/filter.c @@@ -3517,8 -3517,7 +3517,8 @@@ static int __bpf_tx_xdp_map(struct net_ int err;
switch (map->map_type) { - case BPF_MAP_TYPE_DEVMAP: { + case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_DEVMAP_HASH: { struct bpf_dtab_netdev *dst = fwd;
err = dev_map_enqueue(dst, xdp, dev_rx); @@@ -3555,7 -3554,6 +3555,7 @@@ void xdp_do_flush_map(void if (map) { switch (map->map_type) { case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_DEVMAP_HASH: __dev_map_flush(map); break; case BPF_MAP_TYPE_CPUMAP: @@@ -3576,8 -3574,6 +3576,8 @@@ static inline void *__xdp_map_lookup_el switch (map->map_type) { case BPF_MAP_TYPE_DEVMAP: return __dev_map_lookup_elem(map, index); + case BPF_MAP_TYPE_DEVMAP_HASH: + return __dev_map_hash_lookup_elem(map, index); case BPF_MAP_TYPE_CPUMAP: return __cpu_map_lookup_elem(map, index); case BPF_MAP_TYPE_XSKMAP: @@@ -3659,8 -3655,7 +3659,8 @@@ static int xdp_do_generic_redirect_map( ri->tgt_value = NULL; WRITE_ONCE(ri->map, NULL);
- if (map->map_type == BPF_MAP_TYPE_DEVMAP) { + if (map->map_type == BPF_MAP_TYPE_DEVMAP || + map->map_type == BPF_MAP_TYPE_DEVMAP_HASH) { struct bpf_dtab_netdev *dst = fwd;
err = dev_map_generic_redirect(dst, skb, xdp_prog); @@@ -5855,75 -5850,6 +5855,75 @@@ static const struct bpf_func_proto bpf_ .arg5_type = ARG_CONST_SIZE, };
+BPF_CALL_5(bpf_tcp_gen_syncookie, struct sock *, sk, void *, iph, u32, iph_len, + struct tcphdr *, th, u32, th_len) +{ +#ifdef CONFIG_SYN_COOKIES + u32 cookie; + u16 mss; + + if (unlikely(th_len < sizeof(*th) || th_len != th->doff * 4)) + return -EINVAL; + + if (sk->sk_protocol != IPPROTO_TCP || sk->sk_state != TCP_LISTEN) + return -EINVAL; + + if (!sock_net(sk)->ipv4.sysctl_tcp_syncookies) + return -ENOENT; + + if (!th->syn || th->ack || th->fin || th->rst) + return -EINVAL; + + if (unlikely(iph_len < sizeof(struct iphdr))) + return -EINVAL; + + /* Both struct iphdr and struct ipv6hdr have the version field at the + * same offset so we can cast to the shorter header (struct iphdr). + */ + switch (((struct iphdr *)iph)->version) { + case 4: + if (sk->sk_family == AF_INET6 && sk->sk_ipv6only) + return -EINVAL; + + mss = tcp_v4_get_syncookie(sk, iph, th, &cookie); + break; + +#if IS_BUILTIN(CONFIG_IPV6) + case 6: + if (unlikely(iph_len < sizeof(struct ipv6hdr))) + return -EINVAL; + + if (sk->sk_family != AF_INET6) + return -EINVAL; + + mss = tcp_v6_get_syncookie(sk, iph, th, &cookie); + break; +#endif /* CONFIG_IPV6 */ + + default: + return -EPROTONOSUPPORT; + } + if (mss <= 0) + return -ENOENT; + + return cookie | ((u64)mss << 32); +#else + return -EOPNOTSUPP; +#endif /* CONFIG_SYN_COOKIES */ +} + +static const struct bpf_func_proto bpf_tcp_gen_syncookie_proto = { + .func = bpf_tcp_gen_syncookie, + .gpl_only = true, /* __cookie_v*_init_sequence() is GPL */ + .pkt_access = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_SOCK_COMMON, + .arg2_type = ARG_PTR_TO_MEM, + .arg3_type = ARG_CONST_SIZE, + .arg4_type = ARG_PTR_TO_MEM, + .arg5_type = ARG_CONST_SIZE, +}; + #endif /* CONFIG_INET */
bool bpf_helper_changes_pkt_data(void *func) @@@ -6073,8 -5999,6 +6073,8 @@@ sk_filter_func_proto(enum bpf_func_id f return &bpf_get_socket_cookie_proto; case BPF_FUNC_get_socket_uid: return &bpf_get_socket_uid_proto; + case BPF_FUNC_perf_event_output: + return &bpf_skb_event_output_proto; default: return bpf_base_func_proto(func_id); } @@@ -6095,8 -6019,6 +6095,8 @@@ cg_skb_func_proto(enum bpf_func_id func return &bpf_sk_storage_get_proto; case BPF_FUNC_sk_storage_delete: return &bpf_sk_storage_delete_proto; + case BPF_FUNC_perf_event_output: + return &bpf_skb_event_output_proto; #ifdef CONFIG_SOCK_CGROUP_DATA case BPF_FUNC_skb_cgroup_id: return &bpf_skb_cgroup_id_proto; @@@ -6213,8 -6135,6 +6213,8 @@@ tc_cls_act_func_proto(enum bpf_func_id return &bpf_tcp_check_syncookie_proto; case BPF_FUNC_skb_ecn_set_ce: return &bpf_skb_ecn_set_ce_proto; + case BPF_FUNC_tcp_gen_syncookie: + return &bpf_tcp_gen_syncookie_proto; #endif default: return bpf_base_func_proto(func_id); @@@ -6254,8 -6174,6 +6254,8 @@@ xdp_func_proto(enum bpf_func_id func_id return &bpf_xdp_skc_lookup_tcp_proto; case BPF_FUNC_tcp_check_syncookie: return &bpf_tcp_check_syncookie_proto; + case BPF_FUNC_tcp_gen_syncookie: + return &bpf_tcp_gen_syncookie_proto; #endif default: return bpf_base_func_proto(func_id); @@@ -6349,8 -6267,6 +6349,8 @@@ sk_skb_func_proto(enum bpf_func_id func return &bpf_sk_redirect_map_proto; case BPF_FUNC_sk_redirect_hash: return &bpf_sk_redirect_hash_proto; + case BPF_FUNC_perf_event_output: + return &bpf_skb_event_output_proto; #ifdef CONFIG_INET case BPF_FUNC_sk_lookup_tcp: return &bpf_sk_lookup_tcp_proto; @@@ -8841,13 -8757,13 +8841,13 @@@ sk_reuseport_is_valid_access(int off, i return size == size_default;
/* Fields that allow narrowing */ - case offsetof(struct sk_reuseport_md, eth_protocol): + case bpf_ctx_range(struct sk_reuseport_md, eth_protocol): if (size < FIELD_SIZEOF(struct sk_buff, protocol)) return false; /* fall through */ - case offsetof(struct sk_reuseport_md, ip_protocol): - case offsetof(struct sk_reuseport_md, bind_inany): - case offsetof(struct sk_reuseport_md, len): + case bpf_ctx_range(struct sk_reuseport_md, ip_protocol): + case bpf_ctx_range(struct sk_reuseport_md, bind_inany): + case bpf_ctx_range(struct sk_reuseport_md, len): bpf_ctx_record_field_size(info, size_default); return bpf_ctx_narrow_access_ok(off, size, size_default);
diff --combined net/core/flow_dissector.c index 9741b593ea53,2470b4b404e6..7c09d87d3269 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@@ -142,8 -142,8 +142,8 @@@ int skb_flow_dissector_bpf_prog_detach( mutex_unlock(&flow_dissector_mutex); return -ENOENT; } - bpf_prog_put(attached); RCU_INIT_POINTER(net->flow_dissector_prog, NULL); + bpf_prog_put(attached); mutex_unlock(&flow_dissector_mutex); return 0; } @@@ -737,7 -737,6 +737,7 @@@ static void __skb_flow_bpf_to_target(co struct flow_dissector_key_basic *key_basic; struct flow_dissector_key_addrs *key_addrs; struct flow_dissector_key_ports *key_ports; + struct flow_dissector_key_tags *key_tags;
key_control = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_CONTROL, @@@ -782,18 -781,10 +782,18 @@@ key_ports->src = flow_keys->sport; key_ports->dst = flow_keys->dport; } + + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_FLOW_LABEL)) { + key_tags = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_FLOW_LABEL, + target_container); + key_tags->flow_label = ntohl(flow_keys->flow_label); + } }
bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, - __be16 proto, int nhoff, int hlen) + __be16 proto, int nhoff, int hlen, unsigned int flags) { struct bpf_flow_keys *flow_keys = ctx->flow_keys; u32 result; @@@ -804,14 -795,6 +804,14 @@@ flow_keys->nhoff = nhoff; flow_keys->thoff = flow_keys->nhoff;
+ BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG != + (int)FLOW_DISSECTOR_F_PARSE_1ST_FRAG); + BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL != + (int)FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); + BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP != + (int)FLOW_DISSECTOR_F_STOP_AT_ENCAP); + flow_keys->flags = flags; + preempt_disable(); result = BPF_PROG_RUN(prog, ctx); preempt_enable(); @@@ -931,7 -914,7 +931,7 @@@ bool __skb_flow_dissect(const struct ne }
ret = bpf_flow_dissect(attached, &ctx, n_proto, nhoff, - hlen); + hlen, flags); __skb_flow_bpf_to_target(&flow_keys, flow_dissector, target_container); rcu_read_unlock(); diff --combined net/mac80211/cfg.c index ed56b0c6fe19,111c400199ec..7c6edb7c5f10 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@@ -980,8 -980,7 +980,8 @@@ static int ieee80211_start_ap(struct wi BSS_CHANGED_SSID | BSS_CHANGED_P2P_PS | BSS_CHANGED_TXPOWER | - BSS_CHANGED_TWT; + BSS_CHANGED_TWT | + BSS_CHANGED_HE_OBSS_PD; int err; int prev_beacon_int;
@@@ -1052,8 -1051,6 +1052,8 @@@ sdata->vif.bss_conf.enable_beacon = true; sdata->vif.bss_conf.allow_p2p_go_ps = sdata->vif.p2p; sdata->vif.bss_conf.twt_responder = params->twt_responder; + memcpy(&sdata->vif.bss_conf.he_obss_pd, ¶ms->he_obss_pd, + sizeof(struct ieee80211_he_obss_pd));
sdata->vif.bss_conf.ssid_len = params->ssid_len; if (params->ssid_len) @@@ -1546,9 -1543,14 +1546,14 @@@ static int ieee80211_add_station(struc if (ether_addr_equal(mac, sdata->vif.addr)) return -EINVAL;
- if (is_multicast_ether_addr(mac)) + if (!is_valid_ether_addr(mac)) return -EINVAL;
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER) && + sdata->vif.type == NL80211_IFTYPE_STATION && + !sdata->u.mgd.associated) + return -EINVAL; + sta = sta_info_alloc(sdata, mac, GFP_KERNEL); if (!sta) return -ENOMEM; @@@ -1556,10 -1558,6 +1561,6 @@@ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) sta->sta.tdls = true;
- if (sta->sta.tdls && sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated) - return -EINVAL; - err = sta_apply_parameters(local, sta, params); if (err) { sta_info_free(local, sta); diff --combined net/ncsi/ncsi-rsp.c index 5254004f2b42,d876bd55f356..dacabff9c467 --- a/net/ncsi/ncsi-rsp.c +++ b/net/ncsi/ncsi-rsp.c @@@ -47,7 -47,8 +47,8 @@@ static int ncsi_validate_rsp_pkt(struc if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) { netdev_dbg(nr->ndp->ndev.dev, - "NCSI: non zero response/reason code\n"); + "NCSI: non zero response/reason code %04xh, %04xh\n", + ntohs(h->code), ntohs(h->reason)); return -EPERM; }
@@@ -55,7 -56,7 +56,7 @@@ * sender doesn't support checksum according to NCSI * specification. */ - pchecksum = (__be32 *)((void *)(h + 1) + payload - 4); + pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4); if (ntohl(*pchecksum) == 0) return 0;
@@@ -63,7 -64,9 +64,9 @@@ sizeof(*h) + payload - 4);
if (*pchecksum != htonl(checksum)) { - netdev_dbg(nr->ndp->ndev.dev, "NCSI: checksum mismatched\n"); + netdev_dbg(nr->ndp->ndev.dev, + "NCSI: checksum mismatched; recd: %08x calc: %08x\n", + *pchecksum, htonl(checksum)); return -EINVAL; }
@@@ -1083,9 -1086,9 +1086,9 @@@ static struct ncsi_rsp_handler { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi }, { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, { NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp }, - { NCSI_PKT_RSP_GCPS, 172, ncsi_rsp_handler_gcps }, - { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns }, - { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts }, + { NCSI_PKT_RSP_GCPS, 204, ncsi_rsp_handler_gcps }, + { NCSI_PKT_RSP_GNS, 32, ncsi_rsp_handler_gns }, + { NCSI_PKT_RSP_GNPTS, 48, ncsi_rsp_handler_gnpts }, { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps }, { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem }, { NCSI_PKT_RSP_PLDM, 0, NULL }, diff --combined net/wireless/reg.c index 646107af9f41,327479ce69f5..5311d0ae2454 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@@ -2788,7 -2788,7 +2788,7 @@@ static void reg_process_pending_hints(v
/* When last_request->processed becomes true this will be rescheduled */ if (lr && !lr->processed) { - reg_process_hint(lr); + pr_debug("Pending regulatory request, waiting for it to be processed...\n"); return; }
@@@ -3806,9 -3806,8 +3806,9 @@@ void wiphy_regulatory_deregister(struc }
/* - * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for - * UNII band definitions + * See FCC notices for UNII band definitions + * 5GHz: https://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii + * 6GHz: https://www.fcc.gov/document/fcc-proposes-more-spectrum-unlicensed-use-0 */ int cfg80211_get_unii(int freq) { @@@ -3832,22 -3831,6 +3832,22 @@@ if (freq > 5725 && freq <= 5825) return 4;
+ /* UNII-5 */ + if (freq > 5925 && freq <= 6425) + return 5; + + /* UNII-6 */ + if (freq > 6425 && freq <= 6525) + return 6; + + /* UNII-7 */ + if (freq > 6525 && freq <= 6875) + return 7; + + /* UNII-8 */ + if (freq > 6875 && freq <= 7125) + return 8; + return -EINVAL; }
diff --combined net/wireless/util.c index c99939067bb0,e74837824cea..92cb2cbb179b --- a/net/wireless/util.c +++ b/net/wireless/util.c @@@ -91,11 -91,6 +91,11 @@@ int ieee80211_channel_to_frequency(int else return 5000 + chan * 5; break; + case NL80211_BAND_6GHZ: + /* see 802.11ax D4.1 27.3.22.2 */ + if (chan <= 253) + return 5940 + chan * 5; + break; case NL80211_BAND_60GHZ: if (chan < 7) return 56160 + chan * 2160; @@@ -116,11 -111,8 +116,11 @@@ int ieee80211_frequency_to_channel(int return (freq - 2407) / 5; else if (freq >= 4910 && freq <= 4980) return (freq - 4000) / 5; - else if (freq <= 45000) /* DMG band lower limit */ + else if (freq < 5940) return (freq - 5000) / 5; + else if (freq <= 45000) /* DMG band lower limit */ + /* see 802.11ax D4.1 27.3.22.2 */ + return (freq - 5940) / 5; else if (freq >= 58320 && freq <= 70200) return (freq - 56160) / 2160; else @@@ -156,7 -148,6 +156,7 @@@ static void set_mandatory_flags_band(st
switch (sband->band) { case NL80211_BAND_5GHZ: + case NL80211_BAND_6GHZ: want = 3; for (i = 0; i < sband->n_bitrates; i++) { if (sband->bitrates[i].bitrate == 60 || @@@ -242,25 -233,30 +242,30 @@@ int cfg80211_validate_key_settings(stru
switch (params->cipher) { case WLAN_CIPHER_SUITE_TKIP: + /* Extended Key ID can only be used with CCMP/GCMP ciphers */ + if ((pairwise && key_idx) || + params->mode != NL80211_KEY_RX_TX) + return -EINVAL; + break; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_CCMP_256: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: - /* IEEE802.11-2016 allows only 0 and - when using Extended Key - * ID - 1 as index for pairwise keys. + /* IEEE802.11-2016 allows only 0 and - when supporting + * Extended Key ID - 1 as index for pairwise keys. * @NL80211_KEY_NO_TX is only allowed for pairwise keys when * the driver supports Extended Key ID. * @NL80211_KEY_SET_TX can't be set when installing and * validating a key. */ - if (params->mode == NL80211_KEY_NO_TX) { - if (!wiphy_ext_feature_isset(&rdev->wiphy, - NL80211_EXT_FEATURE_EXT_KEY_ID)) - return -EINVAL; - else if (!pairwise || key_idx < 0 || key_idx > 1) + if ((params->mode == NL80211_KEY_NO_TX && !pairwise) || + params->mode == NL80211_KEY_SET_TX) + return -EINVAL; + if (wiphy_ext_feature_isset(&rdev->wiphy, + NL80211_EXT_FEATURE_EXT_KEY_ID)) { + if (pairwise && (key_idx < 0 || key_idx > 1)) return -EINVAL; - } else if ((pairwise && key_idx) || - params->mode == NL80211_KEY_SET_TX) { + } else if (pairwise && key_idx) { return -EINVAL; } break; @@@ -1043,7 -1039,7 +1048,7 @@@ static u32 cfg80211_calculate_bitrate_h return (bitrate + 50000) / 100000; }
-static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) +static u32 cfg80211_calculate_bitrate_dmg(struct rate_info *rate) { static const u32 __mcs2bitrate[] = { /* control PHY */ @@@ -1090,40 -1086,6 +1095,40 @@@ return __mcs2bitrate[rate->mcs]; }
+static u32 cfg80211_calculate_bitrate_edmg(struct rate_info *rate) +{ + static const u32 __mcs2bitrate[] = { + /* control PHY */ + [0] = 275, + /* SC PHY */ + [1] = 3850, + [2] = 7700, + [3] = 9625, + [4] = 11550, + [5] = 12512, /* 1251.25 mbps */ + [6] = 13475, + [7] = 15400, + [8] = 19250, + [9] = 23100, + [10] = 25025, + [11] = 26950, + [12] = 30800, + [13] = 38500, + [14] = 46200, + [15] = 50050, + [16] = 53900, + [17] = 57750, + [18] = 69300, + [19] = 75075, + [20] = 80850, + }; + + if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) + return 0; + + return __mcs2bitrate[rate->mcs] * rate->n_bonded_ch; +} + static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate) { static const u32 base[4][10] = { @@@ -1296,10 -1258,8 +1301,10 @@@ u32 cfg80211_calculate_bitrate(struct r { if (rate->flags & RATE_INFO_FLAGS_MCS) return cfg80211_calculate_bitrate_ht(rate); - if (rate->flags & RATE_INFO_FLAGS_60G) - return cfg80211_calculate_bitrate_60g(rate); + if (rate->flags & RATE_INFO_FLAGS_DMG) + return cfg80211_calculate_bitrate_dmg(rate); + if (rate->flags & RATE_INFO_FLAGS_EDMG) + return cfg80211_calculate_bitrate_edmg(rate); if (rate->flags & RATE_INFO_FLAGS_VHT_MCS) return cfg80211_calculate_bitrate_vht(rate); if (rate->flags & RATE_INFO_FLAGS_HE_MCS) @@@ -1511,9 -1471,6 +1516,9 @@@ bool ieee80211_operating_class_to_band( case 128 ... 130: *band = NL80211_BAND_5GHZ; return true; + case 131 ... 135: + *band = NL80211_BAND_6GHZ; + return true; case 81: case 82: case 83: diff --combined net/xdp/xdp_umem.c index a0607969f8c0,688aac7a6943..0e0062127124 --- a/net/xdp/xdp_umem.c +++ b/net/xdp/xdp_umem.c @@@ -14,7 -14,6 +14,7 @@@ #include <linux/netdevice.h> #include <linux/rtnetlink.h> #include <linux/idr.h> +#include <linux/highmem.h>
#include "xdp_umem.h" #include "xsk_queue.h" @@@ -165,14 -164,6 +165,14 @@@ void xdp_umem_clear_dev(struct xdp_ume umem->zc = false; }
+static void xdp_umem_unmap_pages(struct xdp_umem *umem) +{ + unsigned int i; + + for (i = 0; i < umem->npgs; i++) + kunmap(umem->pgs[i]); +} + static void xdp_umem_unpin_pages(struct xdp_umem *umem) { unsigned int i; @@@ -216,7 -207,6 +216,7 @@@ static void xdp_umem_release(struct xdp
xsk_reuseq_destroy(umem);
+ xdp_umem_unmap_pages(umem); xdp_umem_unpin_pages(umem);
kfree(umem->pages); @@@ -375,14 -365,16 +375,16 @@@ static int xdp_umem_reg(struct xdp_ume umem->pages = kcalloc(umem->npgs, sizeof(*umem->pages), GFP_KERNEL); if (!umem->pages) { err = -ENOMEM; - goto out_account; + goto out_pin; }
for (i = 0; i < umem->npgs; i++) - umem->pages[i].addr = page_address(umem->pgs[i]); + umem->pages[i].addr = kmap(umem->pgs[i]);
return 0;
+ out_pin: + xdp_umem_unpin_pages(umem); out_account: xdp_umem_unaccount_pages(umem); return err; diff --combined tools/testing/selftests/bpf/Makefile index 29001f944db7,96752ebd938f..d69c541e2039 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@@ -34,6 -34,9 +34,9 @@@ TEST_GEN_PROGS = test_verifier test_ta BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES)
+ BTF_C_FILES = $(wildcard progs/btf_dump_test_case_*.c) + TEST_FILES = $(BTF_C_FILES) + # Also test sub-register code-gen if LLVM has eBPF v3 processor support which # contains both ALU32 and JMP32 instructions. SUBREG_CODEGEN := $(shell echo "int cal(int a) { return a > 0; }" | \ @@@ -68,7 -71,8 +71,8 @@@ TEST_PROGS := test_kmod.sh TEST_PROGS_EXTENDED := with_addr.sh \ with_tunnels.sh \ tcp_client.py \ - tcp_server.py + tcp_server.py \ + test_xdp_vlan.sh
# Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user \ @@@ -236,12 -240,18 +240,12 @@@ PROG_TESTS_H := $(PROG_TESTS_DIR)/tests PROG_TESTS_FILES := $(wildcard prog_tests/*.c) test_progs.c: $(PROG_TESTS_H) $(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS) -$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_H) $(PROG_TESTS_FILES) +$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_FILES) | $(PROG_TESTS_H) $(PROG_TESTS_H): $(PROG_TESTS_FILES) | $(PROG_TESTS_DIR) $(shell ( cd prog_tests/; \ echo '/* Generated header, do not edit */'; \ - echo '#ifdef DECLARE'; \ ls *.c 2> /dev/null | \ - sed -e 's@([^.]*).c@extern void test_\1(void);@'; \ - echo '#endif'; \ - echo '#ifdef CALL'; \ - ls *.c 2> /dev/null | \ - sed -e 's@([^.]*).c@test_\1();@'; \ - echo '#endif' \ + sed -e 's@([^.]*).c@DEFINE_TEST(\1)@'; \ ) > $(PROG_TESTS_H))
MAP_TESTS_DIR = $(OUTPUT)/map_tests @@@ -251,7 -261,7 +255,7 @@@ MAP_TESTS_H := $(MAP_TESTS_DIR)/tests. MAP_TESTS_FILES := $(wildcard map_tests/*.c) test_maps.c: $(MAP_TESTS_H) $(OUTPUT)/test_maps: CFLAGS += $(TEST_MAPS_CFLAGS) -$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_H) $(MAP_TESTS_FILES) +$(OUTPUT)/test_maps: test_maps.c $(MAP_TESTS_FILES) | $(MAP_TESTS_H) $(MAP_TESTS_H): $(MAP_TESTS_FILES) | $(MAP_TESTS_DIR) $(shell ( cd map_tests/; \ echo '/* Generated header, do not edit */'; \ @@@ -272,7 -282,7 +276,7 @@@ VERIFIER_TESTS_H := $(VERIFIER_TESTS_DI VERIFIER_TEST_FILES := $(wildcard verifier/*.c) test_verifier.c: $(VERIFIER_TESTS_H) $(OUTPUT)/test_verifier: CFLAGS += $(TEST_VERIFIER_CFLAGS) -$(OUTPUT)/test_verifier: test_verifier.c $(VERIFIER_TESTS_H) +$(OUTPUT)/test_verifier: test_verifier.c | $(VERIFIER_TEST_FILES) $(VERIFIER_TESTS_H) $(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR) $(shell ( cd verifier/; \ echo '/* Generated header, do not edit */'; \
linux-merge@lists.open-mesh.org