diff options
102 files changed, 1838 insertions, 645 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 06c0fd5..5d87ccb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4377,11 +4377,10 @@ F: fs/gfs2/ F: include/uapi/linux/gfs2_ondisk.h GIGASET ISDN DRIVERS -M: Hansjoerg Lipp <hjlipp@web.de> -M: Tilman Schmidt <tilman@imap.cc> +M: Paul Bolle <pebolle@tiscali.nl> L: gigaset307x-common@lists.sourceforge.net W: http://gigaset307x.sourceforge.net/ -S: Maintained +S: Odd Fixes F: Documentation/isdn/README.gigaset F: drivers/isdn/gigaset/ F: include/uapi/linux/gigaset_dev.h @@ -8827,10 +8826,11 @@ W: http://www.emulex.com S: Supported F: drivers/scsi/be2iscsi/ -SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER -M: Sathya Perla <sathya.perla@emulex.com> -M: Subbu Seetharaman <subbu.seetharaman@emulex.com> -M: Ajit Khaparde <ajit.khaparde@emulex.com> +Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER +M: Sathya Perla <sathya.perla@avagotech.com> +M: Ajit Khaparde <ajit.khaparde@avagotech.com> +M: Padmanabh Ratnakar <padmanabh.ratnakar@avagotech.com> +M: Sriharsha Basavapatna <sriharsha.basavapatna@avagotech.com> L: netdev@vger.kernel.org W: http://www.emulex.com S: Supported diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index e1268f9..e0e2358 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -54,6 +54,7 @@ #define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) #define FLAG_NEED_X_RESET (1 << 0) +#define FLAG_IMM_OVERFLOW (1 << 1) struct jit_ctx { const struct bpf_prog *skf; @@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx) /* PC in ARM mode == address of the instruction + 8 */ imm = offset - (8 + ctx->idx * 4); + if (imm & ~0xfff) { + /* + * literal pool is too far, signal it into flags. we + * can only detect it on the second pass unfortunately. + */ + ctx->flags |= FLAG_IMM_OVERFLOW; + return 0; + } + return imm; } @@ -449,10 +459,21 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx) return; } #endif - if (rm != ARM_R0) - emit(ARM_MOV_R(ARM_R0, rm), ctx); + + /* + * For BPF_ALU | BPF_DIV | BPF_K instructions, rm is ARM_R4 + * (r_A) and rn is ARM_R0 (r_scratch) so load rn first into + * ARM_R1 to avoid accidentally overwriting ARM_R0 with rm + * before using it as a source for ARM_R1. + * + * For BPF_ALU | BPF_DIV | BPF_X rm is ARM_R4 (r_A) and rn is + * ARM_R5 (r_X) so there is no particular register overlap + * issues. + */ if (rn != ARM_R1) emit(ARM_MOV_R(ARM_R1, rn), ctx); + if (rm != ARM_R0) + emit(ARM_MOV_R(ARM_R0, rm), ctx); ctx->seen |= SEEN_CALL; emit_mov_i(ARM_R3, (u32)jit_udiv, ctx); @@ -855,6 +876,14 @@ b_epilogue: default: return -1; } + + if (ctx->flags & FLAG_IMM_OVERFLOW) + /* + * this instruction generated an overflow when + * trying to access the literal pool, so + * delegate this filter to the kernel interpreter. + */ + return -1; } /* compute offsets only during the first pass */ @@ -917,7 +946,14 @@ void bpf_jit_compile(struct bpf_prog *fp) ctx.idx = 0; build_prologue(&ctx); - build_body(&ctx); + if (build_body(&ctx) < 0) { +#if __LINUX_ARM_ARCH__ < 7 + if (ctx.imm_count) + kfree(ctx.imms); +#endif + bpf_jit_binary_free(header); + goto out; + } build_epilogue(&ctx); flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 9875143..99f7610 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -559,6 +559,13 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, if (is_ereg(dst_reg)) EMIT1(0x41); EMIT3(0xC1, add_1reg(0xC8, dst_reg), 8); + + /* emit 'movzwl eax, ax' */ + if (is_ereg(dst_reg)) + EMIT3(0x45, 0x0F, 0xB7); + else + EMIT2(0x0F, 0xB7); + EMIT1(add_2reg(0xC0, dst_reg, dst_reg)); break; case 32: /* emit 'bswap eax' to swap lower 4 bytes */ @@ -577,6 +584,27 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, break; case BPF_ALU | BPF_END | BPF_FROM_LE: + switch (imm32) { + case 16: + /* emit 'movzwl eax, ax' to zero extend 16-bit + * into 64 bit + */ + if (is_ereg(dst_reg)) + EMIT3(0x45, 0x0F, 0xB7); + else + EMIT2(0x0F, 0xB7); + EMIT1(add_2reg(0xC0, dst_reg, dst_reg)); + break; + case 32: + /* emit 'mov eax, eax' to clear upper 32-bits */ + if (is_ereg(dst_reg)) + EMIT1(0x45); + EMIT2(0x89, add_2reg(0xC0, dst_reg, dst_reg)); + break; + case 64: + /* nop */ + break; + } break; /* ST: *(u8*)(dst_reg + off) = imm */ diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 4f7e8d4..6de97b3 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -227,7 +227,6 @@ static void bt3c_receive(struct bt3c_info *info) iobase = info->p_dev->resource[0]->start; avail = bt3c_read(iobase, 0x7006); - //printk("bt3c_cs: receiving %d bytes\n", avail); bt3c_address(iobase, 0x7480); while (size < avail) { @@ -250,7 +249,6 @@ static void bt3c_receive(struct bt3c_info *info) bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L); inb(iobase + DATA_H); - //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type); switch (bt_cb(info->rx_skb)->pkt_type) { @@ -364,7 +362,6 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst) if (stat & 0x0001) bt3c_receive(info); if (stat & 0x0002) { - //BT_ERR("Ack (stat=0x%04x)", stat); clear_bit(XMIT_SENDING, &(info->tx_state)); bt3c_write_wakeup(info); } diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index d0741f3..4bba866 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -95,6 +95,78 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); +int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +{ + const struct hci_command_hdr *cmd; + const struct firmware *fw; + const u8 *fw_ptr; + size_t fw_size; + struct sk_buff *skb; + u16 opcode; + int err; + + err = request_firmware(&fw, firmware, &hdev->dev); + if (err < 0) { + BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware); + return err; + } + + /* Start Download */ + skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Download Minidrv command failed (%d)", + hdev->name, err); + goto done; + } + kfree_skb(skb); + + /* 50 msec delay after Download Minidrv completes */ + msleep(50); + + fw_ptr = fw->data; + fw_size = fw->size; + + while (fw_size >= sizeof(*cmd)) { + const u8 *cmd_param; + + cmd = (struct hci_command_hdr *)fw_ptr; + fw_ptr += sizeof(*cmd); + fw_size -= sizeof(*cmd); + + if (fw_size < cmd->plen) { + BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name, + firmware); + err = -EINVAL; + goto done; + } + + cmd_param = fw_ptr; + fw_ptr += cmd->plen; + fw_size -= cmd->plen; + + opcode = le16_to_cpu(cmd->opcode); + + skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Patch command %04x failed (%d)", + hdev->name, opcode, err); + goto done; + } + kfree_skb(skb); + } + + /* 250 msec delay after Launch Ram completes */ + msleep(250); + +done: + release_firmware(fw); + return err; +} +EXPORT_SYMBOL(btbcm_patchram); + static int btbcm_reset(struct hci_dev *hdev) { struct sk_buff *skb; @@ -198,12 +270,8 @@ static const struct { int btbcm_setup_patchram(struct hci_dev *hdev) { - const struct hci_command_hdr *cmd; - const struct firmware *fw; - const u8 *fw_ptr; - size_t fw_size; char fw_name[64]; - u16 opcode, subver, rev, pid, vid; + u16 subver, rev, pid, vid; const char *hw_name = NULL; struct sk_buff *skb; struct hci_rp_read_local_version *ver; @@ -273,74 +341,19 @@ int btbcm_setup_patchram(struct hci_dev *hdev) hw_name ? : "BCM", (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - err = request_firmware(&fw, fw_name, &hdev->dev); - if (err < 0) { - BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); + err = btbcm_patchram(hdev, fw_name); + if (err == -ENOENT) return 0; - } - - /* Start Download */ - skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: Download Minidrv command failed (%d)", - hdev->name, err); - goto reset; - } - kfree_skb(skb); - - /* 50 msec delay after Download Minidrv completes */ - msleep(50); - - fw_ptr = fw->data; - fw_size = fw->size; - - while (fw_size >= sizeof(*cmd)) { - const u8 *cmd_param; - - cmd = (struct hci_command_hdr *)fw_ptr; - fw_ptr += sizeof(*cmd); - fw_size -= sizeof(*cmd); - - if (fw_size < cmd->plen) { - BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, - fw_name); - err = -EINVAL; - goto reset; - } - cmd_param = fw_ptr; - fw_ptr += cmd->plen; - fw_size -= cmd->plen; - - opcode = le16_to_cpu(cmd->opcode); - - skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: patch command %04x failed (%d)", - hdev->name, opcode, err); - goto reset; - } - kfree_skb(skb); - } - - /* 250 msec delay after Launch Ram completes */ - msleep(250); - -reset: /* Reset */ err = btbcm_reset(hdev); if (err) - goto done; + return err; /* Read Local Version Info */ skb = btbcm_read_local_version(hdev); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - goto done; - } + if (IS_ERR(skb)) + return PTR_ERR(skb); ver = (struct hci_rp_read_local_version *)skb->data; rev = le16_to_cpu(ver->hci_rev); @@ -355,10 +368,7 @@ reset: set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); -done: - release_firmware(fw); - - return err; + return 0; } EXPORT_SYMBOL_GPL(btbcm_setup_patchram); diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index 34268ae..eb6ab5f 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h @@ -25,6 +25,7 @@ int btbcm_check_bdaddr(struct hci_dev *hdev); int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +int btbcm_patchram(struct hci_dev *hdev, const char *firmware); int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_apple(struct hci_dev *hdev); @@ -41,6 +42,11 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) return -EOPNOTSUPP; } +static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware) +{ + return -EOPNOTSUPP; +} + static inline int btbcm_setup_patchram(struct hci_dev *hdev) { return 0; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index de7b236..d21f3b4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/usb.h> #include <linux/firmware.h> +#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -57,6 +58,7 @@ static struct usb_driver btusb_driver; #define BTUSB_AMP 0x4000 #define BTUSB_QCA_ROME 0x8000 #define BTUSB_BCM_APPLE 0x10000 +#define BTUSB_REALTEK 0x20000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -288,6 +290,28 @@ static const struct usb_device_id blacklist_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01), .driver_info = BTUSB_IGNORE }, + /* Realtek Bluetooth devices */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), + .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8723AE Bluetooth devices */ + { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8723BE Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK }, + + /* Additional Realtek 8821AE Bluetooth devices */ + { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3458), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK }, + { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK }, + { } /* Terminating entry */ }; @@ -892,7 +916,7 @@ static int btusb_open(struct hci_dev *hdev) */ if (data->setup_on_usb) { err = data->setup_on_usb(hdev); - if (err <0) + if (err < 0) return err; } @@ -1345,6 +1369,378 @@ static int btusb_setup_csr(struct hci_dev *hdev) return ret; } +#define RTL_FRAG_LEN 252 + +struct rtl_download_cmd { + __u8 index; + __u8 data[RTL_FRAG_LEN]; +} __packed; + +struct rtl_download_response { + __u8 status; + __u8 index; +} __packed; + +struct rtl_rom_version_evt { + __u8 status; + __u8 version; +} __packed; + +struct rtl_epatch_header { + __u8 signature[8]; + __le32 fw_version; + __le16 num_patches; +} __packed; + +#define RTL_EPATCH_SIGNATURE "Realtech" +#define RTL_ROM_LMP_3499 0x3499 +#define RTL_ROM_LMP_8723A 0x1200 +#define RTL_ROM_LMP_8723B 0x8723 +#define RTL_ROM_LMP_8821A 0x8821 +#define RTL_ROM_LMP_8761A 0x8761 + +static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) +{ + struct rtl_rom_version_evt *rom_version; + struct sk_buff *skb; + int ret; + + /* Read RTL ROM version command */ + skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Read ROM version failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rom_version)) { + BT_ERR("%s: RTL version event length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rom_version = (struct rtl_rom_version_evt *)skb->data; + BT_INFO("%s: rom_version status=%x version=%x", + hdev->name, rom_version->status, rom_version->version); + + ret = rom_version->status; + if (ret == 0) + *version = rom_version->version; + + kfree_skb(skb); + return ret; +} + +static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, + const struct firmware *fw, + unsigned char **_buf) +{ + const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; + struct rtl_epatch_header *epatch_info; + unsigned char *buf; + int i, ret, len; + size_t min_size; + u8 opcode, length, data, rom_version = 0; + int project_id = -1; + const unsigned char *fwptr, *chip_id_base; + const unsigned char *patch_length_base, *patch_offset_base; + u32 patch_offset = 0; + u16 patch_length, num_patches; + const u16 project_id_to_lmp_subver[] = { + RTL_ROM_LMP_8723A, + RTL_ROM_LMP_8723B, + RTL_ROM_LMP_8821A, + RTL_ROM_LMP_8761A + }; + + ret = rtl_read_rom_version(hdev, &rom_version); + if (ret) + return -bt_to_errno(ret); + + min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; + if (fw->size < min_size) + return -EINVAL; + + fwptr = fw->data + fw->size - sizeof(extension_sig); + if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { + BT_ERR("%s: extension section signature mismatch", hdev->name); + return -EINVAL; + } + + /* Loop from the end of the firmware parsing instructions, until + * we find an instruction that identifies the "project ID" for the + * hardware supported by this firwmare file. + * Once we have that, we double-check that that project_id is suitable + * for the hardware we are working with. + */ + while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { + opcode = *--fwptr; + length = *--fwptr; + data = *--fwptr; + + BT_DBG("check op=%x len=%x data=%x", opcode, length, data); + + if (opcode == 0xff) /* EOF */ + break; + + if (length == 0) { + BT_ERR("%s: found instruction with length 0", + hdev->name); + return -EINVAL; + } + + if (opcode == 0 && length == 1) { + project_id = data; + break; + } + + fwptr -= length; + } + + if (project_id < 0) { + BT_ERR("%s: failed to find version instruction", hdev->name); + return -EINVAL; + } + + if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { + BT_ERR("%s: unknown project id %d", hdev->name, project_id); + return -EINVAL; + } + + if (lmp_subver != project_id_to_lmp_subver[project_id]) { + BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, + project_id_to_lmp_subver[project_id], lmp_subver); + return -EINVAL; + } + + epatch_info = (struct rtl_epatch_header *)fw->data; + if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { + BT_ERR("%s: bad EPATCH signature", hdev->name); + return -EINVAL; + } + + num_patches = le16_to_cpu(epatch_info->num_patches); + BT_DBG("fw_version=%x, num_patches=%d", + le32_to_cpu(epatch_info->fw_version), num_patches); + + /* After the rtl_epatch_header there is a funky patch metadata section. + * Assuming 2 patches, the layout is: + * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 + * + * Find the right patch for this chip. + */ + min_size += 8 * num_patches; + if (fw->size < min_size) + return -EINVAL; + + chip_id_base = fw->data + sizeof(struct rtl_epatch_header); + patch_length_base = chip_id_base + (sizeof(u16) * num_patches); + patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); + for (i = 0; i < num_patches; i++) { + u16 chip_id = get_unaligned_le16(chip_id_base + + (i * sizeof(u16))); + if (chip_id == rom_version + 1) { + patch_length = get_unaligned_le16(patch_length_base + + (i * sizeof(u16))); + patch_offset = get_unaligned_le32(patch_offset_base + + (i * sizeof(u32))); + break; + } + } + + if (!patch_offset) { + BT_ERR("%s: didn't find patch for chip id %d", + hdev->name, rom_version); + return -EINVAL; + } + + BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); + min_size = patch_offset + patch_length; + if (fw->size < min_size) + return -EINVAL; + + /* Copy the firmware into a new buffer and write the version at + * the end. + */ + len = patch_length; + buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); + + *_buf = buf; + return len; +} + +static int rtl_download_firmware(struct hci_dev *hdev, + const unsigned char *data, int fw_len) +{ + struct rtl_download_cmd *dl_cmd; + int frag_num = fw_len / RTL_FRAG_LEN + 1; + int frag_len = RTL_FRAG_LEN; + int ret = 0; + int i; + + dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); + if (!dl_cmd) + return -ENOMEM; + + for (i = 0; i < frag_num; i++) { + struct rtl_download_response *dl_resp; + struct sk_buff *skb; + + BT_DBG("download fw (%d/%d)", i, frag_num); + + dl_cmd->index = i; + if (i == (frag_num - 1)) { + dl_cmd->index |= 0x80; /* data end */ + frag_len = fw_len % RTL_FRAG_LEN; + } + memcpy(dl_cmd->data, data, frag_len); + + /* Send download command */ + skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: download fw command failed (%ld)", + hdev->name, PTR_ERR(skb)); + ret = -PTR_ERR(skb); + goto out; + } + + if (skb->len != sizeof(*dl_resp)) { + BT_ERR("%s: download fw event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto out; + } + + dl_resp = (struct rtl_download_response *)skb->data; + if (dl_resp->status != 0) { + kfree_skb(skb); + ret = bt_to_errno(dl_resp->status); + goto out; + } + + kfree_skb(skb); + data += RTL_FRAG_LEN; + } + +out: + kfree(dl_cmd); + return ret; +} + +static int btusb_setup_rtl8723a(struct hci_dev *hdev) +{ + struct btusb_data *data = dev_get_drvdata(&hdev->dev); + struct usb_device *udev = interface_to_usbdev(data->intf); + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading rtl_bt/rtl8723a_fw.bin", hdev->name); + ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &udev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); + return ret; + } + + if (fw->size < 8) { + ret = -EINVAL; + goto out; + } + + /* Check that the firmware doesn't have the epatch signature + * (which is only for RTL8723B and newer). + */ + if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { + BT_ERR("%s: unexpected EPATCH signature!", hdev->name); + ret = -EINVAL; + goto out; + } + + ret = rtl_download_firmware(hdev, fw->data, fw->size); + +out: + release_firmware(fw); + return ret; +} + +static int btusb_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, + const char *fw_name) +{ + struct btusb_data *data = dev_get_drvdata(&hdev->dev); + struct usb_device *udev = interface_to_usbdev(data->intf); + unsigned char *fw_data = NULL; + const struct firmware *fw; + int ret; + + BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); + ret = request_firmware(&fw, fw_name, &udev->dev); + if (ret < 0) { + BT_ERR("%s: Failed to load %s", hdev->name, fw_name); + return ret; + } + + ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); + if (ret < 0) + goto out; + + ret = rtl_download_firmware(hdev, fw_data, ret); + kfree(fw_data); + if (ret < 0) + goto out; + +out: + release_firmware(fw); + return ret; +} + +static int btusb_setup_realtek(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_local_version *resp; + u16 lmp_subver; + + skb = btusb_read_local_version(hdev); + if (IS_ERR(skb)) + return -PTR_ERR(skb); + + resp = (struct hci_rp_read_local_version *)skb->data; + BT_INFO("%s: rtl: examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x " + "lmp_subver=%04x", hdev->name, resp->hci_ver, resp->hci_rev, + resp->lmp_ver, resp->lmp_subver); + + lmp_subver = le16_to_cpu(resp->lmp_subver); + kfree_skb(skb); + + /* Match a set of subver values that correspond to stock firmware, + * which is not compatible with standard btusb. + * If matched, upload an alternative firmware that does conform to + * standard btusb. Once that firmware is uploaded, the subver changes + * to a different value. + */ + switch (lmp_subver) { + case RTL_ROM_LMP_8723A: + case RTL_ROM_LMP_3499: + return btusb_setup_rtl8723a(hdev); + case RTL_ROM_LMP_8723B: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8723b_fw.bin"); + case RTL_ROM_LMP_8821A: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8821a_fw.bin"); + case RTL_ROM_LMP_8761A: + return btusb_setup_rtl8723b(hdev, lmp_subver, + "rtl_bt/rtl8761a_fw.bin"); + default: + BT_INFO("rtl: assuming no firmware upload needed."); + return 0; + } +} + static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, struct intel_version *ver) { @@ -2577,7 +2973,7 @@ static int btusb_setup_qca(struct hci_dev *hdev) int i, err; err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver, - sizeof(ver)); + sizeof(ver)); if (err < 0) return err; @@ -2776,6 +3172,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->set_bdaddr = btusb_set_bdaddr_ath3012; } + if (id->driver_info & BTUSB_REALTEK) + hdev->setup = btusb_setup_realtek; + if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ data->isoc = NULL; diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 1b3f864..ec8fa0e 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -95,7 +95,6 @@ static void ath_hci_uart_work(struct work_struct *work) hci_uart_tx_wakeup(hu); } -/* Initialize protocol */ static int ath_open(struct hci_uart *hu) { struct ath_struct *ath; @@ -116,8 +115,7 @@ static int ath_open(struct hci_uart *hu) return 0; } -/* Flush protocol data */ -static int ath_flush(struct hci_uart *hu) +static int ath_close(struct hci_uart *hu) { struct ath_struct *ath = hu->priv; @@ -125,11 +123,17 @@ static int ath_flush(struct hci_uart *hu) skb_queue_purge(&ath->txq); + kfree_skb(ath->rx_skb); + + cancel_work_sync(&ath->ctxtsw); + + hu->priv = NULL; + kfree(ath); + return 0; } -/* Close protocol */ -static int ath_close(struct hci_uart *hu) +static int ath_flush(struct hci_uart *hu) { struct ath_struct *ath = hu->priv; @@ -137,19 +141,65 @@ static int ath_close(struct hci_uart *hu) skb_queue_purge(&ath->txq); - kfree_skb(ath->rx_skb); + return 0; +} - cancel_work_sync(&ath->ctxtsw); +static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 buf[10]; + int err; + + buf[0] = 0x01; + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = sizeof(bdaddr_t); + memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Change address command failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); - hu->priv = NULL; - kfree(ath); + return 0; +} + +static int ath_setup(struct hci_uart *hu) +{ + BT_DBG("hu %p", hu); + + hu->hdev->set_bdaddr = ath_set_bdaddr; return 0; } +static const struct h4_recv_pkt ath_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, +}; + +static int ath_recv(struct hci_uart *hu, const void *data, int count) +{ + struct ath_struct *ath = hu->priv; + + ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, + ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); + if (IS_ERR(ath->rx_skb)) { + int err = PTR_ERR(ath->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + return err; + } + + return count; +} + #define HCI_OP_ATH_SLEEP 0xFC04 -/* Enqueue frame for transmittion */ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) { struct ath_struct *ath = hu->priv; @@ -159,8 +209,7 @@ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) return 0; } - /* - * Update power management enable flag with parameters of + /* Update power management enable flag with parameters of * HCI sleep enable vendor specific HCI command. */ if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { @@ -190,37 +239,16 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) return skb_dequeue(&ath->txq); } -static const struct h4_recv_pkt ath_recv_pkts[] = { - { H4_RECV_ACL, .recv = hci_recv_frame }, - { H4_RECV_SCO, .recv = hci_recv_frame }, - { H4_RECV_EVENT, .recv = hci_recv_frame }, -}; - -/* Recv data */ -static int ath_recv(struct hci_uart *hu, const void *data, int count) -{ - struct ath_struct *ath = hu->priv; - - ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, - ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); - if (IS_ERR(ath->rx_skb)) { - int err = PTR_ERR(ath->rx_skb); - BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); - return err; - } - - return count; -} - static const struct hci_uart_proto athp = { .id = HCI_UART_ATH3K, .name = "ATH3K", .open = ath_open, .close = ath_close, + .flush = ath_flush, + .setup = ath_setup, .recv = ath_recv, .enqueue = ath_enqueue, .dequeue = ath_dequeue, - .flush = ath_flush, }; int __init ath_init(void) diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c index 6bddfe0..fc55e8e 100644 --- a/drivers/net/can/xilinx_can.c +++ b/drivers/net/can/xilinx_can.c @@ -509,10 +509,11 @@ static int xcan_rx(struct net_device *ndev) cf->can_id |= CAN_RTR_FLAG; } - if (!(id_xcan & XCAN_IDR_SRR_MASK)) { - data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); - data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + /* DW1/DW2 must always be read to remove message from RXFIFO */ + data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET); + data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET); + if (!(cf->can_id & CAN_RTR_FLAG)) { /* Change Xilinx CAN data format to socketCAN data format */ if (cf->can_dlc > 0) *(__be32 *)(cf->data) = cpu_to_be32(data[0]); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index af639ab..cf309aa9 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1469,6 +1469,9 @@ static void __exit mv88e6xxx_cleanup(void) #if IS_ENABLED(CONFIG_NET_DSA_MV88E6171) unregister_switch_driver(&mv88e6171_switch_driver); #endif +#if IS_ENABLED(CONFIG_NET_DSA_MV88E6352) + unregister_switch_driver(&mv88e6352_switch_driver); +#endif #if IS_ENABLED(CONFIG_NET_DSA_MV88E6123_61_65) unregister_switch_driver(&mv88e6123_61_65_switch_driver); #endif diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 089c269..4269160 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -180,6 +180,7 @@ config SUNLANCE config AMD_XGBE tristate "AMD 10GbE Ethernet driver" depends on (OF_NET || ACPI) && HAS_IOMEM && HAS_DMA + depends on ARM64 || COMPILE_TEST select PHYLIB select AMD_XGBE_PHY select BITREVERSE diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig index f4054d24..19e38af 100644 --- a/drivers/net/ethernet/apm/xgene/Kconfig +++ b/drivers/net/ethernet/apm/xgene/Kconfig @@ -1,6 +1,7 @@ config NET_XGENE tristate "APM X-Gene SoC Ethernet Driver" depends on HAS_DMA + depends on ARCH_XGENE || COMPILE_TEST select PHYLIB help This is the Ethernet driver for the on-chip ethernet interface on the diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index a8bb8f6..ec56a9b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -4786,6 +4786,11 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { struct bnx2x *bp = netdev_priv(dev); + if (pci_num_vf(bp->pdev)) { + DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n"); + return -EPERM; + } + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { BNX2X_ERR("Can't perform change MTU during parity recovery\n"); return -EAGAIN; @@ -4938,11 +4943,6 @@ int bnx2x_resume(struct pci_dev *pdev) } bp = netdev_priv(dev); - if (pci_num_vf(bp->pdev)) { - DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n"); - return -EPERM; - } - if (bp->recovery_state != BNX2X_RECOVERY_DONE) { BNX2X_ERR("Handling parity error recovery. Try again later\n"); return -EAGAIN; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 556dcc1..fd52ce9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -13371,8 +13371,13 @@ static int bnx2x_init_one(struct pci_dev *pdev, /* Management FW 'remembers' living interfaces. Allow it some time * to forget previously living interfaces, allowing a proper re-load. */ - if (is_kdump_kernel()) - msleep(5000); + if (is_kdump_kernel()) { + ktime_t now = ktime_get_boottime(); + ktime_t fw_ready_time = ktime_set(5, 0); + + if (ktime_before(now, fw_ready_time)) + msleep(ktime_ms_delta(fw_ready_time, now)); + } /* An estimated maximum supported CoS number according to the chip * version. diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4104d49..61aa570 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -981,7 +981,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) struct macb_queue *queue = dev_id; struct macb *bp = queue->bp; struct net_device *dev = bp->dev; - u32 status; + u32 status, ctrl; status = queue_readl(queue, ISR); @@ -1037,6 +1037,15 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) * add that if/when we get our hands on a full-blown MII PHY. */ + if (status & MACB_BIT(RXUBR)) { + ctrl = macb_readl(bp, NCR); + macb_writel(bp, NCR, ctrl & ~MACB_BIT(RE)); + macb_writel(bp, NCR, ctrl | MACB_BIT(RE)); + + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) + macb_writel(bp, ISR, MACB_BIT(RXUBR)); + } + if (status & MACB_BIT(ISR_ROVR)) { /* We missed at least one packet */ if (macb_is_gem(bp)) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 5d9ceb1..0abc942 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -40,6 +40,7 @@ #include <linux/ptp_classify.h> #include <linux/mii.h> #include <linux/mdio.h> +#include <linux/pm_qos.h> #include "hw.h" struct e1000_info; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 1b0661e..c754b20 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -610,7 +610,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector, unsigned int total_bytes = 0, total_packets = 0; u16 cleaned_count = fm10k_desc_unused(rx_ring); - do { + while (likely(total_packets < budget)) { union fm10k_rx_desc *rx_desc; /* return some buffers to hardware, one at a time is too slow */ @@ -659,7 +659,7 @@ static bool fm10k_clean_rx_irq(struct fm10k_q_vector *q_vector, /* update budget accounting */ total_packets++; - } while (likely(total_packets < budget)); + } /* place incomplete frames back on ring for completion */ rx_ring->skb = skb; diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 8457d03..a0a9b1fc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1036,7 +1036,7 @@ static void igb_reset_q_vector(struct igb_adapter *adapter, int v_idx) adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL; if (q_vector->rx.ring) - adapter->tx_ring[q_vector->rx.ring->queue_index] = NULL; + adapter->rx_ring[q_vector->rx.ring->queue_index] = NULL; netif_napi_del(&q_vector->napi); @@ -1207,6 +1207,8 @@ static int igb_alloc_q_vector(struct igb_adapter *adapter, q_vector = adapter->q_vector[v_idx]; if (!q_vector) q_vector = kzalloc(size, GFP_KERNEL); + else + memset(q_vector, 0, size); if (!q_vector) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index a16d267..e71cdde 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -3612,7 +3612,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) u8 *dst_mac = skb_header_pointer(skb, 0, 0, NULL); if (!dst_mac || is_link_local_ether_addr(dst_mac)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index 54f0e5a..0a56f01 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -139,7 +139,7 @@ static unsigned long en_stats_adder(__be64 *start, __be64 *next, int num) int i; int offset = next - start; - for (i = 0; i <= num; i++) { + for (i = 0; i < num; i++) { ret += be64_to_cpu(*curr); curr += offset; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index c7f28bf..92fce1b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2845,7 +2845,7 @@ int mlx4_SW2HW_EQ_wrapper(struct mlx4_dev *dev, int slave, { int err; int eqn = vhcr->in_modifier; - int res_id = (slave << 8) | eqn; + int res_id = (slave << 10) | eqn; struct mlx4_eq_context *eqc = inbox->buf; int mtt_base = eq_get_mtt_addr(eqc) / dev->caps.mtt_entry_sz; int mtt_size = eq_get_mtt_size(eqc); @@ -3051,7 +3051,7 @@ int mlx4_HW2SW_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); + int res_id = eqn | (slave << 10); struct res_eq *eq; int err; @@ -3108,7 +3108,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) return 0; mutex_lock(&priv->mfunc.master.gen_eqe_mutex[slave]); - res_id = (slave << 8) | event_eq->eqn; + res_id = (slave << 10) | event_eq->eqn; err = get_res(dev, slave, res_id, RES_EQ, &req); if (err) goto unlock; @@ -3131,7 +3131,7 @@ int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) memcpy(mailbox->buf, (u8 *) eqe, 28); - in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); + in_modifier = (slave & 0xff) | ((event_eq->eqn & 0x3ff) << 16); err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B, @@ -3157,7 +3157,7 @@ int mlx4_QUERY_EQ_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_cmd_info *cmd) { int eqn = vhcr->in_modifier; - int res_id = eqn | (slave << 8); + int res_id = eqn | (slave << 10); struct res_eq *eq; int err; @@ -4714,13 +4714,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave) break; case RES_EQ_HW: - err = mlx4_cmd(dev, slave, eqn & 0xff, + err = mlx4_cmd(dev, slave, eqn & 0x3ff, 1, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n", - slave, eqn); + slave, eqn & 0x3ff); atomic_dec(&eq->mtt->ref_count); state = RES_EQ_RESERVED; break; diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c index 8da7c3f..7b43a3b 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c @@ -1764,7 +1764,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) int done = 0; struct nx_host_tx_ring *tx_ring = adapter->tx_ring; - if (!spin_trylock(&adapter->tx_clean_lock)) + if (!spin_trylock_bh(&adapter->tx_clean_lock)) return 1; sw_consumer = tx_ring->sw_consumer; @@ -1819,7 +1819,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter) */ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer)); done = (sw_consumer == hw_consumer); - spin_unlock(&adapter->tx_clean_lock); + spin_unlock_bh(&adapter->tx_clean_lock); return done; } diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index f66641d..6af028d 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -912,6 +912,8 @@ qca_spi_probe(struct spi_device *spi_device) qca->spi_dev = spi_device; qca->legacy_mode = legacy_mode; + spi_set_drvdata(spi_device, qcaspi_devs); + mac = of_get_mac_address(spi_device->dev.of_node); if (mac) @@ -944,8 +946,6 @@ qca_spi_probe(struct spi_device *spi_device) return -EFAULT; } - spi_set_drvdata(spi_device, qcaspi_devs); - qcaspi_init_device_debugfs(qca); return 0; diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index c70ab40..3df51fa 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -6884,7 +6884,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp, rtl8169_start_xmit(nskb, tp->dev); } while (segs); - dev_kfree_skb(skb); + dev_consume_skb_any(skb); } else if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb_checksum_help(skb) < 0) goto drop; @@ -6896,7 +6896,7 @@ static void r8169_csum_workaround(struct rtl8169_private *tp, drop: stats = &tp->dev->stats; stats->tx_dropped++; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } } diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 14b363a..630f0b7 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2238,9 +2238,10 @@ static int smc_drv_probe(struct platform_device *pdev) const struct of_device_id *match = NULL; struct smc_local *lp; struct net_device *ndev; - struct resource *res, *ires; + struct resource *res; unsigned int __iomem *addr; unsigned long irq_flags = SMC_IRQ_FLAGS; + unsigned long irq_resflags; int ret; ndev = alloc_etherdev(sizeof(struct smc_local)); @@ -2332,16 +2333,19 @@ static int smc_drv_probe(struct platform_device *pdev) goto out_free_netdev; } - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { + ndev->irq = platform_get_irq(pdev, 0); + if (ndev->irq <= 0) { ret = -ENODEV; goto out_release_io; } - - ndev->irq = ires->start; - - if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK) - irq_flags = ires->flags & IRQF_TRIGGER_MASK; + /* + * If this platform does not specify any special irqflags, or if + * the resource supplies a trigger, override the irqflags with + * the trigger flags from the resource. + */ + irq_resflags = irqd_get_trigger_type(irq_get_irq_data(ndev->irq)); + if (irq_flags == -1 || irq_resflags & IRQF_TRIGGER_MASK) + irq_flags = irq_resflags & IRQF_TRIGGER_MASK; ret = smc_request_attrib(pdev, ndev); if (ret) diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 41047c9..959aeea 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2418,9 +2418,9 @@ static int smsc911x_drv_probe(struct platform_device *pdev) struct net_device *dev; struct smsc911x_data *pdata; struct smsc911x_platform_config *config = dev_get_platdata(&pdev->dev); - struct resource *res, *irq_res; + struct resource *res; unsigned int intcfg = 0; - int res_size, irq_flags; + int res_size, irq, irq_flags; int retval; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -2434,8 +2434,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev) } res_size = resource_size(res); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; @@ -2455,8 +2455,8 @@ static int smsc911x_drv_probe(struct platform_device *pdev) SET_NETDEV_DEV(dev, &pdev->dev); pdata = netdev_priv(dev); - dev->irq = irq_res->start; - irq_flags = irq_res->flags & IRQF_TRIGGER_MASK; + dev->irq = irq; + irq_flags = irq_get_trigger_type(irq); pdata->ioaddr = ioremap_nocache(res->start, res_size); pdata->dev = dev; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 705bbdf..68aec5c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -23,6 +23,7 @@ *******************************************************************************/ #include <linux/platform_device.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_net.h> diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 690a4c3..af2694d 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -707,8 +707,8 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) cur_p->app0 |= STS_CTRL_APP0_SOP; cur_p->len = skb_headlen(skb); - cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, skb->len, - DMA_TO_DEVICE); + cur_p->phys = dma_map_single(ndev->dev.parent, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); cur_p->app4 = (unsigned long)skb; for (ii = 0; ii < num_frag; ii++) { diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 2d9ef53..ea091bc 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -826,7 +826,6 @@ int netvsc_send(struct hv_device *device, u16 q_idx = packet->q_idx; u32 pktlen = packet->total_data_buflen, msd_len = 0; unsigned int section_index = NETVSC_INVALID_INDEX; - struct sk_buff *skb = NULL; unsigned long flag; struct multi_send_data *msdp; struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL; @@ -924,12 +923,8 @@ int netvsc_send(struct hv_device *device, if (cur_send) ret = netvsc_send_pkt(cur_send, net_device); - if (ret != 0) { - if (section_index != NETVSC_INVALID_INDEX) - netvsc_free_send_slot(net_device, section_index); - } else if (skb) { - dev_kfree_skb_any(skb); - } + if (ret != 0 && section_index != NETVSC_INVALID_INDEX) + netvsc_free_send_slot(net_device, section_index); return ret; } diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 3802665..67d00fb 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -85,6 +85,7 @@ struct at86rf230_local { struct ieee802154_hw *hw; struct at86rf2xx_chip_data *data; struct regmap *regmap; + int slp_tr; struct completion state_complete; struct at86rf230_state_change state; @@ -95,163 +96,164 @@ struct at86rf230_local { unsigned long cal_timeout; s8 max_frame_retries; bool is_tx; + bool is_tx_from_off; u8 tx_retry; struct sk_buff *tx_skb; struct at86rf230_state_change tx; }; -#define RG_TRX_STATUS (0x01) -#define SR_TRX_STATUS 0x01, 0x1f, 0 -#define SR_RESERVED_01_3 0x01, 0x20, 5 -#define SR_CCA_STATUS 0x01, 0x40, 6 -#define SR_CCA_DONE 0x01, 0x80, 7 -#define RG_TRX_STATE (0x02) -#define SR_TRX_CMD 0x02, 0x1f, 0 -#define SR_TRAC_STATUS 0x02, 0xe0, 5 -#define RG_TRX_CTRL_0 (0x03) -#define SR_CLKM_CTRL 0x03, 0x07, 0 -#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 -#define SR_PAD_IO_CLKM 0x03, 0x30, 4 -#define SR_PAD_IO 0x03, 0xc0, 6 -#define RG_TRX_CTRL_1 (0x04) -#define SR_IRQ_POLARITY 0x04, 0x01, 0 -#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 -#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 -#define SR_RX_BL_CTRL 0x04, 0x10, 4 -#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 -#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 -#define SR_PA_EXT_EN 0x04, 0x80, 7 -#define RG_PHY_TX_PWR (0x05) -#define SR_TX_PWR 0x05, 0x0f, 0 -#define SR_PA_LT 0x05, 0x30, 4 -#define SR_PA_BUF_LT 0x05, 0xc0, 6 -#define RG_PHY_RSSI (0x06) -#define SR_RSSI 0x06, 0x1f, 0 -#define SR_RND_VALUE 0x06, 0x60, 5 -#define SR_RX_CRC_VALID 0x06, 0x80, 7 -#define RG_PHY_ED_LEVEL (0x07) -#define SR_ED_LEVEL 0x07, 0xff, 0 -#define RG_PHY_CC_CCA (0x08) -#define SR_CHANNEL 0x08, 0x1f, 0 -#define SR_CCA_MODE 0x08, 0x60, 5 -#define SR_CCA_REQUEST 0x08, 0x80, 7 -#define RG_CCA_THRES (0x09) -#define SR_CCA_ED_THRES 0x09, 0x0f, 0 -#define SR_RESERVED_09_1 0x09, 0xf0, 4 -#define RG_RX_CTRL (0x0a) -#define SR_PDT_THRES 0x0a, 0x0f, 0 -#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 -#define RG_SFD_VALUE (0x0b) -#define SR_SFD_VALUE 0x0b, 0xff, 0 -#define RG_TRX_CTRL_2 (0x0c) -#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 -#define SR_SUB_MODE 0x0c, 0x04, 2 -#define SR_BPSK_QPSK 0x0c, 0x08, 3 -#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 -#define SR_RESERVED_0c_5 0x0c, 0x60, 5 -#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 -#define RG_ANT_DIV (0x0d) -#define SR_ANT_CTRL 0x0d, 0x03, 0 -#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 -#define SR_ANT_DIV_EN 0x0d, 0x08, 3 -#define SR_RESERVED_0d_2 0x0d, 0x70, 4 -#define SR_ANT_SEL 0x0d, 0x80, 7 -#define RG_IRQ_MASK (0x0e) -#define SR_IRQ_MASK 0x0e, 0xff, 0 -#define RG_IRQ_STATUS (0x0f) -#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 -#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 -#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 -#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 -#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 -#define SR_IRQ_5_AMI 0x0f, 0x20, 5 -#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 -#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 -#define RG_VREG_CTRL (0x10) -#define SR_RESERVED_10_6 0x10, 0x03, 0 -#define SR_DVDD_OK 0x10, 0x04, 2 -#define SR_DVREG_EXT 0x10, 0x08, 3 -#define SR_RESERVED_10_3 0x10, 0x30, 4 -#define SR_AVDD_OK 0x10, 0x40, 6 -#define SR_AVREG_EXT 0x10, 0x80, 7 -#define RG_BATMON (0x11) -#define SR_BATMON_VTH 0x11, 0x0f, 0 -#define SR_BATMON_HR 0x11, 0x10, 4 -#define SR_BATMON_OK 0x11, 0x20, 5 -#define SR_RESERVED_11_1 0x11, 0xc0, 6 -#define RG_XOSC_CTRL (0x12) -#define SR_XTAL_TRIM 0x12, 0x0f, 0 -#define SR_XTAL_MODE 0x12, 0xf0, 4 -#define RG_RX_SYN (0x15) -#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 -#define SR_RESERVED_15_2 0x15, 0x70, 4 -#define SR_RX_PDT_DIS 0x15, 0x80, 7 -#define RG_XAH_CTRL_1 (0x17) -#define SR_RESERVED_17_8 0x17, 0x01, 0 -#define SR_AACK_PROM_MODE 0x17, 0x02, 1 -#define SR_AACK_ACK_TIME 0x17, 0x04, 2 -#define SR_RESERVED_17_5 0x17, 0x08, 3 -#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 -#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 -#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 -#define SR_RESERVED_17_1 0x17, 0x80, 7 -#define RG_FTN_CTRL (0x18) -#define SR_RESERVED_18_2 0x18, 0x7f, 0 -#define SR_FTN_START 0x18, 0x80, 7 -#define RG_PLL_CF (0x1a) -#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 -#define SR_PLL_CF_START 0x1a, 0x80, 7 -#define RG_PLL_DCU (0x1b) -#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 -#define SR_RESERVED_1b_2 0x1b, 0x40, 6 -#define SR_PLL_DCU_START 0x1b, 0x80, 7 -#define RG_PART_NUM (0x1c) -#define SR_PART_NUM 0x1c, 0xff, 0 -#define RG_VERSION_NUM (0x1d) -#define SR_VERSION_NUM 0x1d, 0xff, 0 -#define RG_MAN_ID_0 (0x1e) -#define SR_MAN_ID_0 0x1e, 0xff, 0 -#define RG_MAN_ID_1 (0x1f) -#define SR_MAN_ID_1 0x1f, 0xff, 0 -#define RG_SHORT_ADDR_0 (0x20) -#define SR_SHORT_ADDR_0 0x20, 0xff, 0 -#define RG_SHORT_ADDR_1 (0x21) -#define SR_SHORT_ADDR_1 0x21, 0xff, 0 -#define RG_PAN_ID_0 (0x22) -#define SR_PAN_ID_0 0x22, 0xff, 0 -#define RG_PAN_ID_1 (0x23) -#define SR_PAN_ID_1 0x23, 0xff, 0 -#define RG_IEEE_ADDR_0 (0x24) -#define SR_IEEE_ADDR_0 0x24, 0xff, 0 -#define RG_IEEE_ADDR_1 (0x25) -#define SR_IEEE_ADDR_1 0x25, 0xff, 0 -#define RG_IEEE_ADDR_2 (0x26) -#define SR_IEEE_ADDR_2 0x26, 0xff, 0 -#define RG_IEEE_ADDR_3 (0x27) -#define SR_IEEE_ADDR_3 0x27, 0xff, 0 -#define RG_IEEE_ADDR_4 (0x28) -#define SR_IEEE_ADDR_4 0x28, 0xff, 0 -#define RG_IEEE_ADDR_5 (0x29) -#define SR_IEEE_ADDR_5 0x29, 0xff, 0 -#define RG_IEEE_ADDR_6 (0x2a) -#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 -#define RG_IEEE_ADDR_7 (0x2b) -#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 -#define RG_XAH_CTRL_0 (0x2c) -#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 -#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 -#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 -#define RG_CSMA_SEED_0 (0x2d) -#define SR_CSMA_SEED_0 0x2d, 0xff, 0 -#define RG_CSMA_SEED_1 (0x2e) -#define SR_CSMA_SEED_1 0x2e, 0x07, 0 -#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 -#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 -#define SR_AACK_SET_PD 0x2e, 0x20, 5 -#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 -#define RG_CSMA_BE (0x2f) -#define SR_MIN_BE 0x2f, 0x0f, 0 -#define SR_MAX_BE 0x2f, 0xf0, 4 +#define RG_TRX_STATUS (0x01) +#define SR_TRX_STATUS 0x01, 0x1f, 0 +#define SR_RESERVED_01_3 0x01, 0x20, 5 +#define SR_CCA_STATUS 0x01, 0x40, 6 +#define SR_CCA_DONE 0x01, 0x80, 7 +#define RG_TRX_STATE (0x02) +#define SR_TRX_CMD 0x02, 0x1f, 0 +#define SR_TRAC_STATUS 0x02, 0xe0, 5 +#define RG_TRX_CTRL_0 (0x03) +#define SR_CLKM_CTRL 0x03, 0x07, 0 +#define SR_CLKM_SHA_SEL 0x03, 0x08, 3 +#define SR_PAD_IO_CLKM 0x03, 0x30, 4 +#define SR_PAD_IO 0x03, 0xc0, 6 +#define RG_TRX_CTRL_1 (0x04) +#define SR_IRQ_POLARITY 0x04, 0x01, 0 +#define SR_IRQ_MASK_MODE 0x04, 0x02, 1 +#define SR_SPI_CMD_MODE 0x04, 0x0c, 2 +#define SR_RX_BL_CTRL 0x04, 0x10, 4 +#define SR_TX_AUTO_CRC_ON 0x04, 0x20, 5 +#define SR_IRQ_2_EXT_EN 0x04, 0x40, 6 +#define SR_PA_EXT_EN 0x04, 0x80, 7 +#define RG_PHY_TX_PWR (0x05) +#define SR_TX_PWR 0x05, 0x0f, 0 +#define SR_PA_LT 0x05, 0x30, 4 +#define SR_PA_BUF_LT 0x05, 0xc0, 6 +#define RG_PHY_RSSI (0x06) +#define SR_RSSI 0x06, 0x1f, 0 +#define SR_RND_VALUE 0x06, 0x60, 5 +#define SR_RX_CRC_VALID 0x06, 0x80, 7 +#define RG_PHY_ED_LEVEL (0x07) +#define SR_ED_LEVEL 0x07, 0xff, 0 +#define RG_PHY_CC_CCA (0x08) +#define SR_CHANNEL 0x08, 0x1f, 0 +#define SR_CCA_MODE 0x08, 0x60, 5 +#define SR_CCA_REQUEST 0x08, 0x80, 7 +#define RG_CCA_THRES (0x09) +#define SR_CCA_ED_THRES 0x09, 0x0f, 0 +#define SR_RESERVED_09_1 0x09, 0xf0, 4 +#define RG_RX_CTRL (0x0a) +#define SR_PDT_THRES 0x0a, 0x0f, 0 +#define SR_RESERVED_0a_1 0x0a, 0xf0, 4 +#define RG_SFD_VALUE (0x0b) +#define SR_SFD_VALUE 0x0b, 0xff, 0 +#define RG_TRX_CTRL_2 (0x0c) +#define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 +#define SR_SUB_MODE 0x0c, 0x04, 2 +#define SR_BPSK_QPSK 0x0c, 0x08, 3 +#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 +#define SR_RESERVED_0c_5 0x0c, 0x60, 5 +#define SR_RX_SAFE_MODE 0x0c, 0x80, 7 +#define RG_ANT_DIV (0x0d) +#define SR_ANT_CTRL 0x0d, 0x03, 0 +#define SR_ANT_EXT_SW_EN 0x0d, 0x04, 2 +#define SR_ANT_DIV_EN 0x0d, 0x08, 3 +#define SR_RESERVED_0d_2 0x0d, 0x70, 4 +#define SR_ANT_SEL 0x0d, 0x80, 7 +#define RG_IRQ_MASK (0x0e) +#define SR_IRQ_MASK 0x0e, 0xff, 0 +#define RG_IRQ_STATUS (0x0f) +#define SR_IRQ_0_PLL_LOCK 0x0f, 0x01, 0 +#define SR_IRQ_1_PLL_UNLOCK 0x0f, 0x02, 1 +#define SR_IRQ_2_RX_START 0x0f, 0x04, 2 +#define SR_IRQ_3_TRX_END 0x0f, 0x08, 3 +#define SR_IRQ_4_CCA_ED_DONE 0x0f, 0x10, 4 +#define SR_IRQ_5_AMI 0x0f, 0x20, 5 +#define SR_IRQ_6_TRX_UR 0x0f, 0x40, 6 +#define SR_IRQ_7_BAT_LOW 0x0f, 0x80, 7 +#define RG_VREG_CTRL (0x10) +#define SR_RESERVED_10_6 0x10, 0x03, 0 +#define SR_DVDD_OK 0x10, 0x04, 2 +#define SR_DVREG_EXT 0x10, 0x08, 3 +#define SR_RESERVED_10_3 0x10, 0x30, 4 +#define SR_AVDD_OK 0x10, 0x40, 6 +#define SR_AVREG_EXT 0x10, 0x80, 7 +#define RG_BATMON (0x11) +#define SR_BATMON_VTH 0x11, 0x0f, 0 +#define SR_BATMON_HR 0x11, 0x10, 4 +#define SR_BATMON_OK 0x11, 0x20, 5 +#define SR_RESERVED_11_1 0x11, 0xc0, 6 +#define RG_XOSC_CTRL (0x12) +#define SR_XTAL_TRIM 0x12, 0x0f, 0 +#define SR_XTAL_MODE 0x12, 0xf0, 4 +#define RG_RX_SYN (0x15) +#define SR_RX_PDT_LEVEL 0x15, 0x0f, 0 +#define SR_RESERVED_15_2 0x15, 0x70, 4 +#define SR_RX_PDT_DIS 0x15, 0x80, 7 +#define RG_XAH_CTRL_1 (0x17) +#define SR_RESERVED_17_8 0x17, 0x01, 0 +#define SR_AACK_PROM_MODE 0x17, 0x02, 1 +#define SR_AACK_ACK_TIME 0x17, 0x04, 2 +#define SR_RESERVED_17_5 0x17, 0x08, 3 +#define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 +#define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 +#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 +#define SR_RESERVED_17_1 0x17, 0x80, 7 +#define RG_FTN_CTRL (0x18) +#define SR_RESERVED_18_2 0x18, 0x7f, 0 +#define SR_FTN_START 0x18, 0x80, 7 +#define RG_PLL_CF (0x1a) +#define SR_RESERVED_1a_2 0x1a, 0x7f, 0 +#define SR_PLL_CF_START 0x1a, 0x80, 7 +#define RG_PLL_DCU (0x1b) +#define SR_RESERVED_1b_3 0x1b, 0x3f, 0 +#define SR_RESERVED_1b_2 0x1b, 0x40, 6 +#define SR_PLL_DCU_START 0x1b, 0x80, 7 +#define RG_PART_NUM (0x1c) +#define SR_PART_NUM 0x1c, 0xff, 0 +#define RG_VERSION_NUM (0x1d) +#define SR_VERSION_NUM 0x1d, 0xff, 0 +#define RG_MAN_ID_0 (0x1e) +#define SR_MAN_ID_0 0x1e, 0xff, 0 +#define RG_MAN_ID_1 (0x1f) +#define SR_MAN_ID_1 0x1f, 0xff, 0 +#define RG_SHORT_ADDR_0 (0x20) +#define SR_SHORT_ADDR_0 0x20, 0xff, 0 +#define RG_SHORT_ADDR_1 (0x21) +#define SR_SHORT_ADDR_1 0x21, 0xff, 0 +#define RG_PAN_ID_0 (0x22) +#define SR_PAN_ID_0 0x22, 0xff, 0 +#define RG_PAN_ID_1 (0x23) +#define SR_PAN_ID_1 0x23, 0xff, 0 +#define RG_IEEE_ADDR_0 (0x24) +#define SR_IEEE_ADDR_0 0x24, 0xff, 0 +#define RG_IEEE_ADDR_1 (0x25) +#define SR_IEEE_ADDR_1 0x25, 0xff, 0 +#define RG_IEEE_ADDR_2 (0x26) +#define SR_IEEE_ADDR_2 0x26, 0xff, 0 +#define RG_IEEE_ADDR_3 (0x27) +#define SR_IEEE_ADDR_3 0x27, 0xff, 0 +#define RG_IEEE_ADDR_4 (0x28) +#define SR_IEEE_ADDR_4 0x28, 0xff, 0 +#define RG_IEEE_ADDR_5 (0x29) +#define SR_IEEE_ADDR_5 0x29, 0xff, 0 +#define RG_IEEE_ADDR_6 (0x2a) +#define SR_IEEE_ADDR_6 0x2a, 0xff, 0 +#define RG_IEEE_ADDR_7 (0x2b) +#define SR_IEEE_ADDR_7 0x2b, 0xff, 0 +#define RG_XAH_CTRL_0 (0x2c) +#define SR_SLOTTED_OPERATION 0x2c, 0x01, 0 +#define SR_MAX_CSMA_RETRIES 0x2c, 0x0e, 1 +#define SR_MAX_FRAME_RETRIES 0x2c, 0xf0, 4 +#define RG_CSMA_SEED_0 (0x2d) +#define SR_CSMA_SEED_0 0x2d, 0xff, 0 +#define RG_CSMA_SEED_1 (0x2e) +#define SR_CSMA_SEED_1 0x2e, 0x07, 0 +#define SR_AACK_I_AM_COORD 0x2e, 0x08, 3 +#define SR_AACK_DIS_ACK 0x2e, 0x10, 4 +#define SR_AACK_SET_PD 0x2e, 0x20, 5 +#define SR_AACK_FVN_MODE 0x2e, 0xc0, 6 +#define RG_CSMA_BE (0x2f) +#define SR_MIN_BE 0x2f, 0x0f, 0 +#define SR_MAX_BE 0x2f, 0xf0, 4 #define CMD_REG 0x80 #define CMD_REG_MASK 0x3f @@ -292,6 +294,8 @@ struct at86rf230_local { #define STATE_BUSY_RX_AACK_NOCLK 0x1E #define STATE_TRANSITION_IN_PROGRESS 0x1F +#define TRX_STATE_MASK (0x1F) + #define AT86RF2XX_NUMREGS 0x3F static void @@ -336,6 +340,14 @@ at86rf230_write_subreg(struct at86rf230_local *lp, return regmap_update_bits(lp->regmap, addr, mask, data << shift); } +static inline void +at86rf230_slp_tr_rising_edge(struct at86rf230_local *lp) +{ + gpio_set_value(lp->slp_tr, 1); + udelay(1); + gpio_set_value(lp->slp_tr, 0); +} + static bool at86rf230_reg_writeable(struct device *dev, unsigned int reg) { @@ -509,7 +521,7 @@ at86rf230_async_state_assert(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; const u8 *buf = ctx->buf; - const u8 trx_state = buf[1] & 0x1f; + const u8 trx_state = buf[1] & TRX_STATE_MASK; /* Assert state change */ if (trx_state != ctx->to_state) { @@ -609,11 +621,17 @@ at86rf230_async_state_delay(void *context) switch (ctx->to_state) { case STATE_RX_AACK_ON: tim = ktime_set(0, c->t_off_to_aack * NSEC_PER_USEC); + /* state change from TRX_OFF to RX_AACK_ON to do a + * calibration, we need to reset the timeout for the + * next one. + */ + lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; goto change; + case STATE_TX_ARET_ON: case STATE_TX_ON: tim = ktime_set(0, c->t_off_to_tx_on * NSEC_PER_USEC); - /* state change from TRX_OFF to TX_ON to do a - * calibration, we need to reset the timeout for the + /* state change from TRX_OFF to TX_ON or ARET_ON to do + * a calibration, we need to reset the timeout for the * next one. */ lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; @@ -667,7 +685,7 @@ at86rf230_async_state_change_start(void *context) struct at86rf230_state_change *ctx = context; struct at86rf230_local *lp = ctx->lp; u8 *buf = ctx->buf; - const u8 trx_state = buf[1] & 0x1f; + const u8 trx_state = buf[1] & TRX_STATE_MASK; int rc; /* Check for "possible" STATE_TRANSITION_IN_PROGRESS */ @@ -773,16 +791,6 @@ at86rf230_tx_on(void *context) } static void -at86rf230_tx_trac_error(void *context) -{ - struct at86rf230_state_change *ctx = context; - struct at86rf230_local *lp = ctx->lp; - - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_tx_on, true); -} - -static void at86rf230_tx_trac_check(void *context) { struct at86rf230_state_change *ctx = context; @@ -791,12 +799,12 @@ at86rf230_tx_trac_check(void *context) const u8 trac = (buf[1] & 0xe0) >> 5; /* If trac status is different than zero we need to do a state change - * to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver - * state to TX_ON. + * to STATE_FORCE_TRX_OFF then STATE_RX_AACK_ON to recover the + * transceiver. */ if (trac) at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF, - at86rf230_tx_trac_error, true); + at86rf230_tx_on, true); else at86rf230_tx_on(context); } @@ -941,13 +949,18 @@ at86rf230_write_frame_complete(void *context) u8 *buf = ctx->buf; int rc; - buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; - buf[1] = STATE_BUSY_TX; ctx->trx.len = 2; - ctx->msg.complete = NULL; - rc = spi_async(lp->spi, &ctx->msg); - if (rc) - at86rf230_async_error(lp, ctx, rc); + + if (gpio_is_valid(lp->slp_tr)) { + at86rf230_slp_tr_rising_edge(lp); + } else { + buf[0] = (RG_TRX_STATE & CMD_REG_MASK) | CMD_REG | CMD_WRITE; + buf[1] = STATE_BUSY_TX; + ctx->msg.complete = NULL; + rc = spi_async(lp->spi, &ctx->msg); + if (rc) + at86rf230_async_error(lp, ctx, rc); + } } static void @@ -993,12 +1006,21 @@ at86rf230_xmit_start(void *context) * are in STATE_TX_ON. The pfad differs here, so we change * the complete handler. */ - if (lp->tx_aret) - at86rf230_async_state_change(lp, ctx, STATE_TX_ON, - at86rf230_xmit_tx_on, false); - else + if (lp->tx_aret) { + if (lp->is_tx_from_off) { + lp->is_tx_from_off = false; + at86rf230_async_state_change(lp, ctx, STATE_TX_ARET_ON, + at86rf230_xmit_tx_on, + false); + } else { + at86rf230_async_state_change(lp, ctx, STATE_TX_ON, + at86rf230_xmit_tx_on, + false); + } + } else { at86rf230_async_state_change(lp, ctx, STATE_TX_ON, at86rf230_write_frame, false); + } } static int @@ -1017,11 +1039,13 @@ at86rf230_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) * to TX_ON, the lp->cal_timeout should be reinit by state_delay * function then to start in the next 5 minutes. */ - if (time_is_before_jiffies(lp->cal_timeout)) + if (time_is_before_jiffies(lp->cal_timeout)) { + lp->is_tx_from_off = true; at86rf230_async_state_change(lp, ctx, STATE_TRX_OFF, at86rf230_xmit_start, false); - else + } else { at86rf230_xmit_start(ctx); + } return 0; } @@ -1037,9 +1061,6 @@ at86rf230_ed(struct ieee802154_hw *hw, u8 *level) static int at86rf230_start(struct ieee802154_hw *hw) { - struct at86rf230_local *lp = hw->priv; - - lp->cal_timeout = jiffies + AT86RF2XX_CAL_LOOP_TIMEOUT; return at86rf230_sync_state_change(hw->priv, STATE_RX_AACK_ON); } @@ -1673,6 +1694,7 @@ static int at86rf230_probe(struct spi_device *spi) lp = hw->priv; lp->hw = hw; lp->spi = spi; + lp->slp_tr = slp_tr; hw->parent = &spi->dev; hw->vif_data_size = sizeof(*lp); ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index b227a13..9f59f17 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -599,10 +599,18 @@ static int macvlan_open(struct net_device *dev) goto del_unicast; } + if (dev->flags & IFF_PROMISC) { + err = dev_set_promiscuity(lowerdev, 1); + if (err < 0) + goto clear_multi; + } + hash_add: macvlan_hash_add(vlan); return 0; +clear_multi: + dev_set_allmulti(lowerdev, -1); del_unicast: dev_uc_del(lowerdev, dev->dev_addr); out: @@ -638,6 +646,9 @@ static int macvlan_stop(struct net_device *dev) if (dev->flags & IFF_ALLMULTI) dev_set_allmulti(lowerdev, -1); + if (dev->flags & IFF_PROMISC) + dev_set_promiscuity(lowerdev, -1); + dev_uc_del(lowerdev, dev->dev_addr); hash_del: @@ -696,6 +707,10 @@ static void macvlan_change_rx_flags(struct net_device *dev, int change) if (dev->flags & IFF_UP) { if (change & IFF_ALLMULTI) dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1); + if (change & IFF_PROMISC) + dev_set_promiscuity(lowerdev, + dev->flags & IFF_PROMISC ? 1 : -1); + } } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 8fadaa1..70641d2 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -27,6 +27,7 @@ config AMD_PHY config AMD_XGBE_PHY tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs" depends on (OF || ACPI) && HAS_IOMEM + depends on ARM64 || COMPILE_TEST ---help--- Currently supports the AMD 10GbE PHY diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index c9cb486c..53d1815 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -168,7 +168,10 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, if (!new_bus->irq[i]) new_bus->irq[i] = PHY_POLL; - snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); + if (bus_id != -1) + snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); + else + strncpy(new_bus->id, "gpio", MII_BUS_ID_SIZE); if (devm_gpio_request(dev, bitbang->mdc, "mdc")) goto out_free_bus; diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 1190fd8..ebdc357 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -548,7 +548,8 @@ static int kszphy_probe(struct phy_device *phydev) } clk = devm_clk_get(&phydev->dev, "rmii-ref"); - if (!IS_ERR(clk)) { + /* NOTE: clk may be NULL if building without CONFIG_HAVE_CLK */ + if (!IS_ERR_OR_NULL(clk)) { unsigned long rate = clk_get_rate(clk); bool rmii_ref_clk_sel_25_mhz; diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index aa1dd92..b62a5e3 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -465,6 +465,10 @@ static void pppoe_unbind_sock_work(struct work_struct *work) struct sock *sk = sk_pppox(po); lock_sock(sk); + if (po->pppoe_dev) { + dev_put(po->pppoe_dev); + po->pppoe_dev = NULL; + } pppox_unbind_sock(sk); release_sock(sk); sock_put(sk); diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index ac4d03b..aafa1a1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -4116,6 +4116,7 @@ static struct usb_device_id rtl8152_table[] = { {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, 0x8153)}, {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, 0xa101)}, {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x7205)}, + {REALTEK_USB_DEVICE(VENDOR_ID_LENOVO, 0x304f)}, {} }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 733f4fe..3c86b10 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1285,7 +1285,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, struct net_device *net) { struct usbnet *dev = netdev_priv(net); - int length; + unsigned int length; struct urb *urb = NULL; struct skb_data *entry; struct driver_info *info = dev->driver_info; @@ -1413,7 +1413,7 @@ not_drop: } } else netif_dbg(dev, tx_queued, dev->net, - "> tx, len %d, type 0x%x\n", length, skb->protocol); + "> tx, len %u, type 0x%x\n", length, skb->protocol); #ifdef CONFIG_PM deferred: #endif diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0acd079..3ad79bb 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1103,28 +1103,14 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ath_frame_info *fi; struct ieee80211_tx_info *info; - struct ieee80211_vif *vif; struct ath_hw *ah = sc->sc_ah; if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; skb = bf->bf_mpdu; - info = IEEE80211_SKB_CB(skb); - vif = info->control.vif; - - if (!vif) { - max_power = sc->cur_chan->cur_txpower; - goto out; - } - - if (vif->bss_conf.txpower_type != NL80211_TX_POWER_LIMITED) { - max_power = min_t(u8, sc->cur_chan->cur_txpower, - 2 * vif->bss_conf.txpower); - goto out; - } - fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); if (!AR_SREV_9300_20_OR_LATER(ah)) { int txpower = fi->tx_power; @@ -1161,25 +1147,26 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, txpower -= 2; txpower = max(txpower, 0); - max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min_t(u8, max_power, txpower); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) max_power = min_t(u8, ah->tx_power_stbc[rateidx], - 2 * vif->bss_conf.txpower); + fi->tx_power); else max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min(max_power, fi->tx_power); + fi->tx_power); } else { max_power = ah->paprd_training_power; } -out: - /* XXX: clamp minimum TX power at 1 for AR9160 since if max_power - * is set to 0, frames are transmitted at max TX power - */ - return (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) ? 1 : max_power; + + return max_power; } static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -2129,6 +2116,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct ath_node *an = NULL; enum ath9k_key_type keytype; bool short_preamble = false; + u8 txpower; /* * We check if Short Preamble is needed for the CTS rate by @@ -2145,6 +2133,16 @@ static void setup_frame_info(struct ieee80211_hw *hw, if (sta) an = (struct ath_node *) sta->drv_priv; + if (tx_info->control.vif) { + struct ieee80211_vif *vif = tx_info->control.vif; + + txpower = 2 * vif->bss_conf.txpower; + } else { + struct ath_softc *sc = hw->priv; + + txpower = sc->cur_chan->cur_txpower; + } + memset(fi, 0, sizeof(*fi)); fi->txq = -1; if (hw_key) @@ -2155,7 +2153,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; - fi->tx_power = MAX_RATE_POWER; + fi->tx_power = txpower; if (!rate) return; diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index bfdf3fa..62db2e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -244,6 +244,7 @@ enum iwl_ucode_tlv_flag { * longer than the passive one, which is essential for fragmented scan. * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source. * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR + * @IWL_UCODE_TLV_API_TX_POWER_DEV: new API for tx power. * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command, * regardless of the band or the number of the probes. FW will calculate * the actual dwell time. @@ -260,6 +261,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8), IWL_UCODE_TLV_API_WIFI_MCC_UPDATE = BIT(9), IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10), + IWL_UCODE_TLV_API_TX_POWER_DEV = BIT(11), IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13), IWL_UCODE_TLV_API_SCD_CFG = BIT(15), IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16), diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 6dfed12..56254a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -421,8 +421,9 @@ struct iwl_trans_txq_scd_cfg { * * All the handlers MUST be implemented * - * @start_hw: starts the HW- from that point on, the HW can send interrupts - * May sleep + * @start_hw: starts the HW. If low_power is true, the NIC needs to be taken + * out of a low power state. From that point on, the HW can send + * interrupts. May sleep. * @op_mode_leave: Turn off the HW RF kill indication if on * May sleep * @start_fw: allocates and inits all the resources for the transport @@ -432,10 +433,11 @@ struct iwl_trans_txq_scd_cfg { * the SCD base address in SRAM, then provide it here, or 0 otherwise. * May sleep * @stop_device: stops the whole device (embedded CPU put to reset) and stops - * the HW. From that point on, the HW will be in low power but will still - * issue interrupt if the HW RF kill is triggered. This callback must do - * the right thing and not crash even if start_hw() was called but not - * start_fw(). May sleep + * the HW. If low_power is true, the NIC will be put in low power state. + * From that point on, the HW will be stopped but will still issue an + * interrupt if the HW RF kill switch is triggered. + * This callback must do the right thing and not crash even if %start_hw() + * was called but not &start_fw(). May sleep. * @d3_suspend: put the device into the correct mode for WoWLAN during * suspend. This is optional, if not implemented WoWLAN will not be * supported. This callback may sleep. @@ -491,14 +493,14 @@ struct iwl_trans_txq_scd_cfg { */ struct iwl_trans_ops { - int (*start_hw)(struct iwl_trans *iwl_trans); + int (*start_hw)(struct iwl_trans *iwl_trans, bool low_power); void (*op_mode_leave)(struct iwl_trans *iwl_trans); int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill); int (*update_sf)(struct iwl_trans *trans, struct iwl_sf_region *st_fwrd_space); void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); - void (*stop_device)(struct iwl_trans *trans); + void (*stop_device)(struct iwl_trans *trans, bool low_power); void (*d3_suspend)(struct iwl_trans *trans, bool test); int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, @@ -652,11 +654,16 @@ static inline void iwl_trans_configure(struct iwl_trans *trans, trans->ops->configure(trans, trans_cfg); } -static inline int iwl_trans_start_hw(struct iwl_trans *trans) +static inline int _iwl_trans_start_hw(struct iwl_trans *trans, bool low_power) { might_sleep(); - return trans->ops->start_hw(trans); + return trans->ops->start_hw(trans, low_power); +} + +static inline int iwl_trans_start_hw(struct iwl_trans *trans) +{ + return trans->ops->start_hw(trans, true); } static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans) @@ -703,15 +710,21 @@ static inline int iwl_trans_update_sf(struct iwl_trans *trans, return 0; } -static inline void iwl_trans_stop_device(struct iwl_trans *trans) +static inline void _iwl_trans_stop_device(struct iwl_trans *trans, + bool low_power) { might_sleep(); - trans->ops->stop_device(trans); + trans->ops->stop_device(trans, low_power); trans->state = IWL_TRANS_NO_FW; } +static inline void iwl_trans_stop_device(struct iwl_trans *trans) +{ + _iwl_trans_stop_device(trans, true); +} + static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test) { might_sleep(); diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index a6c48c7..1b1b2bf 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -1726,7 +1726,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, results->matched_profiles = le32_to_cpu(query->matched_profiles); memcpy(results->matches, query->matches, sizeof(results->matches)); -#ifdef CPTCFG_IWLWIFI_DEBUGFS +#ifdef CONFIG_IWLWIFI_DEBUGFS mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done); #endif diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index 4fc0938b..b1baa33 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -298,6 +298,40 @@ struct iwl_uapsd_misbehaving_ap_notif { } __packed; /** + * struct iwl_reduce_tx_power_cmd - TX power reduction command + * REDUCE_TX_POWER_CMD = 0x9f + * @flags: (reserved for future implementation) + * @mac_context_id: id of the mac ctx for which we are reducing TX power. + * @pwr_restriction: TX power restriction in dBms. + */ +struct iwl_reduce_tx_power_cmd { + u8 flags; + u8 mac_context_id; + __le16 pwr_restriction; +} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ + +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * REDUCE_TX_POWER_CMD = 0x9f + * @set_mode: 0 - MAC tx power, 1 - device tx power + * @mac_context_id: id of the mac ctx for which we are reducing TX power. + * @pwr_restriction: TX power restriction in 1/8 dBms. + * @dev_24: device TX power restriction in 1/8 dBms + * @dev_52_low: device TX power restriction upper band - low + * @dev_52_high: device TX power restriction upper band - high + */ +struct iwl_dev_tx_power_cmd { + __le32 set_mode; + __le32 mac_context_id; + __le16 pwr_restriction; + __le16 dev_24; + __le16 dev_52_low; + __le16 dev_52_high; +} __packed; /* TX_REDUCED_POWER_API_S_VER_2 */ + +#define IWL_DEV_MAX_TX_POWER 0x7FFF + +/** * struct iwl_beacon_filter_cmd * REPLY_BEACON_FILTERING_CMD = 0xd2 (command) * @id_and_color: MAC contex identifier diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 4f81dcf..d6cced4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -122,46 +122,6 @@ enum iwl_scan_complete_status { SCAN_COMP_STATUS_ERR_ALLOC_TE = 0x0C, }; -/** - * struct iwl_scan_results_notif - scan results for one channel - * ( SCAN_RESULTS_NOTIFICATION = 0x83 ) - * @channel: which channel the results are from - * @band: 0 for 5.2 GHz, 1 for 2.4 GHz - * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request - * @num_probe_not_sent: # of request that weren't sent due to not enough time - * @duration: duration spent in channel, in usecs - * @statistics: statistics gathered for this channel - */ -struct iwl_scan_results_notif { - u8 channel; - u8 band; - u8 probe_status; - u8 num_probe_not_sent; - __le32 duration; - __le32 statistics[SCAN_RESULTS_STATISTICS]; -} __packed; /* SCAN_RESULT_NTF_API_S_VER_2 */ - -/** - * struct iwl_scan_complete_notif - notifies end of scanning (all channels) - * ( SCAN_COMPLETE_NOTIFICATION = 0x84 ) - * @scanned_channels: number of channels scanned (and number of valid results) - * @status: one of SCAN_COMP_STATUS_* - * @bt_status: BT on/off status - * @last_channel: last channel that was scanned - * @tsf_low: TSF timer (lower half) in usecs - * @tsf_high: TSF timer (higher half) in usecs - * @results: array of scan results, only "scanned_channels" of them are valid - */ -struct iwl_scan_complete_notif { - u8 scanned_channels; - u8 status; - u8 bt_status; - u8 last_channel; - __le32 tsf_low; - __le32 tsf_high; - struct iwl_scan_results_notif results[]; -} __packed; /* SCAN_COMPLETE_NTF_API_S_VER_2 */ - /* scan offload */ #define IWL_SCAN_MAX_BLACKLIST_LEN 64 #define IWL_SCAN_SHORT_BLACKLIST_LEN 16 @@ -554,7 +514,7 @@ struct iwl_scan_req_unified_lmac { } __packed; /** - * struct iwl_lmac_scan_results_notif - scan results for one channel - + * struct iwl_scan_results_notif - scan results for one channel - * SCAN_RESULT_NTF_API_S_VER_3 * @channel: which channel the results are from * @band: 0 for 5.2 GHz, 1 for 2.4 GHz @@ -562,7 +522,7 @@ struct iwl_scan_req_unified_lmac { * @num_probe_not_sent: # of request that weren't sent due to not enough time * @duration: duration spent in channel, in usecs */ -struct iwl_lmac_scan_results_notif { +struct iwl_scan_results_notif { u8 channel; u8 band; u8 probe_status; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index aab68cb..01b1da6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -281,19 +281,6 @@ struct iwl_tx_ant_cfg_cmd { __le32 valid; } __packed; -/** - * struct iwl_reduce_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @flags: (reserved for future implementation) - * @mac_context_id: id of the mac ctx for which we are reducing TX power. - * @pwr_restriction: TX power restriction in dBms. - */ -struct iwl_reduce_tx_power_cmd { - u8 flags; - u8 mac_context_id; - __le16 pwr_restriction; -} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ - /* * Calibration control struct. * Sent as part of the phy configuration command. diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index bc5eac4..df86963 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,7 +32,7 @@ * BSD LICENSE * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -322,7 +322,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) lockdep_assert_held(&mvm->mutex); - if (WARN_ON_ONCE(mvm->init_ucode_complete || mvm->calibrating)) + if (WARN_ON_ONCE(mvm->calibrating)) return 0; iwl_init_notification_wait(&mvm->notif_wait, @@ -396,8 +396,6 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) */ ret = iwl_wait_notification(&mvm->notif_wait, &calib_wait, MVM_UCODE_CALIB_TIMEOUT); - if (!ret) - mvm->init_ucode_complete = true; if (ret && iwl_mvm_is_radio_killed(mvm)) { IWL_DEBUG_RF_KILL(mvm, "RFKILL while calibrating.\n"); @@ -494,15 +492,6 @@ int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm, mvm->fw_dump_desc = desc; - /* stop recording */ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); - } else { - iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); - /* wait before we collect the data till the DBGC stop */ - udelay(100); - } - queue_delayed_work(system_wq, &mvm->fw_dump_wk, delay); return 0; @@ -658,25 +647,24 @@ int iwl_mvm_up(struct iwl_mvm *mvm) * module loading, load init ucode now * (for example, if we were in RFKILL) */ - if (!mvm->init_ucode_complete) { - ret = iwl_run_init_mvm_ucode(mvm, false); - if (ret && !iwlmvm_mod_params.init_dbg) { - IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); - /* this can't happen */ - if (WARN_ON(ret > 0)) - ret = -ERFKILL; - goto error; - } - if (!iwlmvm_mod_params.init_dbg) { - /* - * should stop and start HW since that INIT - * image just loaded - */ - iwl_trans_stop_device(mvm->trans); - ret = iwl_trans_start_hw(mvm->trans); - if (ret) - return ret; - } + ret = iwl_run_init_mvm_ucode(mvm, false); + if (ret && !iwlmvm_mod_params.init_dbg) { + IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); + /* this can't happen */ + if (WARN_ON(ret > 0)) + ret = -ERFKILL; + goto error; + } + if (!iwlmvm_mod_params.init_dbg) { + /* + * Stop and start the transport without entering low power + * mode. This will save the state of other components on the + * device that are triggered by the INIT firwmare (MFUART). + */ + _iwl_trans_stop_device(mvm->trans, false); + _iwl_trans_start_hw(mvm->trans, false); + if (ret) + return ret; } if (iwlmvm_mod_params.init_dbg) diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 8455517..40265b9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1322,7 +1322,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); iwl_mvm_d0i3_enable_tx(mvm, NULL); - ret = iwl_mvm_update_quotas(mvm, false, NULL); + ret = iwl_mvm_update_quotas(mvm, true, NULL); if (ret) IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", ret); @@ -1471,8 +1471,8 @@ static struct iwl_mvm_phy_ctxt *iwl_mvm_get_free_phy_ctxt(struct iwl_mvm *mvm) return NULL; } -static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - s8 tx_power) +static int iwl_mvm_set_tx_power_old(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, s8 tx_power) { /* FW is in charge of regulatory enforcement */ struct iwl_reduce_tx_power_cmd reduce_txpwr_cmd = { @@ -1485,6 +1485,26 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &reduce_txpwr_cmd); } +static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + s16 tx_power) +{ + struct iwl_dev_tx_power_cmd cmd = { + .set_mode = 0, + .mac_context_id = + cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), + .pwr_restriction = cpu_to_le16(8 * tx_power), + }; + + if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_TX_POWER_DEV)) + return iwl_mvm_set_tx_power_old(mvm, vif, tx_power); + + if (tx_power == IWL_DEFAULT_MAX_TX_POWER) + cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, + sizeof(cmd), &cmd); +} + static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index d5522a1..cf70f68 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -603,7 +603,6 @@ struct iwl_mvm { enum iwl_ucode_type cur_ucode; bool ucode_loaded; - bool init_ucode_complete; bool calibrating; u32 error_event_table; u32 log_event_table; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a08b03d..1c66297 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -865,6 +865,16 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) return; mutex_lock(&mvm->mutex); + + /* stop recording */ + if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + } else { + iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); + /* wait before we collect the data till the DBGC stop */ + udelay(100); + } + iwl_mvm_fw_error_dump(mvm); /* start recording again if the firmware is not crashed */ diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 78ec7db..d6314dd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -478,6 +478,11 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac, if (vif->type != NL80211_IFTYPE_STATION) return; + if (sig == 0) { + IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); + return; + } + mvmvif->bf_data.ave_beacon_signal = sig; /* BT Coex */ diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 74e1c86..1075a21 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -319,7 +319,7 @@ int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_scan_complete_notif *notif = (void *)pkt->data; + struct iwl_lmac_scan_complete_notif *notif = (void *)pkt->data; IWL_DEBUG_SCAN(mvm, "Scan offload iteration complete: status=0x%x scanned channels=%d\n", diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 2de8fbf..47bbf57 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -5,8 +5,8 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2007 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,8 +31,8 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2005 - 2015 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -104,7 +104,7 @@ static void iwl_pcie_free_fw_monitor(struct iwl_trans *trans) static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct page *page; + struct page *page = NULL; dma_addr_t phys; u32 size; u8 power; @@ -131,6 +131,7 @@ static void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans) DMA_FROM_DEVICE); if (dma_mapping_error(trans->dev, phys)) { __free_pages(page, order); + page = NULL; continue; } IWL_INFO(trans, @@ -1020,7 +1021,7 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill, was_hw_rfkill; @@ -1115,7 +1116,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) { if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - iwl_trans_pcie_stop_device(trans); + iwl_trans_pcie_stop_device(trans, true); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -1200,7 +1201,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { bool hw_rfkill; int err; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f0188c8..2721cf8 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -126,7 +126,7 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, do { status = usb_control_msg(udev, pipe, request, reqtype, value, - index, pdata, len, 0); /*max. timeout*/ + index, pdata, len, 1000); if (status < 0) { /* firmware download is checksumed, don't retry */ if ((value >= FW_8192C_START_ADDRESS && diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 1899c74..05b9a69 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -25,7 +25,6 @@ #ifndef _LINUX_NETDEVICE_H #define _LINUX_NETDEVICE_H -#include <linux/pm_qos.h> #include <linux/timer.h> #include <linux/bug.h> #include <linux/delay.h> @@ -1499,8 +1498,6 @@ enum netdev_priv_flags { * * @qdisc_tx_busylock: XXX: need comments on this one * - * @pm_qos_req: Power Management QoS object - * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 0caa3a2..3b29115 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -145,11 +145,19 @@ struct tcp_sock { * read the code and the spec side by side (and laugh ...) * See RFC793 and RFC1122. The RFC writes these in capitals. */ + u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived + * sum(delta(rcv_nxt)), or how many bytes + * were acked. + */ u32 rcv_nxt; /* What we want to receive next */ u32 copied_seq; /* Head of yet unread data */ u32 rcv_wup; /* rcv_nxt on last window update sent */ u32 snd_nxt; /* Next sequence we send */ + u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked + * sum(delta(snd_una)), or how many bytes + * were acked. + */ u32 snd_una; /* First byte we want an ack for */ u32 snd_sml; /* Last byte of the most recently transmitted small packet */ u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index eeda676..6ea16c8 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -30,11 +30,13 @@ struct wpan_phy_cca; struct cfg802154_ops { struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); int (*add_virtual_intf)(struct wpan_phy *wpan_phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr); int (*del_virtual_intf)(struct wpan_phy *wpan_phy, diff --git a/include/net/codel.h b/include/net/codel.h index aeee280..1e18005 100644 --- a/include/net/codel.h +++ b/include/net/codel.h @@ -120,11 +120,13 @@ static inline u32 codel_time_to_us(codel_time_t val) * struct codel_params - contains codel parameters * @target: target queue size (in time units) * @interval: width of moving time window + * @mtu: device mtu, or minimal queue backlog in bytes. * @ecn: is Explicit Congestion Notification enabled */ struct codel_params { codel_time_t target; codel_time_t interval; + u32 mtu; bool ecn; }; @@ -166,10 +168,12 @@ struct codel_stats { u32 ecn_mark; }; -static void codel_params_init(struct codel_params *params) +static void codel_params_init(struct codel_params *params, + const struct Qdisc *sch) { params->interval = MS2TIME(100); params->target = MS2TIME(5); + params->mtu = psched_mtu(qdisc_dev(sch)); params->ecn = false; } @@ -180,7 +184,7 @@ static void codel_vars_init(struct codel_vars *vars) static void codel_stats_init(struct codel_stats *stats) { - stats->maxpacket = 256; + stats->maxpacket = 0; } /* @@ -234,7 +238,7 @@ static bool codel_should_drop(const struct sk_buff *skb, stats->maxpacket = qdisc_pkt_len(skb); if (codel_time_before(vars->ldelay, params->target) || - sch->qstats.backlog <= stats->maxpacket) { + sch->qstats.backlog <= params->mtu) { /* went below - stay below for at least interval */ vars->first_above_time = 0; return false; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index b4bef11..8e3668b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1666,6 +1666,8 @@ struct ieee80211_tx_control { * @sta: station table entry, %NULL for per-vif queue * @tid: the TID for this queue (unused for per-vif queue) * @ac: the AC for this queue + * @drv_priv: data area for driver use, will always be aligned to + * sizeof(void *). * * The driver can obtain packets from this queue by calling * ieee80211_tx_dequeue(). diff --git a/include/net/mac802154.h b/include/net/mac802154.h index e18e7fd..7df28a4 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -247,19 +247,109 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) __put_unaligned_memmove64(swab64p(le64_src), be64_dst); } -/* Basic interface to register ieee802154 device */ +/** + * ieee802154_alloc_hw - Allocate a new hardware device + * + * This must be called once for each hardware device. The returned pointer + * must be used to refer to this device when calling other functions. + * mac802154 allocates a private data area for the driver pointed to by + * @priv in &struct ieee802154_hw, the size of this area is given as + * @priv_data_len. + * + * @priv_data_len: length of private data + * @ops: callbacks for this device + * + * Return: A pointer to the new hardware device, or %NULL on error. + */ struct ieee802154_hw * ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); + +/** + * ieee802154_free_hw - free hardware descriptor + * + * This function frees everything that was allocated, including the + * private data for the driver. You must call ieee802154_unregister_hw() + * before calling this function. + * + * @hw: the hardware to free + */ void ieee802154_free_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_register_hw - Register hardware device + * + * You must call this function before any other functions in + * mac802154. Note that before a hardware can be registered, you + * need to fill the contained wpan_phy's information. + * + * @hw: the device to register as returned by ieee802154_alloc_hw() + * + * Return: 0 on success. An error code otherwise. + */ int ieee802154_register_hw(struct ieee802154_hw *hw); + +/** + * ieee802154_unregister_hw - Unregister a hardware device + * + * This function instructs mac802154 to free allocated resources + * and unregister netdevices from the networking subsystem. + * + * @hw: the hardware to unregister + */ void ieee802154_unregister_hw(struct ieee802154_hw *hw); +/** + * ieee802154_rx - receive frame + * + * Use this function to hand received frames to mac802154. The receive + * buffer in @skb must start with an IEEE 802.15.4 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee802154 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + */ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); + +/** + * ieee802154_rx_irqsafe - receive frame + * + * Like ieee802154_rx() but can be called in IRQ context + * (internally defers to a tasklet.) + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac802154 after this call + * @lqi: link quality indicator + */ void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi); - +/** + * ieee802154_wake_queue - wake ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_wake_queue. + */ void ieee802154_wake_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_stop_queue - stop ieee802154 queue + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * + * Drivers should use this function instead of netif_stop_queue. + */ void ieee802154_stop_queue(struct ieee802154_hw *hw); + +/** + * ieee802154_xmit_complete - frame transmission complete + * + * @hw: pointer as obtained from ieee802154_alloc_hw(). + * @skb: buffer for transmission + * @ifs_handling: indicate interframe space handling + */ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, bool ifs_handling); diff --git a/include/net/tcp.h b/include/net/tcp.h index 051dc5c2..6d204f3 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -576,7 +576,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) } /* tcp.c */ -void tcp_get_info(const struct sock *, struct tcp_info *); +void tcp_get_info(struct sock *, struct tcp_info *); /* Read 'sendfile()'-style from a TCP socket */ typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, @@ -804,6 +804,8 @@ enum tcp_ca_ack_event_flags { /* Requires ECN/ECT set on all packets */ #define TCP_CONG_NEEDS_ECN 0x2 +union tcp_cc_info; + struct tcp_congestion_ops { struct list_head list; u32 key; @@ -829,7 +831,8 @@ struct tcp_congestion_ops { /* hook for packet ack accounting (optional) */ void (*pkts_acked)(struct sock *sk, u32 num_acked, s32 rtt_us); /* get info for inet_diag (optional) */ - int (*get_info)(struct sock *sk, u32 ext, struct sk_buff *skb); + size_t (*get_info)(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); char name[TCP_CA_NAME_MAX]; struct module *owner; diff --git a/include/uapi/linux/inet_diag.h b/include/uapi/linux/inet_diag.h index d65c0a0..c7093c7 100644 --- a/include/uapi/linux/inet_diag.h +++ b/include/uapi/linux/inet_diag.h @@ -143,4 +143,8 @@ struct tcp_dctcp_info { __u32 dctcp_ab_tot; }; +union tcp_cc_info { + struct tcpvegas_info vegas; + struct tcp_dctcp_info dctcp; +}; #endif /* _UAPI_INET_DIAG_H_ */ diff --git a/include/uapi/linux/mpls.h b/include/uapi/linux/mpls.h index bc9abfe..139d4dd 100644 --- a/include/uapi/linux/mpls.h +++ b/include/uapi/linux/mpls.h @@ -31,4 +31,14 @@ struct mpls_label { #define MPLS_LS_TTL_MASK 0x000000FF #define MPLS_LS_TTL_SHIFT 0 +/* Reserved labels */ +#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */ +#define MPLS_LABEL_RTALERT 1 /* RFC3032 */ +#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */ +#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */ +#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */ +#define MPLS_LABEL_GAL 13 /* RFC5586 */ +#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */ +#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ + #endif /* _UAPI_MPLS_H */ diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 3b97183..faa72f4 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -112,6 +112,7 @@ enum { #define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ #define TCP_TIMESTAMP 24 #define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ +#define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ struct tcp_repair_opt { __u32 opt_code; @@ -189,6 +190,8 @@ struct tcp_info { __u64 tcpi_pacing_rate; __u64 tcpi_max_pacing_rate; + __u64 tcpi_bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked */ + __u64 tcpi_bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived */ }; /* for TCP_MD5SIG socket option */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 476709b..4663c3d 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1557,7 +1557,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); - if (!hci_dev_test_flag(hdev, HCI_UNREGISTER)) { + if (!hci_dev_test_flag(hdev, HCI_UNREGISTER) && + test_bit(HCI_UP, &hdev->flags)) { /* Execute vendor specific shutdown routine */ if (hdev->shutdown) hdev->shutdown(hdev); diff --git a/net/core/dev.c b/net/core/dev.c index c7ba038..2c1c67f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5209,7 +5209,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, if (__netdev_find_adj(upper_dev, dev, &upper_dev->all_adj_list.upper)) return -EBUSY; - if (__netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper)) + if (__netdev_find_adj(dev, upper_dev, &dev->adj_list.upper)) return -EEXIST; if (master && netdev_master_upper_dev_get(dev)) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 78fc04a..572af00 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -601,7 +601,7 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) } err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - RTM_GETNSID, net, peer, -1); + RTM_NEWNSID, net, peer, -1); if (err < 0) goto err_out; diff --git a/net/core/sock.c b/net/core/sock.c index e891bcf..292f422 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1474,8 +1474,8 @@ void sk_release_kernel(struct sock *sk) return; sock_hold(sk); - sock_net_set(sk, get_net(&init_net)); sock_release(sk->sk_socket); + sock_net_set(sk, get_net(&init_net)); sock_put(sk); } EXPORT_SYMBOL(sk_release_kernel); diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 05dab29..4adfd4d 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -3,7 +3,9 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o obj-y += 6lowpan/ ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ - header_ops.o sysfs.o nl802154.o + header_ops.o sysfs.o nl802154.o trace.o ieee802154_socket-y := socket.o +CFLAGS_trace.o := -I$(src) + ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c index 1b9d25f6..346c666 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -175,6 +175,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) int rc = -ENOBUFS; struct net_device *dev; int type = __IEEE802154_DEV_INVALID; + unsigned char name_assign_type; pr_debug("%s\n", __func__); @@ -190,8 +191,10 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) if (devname[nla_len(info->attrs[IEEE802154_ATTR_DEV_NAME]) - 1] != '\0') return -EINVAL; /* phy name should be null-terminated */ + name_assign_type = NET_NAME_USER; } else { devname = "wpan%d"; + name_assign_type = NET_NAME_ENUM; } if (strlen(devname) >= IFNAMSIZ) @@ -221,7 +224,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info) } dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname, - type); + name_assign_type, type); if (IS_ERR(dev)) { rc = PTR_ERR(dev); goto nla_put_failure; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index a4daf91..f3c12f6 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -589,7 +589,7 @@ static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info) return rdev_add_virtual_intf(rdev, nla_data(info->attrs[NL802154_ATTR_IFNAME]), - type, extended_addr); + NET_NAME_USER, type, extended_addr); } static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info) diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 7c46732..7b5a9dd 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -4,13 +4,16 @@ #include <net/cfg802154.h> #include "core.h" +#include "trace.h" static inline struct net_device * rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, - const char *name, int type) + const char *name, + unsigned char name_assign_type, + int type) { return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name, - type); + name_assign_type, type); } static inline void @@ -22,75 +25,131 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, static inline int rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { - return rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, type, + int ret; + + trace_802154_rdev_add_virtual_intf(&rdev->wpan_phy, name, type, extended_addr); + ret = rdev->ops->add_virtual_intf(&rdev->wpan_phy, name, + name_assign_type, type, + extended_addr); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_del_virtual_intf(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev) { - return rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev); + int ret; + + trace_802154_rdev_del_virtual_intf(&rdev->wpan_phy, wpan_dev); + ret = rdev->ops->del_virtual_intf(&rdev->wpan_phy, wpan_dev); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_channel(struct cfg802154_registered_device *rdev, u8 page, u8 channel) { - return rdev->ops->set_channel(&rdev->wpan_phy, page, channel); + int ret; + + trace_802154_rdev_set_channel(&rdev->wpan_phy, page, channel); + ret = rdev->ops->set_channel(&rdev->wpan_phy, page, channel); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_cca_mode(struct cfg802154_registered_device *rdev, const struct wpan_phy_cca *cca) { - return rdev->ops->set_cca_mode(&rdev->wpan_phy, cca); + int ret; + + trace_802154_rdev_set_cca_mode(&rdev->wpan_phy, cca); + ret = rdev->ops->set_cca_mode(&rdev->wpan_phy, cca); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_pan_id(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, __le16 pan_id) { - return rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + int ret; + + trace_802154_rdev_set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + ret = rdev->ops->set_pan_id(&rdev->wpan_phy, wpan_dev, pan_id); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_short_addr(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, __le16 short_addr) { - return rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + int ret; + + trace_802154_rdev_set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + ret = rdev->ops->set_short_addr(&rdev->wpan_phy, wpan_dev, short_addr); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_backoff_exponent(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, u8 min_be, u8 max_be) { - return rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, + int ret; + + trace_802154_rdev_set_backoff_exponent(&rdev->wpan_phy, wpan_dev, min_be, max_be); + ret = rdev->ops->set_backoff_exponent(&rdev->wpan_phy, wpan_dev, + min_be, max_be); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_max_csma_backoffs(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, u8 max_csma_backoffs) { - return rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, - max_csma_backoffs); + int ret; + + trace_802154_rdev_set_csma_backoffs(&rdev->wpan_phy, wpan_dev, + max_csma_backoffs); + ret = rdev->ops->set_max_csma_backoffs(&rdev->wpan_phy, wpan_dev, + max_csma_backoffs); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_max_frame_retries(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, s8 max_frame_retries) { - return rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, + int ret; + + trace_802154_rdev_set_max_frame_retries(&rdev->wpan_phy, wpan_dev, max_frame_retries); + ret = rdev->ops->set_max_frame_retries(&rdev->wpan_phy, wpan_dev, + max_frame_retries); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } static inline int rdev_set_lbt_mode(struct cfg802154_registered_device *rdev, struct wpan_dev *wpan_dev, bool mode) { - return rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + int ret; + + trace_802154_rdev_set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + ret = rdev->ops->set_lbt_mode(&rdev->wpan_phy, wpan_dev, mode); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; } #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/ieee802154/trace.c b/net/ieee802154/trace.c new file mode 100644 index 0000000..95f997f --- /dev/null +++ b/net/ieee802154/trace.c @@ -0,0 +1,7 @@ +#include <linux/module.h> + +#ifndef __CHECKER__ +#define CREATE_TRACE_POINTS +#include "trace.h" + +#endif diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h new file mode 100644 index 0000000..5ac25eb --- /dev/null +++ b/net/ieee802154/trace.h @@ -0,0 +1,247 @@ +/* Based on net/wireless/tracing.h */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cfg802154 + +#if !defined(__RDEV_CFG802154_OPS_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define __RDEV_CFG802154_OPS_TRACE + +#include <linux/tracepoint.h> + +#include <net/cfg802154.h> + +#define MAXNAME 32 +#define WPAN_PHY_ENTRY __array(char, wpan_phy_name, MAXNAME) +#define WPAN_PHY_ASSIGN strlcpy(__entry->wpan_phy_name, \ + wpan_phy_name(wpan_phy), \ + MAXNAME) +#define WPAN_PHY_PR_FMT "%s" +#define WPAN_PHY_PR_ARG __entry->wpan_phy_name + +#define WPAN_DEV_ENTRY __field(u32, identifier) +#define WPAN_DEV_ASSIGN (__entry->identifier) = (!IS_ERR_OR_NULL(wpan_dev) \ + ? wpan_dev->identifier : 0) +#define WPAN_DEV_PR_FMT "wpan_dev(%u)" +#define WPAN_DEV_PR_ARG (__entry->identifier) + +#define WPAN_CCA_ENTRY __field(enum nl802154_cca_modes, cca_mode) \ + __field(enum nl802154_cca_opts, cca_opt) +#define WPAN_CCA_ASSIGN \ + do { \ + (__entry->cca_mode) = cca->mode; \ + (__entry->cca_opt) = cca->opt; \ + } while (0) +#define WPAN_CCA_PR_FMT "cca_mode: %d, cca_opt: %d" +#define WPAN_CCA_PR_ARG __entry->cca_mode, __entry->cca_opt + +#define BOOL_TO_STR(bo) (bo) ? "true" : "false" + +/************************************************************* + * rdev->ops traces * + *************************************************************/ + +TRACE_EVENT(802154_rdev_add_virtual_intf, + TP_PROTO(struct wpan_phy *wpan_phy, char *name, + enum nl802154_iftype type, __le64 extended_addr), + TP_ARGS(wpan_phy, name, type, extended_addr), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __string(vir_intf_name, name ? name : "<noname>") + __field(enum nl802154_iftype, type) + __field(__le64, extended_addr) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __assign_str(vir_intf_name, name ? name : "<noname>"); + __entry->type = type; + __entry->extended_addr = extended_addr; + ), + TP_printk(WPAN_PHY_PR_FMT ", virtual intf name: %s, type: %d, ea %llx", + WPAN_PHY_PR_ARG, __get_str(vir_intf_name), __entry->type, + __le64_to_cpu(__entry->extended_addr)) +); + +TRACE_EVENT(802154_rdev_del_virtual_intf, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), + TP_ARGS(wpan_phy, wpan_dev), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT, WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG) +); + +TRACE_EVENT(802154_rdev_set_channel, + TP_PROTO(struct wpan_phy *wpan_phy, u8 page, u8 channel), + TP_ARGS(wpan_phy, page, channel), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(u8, page) + __field(u8, channel) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->page = page; + __entry->channel = channel; + ), + TP_printk(WPAN_PHY_PR_FMT ", page: %d, channel: %d", WPAN_PHY_PR_ARG, + __entry->page, __entry->channel) +); + +TRACE_EVENT(802154_rdev_set_cca_mode, + TP_PROTO(struct wpan_phy *wpan_phy, const struct wpan_phy_cca *cca), + TP_ARGS(wpan_phy, cca), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_CCA_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_CCA_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_CCA_PR_FMT, WPAN_PHY_PR_ARG, + WPAN_CCA_PR_ARG) +); + +DECLARE_EVENT_CLASS(802154_le16_template, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(__le16, le16arg) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->le16arg = le16arg; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", pan id: 0x%04x", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, + __le16_to_cpu(__entry->le16arg)) +); + +DEFINE_EVENT(802154_le16_template, 802154_rdev_set_pan_id, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg) +); + +DEFINE_EVENT_PRINT(802154_le16_template, 802154_rdev_set_short_addr, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + __le16 le16arg), + TP_ARGS(wpan_phy, wpan_dev, le16arg), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT ", sa: 0x%04x", + WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG, + __le16_to_cpu(__entry->le16arg)) +); + +TRACE_EVENT(802154_rdev_set_backoff_exponent, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + u8 min_be, u8 max_be), + TP_ARGS(wpan_phy, wpan_dev, min_be, max_be), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(u8, min_be) + __field(u8, max_be) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->min_be = min_be; + __entry->max_be = max_be; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", min be: %d, max_be: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->min_be, __entry->max_be) +); + +TRACE_EVENT(802154_rdev_set_csma_backoffs, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + u8 max_csma_backoffs), + TP_ARGS(wpan_phy, wpan_dev, max_csma_backoffs), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(u8, max_csma_backoffs) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->max_csma_backoffs = max_csma_backoffs; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", max csma backoffs: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->max_csma_backoffs) +); + +TRACE_EVENT(802154_rdev_set_max_frame_retries, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + s8 max_frame_retries), + TP_ARGS(wpan_phy, wpan_dev, max_frame_retries), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(s8, max_frame_retries) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->max_frame_retries = max_frame_retries; + ), + + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", max frame retries: %d", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, __entry->max_frame_retries) +); + +TRACE_EVENT(802154_rdev_set_lbt_mode, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + bool mode), + TP_ARGS(wpan_phy, wpan_dev, mode), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(bool, mode) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->mode = mode; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", lbt mode: %s", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->mode)) +); + +TRACE_EVENT(802154_rdev_return_int, + TP_PROTO(struct wpan_phy *wpan_phy, int ret), + TP_ARGS(wpan_phy, ret), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + __field(int, ret) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + __entry->ret = ret; + ), + TP_printk(WPAN_PHY_PR_FMT ", returned: %d", WPAN_PHY_PR_ARG, + __entry->ret) +); + +#endif /* !__RDEV_CFG802154_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace +#include <trace/define_trace.h> diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index bb77ebd..4d32262 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -224,14 +224,16 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, handler->idiag_get_info(sk, r, info); if (sk->sk_state < TCP_TIME_WAIT) { - int err = 0; + union tcp_cc_info info; + size_t sz = 0; + int attr; rcu_read_lock(); ca_ops = READ_ONCE(icsk->icsk_ca_ops); if (ca_ops && ca_ops->get_info) - err = ca_ops->get_info(sk, ext, skb); + sz = ca_ops->get_info(sk, ext, &attr, &info); rcu_read_unlock(); - if (err < 0) + if (sz && nla_put(skb, attr, sz, &info) < 0) goto errout; } diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 8c5cd9e..46efa03 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -252,6 +252,7 @@ #include <linux/types.h> #include <linux/fcntl.h> #include <linux/poll.h> +#include <linux/inet_diag.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/skbuff.h> @@ -2592,7 +2593,7 @@ EXPORT_SYMBOL(compat_tcp_setsockopt); #endif /* Return information about state of tcp endpoint in API format. */ -void tcp_get_info(const struct sock *sk, struct tcp_info *info) +void tcp_get_info(struct sock *sk, struct tcp_info *info) { const struct tcp_sock *tp = tcp_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); @@ -2663,6 +2664,11 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info) rate = READ_ONCE(sk->sk_max_pacing_rate); info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL; + + spin_lock_bh(&sk->sk_lock.slock); + info->tcpi_bytes_acked = tp->bytes_acked; + info->tcpi_bytes_received = tp->bytes_received; + spin_unlock_bh(&sk->sk_lock.slock); } EXPORT_SYMBOL_GPL(tcp_get_info); @@ -2734,6 +2740,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level, return -EFAULT; return 0; } + case TCP_CC_INFO: { + const struct tcp_congestion_ops *ca_ops; + union tcp_cc_info info; + size_t sz = 0; + int attr; + + if (get_user(len, optlen)) + return -EFAULT; + + ca_ops = icsk->icsk_ca_ops; + if (ca_ops && ca_ops->get_info) + sz = ca_ops->get_info(sk, ~0U, &attr, &info); + + len = min_t(unsigned int, len, sz); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &info, len)) + return -EFAULT; + return 0; + } case TCP_QUICKACK: val = !icsk->icsk_ack.pingpong; break; diff --git a/net/ipv4/tcp_dctcp.c b/net/ipv4/tcp_dctcp.c index 4376016..4c41c12 100644 --- a/net/ipv4/tcp_dctcp.c +++ b/net/ipv4/tcp_dctcp.c @@ -277,7 +277,8 @@ static void dctcp_cwnd_event(struct sock *sk, enum tcp_ca_event ev) } } -static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t dctcp_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct dctcp *ca = inet_csk_ca(sk); @@ -286,18 +287,17 @@ static int dctcp_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) */ if (ext & (1 << (INET_DIAG_DCTCPINFO - 1)) || ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcp_dctcp_info info; - - memset(&info, 0, sizeof(info)); + memset(info, 0, sizeof(struct tcp_dctcp_info)); if (inet_csk(sk)->icsk_ca_ops != &dctcp_reno) { - info.dctcp_enabled = 1; - info.dctcp_ce_state = (u16) ca->ce_state; - info.dctcp_alpha = ca->dctcp_alpha; - info.dctcp_ab_ecn = ca->acked_bytes_ecn; - info.dctcp_ab_tot = ca->acked_bytes_total; + info->dctcp.dctcp_enabled = 1; + info->dctcp.dctcp_ce_state = (u16) ca->ce_state; + info->dctcp.dctcp_alpha = ca->dctcp_alpha; + info->dctcp.dctcp_ab_ecn = ca->acked_bytes_ecn; + info->dctcp.dctcp_ab_tot = ca->acked_bytes_total; } - return nla_put(skb, INET_DIAG_DCTCPINFO, sizeof(info), &info); + *attr = INET_DIAG_DCTCPINFO; + return sizeof(*info); } return 0; } diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index e3d87ac..3c673d5 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -206,6 +206,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, skb_set_owner_r(skb2, child); __skb_queue_tail(&child->sk_receive_queue, skb2); tp->syn_data_acked = 1; + tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1; } else { end_seq = TCP_SKB_CB(skb)->seq + 1; } diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index 67476f0..f71002e 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -300,24 +300,25 @@ static u32 tcp_illinois_ssthresh(struct sock *sk) } /* Extract info for Tcp socket info provided via netlink. */ -static int tcp_illinois_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t tcp_illinois_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct illinois *ca = inet_csk_ca(sk); if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = 1, - .tcpv_rttcnt = ca->cnt_rtt, - .tcpv_minrtt = ca->base_rtt, - }; + info->vegas.tcpv_enabled = 1; + info->vegas.tcpv_rttcnt = ca->cnt_rtt; + info->vegas.tcpv_minrtt = ca->base_rtt; + info->vegas.tcpv_rtt = 0; - if (info.tcpv_rttcnt > 0) { + if (info->vegas.tcpv_rttcnt > 0) { u64 t = ca->sum_rtt; - do_div(t, info.tcpv_rttcnt); - info.tcpv_rtt = t; + do_div(t, info->vegas.tcpv_rttcnt); + info->vegas.tcpv_rtt = t; } - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3a4d9b34..bc790ea 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1820,14 +1820,12 @@ advance_sp: for (j = 0; j < used_sacks; j++) tp->recv_sack_cache[i++] = sp[j]; - tcp_mark_lost_retrans(sk); - - tcp_verify_left_out(tp); - if ((state.reord < tp->fackets_out) && ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker)) tcp_update_reordering(sk, tp->fackets_out - state.reord, 0); + tcp_mark_lost_retrans(sk); + tcp_verify_left_out(tp); out: #if FASTRETRANS_DEBUG > 0 @@ -3280,6 +3278,24 @@ static inline bool tcp_may_update_window(const struct tcp_sock *tp, (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd); } +/* If we update tp->snd_una, also update tp->bytes_acked */ +static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) +{ + u32 delta = ack - tp->snd_una; + + tp->bytes_acked += delta; + tp->snd_una = ack; +} + +/* If we update tp->rcv_nxt, also update tp->bytes_received */ +static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) +{ + u32 delta = seq - tp->rcv_nxt; + + tp->bytes_received += delta; + tp->rcv_nxt = seq; +} + /* Update our send window. * * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 @@ -3315,7 +3331,7 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 } } - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); return flag; } @@ -3497,7 +3513,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) * Note, we use the fact that SND.UNA>=SND.WL2. */ tcp_update_wl(tp, ack_seq); - tp->snd_una = ack; + tcp_snd_una_update(tp, ack); flag |= FLAG_WIN_UPDATE; tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); @@ -4236,7 +4252,7 @@ static void tcp_ofo_queue(struct sock *sk) tail = skb_peek_tail(&sk->sk_receive_queue); eaten = tail && tcp_try_coalesce(sk, tail, skb, &fragstolen); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (!eaten) __skb_queue_tail(&sk->sk_receive_queue, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -4404,7 +4420,7 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int __skb_pull(skb, hdrlen); eaten = (tail && tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0; - tcp_sk(sk)->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq); if (!eaten) { __skb_queue_tail(&sk->sk_receive_queue, skb); skb_set_owner_r(skb, sk); @@ -4497,7 +4513,7 @@ queue_and_out: eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); } - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); if (skb->len) tcp_event_data_recv(sk, skb); if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) @@ -5245,7 +5261,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tcp_rcv_rtt_measure_ts(sk, skb); __skb_pull(skb, tcp_header_len); - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPHPHITSTOUSER); eaten = 1; } diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index c71a1b8..a6cea1d 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -286,18 +286,19 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) } /* Extract info for Tcp socket info provided via netlink. */ -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb) +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct vegas *ca = inet_csk_ca(sk); + if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = ca->doing_vegas_now, - .tcpv_rttcnt = ca->cntRTT, - .tcpv_rtt = ca->baseRTT, - .tcpv_minrtt = ca->minRTT, - }; - - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + info->vegas.tcpv_enabled = ca->doing_vegas_now, + info->vegas.tcpv_rttcnt = ca->cntRTT, + info->vegas.tcpv_rtt = ca->baseRTT, + info->vegas.tcpv_minrtt = ca->minRTT, + + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv4/tcp_vegas.h b/net/ipv4/tcp_vegas.h index e8a6b33..ef9da53 100644 --- a/net/ipv4/tcp_vegas.h +++ b/net/ipv4/tcp_vegas.h @@ -19,6 +19,7 @@ void tcp_vegas_init(struct sock *sk); void tcp_vegas_state(struct sock *sk, u8 ca_state); void tcp_vegas_pkts_acked(struct sock *sk, u32 cnt, s32 rtt_us); void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event); -int tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb); +size_t tcp_vegas_get_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info); #endif /* __TCP_VEGAS_H */ diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c index b3c57cc..c10732e 100644 --- a/net/ipv4/tcp_westwood.c +++ b/net/ipv4/tcp_westwood.c @@ -256,18 +256,19 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event) } /* Extract info for Tcp socket info provided via netlink. */ -static int tcp_westwood_info(struct sock *sk, u32 ext, struct sk_buff *skb) +static size_t tcp_westwood_info(struct sock *sk, u32 ext, int *attr, + union tcp_cc_info *info) { const struct westwood *ca = inet_csk_ca(sk); if (ext & (1 << (INET_DIAG_VEGASINFO - 1))) { - struct tcpvegas_info info = { - .tcpv_enabled = 1, - .tcpv_rtt = jiffies_to_usecs(ca->rtt), - .tcpv_minrtt = jiffies_to_usecs(ca->rtt_min), - }; + info->vegas.tcpv_enabled = 1; + info->vegas.tcpv_rttcnt = 0; + info->vegas.tcpv_rtt = jiffies_to_usecs(ca->rtt), + info->vegas.tcpv_minrtt = jiffies_to_usecs(ca->rtt_min), - return nla_put(skb, INET_DIAG_VEGASINFO, sizeof(info), &info); + *attr = INET_DIAG_VEGASINFO; + return sizeof(struct tcpvegas_info); } return 0; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7fde1f2..c217775 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -886,22 +886,45 @@ static int ip6_dst_lookup_tail(struct sock *sk, #endif int err; - if (!*dst) - *dst = ip6_route_output(net, sk, fl6); - - err = (*dst)->error; - if (err) - goto out_err_release; + /* The correct way to handle this would be to do + * ip6_route_get_saddr, and then ip6_route_output; however, + * the route-specific preferred source forces the + * ip6_route_output call _before_ ip6_route_get_saddr. + * + * In source specific routing (no src=any default route), + * ip6_route_output will fail given src=any saddr, though, so + * that's why we try it again later. + */ + if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { + struct rt6_info *rt; + bool had_dst = *dst != NULL; - if (ipv6_addr_any(&fl6->saddr)) { - struct rt6_info *rt = (struct rt6_info *) *dst; + if (!had_dst) + *dst = ip6_route_output(net, sk, fl6); + rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; err = ip6_route_get_saddr(net, rt, &fl6->daddr, sk ? inet6_sk(sk)->srcprefs : 0, &fl6->saddr); if (err) goto out_err_release; + + /* If we had an erroneous initial result, pretend it + * never existed and let the SA-enabled version take + * over. + */ + if (!had_dst && (*dst)->error) { + dst_release(*dst); + *dst = NULL; + } } + if (!*dst) + *dst = ip6_route_output(net, sk, fl6); + + err = (*dst)->error; + if (err) + goto out_err_release; + #ifdef CONFIG_IPV6_OPTIMISTIC_DAD /* * Here if the dst entry we've looked up diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5c48293..d358888 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2245,9 +2245,10 @@ int ip6_route_get_saddr(struct net *net, unsigned int prefs, struct in6_addr *saddr) { - struct inet6_dev *idev = ip6_dst_idev((struct dst_entry *)rt); + struct inet6_dev *idev = + rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; int err = 0; - if (rt->rt6i_prefsrc.plen) + if (rt && rt->rt6i_prefsrc.plen) *saddr = rt->rt6i_prefsrc.addr; else err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b4ac596..bab5c63 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -819,13 +819,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, * (because if we remove a STA after ops->remove_interface() * the driver will have removed the vif info already!) * - * This is relevant only in WDS mode, in all other modes we've - * already removed all stations when disconnecting or similar, - * so warn otherwise. + * In WDS mode a station must exist here and be flushed, for + * AP_VLANs stations may exist since there's nothing else that + * would have removed them, but in other modes there shouldn't + * be any stations. */ flushed = sta_info_flush(sdata); - WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || - (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); + WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || + (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1))); /* don't count this interface for promisc/allmulti while it is down */ if (sdata->flags & IEEE80211_SDATA_ALLMULTI) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 12971b7..2880f2a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -66,6 +66,7 @@ static const struct rhashtable_params sta_rht_params = { .nelem_hint = 3, /* start small */ + .automatic_shrinking = true, .head_offset = offsetof(struct sta_info, hash_node), .key_offset = offsetof(struct sta_info, sta.addr), .key_len = ETH_ALEN, @@ -157,8 +158,24 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, const u8 *addr) { struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + struct rhash_head *tmp; + const struct bucket_table *tbl; + + rcu_read_lock(); + tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); - return rhashtable_lookup_fast(&local->sta_hash, addr, sta_rht_params); + for_each_sta_info(local, tbl, addr, sta, tmp) { + if (sta->sdata == sdata) { + rcu_read_unlock(); + /* this is safe as the caller must already hold + * another rcu read section or the mutex + */ + return sta; + } + } + rcu_read_unlock(); + return NULL; } /* diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 5d9f68c..70be9c7 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -22,13 +22,14 @@ static struct net_device * ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy, - const char *name, int type) + const char *name, + unsigned char name_assign_type, int type) { struct ieee802154_local *local = wpan_phy_priv(wpan_phy); struct net_device *dev; rtnl_lock(); - dev = ieee802154_if_add(local, name, type, + dev = ieee802154_if_add(local, name, name_assign_type, type, cpu_to_le64(0x0000000000000000ULL)); rtnl_unlock(); @@ -45,12 +46,14 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, static int ieee802154_add_iface(struct wpan_phy *phy, const char *name, + unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr) { struct ieee802154_local *local = wpan_phy_priv(phy); struct net_device *err; - err = ieee802154_if_add(local, name, type, extended_addr); + err = ieee802154_if_add(local, name, name_assign_type, type, + extended_addr); return PTR_ERR_OR_ZERO(err); } diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index bebd70f..127ba18 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -182,7 +182,8 @@ void ieee802154_iface_exit(void); void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata); struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr); + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr); void ieee802154_remove_interfaces(struct ieee802154_local *local); #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 38b56f9..91b75ab 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -522,7 +522,8 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, struct net_device * ieee802154_if_add(struct ieee802154_local *local, const char *name, - enum nl802154_iftype type, __le64 extended_addr) + unsigned char name_assign_type, enum nl802154_iftype type, + __le64 extended_addr) { struct net_device *ndev = NULL; struct ieee802154_sub_if_data *sdata = NULL; @@ -531,7 +532,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, ASSERT_RTNL(); ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, - NET_NAME_UNKNOWN, ieee802154_if_setup); + name_assign_type, ieee802154_if_setup); if (!ndev) return ERR_PTR(-ENOMEM); diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c index dcf7395..5b2be12 100644 --- a/net/mac802154/llsec.c +++ b/net/mac802154/llsec.c @@ -134,7 +134,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template) for (i = 0; i < ARRAY_SIZE(key->tfm); i++) { key->tfm[i] = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); - if (!key->tfm[i]) + if (IS_ERR(key->tfm[i])) goto err_tfm; if (crypto_aead_setkey(key->tfm[i], template->key, IEEE802154_LLSEC_KEY_SIZE)) @@ -144,7 +144,7 @@ llsec_key_alloc(const struct ieee802154_llsec_key *template) } key->tfm0 = crypto_alloc_blkcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC); - if (!key->tfm0) + if (IS_ERR(key->tfm0)) goto err_tfm; if (crypto_blkcipher_setkey(key->tfm0, template->key, diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 8500378..08cb32d 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -161,18 +161,21 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) rtnl_lock(); - dev = ieee802154_if_add(local, "wpan%d", NL802154_IFTYPE_NODE, + dev = ieee802154_if_add(local, "wpan%d", NET_NAME_ENUM, + NL802154_IFTYPE_NODE, cpu_to_le64(0x0000000000000000ULL)); if (IS_ERR(dev)) { rtnl_unlock(); rc = PTR_ERR(dev); - goto out_wq; + goto out_phy; } rtnl_unlock(); return 0; +out_phy: + wpan_phy_unregister(local->phy); out_wq: destroy_workqueue(local->workqueue); out: diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 954810c..7b3f732 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -647,7 +647,7 @@ int nla_get_labels(const struct nlattr *nla, return -EINVAL; switch (dec.label) { - case LABEL_IMPLICIT_NULL: + case MPLS_LABEL_IMPLNULL: /* RFC3032: This is a label that an LSR may * assign and distribute, but which never * actually appears in the encapsulation. @@ -935,7 +935,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) } /* In case the predefined labels need to be populated */ - if (limit > LABEL_IPV4_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV4NULL) { struct net_device *lo = net->loopback_dev; rt0 = mpls_rt_alloc(lo->addr_len); if (!rt0) @@ -945,7 +945,7 @@ static int resize_platform_label_table(struct net *net, size_t limit) rt0->rt_via_table = NEIGH_LINK_TABLE; memcpy(rt0->rt_via, lo->dev_addr, lo->addr_len); } - if (limit > LABEL_IPV6_EXPLICIT_NULL) { + if (limit > MPLS_LABEL_IPV6NULL) { struct net_device *lo = net->loopback_dev; rt2 = mpls_rt_alloc(lo->addr_len); if (!rt2) @@ -973,15 +973,15 @@ static int resize_platform_label_table(struct net *net, size_t limit) memcpy(labels, old, cp_size); /* If needed set the predefined labels */ - if ((old_limit <= LABEL_IPV6_EXPLICIT_NULL) && - (limit > LABEL_IPV6_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV6_EXPLICIT_NULL], rt2); + if ((old_limit <= MPLS_LABEL_IPV6NULL) && + (limit > MPLS_LABEL_IPV6NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2); rt2 = NULL; } - if ((old_limit <= LABEL_IPV4_EXPLICIT_NULL) && - (limit > LABEL_IPV4_EXPLICIT_NULL)) { - RCU_INIT_POINTER(labels[LABEL_IPV4_EXPLICIT_NULL], rt0); + if ((old_limit <= MPLS_LABEL_IPV4NULL) && + (limit > MPLS_LABEL_IPV4NULL)) { + RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0); rt0 = NULL; } diff --git a/net/mpls/internal.h b/net/mpls/internal.h index 693877d..b064c34 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -1,16 +1,6 @@ #ifndef MPLS_INTERNAL_H #define MPLS_INTERNAL_H -#define LABEL_IPV4_EXPLICIT_NULL 0 /* RFC3032 */ -#define LABEL_ROUTER_ALERT_LABEL 1 /* RFC3032 */ -#define LABEL_IPV6_EXPLICIT_NULL 2 /* RFC3032 */ -#define LABEL_IMPLICIT_NULL 3 /* RFC3032 */ -#define LABEL_ENTROPY_INDICATOR 7 /* RFC6790 */ -#define LABEL_GAL 13 /* RFC5586 */ -#define LABEL_OAM_ALERT 14 /* RFC3429 */ -#define LABEL_EXTENSION 15 /* RFC7274 */ - - struct mpls_shim_hdr { __be32 label_stack_entry; }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ec4adbd..daa0b81 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -3139,7 +3139,6 @@ static const struct rhashtable_params netlink_rhashtable_params = { .key_len = netlink_compare_arg_len, .obj_hashfn = netlink_hash, .obj_cmpfn = netlink_compare, - .max_size = 65536, .automatic_shrinking = true, }; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 5102c3c..b5989c6 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2311,11 +2311,14 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) tlen = dev->needed_tailroom; skb = sock_alloc_send_skb(&po->sk, hlen + tlen + sizeof(struct sockaddr_ll), - 0, &err); + !need_wait, &err); - if (unlikely(skb == NULL)) + if (unlikely(skb == NULL)) { + /* we assume the socket was initially writeable ... */ + if (likely(len_sum > 0)) + err = len_sum; goto out_status; - + } tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto, addr, hlen); if (tp_len > dev->mtu + dev->hard_header_len) { diff --git a/net/rds/connection.c b/net/rds/connection.c index 14f04139..da6da57 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -126,7 +126,10 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, struct rds_transport *loop_trans; unsigned long flags; int ret; + struct rds_transport *otrans = trans; + if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) + goto new_conn; rcu_read_lock(); conn = rds_conn_lookup(head, laddr, faddr, trans); if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && @@ -142,6 +145,7 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, if (conn) goto out; +new_conn: conn = kmem_cache_zalloc(rds_conn_slab, gfp); if (!conn) { conn = ERR_PTR(-ENOMEM); @@ -230,13 +234,22 @@ static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr, /* Creating normal conn */ struct rds_connection *found; - found = rds_conn_lookup(head, laddr, faddr, trans); + if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) + found = NULL; + else + found = rds_conn_lookup(head, laddr, faddr, trans); if (found) { trans->conn_free(conn->c_transport_data); kmem_cache_free(rds_conn_slab, conn); conn = found; } else { - hlist_add_head_rcu(&conn->c_hash_node, head); + if ((is_outgoing && otrans->t_type == RDS_TRANS_TCP) || + (otrans->t_type != RDS_TRANS_TCP)) { + /* Only the active side should be added to + * reconnect list for TCP. + */ + hlist_add_head_rcu(&conn->c_hash_node, head); + } rds_cong_add_conn(conn); rds_conn_count++; } diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 31b74f5..8a09ee7 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -183,8 +183,17 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even /* If the peer gave us the last packet it saw, process this as if * we had received a regular ACK. */ - if (dp && dp->dp_ack_seq) - rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL); + if (dp) { + /* dp structure start is not guaranteed to be 8 bytes aligned. + * Since dp_ack_seq is 64-bit extended load operations can be + * used so go through get_unaligned to avoid unaligned errors. + */ + __be64 dp_ack_seq = get_unaligned(&dp->dp_ack_seq); + + if (dp_ack_seq) + rds_send_drop_acked(conn, be64_to_cpu(dp_ack_seq), + NULL); + } rds_connect_complete(conn); } diff --git a/net/rds/tcp_connect.c b/net/rds/tcp_connect.c index f9f564a..973109c7 100644 --- a/net/rds/tcp_connect.c +++ b/net/rds/tcp_connect.c @@ -62,6 +62,7 @@ void rds_tcp_state_change(struct sock *sk) case TCP_ESTABLISHED: rds_connect_complete(conn); break; + case TCP_CLOSE_WAIT: case TCP_CLOSE: rds_conn_drop(conn); default: diff --git a/net/rds/tcp_listen.c b/net/rds/tcp_listen.c index 23ab4dcd..0da49e3 100644 --- a/net/rds/tcp_listen.c +++ b/net/rds/tcp_listen.c @@ -45,12 +45,45 @@ static void rds_tcp_accept_worker(struct work_struct *work); static DECLARE_WORK(rds_tcp_listen_work, rds_tcp_accept_worker); static struct socket *rds_tcp_listen_sock; +static int rds_tcp_keepalive(struct socket *sock) +{ + /* values below based on xs_udp_default_timeout */ + int keepidle = 5; /* send a probe 'keepidle' secs after last data */ + int keepcnt = 5; /* number of unack'ed probes before declaring dead */ + int keepalive = 1; + int ret = 0; + + ret = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&keepalive, sizeof(keepalive)); + if (ret < 0) + goto bail; + + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, + (char *)&keepcnt, sizeof(keepcnt)); + if (ret < 0) + goto bail; + + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, + (char *)&keepidle, sizeof(keepidle)); + if (ret < 0) + goto bail; + + /* KEEPINTVL is the interval between successive probes. We follow + * the model in xs_tcp_finish_connecting() and re-use keepidle. + */ + ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, + (char *)&keepidle, sizeof(keepidle)); +bail: + return ret; +} + static int rds_tcp_accept_one(struct socket *sock) { struct socket *new_sock = NULL; struct rds_connection *conn; int ret; struct inet_sock *inet; + struct rds_tcp_connection *rs_tcp; ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, sock->sk->sk_protocol, &new_sock); @@ -63,6 +96,10 @@ static int rds_tcp_accept_one(struct socket *sock) if (ret < 0) goto out; + ret = rds_tcp_keepalive(new_sock); + if (ret < 0) + goto out; + rds_tcp_tune(new_sock); inet = inet_sk(new_sock->sk); @@ -77,6 +114,15 @@ static int rds_tcp_accept_one(struct socket *sock) ret = PTR_ERR(conn); goto out; } + /* An incoming SYN request came in, and TCP just accepted it. + * We always create a new conn for listen side of TCP, and do not + * add it to the c_hash_list. + * + * If the client reboots, this conn will need to be cleaned up. + * rds_tcp_state_change() will do that cleanup + */ + rs_tcp = (struct rds_tcp_connection *)conn->c_transport_data; + WARN_ON(!rs_tcp || rs_tcp->t_sock); /* * see the comment above rds_queue_delayed_reconnect() diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8b0470e..b6ef9a0 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -308,12 +308,11 @@ replay: case RTM_DELTFILTER: err = tp->ops->delete(tp, fh); if (err == 0) { - tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); - if (tcf_destroy(tp, false)) { - struct tcf_proto *next = rtnl_dereference(tp->next); + struct tcf_proto *next = rtnl_dereference(tp->next); + tfilter_notify(net, skb, n, tp, fh, RTM_DELTFILTER); + if (tcf_destroy(tp, false)) RCU_INIT_POINTER(*back, next); - } } goto errout; case RTM_GETTFILTER: diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index de28f8e..7a0bdb1 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -164,7 +164,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt) sch->limit = DEFAULT_CODEL_LIMIT; - codel_params_init(&q->params); + codel_params_init(&q->params, sch); codel_vars_init(&q->vars); codel_stats_init(&q->stats); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 1e52dec..c244c45b 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -391,7 +391,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) q->perturbation = prandom_u32(); INIT_LIST_HEAD(&q->new_flows); INIT_LIST_HEAD(&q->old_flows); - codel_params_init(&q->cparams); + codel_params_init(&q->cparams, sch); codel_stats_init(&q->cstats); q->cparams.ecn = true; diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index a4ca451..634529e 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -229,7 +229,7 @@ static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) break; } - if (q->backlog + qdisc_pkt_len(skb) <= q->limit) { + if (gred_backlog(t, q, sch) + qdisc_pkt_len(skb) <= q->limit) { q->backlog += qdisc_pkt_len(skb); return qdisc_enqueue_tail(skb, sch); } @@ -553,7 +553,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) opt.limit = q->limit; opt.DP = q->DP; - opt.backlog = q->backlog; + opt.backlog = gred_backlog(table, q, sch); opt.prio = q->prio; opt.qth_min = q->parms.qth_min >> q->parms.Wlog; opt.qth_max = q->parms.qth_max >> q->parms.Wlog; |