From edfac0ea4d89825a5e6ef60e66d78dd6128cdfb7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 27 May 2012 00:21:22 +0000 Subject: [PATCH 01/13] be2net: Backport most changes up to Linux 3.5-rc1 (Closes: #673391) svn path=/dists/sid/linux-2.6/; revision=19037 --- debian/changelog | 8 + ...ol-null-terminate-filename-passed-to.patch | 53 + ...-and-convert-some-.get_drvinfo-routi.patch | 47 + ...if_handle-vf_pmac_id-to-handle-failu.patch | 227 ++ ...king-the-UE-registers-after-an-EEH-e.patch | 40 + ...-more-than-one-error-on-detecting-EE.patch | 73 + ...issuing-FW-cmds-if-any-cmd-times-out.patch | 158 ++ ...e2net-Fix-TX-queue-create-for-Lancer.patch | 99 + ...add-register-dump-feature-for-Lancer.patch | 234 ++ ...t-Add-EEPROM-dump-feature-for-Lancer.patch | 70 + ...-Fix-VLAN-promiscous-mode-for-Lancer.patch | 33 + ...query-link-status-command-for-lancer.patch | 31 + ...-new-SR-IOV-implementation-in-Lancer.patch | 393 ++++ ...0012-be2net-Fix-error-recovery-paths.patch | 37 + ...be2net-Add-error-handling-for-Lancer.patch | 212 ++ .../be2net/0014-be2net-Use-new-hash-key.patch | 34 + ...net-Fix-non-utilization-of-RX-queues.patch | 54 + .../be2net/0016-be2net-netpoll-support.patch | 53 + ...some-counters-to-display-via-ethtool.patch | 30 + ...be2net-workaround-to-fix-a-bug-in-BE.patch | 98 + ...2net-fix-ethtool-ringparam-reporting.patch | 46 + ...factor-cleanup-vf-configuration-code.patch | 416 ++++ ...be2net-Add-support-for-Skyhawk-cards.patch | 65 + ...e2net-Fix-INTx-processing-for-Lancer.patch | 53 + .../0023-be2net-fix-be_vlan_add-rem_vid.patch | 65 + ...fix-range-check-for-set_qos-for-a-VF.patch | 47 + ...-be2net-query-link-status-in-be_open.patch | 234 ++ ...026-netdev-make-net_device_ops-const.patch | 31 + ...S-rings-even-in-multi-channel-config.patch | 36 + ...ocate-more-headroom-in-incoming-skbs.patch | 57 + ...iptions-for-stat-counters-reported-v.patch | 259 +++ ...be2net-Fix-link-status-query-command.patch | 39 + ...mplementation-of-get-mac-list-comman.patch | 237 +++ .../0032-be2net-event-queue-re-design.patch | 1895 +++++++++++++++++ ...cancel-be_worker-during-EEH-recovery.patch | 90 + ...034-be2net-fix-tx-completion-cleanup.patch | 133 ++ ...et-reset-queue-address-after-freeing.patch | 44 + ...0036-be2net-enable-RSS-for-ipv6-pkts.patch | 29 + .../0037-be2net-update-driver-version.patch | 28 + ...t-Remove-unused-OFFSET_IN_PAGE-macro.patch | 30 + ...le-WOL-by-default-if-h-w-supports-it.patch | 274 +++ ...econdary-UC-MAC-address-into-MAC-fil.patch | 177 ++ ...ix-number-of-vlan-slots-in-flex-mode.patch | 30 + ...-fix-programming-of-VLAN-tags-for-VF.patch | 255 +++ ...0043-be2net-fix-ethtool-get-settings.patch | 521 +++++ ...-Fix-VLAN-multicast-packet-reception.patch | 94 + ...045-be2net-Fix-FW-download-in-Lancer.patch | 44 + ...net-Fix-ethtool-self-test-for-Lancer.patch | 31 + ...7-be2net-Fix-traffic-stall-INTx-mode.patch | 36 + .../0048-be2net-Fix-Lancer-statistics.patch | 55 + ...-status-getting-returned-for-MCC-com.patch | 232 ++ .../0050-be2net-Fix-FW-download-for-BE.patch | 383 ++++ ...atus-of-some-ioctls-during-driver-lo.patch | 49 + ...-displayed-by-ethtool-on-certain-SKU.patch | 30 + ...053-be2net-update-the-driver-version.patch | 28 + ...t-set-link-speed-for-disabled-functi.patch | 33 + ...ply-duplex-value-as-unknown-when-lin.patch | 31 + ...eceive-queue-index-in-skb-to-aid-RPS.patch | 36 + ...rror-reset-before-a-flash-dump-compl.patch | 37 + ...sabling-sriov-while-VFs-are-assigned.patch | 473 ++++ debian/patches/series/base | 61 + 61 files changed, 8728 insertions(+) create mode 100644 debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch create mode 100644 debian/patches/features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch create mode 100644 debian/patches/features/all/be2net/0002-be2net-init-vf-_if_handle-vf_pmac_id-to-handle-failu.patch create mode 100644 debian/patches/features/all/be2net/0003-be2net-stop-checking-the-UE-registers-after-an-EEH-e.patch create mode 100644 debian/patches/features/all/be2net/0004-be2net-don-t-log-more-than-one-error-on-detecting-EE.patch create mode 100644 debian/patches/features/all/be2net/0005-be2net-stop-issuing-FW-cmds-if-any-cmd-times-out.patch create mode 100644 debian/patches/features/all/be2net/0006-be2net-Fix-TX-queue-create-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0007-be2net-add-register-dump-feature-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0008-be2net-Add-EEPROM-dump-feature-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0009-be2net-Fix-VLAN-promiscous-mode-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0010-be2net-Use-V1-query-link-status-command-for-lancer.patch create mode 100644 debian/patches/features/all/be2net/0011-be2net-Move-to-new-SR-IOV-implementation-in-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0012-be2net-Fix-error-recovery-paths.patch create mode 100644 debian/patches/features/all/be2net/0013-be2net-Add-error-handling-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0014-be2net-Use-new-hash-key.patch create mode 100644 debian/patches/features/all/be2net/0015-be2net-Fix-non-utilization-of-RX-queues.patch create mode 100644 debian/patches/features/all/be2net/0016-be2net-netpoll-support.patch create mode 100644 debian/patches/features/all/be2net/0017-be2net-update-some-counters-to-display-via-ethtool.patch create mode 100644 debian/patches/features/all/be2net/0018-be2net-workaround-to-fix-a-bug-in-BE.patch create mode 100644 debian/patches/features/all/be2net/0019-be2net-fix-ethtool-ringparam-reporting.patch create mode 100644 debian/patches/features/all/be2net/0020-be2net-refactor-cleanup-vf-configuration-code.patch create mode 100644 debian/patches/features/all/be2net/0021-be2net-Add-support-for-Skyhawk-cards.patch create mode 100644 debian/patches/features/all/be2net/0022-be2net-Fix-INTx-processing-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0023-be2net-fix-be_vlan_add-rem_vid.patch create mode 100644 debian/patches/features/all/be2net/0024-be2net-fix-range-check-for-set_qos-for-a-VF.patch create mode 100644 debian/patches/features/all/be2net/0025-be2net-query-link-status-in-be_open.patch create mode 100644 debian/patches/features/all/be2net/0026-netdev-make-net_device_ops-const.patch create mode 100644 debian/patches/features/all/be2net/0027-be2net-create-RSS-rings-even-in-multi-channel-config.patch create mode 100644 debian/patches/features/all/be2net/0028-be2net-allocate-more-headroom-in-incoming-skbs.patch create mode 100644 debian/patches/features/all/be2net/0029-be2net-add-descriptions-for-stat-counters-reported-v.patch create mode 100644 debian/patches/features/all/be2net/0030-be2net-Fix-link-status-query-command.patch create mode 100644 debian/patches/features/all/be2net/0031-be2net-Use-new-implementation-of-get-mac-list-comman.patch create mode 100644 debian/patches/features/all/be2net/0032-be2net-event-queue-re-design.patch create mode 100644 debian/patches/features/all/be2net/0033-be2net-cancel-be_worker-during-EEH-recovery.patch create mode 100644 debian/patches/features/all/be2net/0034-be2net-fix-tx-completion-cleanup.patch create mode 100644 debian/patches/features/all/be2net/0035-be2net-reset-queue-address-after-freeing.patch create mode 100644 debian/patches/features/all/be2net/0036-be2net-enable-RSS-for-ipv6-pkts.patch create mode 100644 debian/patches/features/all/be2net/0037-be2net-update-driver-version.patch create mode 100644 debian/patches/features/all/be2net/0038-be2net-Remove-unused-OFFSET_IN_PAGE-macro.patch create mode 100644 debian/patches/features/all/be2net/0039-be2net-enable-WOL-by-default-if-h-w-supports-it.patch create mode 100644 debian/patches/features/all/be2net/0040-be2net-Program-secondary-UC-MAC-address-into-MAC-fil.patch create mode 100644 debian/patches/features/all/be2net/0041-be2net-Fix-number-of-vlan-slots-in-flex-mode.patch create mode 100644 debian/patches/features/all/be2net/0042-be2net-fix-programming-of-VLAN-tags-for-VF.patch create mode 100644 debian/patches/features/all/be2net/0043-be2net-fix-ethtool-get-settings.patch create mode 100644 debian/patches/features/all/be2net/0044-be2net-Fix-VLAN-multicast-packet-reception.patch create mode 100644 debian/patches/features/all/be2net/0045-be2net-Fix-FW-download-in-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0046-be2net-Fix-ethtool-self-test-for-Lancer.patch create mode 100644 debian/patches/features/all/be2net/0047-be2net-Fix-traffic-stall-INTx-mode.patch create mode 100644 debian/patches/features/all/be2net/0048-be2net-Fix-Lancer-statistics.patch create mode 100644 debian/patches/features/all/be2net/0049-be2net-Fix-wrong-status-getting-returned-for-MCC-com.patch create mode 100644 debian/patches/features/all/be2net/0050-be2net-Fix-FW-download-for-BE.patch create mode 100644 debian/patches/features/all/be2net/0051-be2net-Ignore-status-of-some-ioctls-during-driver-lo.patch create mode 100644 debian/patches/features/all/be2net/0052-be2net-fix-speed-displayed-by-ethtool-on-certain-SKU.patch create mode 100644 debian/patches/features/all/be2net/0053-be2net-update-the-driver-version.patch create mode 100644 debian/patches/features/all/be2net/0054-be2net-Fix-to-not-set-link-speed-for-disabled-functi.patch create mode 100644 debian/patches/features/all/be2net/0055-be2net-Fix-to-apply-duplex-value-as-unknown-when-lin.patch create mode 100644 debian/patches/features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch create mode 100644 debian/patches/features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch create mode 100644 debian/patches/features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch diff --git a/debian/changelog b/debian/changelog index 86e7aeacb..0c136dc8c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +linux-2.6 (3.2.18-2) UNRELEASED; urgency=low + + [ Ben Hutchings ] + * be2net: Backport most changes up to Linux 3.5-rc1 (Closes: #673391) + - Add support for Skyhawk cards + + -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 + linux-2.6 (3.2.18-1) unstable; urgency=low * New upstream stable update: diff --git a/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch b/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch new file mode 100644 index 000000000..22b472be7 --- /dev/null +++ b/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch @@ -0,0 +1,53 @@ +From: Ben Hutchings +Date: Wed, 1 Feb 2012 09:32:25 +0000 +Subject: [PATCH] ethtool: Null-terminate filename passed to + ethtool_ops::flash_device + +commit 786f528119722f564a22ad953411374e06116333 upstream. + +The parameters for ETHTOOL_FLASHDEV include a filename, which ought to +be null-terminated. Currently the only driver that implements +ethtool_ops::flash_device attempts to add a null terminator if +necessary, but does it wrongly. Do it in the ethtool core instead. + +Signed-off-by: Ben Hutchings +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 6 +----- + net/core/ethtool.c | 2 ++ + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 6db6b6a..802e5dd 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -716,12 +716,8 @@ static int + be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) + { + struct be_adapter *adapter = netdev_priv(netdev); +- char file_name[ETHTOOL_FLASH_MAX_FILENAME]; + +- file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; +- strcpy(file_name, efl->data); +- +- return be_load_fw(adapter, file_name); ++ return be_load_fw(adapter, efl->data); + } + + static int +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index 369b418..3f79db1 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -1190,6 +1190,8 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, + if (!dev->ethtool_ops->flash_device) + return -EOPNOTSUPP; + ++ efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; ++ + return dev->ethtool_ops->flash_device(dev, &efl); + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch b/debian/patches/features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch new file mode 100644 index 000000000..d62f1fc87 --- /dev/null +++ b/debian/patches/features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch @@ -0,0 +1,47 @@ +From: Rick Jones +Date: Mon, 7 Nov 2011 13:29:27 +0000 +Subject: [PATCH 01/58] sweep the floors and convert some .get_drvinfo + routines to strlcpy + +commit 68aad78c5023b8aa82da99b47f9d8cf40e8ca453 upstream. + +Per the mention made by Ben Hutchings that strlcpy is now the preferred +string copy routine for a .get_drvinfo routine, do a bit of floor +sweeping and convert some of the as-yet unconverted ethernet drivers to +it. + +Signed-off-by: Rick Jones +Signed-off-by: David S. Miller +[bwh: Restrict to drivers/net/ethernet/emulex/benet/] +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index bf8153e..1ad7a28 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -127,8 +127,8 @@ static void be_get_drvinfo(struct net_device *netdev, + memset(fw_on_flash, 0 , sizeof(fw_on_flash)); + be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash); + +- strcpy(drvinfo->driver, DRV_NAME); +- strcpy(drvinfo->version, DRV_VER); ++ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); ++ strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version)); + strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN); + if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) { + strcat(drvinfo->fw_version, " ["); +@@ -136,7 +136,8 @@ static void be_get_drvinfo(struct net_device *netdev, + strcat(drvinfo->fw_version, "]"); + } + +- strcpy(drvinfo->bus_info, pci_name(adapter->pdev)); ++ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev), ++ sizeof(drvinfo->bus_info)); + drvinfo->testinfo_len = 0; + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0002-be2net-init-vf-_if_handle-vf_pmac_id-to-handle-failu.patch b/debian/patches/features/all/be2net/0002-be2net-init-vf-_if_handle-vf_pmac_id-to-handle-failu.patch new file mode 100644 index 000000000..ef3dd3937 --- /dev/null +++ b/debian/patches/features/all/be2net/0002-be2net-init-vf-_if_handle-vf_pmac_id-to-handle-failu.patch @@ -0,0 +1,227 @@ +From: Sathya Perla +Date: Thu, 10 Nov 2011 19:17:57 +0000 +Subject: [PATCH 02/58] be2net: init (vf)_if_handle/vf_pmac_id to handle + failure scenarios + +commit 30128031d71741ef7d0e32c345e3bf02aa8a0704 upstream. + +Initialize if_handle, vf_if_handle and vf_pmac_id with "-1" so that in +failure cases when be_clear() is called, we can skip over +if_destroy/pmac_del cmds if they have not been created. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 8 ++-- + drivers/net/ethernet/emulex/benet/be_cmds.c | 9 +++-- + drivers/net/ethernet/emulex/benet/be_cmds.h | 4 +- + drivers/net/ethernet/emulex/benet/be_main.c | 55 +++++++++++++++------------ + 4 files changed, 42 insertions(+), 34 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 644e8fe..4163980 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -289,14 +289,12 @@ struct be_drv_stats { + + struct be_vf_cfg { + unsigned char vf_mac_addr[ETH_ALEN]; +- u32 vf_if_handle; +- u32 vf_pmac_id; ++ int vf_if_handle; ++ int vf_pmac_id; + u16 vf_vlan_tag; + u32 vf_tx_rate; + }; + +-#define BE_INVALID_PMAC_ID 0xffffffff +- + struct be_adapter { + struct pci_dev *pdev; + struct net_device *netdev; +@@ -347,7 +345,7 @@ struct be_adapter { + + /* Ethtool knobs and info */ + char fw_ver[FW_VER_LEN]; +- u32 if_handle; /* Used to configure filtering */ ++ int if_handle; /* Used to configure filtering */ + u32 pmac_id; /* MAC addr handle used by BE card */ + u32 beacon_state; /* for set_phys_id */ + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 2c7b366..c5912c4 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -695,12 +695,15 @@ err: + } + + /* Uses synchronous MCCQ */ +-int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id, u32 dom) ++int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, int pmac_id, u32 dom) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_pmac_del *req; + int status; + ++ if (pmac_id == -1) ++ return 0; ++ + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); +@@ -1136,7 +1139,7 @@ err: + } + + /* Uses MCCQ */ +-int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) ++int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_if_destroy *req; +@@ -1145,7 +1148,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain) + if (adapter->eeh_err) + return -EIO; + +- if (!interface_id) ++ if (interface_id == -1) + return 0; + + spin_lock_bh(&adapter->mcc_lock); +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index a35cd03..0818039 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1417,11 +1417,11 @@ extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, + u32 if_id, u32 *pmac_id, u32 domain); + extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, +- u32 pmac_id, u32 domain); ++ int pmac_id, u32 domain); + extern int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, + u32 en_flags, u8 *mac, u32 *if_handle, u32 *pmac_id, + u32 domain); +-extern int be_cmd_if_destroy(struct be_adapter *adapter, u32 if_handle, ++extern int be_cmd_if_destroy(struct be_adapter *adapter, int if_handle, + u32 domain); + extern int be_cmd_eq_create(struct be_adapter *adapter, + struct be_queue_info *eq, int eq_delay); +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index bf266a0..83d971d 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -848,15 +848,11 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) + if (!is_valid_ether_addr(mac) || (vf >= num_vfs)) + return -EINVAL; + +- if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) +- status = be_cmd_pmac_del(adapter, +- adapter->vf_cfg[vf].vf_if_handle, +- adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ status = be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, ++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1); + +- status = be_cmd_pmac_add(adapter, mac, +- adapter->vf_cfg[vf].vf_if_handle, ++ status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle, + &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); +- + if (status) + dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", + mac, vf); +@@ -2488,17 +2484,13 @@ static void be_vf_clear(struct be_adapter *adapter) + { + u32 vf; + +- for (vf = 0; vf < num_vfs; vf++) { +- if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID) +- be_cmd_pmac_del(adapter, +- adapter->vf_cfg[vf].vf_if_handle, +- adapter->vf_cfg[vf].vf_pmac_id, vf + 1); +- } ++ for (vf = 0; vf < num_vfs; vf++) ++ be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, ++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1); + + for (vf = 0; vf < num_vfs; vf++) +- if (adapter->vf_cfg[vf].vf_if_handle) +- be_cmd_if_destroy(adapter, +- adapter->vf_cfg[vf].vf_if_handle, vf + 1); ++ be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle, ++ vf + 1); + } + + static int be_clear(struct be_adapter *adapter) +@@ -2511,22 +2503,30 @@ static int be_clear(struct be_adapter *adapter) + be_mcc_queues_destroy(adapter); + be_rx_queues_destroy(adapter); + be_tx_queues_destroy(adapter); +- adapter->eq_next_idx = 0; +- +- adapter->be3_native = false; +- adapter->promiscuous = false; + + /* tell fw we're done with firing cmds */ + be_cmd_fw_clean(adapter); + return 0; + } + ++static void be_vf_setup_init(struct be_adapter *adapter) ++{ ++ int vf; ++ ++ for (vf = 0; vf < num_vfs; vf++) { ++ adapter->vf_cfg[vf].vf_if_handle = -1; ++ adapter->vf_cfg[vf].vf_pmac_id = -1; ++ } ++} ++ + static int be_vf_setup(struct be_adapter *adapter) + { + u32 cap_flags, en_flags, vf; + u16 lnk_speed; + int status; + ++ be_vf_setup_init(adapter); ++ + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST; + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, +@@ -2534,7 +2534,6 @@ static int be_vf_setup(struct be_adapter *adapter) + NULL, vf+1); + if (status) + goto err; +- adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID; + } + + if (!lancer_chip(adapter)) { +@@ -2555,6 +2554,16 @@ err: + return status; + } + ++static void be_setup_init(struct be_adapter *adapter) ++{ ++ adapter->vlan_prio_bmap = 0xff; ++ adapter->link_speed = -1; ++ adapter->if_handle = -1; ++ adapter->be3_native = false; ++ adapter->promiscuous = false; ++ adapter->eq_next_idx = 0; ++} ++ + static int be_setup(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +@@ -2563,9 +2572,7 @@ static int be_setup(struct be_adapter *adapter) + int status; + u8 mac[ETH_ALEN]; + +- /* Allow all priorities by default. A GRP5 evt may modify this */ +- adapter->vlan_prio_bmap = 0xff; +- adapter->link_speed = -1; ++ be_setup_init(adapter); + + be_cmd_req_native_mode(adapter); + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0003-be2net-stop-checking-the-UE-registers-after-an-EEH-e.patch b/debian/patches/features/all/be2net/0003-be2net-stop-checking-the-UE-registers-after-an-EEH-e.patch new file mode 100644 index 000000000..7eaf85073 --- /dev/null +++ b/debian/patches/features/all/be2net/0003-be2net-stop-checking-the-UE-registers-after-an-EEH-e.patch @@ -0,0 +1,40 @@ +From: Sathya Perla +Date: Thu, 10 Nov 2011 19:17:58 +0000 +Subject: [PATCH 03/58] be2net: stop checking the UE registers after an EEH + error + +commit 72f02485626b3e71955e54d227ede1b54021d571 upstream. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 83d971d..99da07f 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1978,6 +1978,9 @@ void be_detect_dump_ue(struct be_adapter *adapter) + u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; + u32 i; + ++ if (adapter->eeh_err || adapter->ue_detected) ++ return; ++ + if (lancer_chip(adapter)) { + sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); + if (sliport_status & SLIPORT_STATUS_ERR_MASK) { +@@ -2039,8 +2042,7 @@ static void be_worker(struct work_struct *work) + struct be_rx_obj *rxo; + int i; + +- if (!adapter->ue_detected) +- be_detect_dump_ue(adapter); ++ be_detect_dump_ue(adapter); + + /* when interrupts are not yet enabled, just reap any pending + * mcc completions */ +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0004-be2net-don-t-log-more-than-one-error-on-detecting-EE.patch b/debian/patches/features/all/be2net/0004-be2net-don-t-log-more-than-one-error-on-detecting-EE.patch new file mode 100644 index 000000000..a38df1341 --- /dev/null +++ b/debian/patches/features/all/be2net/0004-be2net-don-t-log-more-than-one-error-on-detecting-EE.patch @@ -0,0 +1,73 @@ +From: Sathya Perla +Date: Thu, 10 Nov 2011 19:17:59 +0000 +Subject: [PATCH 04/58] be2net: don't log more than one error on detecting + EEH/UE errors + +commit 434b3648e9a58600cea5f3a1a0a7a89048e4df61 upstream. + +Currently we're spamming error messages each time a FW cmd call is made +while in EEH/UE error state. One log msg on error detection is enough. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 15 +++------------ + drivers/net/ethernet/emulex/benet/be_main.c | 3 ++- + 2 files changed, 5 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index c5912c4..94cd77c 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -31,11 +31,8 @@ static void be_mcc_notify(struct be_adapter *adapter) + struct be_queue_info *mccq = &adapter->mcc_obj.q; + u32 val = 0; + +- if (adapter->eeh_err) { +- dev_info(&adapter->pdev->dev, +- "Error in Card Detected! Cannot issue commands\n"); ++ if (adapter->eeh_err) + return; +- } + + val |= mccq->id & DB_MCCQ_RING_ID_MASK; + val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; +@@ -298,19 +295,13 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) + int msecs = 0; + u32 ready; + +- if (adapter->eeh_err) { +- dev_err(&adapter->pdev->dev, +- "Error detected in card.Cannot issue commands\n"); ++ if (adapter->eeh_err) + return -EIO; +- } + + do { + ready = ioread32(db); +- if (ready == 0xffffffff) { +- dev_err(&adapter->pdev->dev, +- "pci slot disconnected\n"); ++ if (ready == 0xffffffff) + return -1; +- } + + ready &= MPU_MAILBOX_DB_RDY_MASK; + if (ready) +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 99da07f..0e97b6d 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2007,7 +2007,8 @@ void be_detect_dump_ue(struct be_adapter *adapter) + sliport_status & SLIPORT_STATUS_ERR_MASK) { + adapter->ue_detected = true; + adapter->eeh_err = true; +- dev_err(&adapter->pdev->dev, "UE Detected!!\n"); ++ dev_err(&adapter->pdev->dev, ++ "Unrecoverable error in the card\n"); + } + + if (ue_lo) { +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0005-be2net-stop-issuing-FW-cmds-if-any-cmd-times-out.patch b/debian/patches/features/all/be2net/0005-be2net-stop-issuing-FW-cmds-if-any-cmd-times-out.patch new file mode 100644 index 000000000..a59c78840 --- /dev/null +++ b/debian/patches/features/all/be2net/0005-be2net-stop-issuing-FW-cmds-if-any-cmd-times-out.patch @@ -0,0 +1,158 @@ +From: Sathya Perla +Date: Thu, 10 Nov 2011 19:18:00 +0000 +Subject: [PATCH 05/58] be2net: stop issuing FW cmds if any cmd times out + +commit 6589ade019dcab245d3bb847370f855b56cdf6ad upstream. + +A FW cmd timeout (with a sufficiently large timeout value in the +order of tens of seconds) indicates an unresponsive FW. In this state +issuing further cmds and waiting for a completion will only stall the process. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 8 +++++++- + drivers/net/ethernet/emulex/benet/be_cmds.c | 29 ++++++++++----------------- + drivers/net/ethernet/emulex/benet/be_main.c | 2 ++ + 3 files changed, 20 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 4163980..34f162d 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -350,6 +350,8 @@ struct be_adapter { + u32 beacon_state; /* for set_phys_id */ + + bool eeh_err; ++ bool ue_detected; ++ bool fw_timeout; + u32 port_num; + bool promiscuous; + bool wol; +@@ -357,7 +359,6 @@ struct be_adapter { + u32 function_caps; + u32 rx_fc; /* Rx flow control */ + u32 tx_fc; /* Tx flow control */ +- bool ue_detected; + bool stats_cmd_sent; + int link_speed; + u8 port_type; +@@ -522,6 +523,11 @@ static inline bool be_multi_rxq(const struct be_adapter *adapter) + return adapter->num_rx_qs > 1; + } + ++static inline bool be_error(struct be_adapter *adapter) ++{ ++ return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout; ++} ++ + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, + u16 num_popped); + extern void be_link_status_update(struct be_adapter *adapter, u32 link_status); +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 94cd77c..ad3eef0 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -31,7 +31,7 @@ static void be_mcc_notify(struct be_adapter *adapter) + struct be_queue_info *mccq = &adapter->mcc_obj.q; + u32 val = 0; + +- if (adapter->eeh_err) ++ if (be_error(adapter)) + return; + + val |= mccq->id & DB_MCCQ_RING_ID_MASK; +@@ -263,10 +263,10 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) + int i, num, status = 0; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + +- if (adapter->eeh_err) +- return -EIO; +- + for (i = 0; i < mcc_timeout; i++) { ++ if (be_error(adapter)) ++ return -EIO; ++ + num = be_process_mcc(adapter, &status); + if (num) + be_cq_notify(adapter, mcc_obj->cq.id, +@@ -277,7 +277,8 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) + udelay(100); + } + if (i == mcc_timeout) { +- dev_err(&adapter->pdev->dev, "mccq poll timed out\n"); ++ dev_err(&adapter->pdev->dev, "FW not responding\n"); ++ adapter->fw_timeout = true; + return -1; + } + return status; +@@ -295,10 +296,10 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) + int msecs = 0; + u32 ready; + +- if (adapter->eeh_err) +- return -EIO; +- + do { ++ if (be_error(adapter)) ++ return -EIO; ++ + ready = ioread32(db); + if (ready == 0xffffffff) + return -1; +@@ -308,7 +309,8 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) + break; + + if (msecs > 4000) { +- dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); ++ dev_err(&adapter->pdev->dev, "FW not responding\n"); ++ adapter->fw_timeout = true; + be_detect_dump_ue(adapter); + return -1; + } +@@ -546,9 +548,6 @@ int be_cmd_fw_clean(struct be_adapter *adapter) + u8 *wrb; + int status; + +- if (adapter->eeh_err) +- return -EIO; +- + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + +@@ -1012,9 +1011,6 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + u8 subsys = 0, opcode = 0; + int status; + +- if (adapter->eeh_err) +- return -EIO; +- + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + +@@ -1136,9 +1132,6 @@ int be_cmd_if_destroy(struct be_adapter *adapter, int interface_id, u32 domain) + struct be_cmd_req_if_destroy *req; + int status; + +- if (adapter->eeh_err) +- return -EIO; +- + if (interface_id == -1) + return 0; + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 0e97b6d..ce20d64 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -3569,6 +3569,8 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) + + dev_info(&adapter->pdev->dev, "EEH reset\n"); + adapter->eeh_err = false; ++ adapter->ue_detected = false; ++ adapter->fw_timeout = false; + + status = pci_enable_device(pdev); + if (status) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0006-be2net-Fix-TX-queue-create-for-Lancer.patch b/debian/patches/features/all/be2net/0006-be2net-Fix-TX-queue-create-for-Lancer.patch new file mode 100644 index 000000000..c91fa961d --- /dev/null +++ b/debian/patches/features/all/be2net/0006-be2net-Fix-TX-queue-create-for-Lancer.patch @@ -0,0 +1,99 @@ +From: Padmanabh Ratnakar +Date: Wed, 16 Nov 2011 02:02:23 +0000 +Subject: [PATCH 06/58] be2net: Fix TX queue create for Lancer + +commit 293c4a7d9b95d0beeb5df03c14bd35bc21f9e6f2 upstream. + +Lancer uses V1 version of TXQ create. This command needs interface +id for TX queue creation. Rearrange code such that tx queue create +is after interface create. As TXQ create is now called after MCC +ring create use MCC instead of MBOX. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 15 ++++++++++----- + drivers/net/ethernet/emulex/benet/be_main.c | 12 ++++++++---- + 2 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index ad3eef0..d35a214 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -916,10 +916,14 @@ int be_cmd_txq_create(struct be_adapter *adapter, + void *ctxt; + int status; + +- if (mutex_lock_interruptible(&adapter->mbox_lock)) +- return -1; ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } + +- wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + +@@ -945,14 +949,15 @@ int be_cmd_txq_create(struct be_adapter *adapter, + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + +- status = be_mbox_notify_wait(adapter); ++ status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb); + txq->id = le16_to_cpu(resp->cid); + txq->created = true; + } + +- mutex_unlock(&adapter->mbox_lock); ++err: ++ spin_unlock_bh(&adapter->mcc_lock); + + return status; + } +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index ce20d64..c982b51 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1689,9 +1689,6 @@ static int be_tx_queues_create(struct be_adapter *adapter) + if (be_queue_alloc(adapter, q, TX_Q_LEN, + sizeof(struct be_eth_wrb))) + goto err; +- +- if (be_cmd_txq_create(adapter, q, cq)) +- goto err; + } + return 0; + +@@ -2572,8 +2569,9 @@ static int be_setup(struct be_adapter *adapter) + struct net_device *netdev = adapter->netdev; + u32 cap_flags, en_flags; + u32 tx_fc, rx_fc; +- int status; ++ int status, i; + u8 mac[ETH_ALEN]; ++ struct be_tx_obj *txo; + + be_setup_init(adapter); + +@@ -2613,6 +2611,12 @@ static int be_setup(struct be_adapter *adapter) + if (status != 0) + goto err; + ++ for_all_tx_queues(adapter, txo, i) { ++ status = be_cmd_txq_create(adapter, &txo->q, &txo->cq); ++ if (status) ++ goto err; ++ } ++ + /* For BEx, the VF's permanent mac queried from card is incorrect. + * Query the mac configued by the PF using if_handle + */ +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0007-be2net-add-register-dump-feature-for-Lancer.patch b/debian/patches/features/all/be2net/0007-be2net-add-register-dump-feature-for-Lancer.patch new file mode 100644 index 000000000..da53f4a31 --- /dev/null +++ b/debian/patches/features/all/be2net/0007-be2net-add-register-dump-feature-for-Lancer.patch @@ -0,0 +1,234 @@ +From: Padmanabh Ratnakar +Date: Wed, 16 Nov 2011 02:02:43 +0000 +Subject: [PATCH 07/58] be2net: add register dump feature for Lancer + +commit de49bd5a447887fa630c54bb2769102d50fbe40a upstream. + +Implement register dump using ethtool for Lancer. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 47 +++++++++++++++ + drivers/net/ethernet/emulex/benet/be_cmds.h | 34 +++++++++++ + drivers/net/ethernet/emulex/benet/be_ethtool.c | 74 ++++++++++++++++++++++-- + 3 files changed, 151 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index d35a214..1522065 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1828,6 +1828,53 @@ err_unlock: + return status; + } + ++int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, ++ u32 data_size, u32 data_offset, const char *obj_name, ++ u32 *data_read, u32 *eof, u8 *addn_status) ++{ ++ struct be_mcc_wrb *wrb; ++ struct lancer_cmd_req_read_object *req; ++ struct lancer_cmd_resp_read_object *resp; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err_unlock; ++ } ++ ++ req = embedded_payload(wrb); ++ ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_READ_OBJECT, ++ sizeof(struct lancer_cmd_req_read_object), wrb, ++ NULL); ++ ++ req->desired_read_len = cpu_to_le32(data_size); ++ req->read_offset = cpu_to_le32(data_offset); ++ strcpy(req->object_name, obj_name); ++ req->descriptor_count = cpu_to_le32(1); ++ req->buf_len = cpu_to_le32(data_size); ++ req->addr_low = cpu_to_le32((cmd->dma & 0xFFFFFFFF)); ++ req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma)); ++ ++ status = be_mcc_notify_wait(adapter); ++ ++ resp = embedded_payload(wrb); ++ if (!status) { ++ *data_read = le32_to_cpu(resp->actual_read_len); ++ *eof = le32_to_cpu(resp->eof); ++ } else { ++ *addn_status = resp->additional_status; ++ } ++ ++err_unlock: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ + int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, + u32 flash_type, u32 flash_opcode, u32 buf_size) + { +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 0818039..2d3fe6a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -189,6 +189,7 @@ struct be_mcc_mailbox { + #define OPCODE_COMMON_GET_PHY_DETAILS 102 + #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 + #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 ++#define OPCODE_COMMON_READ_OBJECT 171 + #define OPCODE_COMMON_WRITE_OBJECT 172 + + #define OPCODE_ETH_RSS_CONFIG 1 +@@ -1161,6 +1162,36 @@ struct lancer_cmd_resp_write_object { + u32 actual_write_len; + }; + ++/************************ Lancer Read FW info **************/ ++#define LANCER_READ_FILE_CHUNK (32*1024) ++#define LANCER_READ_FILE_EOF_MASK 0x80000000 ++ ++#define LANCER_FW_DUMP_FILE "/dbg/dump.bin" ++ ++struct lancer_cmd_req_read_object { ++ struct be_cmd_req_hdr hdr; ++ u32 desired_read_len; ++ u32 read_offset; ++ u8 object_name[104]; ++ u32 descriptor_count; ++ u32 buf_len; ++ u32 addr_low; ++ u32 addr_high; ++}; ++ ++struct lancer_cmd_resp_read_object { ++ u8 opcode; ++ u8 subsystem; ++ u8 rsvd1[2]; ++ u8 status; ++ u8 additional_status; ++ u8 rsvd2[2]; ++ u32 resp_len; ++ u32 actual_resp_len; ++ u32 actual_read_len; ++ u32 eof; ++}; ++ + /************************ WOL *******************************/ + struct be_cmd_req_acpi_wol_magic_config{ + struct be_cmd_req_hdr hdr; +@@ -1480,6 +1511,9 @@ extern int lancer_cmd_write_object(struct be_adapter *adapter, + u32 data_size, u32 data_offset, + const char *obj_name, + u32 *data_written, u8 *addn_status); ++int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd, ++ u32 data_size, u32 data_offset, const char *obj_name, ++ u32 *data_read, u32 *eof, u8 *addn_status); + int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + int offset); + extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 1ad7a28..1e7252e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -143,15 +143,77 @@ static void be_get_drvinfo(struct net_device *netdev, + drvinfo->eedump_len = 0; + } + ++static u32 ++lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name) ++{ ++ u32 data_read = 0, eof; ++ u8 addn_status; ++ struct be_dma_mem data_len_cmd; ++ int status; ++ ++ memset(&data_len_cmd, 0, sizeof(data_len_cmd)); ++ /* data_offset and data_size should be 0 to get reg len */ ++ status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0, ++ file_name, &data_read, &eof, &addn_status); ++ ++ return data_read; ++} ++ ++static int ++lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name, ++ u32 buf_len, void *buf) ++{ ++ struct be_dma_mem read_cmd; ++ u32 read_len = 0, total_read_len = 0, chunk_size; ++ u32 eof = 0; ++ u8 addn_status; ++ int status = 0; ++ ++ read_cmd.size = LANCER_READ_FILE_CHUNK; ++ read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size, ++ &read_cmd.dma); ++ ++ if (!read_cmd.va) { ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure while reading dump\n"); ++ return -ENOMEM; ++ } ++ ++ while ((total_read_len < buf_len) && !eof) { ++ chunk_size = min_t(u32, (buf_len - total_read_len), ++ LANCER_READ_FILE_CHUNK); ++ chunk_size = ALIGN(chunk_size, 4); ++ status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size, ++ total_read_len, file_name, &read_len, ++ &eof, &addn_status); ++ if (!status) { ++ memcpy(buf + total_read_len, read_cmd.va, read_len); ++ total_read_len += read_len; ++ eof &= LANCER_READ_FILE_EOF_MASK; ++ } else { ++ status = -EIO; ++ break; ++ } ++ } ++ pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va, ++ read_cmd.dma); ++ ++ return status; ++} ++ + static int + be_get_reg_len(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); + u32 log_size = 0; + +- if (be_physfn(adapter)) +- be_cmd_get_reg_len(adapter, &log_size); +- ++ if (be_physfn(adapter)) { ++ if (lancer_chip(adapter)) ++ log_size = lancer_cmd_get_file_len(adapter, ++ LANCER_FW_DUMP_FILE); ++ else ++ be_cmd_get_reg_len(adapter, &log_size); ++ } + return log_size; + } + +@@ -162,7 +224,11 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) + + if (be_physfn(adapter)) { + memset(buf, 0, regs->len); +- be_cmd_get_regs(adapter, regs->len, buf); ++ if (lancer_chip(adapter)) ++ lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE, ++ regs->len, buf); ++ else ++ be_cmd_get_regs(adapter, regs->len, buf); + } + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0008-be2net-Add-EEPROM-dump-feature-for-Lancer.patch b/debian/patches/features/all/be2net/0008-be2net-Add-EEPROM-dump-feature-for-Lancer.patch new file mode 100644 index 000000000..cc5e232dd --- /dev/null +++ b/debian/patches/features/all/be2net/0008-be2net-Add-EEPROM-dump-feature-for-Lancer.patch @@ -0,0 +1,70 @@ +From: Padmanabh Ratnakar +Date: Wed, 16 Nov 2011 02:03:07 +0000 +Subject: [PATCH 08/58] be2net: Add EEPROM dump feature for Lancer + +commit af5875bdfed02a10a0c76bbd547753fea7979244 upstream. + +Implemented eeprom dump using ethtool feature for Lancer. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.h | 2 ++ + drivers/net/ethernet/emulex/benet/be_ethtool.c | 21 ++++++++++++++++++++- + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 2d3fe6a..ac11246 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1167,6 +1167,8 @@ struct lancer_cmd_resp_write_object { + #define LANCER_READ_FILE_EOF_MASK 0x80000000 + + #define LANCER_FW_DUMP_FILE "/dbg/dump.bin" ++#define LANCER_VPD_PF_FILE "/vpd/ntr_pf.vpd" ++#define LANCER_VPD_VF_FILE "/vpd/ntr_vf.vpd" + + struct lancer_cmd_req_read_object { + struct be_cmd_req_hdr hdr; +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 1e7252e..575c783 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -727,7 +727,17 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) + static int + be_get_eeprom_len(struct net_device *netdev) + { +- return BE_READ_SEEPROM_LEN; ++ struct be_adapter *adapter = netdev_priv(netdev); ++ if (lancer_chip(adapter)) { ++ if (be_physfn(adapter)) ++ return lancer_cmd_get_file_len(adapter, ++ LANCER_VPD_PF_FILE); ++ else ++ return lancer_cmd_get_file_len(adapter, ++ LANCER_VPD_VF_FILE); ++ } else { ++ return BE_READ_SEEPROM_LEN; ++ } + } + + static int +@@ -742,6 +752,15 @@ be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, + if (!eeprom->len) + return -EINVAL; + ++ if (lancer_chip(adapter)) { ++ if (be_physfn(adapter)) ++ return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE, ++ eeprom->len, data); ++ else ++ return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE, ++ eeprom->len, data); ++ } ++ + eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16); + + memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem)); +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0009-be2net-Fix-VLAN-promiscous-mode-for-Lancer.patch b/debian/patches/features/all/be2net/0009-be2net-Fix-VLAN-promiscous-mode-for-Lancer.patch new file mode 100644 index 000000000..6dc104bf4 --- /dev/null +++ b/debian/patches/features/all/be2net/0009-be2net-Fix-VLAN-promiscous-mode-for-Lancer.patch @@ -0,0 +1,33 @@ +From: Padmanabh Ratnakar +Date: Wed, 16 Nov 2011 02:03:32 +0000 +Subject: [PATCH 09/58] be2net: Fix VLAN promiscous mode for Lancer + +commit 5d5adb93d0efca8b47cc3e649a41ba650ff3d270 upstream. + +To enable VLAN promiscous mode, the HW interface should be created +with VLAN promiscous capability in Lancer. Add this capability during +creation of the HW interface. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index c982b51..93869d4 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2600,7 +2600,8 @@ static int be_setup(struct be_adapter *adapter) + en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS; + cap_flags = en_flags | BE_IF_FLAGS_MCAST_PROMISCUOUS | +- BE_IF_FLAGS_PROMISCUOUS; ++ BE_IF_FLAGS_VLAN_PROMISCUOUS | BE_IF_FLAGS_PROMISCUOUS; ++ + if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) { + cap_flags |= BE_IF_FLAGS_RSS; + en_flags |= BE_IF_FLAGS_RSS; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0010-be2net-Use-V1-query-link-status-command-for-lancer.patch b/debian/patches/features/all/be2net/0010-be2net-Use-V1-query-link-status-command-for-lancer.patch new file mode 100644 index 000000000..1220a6791 --- /dev/null +++ b/debian/patches/features/all/be2net/0010-be2net-Use-V1-query-link-status-command-for-lancer.patch @@ -0,0 +1,31 @@ +From: Padmanabh Ratnakar +Date: Wed, 16 Nov 2011 02:03:45 +0000 +Subject: [PATCH 10/58] be2net: Use V1 query link status command for lancer + +commit daad6167d97b43cfc448cfe698784730b53ed3d6 upstream. + +Use V1 version of query link status command for Lancer. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 1522065..64f0c1a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1246,6 +1246,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + } + req = embedded_payload(wrb); + ++ if (lancer_chip(adapter)) ++ req->hdr.version = 1; ++ + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL); + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0011-be2net-Move-to-new-SR-IOV-implementation-in-Lancer.patch b/debian/patches/features/all/be2net/0011-be2net-Move-to-new-SR-IOV-implementation-in-Lancer.patch new file mode 100644 index 000000000..107b345d8 --- /dev/null +++ b/debian/patches/features/all/be2net/0011-be2net-Move-to-new-SR-IOV-implementation-in-Lancer.patch @@ -0,0 +1,393 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 Nov 2011 05:47:26 +0000 +Subject: [PATCH 11/58] be2net: Move to new SR-IOV implementation in Lancer + +commit 590c391dd362479b27a67c8d797ce348c5798b93 upstream. + +SR-IOV implementation is Lancer has changed in following ways - +1)PF driver assigns one MAC addresses for VF using COMMON_SET_IFACE_MAC_LIST. +2)VF driver queries its MAC address using COMMON_GET_IFACE_MAC_LIST command +and assigns it to its interface. + +Signed-off-by: Mammatha Edhala +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 99 ++++++++++++++++++++++++++- + drivers/net/ethernet/emulex/benet/be_cmds.h | 37 +++++++++- + drivers/net/ethernet/emulex/benet/be_main.c | 89 +++++++++++++++++------- + 3 files changed, 200 insertions(+), 25 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 64f0c1a..7988798 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -609,7 +609,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, + + /* Use MCC */ + int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, +- u8 type, bool permanent, u32 if_handle) ++ u8 type, bool permanent, u32 if_handle, u32 pmac_id) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_mac_query *req; +@@ -631,6 +631,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, + req->permanent = 1; + } else { + req->if_id = cpu_to_le16((u16) if_handle); ++ req->pmac_id = cpu_to_le32(pmac_id); + req->permanent = 0; + } + +@@ -2280,3 +2281,99 @@ err: + mutex_unlock(&adapter->mbox_lock); + return status; + } ++ ++/* Uses synchronous MCCQ */ ++int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, ++ u32 *pmac_id) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_mac_list *req; ++ int status; ++ int mac_count; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ req = embedded_payload(wrb); ++ ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_MAC_LIST, sizeof(*req), ++ wrb, NULL); ++ ++ req->hdr.domain = domain; ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_mac_list *resp = ++ embedded_payload(wrb); ++ int i; ++ u8 *ctxt = &resp->context[0][0]; ++ status = -EIO; ++ mac_count = resp->mac_count; ++ be_dws_le_to_cpu(&resp->context, sizeof(resp->context)); ++ for (i = 0; i < mac_count; i++) { ++ if (!AMAP_GET_BITS(struct amap_get_mac_list_context, ++ act, ctxt)) { ++ *pmac_id = AMAP_GET_BITS ++ (struct amap_get_mac_list_context, ++ macid, ctxt); ++ status = 0; ++ break; ++ } ++ ctxt += sizeof(struct amap_get_mac_list_context) / 8; ++ } ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Uses synchronous MCCQ */ ++int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, ++ u8 mac_count, u32 domain) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_mac_list *req; ++ int status; ++ struct be_dma_mem cmd; ++ ++ memset(&cmd, 0, sizeof(struct be_dma_mem)); ++ cmd.size = sizeof(struct be_cmd_req_set_mac_list); ++ cmd.va = dma_alloc_coherent(&adapter->pdev->dev, cmd.size, ++ &cmd.dma, GFP_KERNEL); ++ if (!cmd.va) { ++ dev_err(&adapter->pdev->dev, "Memory alloc failure\n"); ++ return -ENOMEM; ++ } ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = cmd.va; ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_MAC_LIST, sizeof(*req), ++ wrb, &cmd); ++ ++ req->hdr.domain = domain; ++ req->mac_count = mac_count; ++ if (mac_count) ++ memcpy(req->mac, mac_array, ETH_ALEN*mac_count); ++ ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ dma_free_coherent(&adapter->pdev->dev, cmd.size, ++ cmd.va, cmd.dma); ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index ac11246..0b694c6 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -189,6 +189,8 @@ struct be_mcc_mailbox { + #define OPCODE_COMMON_GET_PHY_DETAILS 102 + #define OPCODE_COMMON_SET_DRIVER_FUNCTION_CAP 103 + #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 ++#define OPCODE_COMMON_GET_MAC_LIST 147 ++#define OPCODE_COMMON_SET_MAC_LIST 148 + #define OPCODE_COMMON_READ_OBJECT 171 + #define OPCODE_COMMON_WRITE_OBJECT 172 + +@@ -295,6 +297,7 @@ struct be_cmd_req_mac_query { + u8 type; + u8 permanent; + u16 if_id; ++ u32 pmac_id; + } __packed; + + struct be_cmd_resp_mac_query { +@@ -1340,6 +1343,34 @@ struct be_cmd_resp_set_func_cap { + u8 rsvd[212]; + }; + ++/******************** GET/SET_MACLIST **************************/ ++#define BE_MAX_MAC 64 ++struct amap_get_mac_list_context { ++ u8 macid[31]; ++ u8 act; ++} __packed; ++ ++struct be_cmd_req_get_mac_list { ++ struct be_cmd_req_hdr hdr; ++ u32 rsvd; ++} __packed; ++ ++struct be_cmd_resp_get_mac_list { ++ struct be_cmd_resp_hdr hdr; ++ u8 mac_count; ++ u8 rsvd1; ++ u16 rsvd2; ++ u8 context[sizeof(struct amap_get_mac_list_context) / 8][BE_MAX_MAC]; ++} __packed; ++ ++struct be_cmd_req_set_mac_list { ++ struct be_cmd_req_hdr hdr; ++ u8 mac_count; ++ u8 rsvd1; ++ u16 rsvd2; ++ struct macaddr mac[BE_MAX_MAC]; ++} __packed; ++ + /*************** HW Stats Get v1 **********************************/ + #define BE_TXP_SW_SZ 48 + struct be_port_rxf_stats_v1 { +@@ -1446,7 +1477,7 @@ static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter) + extern int be_pci_fnum_get(struct be_adapter *adapter); + extern int be_cmd_POST(struct be_adapter *adapter); + extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, +- u8 type, bool permanent, u32 if_handle); ++ u8 type, bool permanent, u32 if_handle, u32 pmac_id); + extern int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, + u32 if_id, u32 *pmac_id, u32 domain); + extern int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, +@@ -1542,4 +1573,8 @@ extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter); + extern int be_cmd_req_native_mode(struct be_adapter *adapter); + extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); + extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); ++extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, ++ u32 *pmac_id); ++extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, ++ u8 mac_count, u32 domain); + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 93869d4..c6fb7c3 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -237,7 +237,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) + return -EADDRNOTAVAIL; + + status = be_cmd_mac_addr_query(adapter, current_mac, +- MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); ++ MAC_ADDRESS_TYPE_NETWORK, false, ++ adapter->if_handle, 0); + if (status) + goto err; + +@@ -848,11 +849,18 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) + if (!is_valid_ether_addr(mac) || (vf >= num_vfs)) + return -EINVAL; + +- status = be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, ++ if (lancer_chip(adapter)) { ++ status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); ++ } else { ++ status = be_cmd_pmac_del(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, + adapter->vf_cfg[vf].vf_pmac_id, vf + 1); + +- status = be_cmd_pmac_add(adapter, mac, adapter->vf_cfg[vf].vf_if_handle, ++ status = be_cmd_pmac_add(adapter, mac, ++ adapter->vf_cfg[vf].vf_if_handle, + &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ } ++ + if (status) + dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", + mac, vf); +@@ -2465,13 +2473,18 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) + be_vf_eth_addr_generate(adapter, mac); + + for (vf = 0; vf < num_vfs; vf++) { +- status = be_cmd_pmac_add(adapter, mac, ++ if (lancer_chip(adapter)) { ++ status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); ++ } else { ++ status = be_cmd_pmac_add(adapter, mac, + adapter->vf_cfg[vf].vf_if_handle, + &adapter->vf_cfg[vf].vf_pmac_id, + vf + 1); ++ } ++ + if (status) + dev_err(&adapter->pdev->dev, +- "Mac address add failed for VF %d\n", vf); ++ "Mac address assignment failed for VF %d\n", vf); + else + memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); + +@@ -2484,9 +2497,14 @@ static void be_vf_clear(struct be_adapter *adapter) + { + u32 vf; + +- for (vf = 0; vf < num_vfs; vf++) +- be_cmd_pmac_del(adapter, adapter->vf_cfg[vf].vf_if_handle, +- adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ for (vf = 0; vf < num_vfs; vf++) { ++ if (lancer_chip(adapter)) ++ be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); ++ else ++ be_cmd_pmac_del(adapter, ++ adapter->vf_cfg[vf].vf_if_handle, ++ adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ } + + for (vf = 0; vf < num_vfs; vf++) + be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle, +@@ -2527,7 +2545,9 @@ static int be_vf_setup(struct be_adapter *adapter) + + be_vf_setup_init(adapter); + +- cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST; ++ cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | ++ BE_IF_FLAGS_MULTICAST; ++ + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, + &adapter->vf_cfg[vf].vf_if_handle, +@@ -2536,11 +2556,9 @@ static int be_vf_setup(struct be_adapter *adapter) + goto err; + } + +- if (!lancer_chip(adapter)) { +- status = be_vf_eth_addr_config(adapter); +- if (status) +- goto err; +- } ++ status = be_vf_eth_addr_config(adapter); ++ if (status) ++ goto err; + + for (vf = 0; vf < num_vfs; vf++) { + status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, +@@ -2564,6 +2582,23 @@ static void be_setup_init(struct be_adapter *adapter) + adapter->eq_next_idx = 0; + } + ++static int be_configure_mac_from_list(struct be_adapter *adapter, u8 *mac) ++{ ++ u32 pmac_id; ++ int status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id); ++ if (status != 0) ++ goto do_none; ++ status = be_cmd_mac_addr_query(adapter, mac, ++ MAC_ADDRESS_TYPE_NETWORK, ++ false, adapter->if_handle, pmac_id); ++ if (status != 0) ++ goto do_none; ++ status = be_cmd_pmac_add(adapter, mac, adapter->if_handle, ++ &adapter->pmac_id, 0); ++do_none: ++ return status; ++} ++ + static int be_setup(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +@@ -2591,7 +2626,7 @@ static int be_setup(struct be_adapter *adapter) + + memset(mac, 0, ETH_ALEN); + status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, +- true /*permanent */, 0); ++ true /*permanent */, 0, 0); + if (status) + return status; + memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); +@@ -2618,12 +2653,17 @@ static int be_setup(struct be_adapter *adapter) + goto err; + } + +- /* For BEx, the VF's permanent mac queried from card is incorrect. +- * Query the mac configued by the PF using if_handle +- */ +- if (!be_physfn(adapter) && !lancer_chip(adapter)) { +- status = be_cmd_mac_addr_query(adapter, mac, +- MAC_ADDRESS_TYPE_NETWORK, false, adapter->if_handle); ++ /* The VF's permanent mac queried from card is incorrect. ++ * For BEx: Query the mac configued by the PF using if_handle ++ * For Lancer: Get and use mac_list to obtain mac address. ++ */ ++ if (!be_physfn(adapter)) { ++ if (lancer_chip(adapter)) ++ status = be_configure_mac_from_list(adapter, mac); ++ else ++ status = be_cmd_mac_addr_query(adapter, mac, ++ MAC_ADDRESS_TYPE_NETWORK, false, ++ adapter->if_handle, 0); + if (!status) { + memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); + memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); +@@ -2639,12 +2679,15 @@ static int be_setup(struct be_adapter *adapter) + be_set_rx_mode(adapter->netdev); + + status = be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); +- if (status) ++ /* For Lancer: It is legal for this cmd to fail on VF */ ++ if (status && (be_physfn(adapter) || !lancer_chip(adapter))) + goto err; ++ + if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) { + status = be_cmd_set_flow_control(adapter, adapter->tx_fc, + adapter->rx_fc); +- if (status) ++ /* For Lancer: It is legal for this cmd to fail on VF */ ++ if (status && (be_physfn(adapter) || !lancer_chip(adapter))) + goto err; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0012-be2net-Fix-error-recovery-paths.patch b/debian/patches/features/all/be2net/0012-be2net-Fix-error-recovery-paths.patch new file mode 100644 index 000000000..dc251f391 --- /dev/null +++ b/debian/patches/features/all/be2net/0012-be2net-Fix-error-recovery-paths.patch @@ -0,0 +1,37 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 Nov 2011 05:48:06 +0000 +Subject: [PATCH 12/58] be2net: Fix error recovery paths + +commit 3bb62f4f95ba004048bafb460179b5db33aff787 upstream. + +When TX queues are created again after error recovery, +netif_set_real_num_tx_queues() is invoked to update number of real +TX queues created. rtnl lock needs to be held when invoking this routine. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index c6fb7c3..a1b8ebc 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1666,9 +1666,12 @@ static int be_tx_queues_create(struct be_adapter *adapter) + u8 i; + + adapter->num_tx_qs = be_num_txqs_want(adapter); +- if (adapter->num_tx_qs != MAX_TX_QS) ++ if (adapter->num_tx_qs != MAX_TX_QS) { ++ rtnl_lock(); + netif_set_real_num_tx_queues(adapter->netdev, + adapter->num_tx_qs); ++ rtnl_unlock(); ++ } + + adapter->tx_eq.max_eqd = 0; + adapter->tx_eq.min_eqd = 0; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0013-be2net-Add-error-handling-for-Lancer.patch b/debian/patches/features/all/be2net/0013-be2net-Add-error-handling-for-Lancer.patch new file mode 100644 index 000000000..f56a473c9 --- /dev/null +++ b/debian/patches/features/all/be2net/0013-be2net-Add-error-handling-for-Lancer.patch @@ -0,0 +1,212 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 Nov 2011 05:48:23 +0000 +Subject: [PATCH 13/58] be2net: Add error handling for Lancer + +commit d8110f62c020ebc49108de57510a1482bfcbe86a upstream. + +Detect error in Lancer by polling a HW register and +recover from this error if it is recoverable. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 155 ++++++++++++++++++--------- + 1 file changed, 106 insertions(+), 49 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index a1b8ebc..66429ea 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2044,52 +2044,6 @@ void be_detect_dump_ue(struct be_adapter *adapter) + } + } + +-static void be_worker(struct work_struct *work) +-{ +- struct be_adapter *adapter = +- container_of(work, struct be_adapter, work.work); +- struct be_rx_obj *rxo; +- int i; +- +- be_detect_dump_ue(adapter); +- +- /* when interrupts are not yet enabled, just reap any pending +- * mcc completions */ +- if (!netif_running(adapter->netdev)) { +- int mcc_compl, status = 0; +- +- mcc_compl = be_process_mcc(adapter, &status); +- +- if (mcc_compl) { +- struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; +- be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); +- } +- +- goto reschedule; +- } +- +- if (!adapter->stats_cmd_sent) { +- if (lancer_chip(adapter)) +- lancer_cmd_get_pport_stats(adapter, +- &adapter->stats_cmd); +- else +- be_cmd_get_stats(adapter, &adapter->stats_cmd); +- } +- +- for_all_rx_queues(adapter, rxo, i) { +- be_rx_eqd_update(adapter, rxo); +- +- if (rxo->rx_post_starved) { +- rxo->rx_post_starved = false; +- be_post_rx_frags(rxo, GFP_KERNEL); +- } +- } +- +-reschedule: +- adapter->work_counter++; +- schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); +-} +- + static void be_msix_disable(struct be_adapter *adapter) + { + if (msix_enabled(adapter)) { +@@ -3328,7 +3282,7 @@ static int be_dev_family_check(struct be_adapter *adapter) + + static int lancer_wait_ready(struct be_adapter *adapter) + { +-#define SLIPORT_READY_TIMEOUT 500 ++#define SLIPORT_READY_TIMEOUT 30 + u32 sliport_status; + int status = 0, i; + +@@ -3337,7 +3291,7 @@ static int lancer_wait_ready(struct be_adapter *adapter) + if (sliport_status & SLIPORT_STATUS_RDY_MASK) + break; + +- msleep(20); ++ msleep(1000); + } + + if (i == SLIPORT_READY_TIMEOUT) +@@ -3374,6 +3328,104 @@ static int lancer_test_and_set_rdy_state(struct be_adapter *adapter) + return status; + } + ++static void lancer_test_and_recover_fn_err(struct be_adapter *adapter) ++{ ++ int status; ++ u32 sliport_status; ++ ++ if (adapter->eeh_err || adapter->ue_detected) ++ return; ++ ++ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); ++ ++ if (sliport_status & SLIPORT_STATUS_ERR_MASK) { ++ dev_err(&adapter->pdev->dev, ++ "Adapter in error state." ++ "Trying to recover.\n"); ++ ++ status = lancer_test_and_set_rdy_state(adapter); ++ if (status) ++ goto err; ++ ++ netif_device_detach(adapter->netdev); ++ ++ if (netif_running(adapter->netdev)) ++ be_close(adapter->netdev); ++ ++ be_clear(adapter); ++ ++ adapter->fw_timeout = false; ++ ++ status = be_setup(adapter); ++ if (status) ++ goto err; ++ ++ if (netif_running(adapter->netdev)) { ++ status = be_open(adapter->netdev); ++ if (status) ++ goto err; ++ } ++ ++ netif_device_attach(adapter->netdev); ++ ++ dev_err(&adapter->pdev->dev, ++ "Adapter error recovery succeeded\n"); ++ } ++ return; ++err: ++ dev_err(&adapter->pdev->dev, ++ "Adapter error recovery failed\n"); ++} ++ ++static void be_worker(struct work_struct *work) ++{ ++ struct be_adapter *adapter = ++ container_of(work, struct be_adapter, work.work); ++ struct be_rx_obj *rxo; ++ int i; ++ ++ if (lancer_chip(adapter)) ++ lancer_test_and_recover_fn_err(adapter); ++ ++ be_detect_dump_ue(adapter); ++ ++ /* when interrupts are not yet enabled, just reap any pending ++ * mcc completions */ ++ if (!netif_running(adapter->netdev)) { ++ int mcc_compl, status = 0; ++ ++ mcc_compl = be_process_mcc(adapter, &status); ++ ++ if (mcc_compl) { ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; ++ be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); ++ } ++ ++ goto reschedule; ++ } ++ ++ if (!adapter->stats_cmd_sent) { ++ if (lancer_chip(adapter)) ++ lancer_cmd_get_pport_stats(adapter, ++ &adapter->stats_cmd); ++ else ++ be_cmd_get_stats(adapter, &adapter->stats_cmd); ++ } ++ ++ for_all_rx_queues(adapter, rxo, i) { ++ be_rx_eqd_update(adapter, rxo); ++ ++ if (rxo->rx_post_starved) { ++ rxo->rx_post_starved = false; ++ be_post_rx_frags(rxo, GFP_KERNEL); ++ } ++ } ++ ++reschedule: ++ adapter->work_counter++; ++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); ++} ++ + static int __devinit be_probe(struct pci_dev *pdev, + const struct pci_device_id *pdev_id) + { +@@ -3426,7 +3478,12 @@ static int __devinit be_probe(struct pci_dev *pdev, + goto disable_sriov; + + if (lancer_chip(adapter)) { +- status = lancer_test_and_set_rdy_state(adapter); ++ status = lancer_wait_ready(adapter); ++ if (!status) { ++ iowrite32(SLI_PORT_CONTROL_IP_MASK, ++ adapter->db + SLIPORT_CONTROL_OFFSET); ++ status = lancer_test_and_set_rdy_state(adapter); ++ } + if (status) { + dev_err(&pdev->dev, "Adapter in non recoverable error\n"); + goto ctrl_clean; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0014-be2net-Use-new-hash-key.patch b/debian/patches/features/all/be2net/0014-be2net-Use-new-hash-key.patch new file mode 100644 index 000000000..67f33382c --- /dev/null +++ b/debian/patches/features/all/be2net/0014-be2net-Use-new-hash-key.patch @@ -0,0 +1,34 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 Nov 2011 05:48:38 +0000 +Subject: [PATCH 14/58] be2net: Use new hash key + +commit 65f8584e253f4676c8b39e976a10e918ec984b7c upstream. + +This new hash key gives better distribution of packets across RX +queues. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 7988798..62868ea 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1669,8 +1669,9 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_rss_config *req; +- u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF, +- 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF}; ++ u32 myhash[10] = {0x15d43fa5, 0x2534685a, 0x5f87693a, 0x5668494e, ++ 0x33cf6a53, 0x383334c6, 0x76ac4257, 0x59b242b2, ++ 0x3ea83c02, 0x4a110304}; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0015-be2net-Fix-non-utilization-of-RX-queues.patch b/debian/patches/features/all/be2net/0015-be2net-Fix-non-utilization-of-RX-queues.patch new file mode 100644 index 000000000..403111cf5 --- /dev/null +++ b/debian/patches/features/all/be2net/0015-be2net-Fix-non-utilization-of-RX-queues.patch @@ -0,0 +1,54 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 Nov 2011 05:48:53 +0000 +Subject: [PATCH 15/58] be2net: Fix non utilization of RX queues + +commit e9008ee99c77207b2f6aee67e5f849b1e1400a11 upstream. + +When non power of two MSIX vectors are given to driver, some RX queues +are not utilized. Program RSS table in such a way that all queues +are utilized. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 66429ea..7236280 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2312,8 +2312,8 @@ static int be_close(struct net_device *netdev) + static int be_rx_queues_setup(struct be_adapter *adapter) + { + struct be_rx_obj *rxo; +- int rc, i; +- u8 rsstable[MAX_RSS_QS]; ++ int rc, i, j; ++ u8 rsstable[128]; + + for_all_rx_queues(adapter, rxo, i) { + rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, +@@ -2325,11 +2325,15 @@ static int be_rx_queues_setup(struct be_adapter *adapter) + } + + if (be_multi_rxq(adapter)) { +- for_all_rss_queues(adapter, rxo, i) +- rsstable[i] = rxo->rss_id; ++ for (j = 0; j < 128; j += adapter->num_rx_qs - 1) { ++ for_all_rss_queues(adapter, rxo, i) { ++ if ((j + i) >= 128) ++ break; ++ rsstable[j + i] = rxo->rss_id; ++ } ++ } ++ rc = be_cmd_rss_config(adapter, rsstable, 128); + +- rc = be_cmd_rss_config(adapter, rsstable, +- adapter->num_rx_qs - 1); + if (rc) + return rc; + } +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0016-be2net-netpoll-support.patch b/debian/patches/features/all/be2net/0016-be2net-netpoll-support.patch new file mode 100644 index 000000000..f83eb402b --- /dev/null +++ b/debian/patches/features/all/be2net/0016-be2net-netpoll-support.patch @@ -0,0 +1,53 @@ +From: Ivan Vecera +Date: Thu, 8 Dec 2011 01:31:21 +0000 +Subject: [PATCH 16/58] be2net: netpoll support + +commit 6626873980475f303367f7b709f4703b571cf854 upstream. + +Add missing netpoll support. + +Signed-off-by: Ivan Vecera +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 7236280..3854fb0 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2666,6 +2666,19 @@ err: + return status; + } + ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void be_netpoll(struct net_device *netdev) ++{ ++ struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_rx_obj *rxo; ++ int i; ++ ++ event_handle(adapter, &adapter->tx_eq, false); ++ for_all_rx_queues(adapter, rxo, i) ++ event_handle(adapter, &rxo->rx_eq, true); ++} ++#endif ++ + #define FW_FILE_HDR_SIGN "ServerEngines Corp. " + static bool be_flash_redboot(struct be_adapter *adapter, + const u8 *p, u32 img_start, int image_size, +@@ -3014,7 +3027,10 @@ static struct net_device_ops be_netdev_ops = { + .ndo_set_vf_mac = be_set_vf_mac, + .ndo_set_vf_vlan = be_set_vf_vlan, + .ndo_set_vf_tx_rate = be_set_vf_tx_rate, +- .ndo_get_vf_config = be_get_vf_config ++ .ndo_get_vf_config = be_get_vf_config, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = be_netpoll, ++#endif + }; + + static void be_netdev_init(struct net_device *netdev) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0017-be2net-update-some-counters-to-display-via-ethtool.patch b/debian/patches/features/all/be2net/0017-be2net-update-some-counters-to-display-via-ethtool.patch new file mode 100644 index 000000000..3c6e3b445 --- /dev/null +++ b/debian/patches/features/all/be2net/0017-be2net-update-some-counters-to-display-via-ethtool.patch @@ -0,0 +1,30 @@ +From: Ajit Khaparde +Date: Fri, 9 Dec 2011 13:53:09 +0000 +Subject: [PATCH 17/58] be2net: update some counters to display via ethtool + +commit 02fe7027961969a052fbbe453304f329d4e9735a upstream. + +update pmem_fifo_overflow_drop, rx_priority_pause_frames counters. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 3854fb0..0da3df0 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -316,6 +316,8 @@ static void populate_be3_stats(struct be_adapter *adapter) + struct be_drv_stats *drvs = &adapter->drv_stats; + + be_dws_le_to_cpu(hw_stats, sizeof(*hw_stats)); ++ drvs->pmem_fifo_overflow_drop = port_stats->pmem_fifo_overflow_drop; ++ drvs->rx_priority_pause_frames = port_stats->rx_priority_pause_frames; + drvs->rx_pause_frames = port_stats->rx_pause_frames; + drvs->rx_crc_errors = port_stats->rx_crc_errors; + drvs->rx_control_frames = port_stats->rx_control_frames; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0018-be2net-workaround-to-fix-a-bug-in-BE.patch b/debian/patches/features/all/be2net/0018-be2net-workaround-to-fix-a-bug-in-BE.patch new file mode 100644 index 000000000..7110bc660 --- /dev/null +++ b/debian/patches/features/all/be2net/0018-be2net-workaround-to-fix-a-bug-in-BE.patch @@ -0,0 +1,98 @@ +From: Ajit Khaparde +Date: Fri, 9 Dec 2011 13:53:17 +0000 +Subject: [PATCH 18/58] be2net: workaround to fix a bug in BE + +commit 1ded132d4c3442aa3a619c94c245d7b5e0eb9731 upstream. + +disable Tx vlan offloading in certain cases. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 46 ++++++++++++++++++++++----- + 1 file changed, 38 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 0da3df0..f180f49 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -552,11 +552,26 @@ static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len) + wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK; + } + ++static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter, ++ struct sk_buff *skb) ++{ ++ u8 vlan_prio; ++ u16 vlan_tag; ++ ++ vlan_tag = vlan_tx_tag_get(skb); ++ vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; ++ /* If vlan priority provided by OS is NOT in available bmap */ ++ if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) ++ vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | ++ adapter->recommended_prio; ++ ++ return vlan_tag; ++} ++ + static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, + struct sk_buff *skb, u32 wrb_cnt, u32 len) + { +- u8 vlan_prio = 0; +- u16 vlan_tag = 0; ++ u16 vlan_tag; + + memset(hdr, 0, sizeof(*hdr)); + +@@ -587,12 +602,7 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr, + + if (vlan_tx_tag_present(skb)) { + AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1); +- vlan_tag = vlan_tx_tag_get(skb); +- vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; +- /* If vlan priority provided by OS is NOT in available bmap */ +- if (!(adapter->vlan_prio_bmap & (1 << vlan_prio))) +- vlan_tag = (vlan_tag & ~VLAN_PRIO_MASK) | +- adapter->recommended_prio; ++ vlan_tag = be_get_tx_vlan_tag(adapter, skb); + AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag, hdr, vlan_tag); + } + +@@ -695,6 +705,25 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, + u32 start = txq->head; + bool dummy_wrb, stopped = false; + ++ /* For vlan tagged pkts, BE ++ * 1) calculates checksum even when CSO is not requested ++ * 2) calculates checksum wrongly for padded pkt less than ++ * 60 bytes long. ++ * As a workaround disable TX vlan offloading in such cases. ++ */ ++ if (unlikely(vlan_tx_tag_present(skb) && ++ (skb->ip_summed != CHECKSUM_PARTIAL || skb->len <= 60))) { ++ skb = skb_share_check(skb, GFP_ATOMIC); ++ if (unlikely(!skb)) ++ goto tx_drop; ++ ++ skb = __vlan_put_tag(skb, be_get_tx_vlan_tag(adapter, skb)); ++ if (unlikely(!skb)) ++ goto tx_drop; ++ ++ skb->vlan_tci = 0; ++ } ++ + wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb); + + copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb); +@@ -722,6 +751,7 @@ static netdev_tx_t be_xmit(struct sk_buff *skb, + txq->head = start; + dev_kfree_skb_any(skb); + } ++tx_drop: + return NETDEV_TX_OK; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0019-be2net-fix-ethtool-ringparam-reporting.patch b/debian/patches/features/all/be2net/0019-be2net-fix-ethtool-ringparam-reporting.patch new file mode 100644 index 000000000..3572af57b --- /dev/null +++ b/debian/patches/features/all/be2net/0019-be2net-fix-ethtool-ringparam-reporting.patch @@ -0,0 +1,46 @@ +From: Sathya Perla +Date: Tue, 13 Dec 2011 00:58:49 +0000 +Subject: [PATCH 19/58] be2net: fix ethtool ringparam reporting + +commit 110b82bc6265a48c1a0bf198109bed325ed055e2 upstream. + +The ethtool "-g" option is supposed to report the max queue length and +user modified queue length for RX and TX queues. be2net doesn't support +user modification of queue lengths. So, the correct values for these +would be the max numbers. +be2net incorrectly reports the queue used values for these fields. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 575c783..6ba2dc6 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -520,16 +520,13 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + return 0; + } + +-static void +-be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ++static void be_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) + { + struct be_adapter *adapter = netdev_priv(netdev); + +- ring->rx_max_pending = adapter->rx_obj[0].q.len; +- ring->tx_max_pending = adapter->tx_obj[0].q.len; +- +- ring->rx_pending = atomic_read(&adapter->rx_obj[0].q.used); +- ring->tx_pending = atomic_read(&adapter->tx_obj[0].q.used); ++ ring->rx_max_pending = ring->rx_pending = adapter->rx_obj[0].q.len; ++ ring->tx_max_pending = ring->tx_pending = adapter->tx_obj[0].q.len; + } + + static void +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0020-be2net-refactor-cleanup-vf-configuration-code.patch b/debian/patches/features/all/be2net/0020-be2net-refactor-cleanup-vf-configuration-code.patch new file mode 100644 index 000000000..184bf8bbf --- /dev/null +++ b/debian/patches/features/all/be2net/0020-be2net-refactor-cleanup-vf-configuration-code.patch @@ -0,0 +1,416 @@ +From: Sathya Perla +Date: Tue, 13 Dec 2011 00:58:50 +0000 +Subject: [PATCH 20/58] be2net: refactor/cleanup vf configuration code + +commit 11ac75ed1eb9d8f5ff067fa9a82ebf5075989281 upstream. + +- use adapter->num_vfs (and not the module param) to store the actual +number of vfs created. Use the same variable to reflect SRIOV +enable/disable state. So, drop the adapter->sriov_enabled field. + +- use for_all_vfs() macro in VF configuration code + +- drop the "vf_" prefix for the fields of be_vf_cfg; the prefix is +redundant and removing it helps reduce line wrap + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 20 ++-- + drivers/net/ethernet/emulex/benet/be_main.c | 137 +++++++++++++-------------- + 2 files changed, 80 insertions(+), 77 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 34f162d..a3588fb 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -288,11 +288,11 @@ struct be_drv_stats { + }; + + struct be_vf_cfg { +- unsigned char vf_mac_addr[ETH_ALEN]; +- int vf_if_handle; +- int vf_pmac_id; +- u16 vf_vlan_tag; +- u32 vf_tx_rate; ++ unsigned char mac_addr[ETH_ALEN]; ++ int if_handle; ++ int pmac_id; ++ u16 vlan_tag; ++ u32 tx_rate; + }; + + struct be_adapter { +@@ -368,16 +368,20 @@ struct be_adapter { + u32 flash_status; + struct completion flash_compl; + +- bool be3_native; +- bool sriov_enabled; +- struct be_vf_cfg *vf_cfg; ++ u32 num_vfs; + u8 is_virtfn; ++ struct be_vf_cfg *vf_cfg; ++ bool be3_native; + u32 sli_family; + u8 hba_port_num; + u16 pvid; + }; + + #define be_physfn(adapter) (!adapter->is_virtfn) ++#define sriov_enabled(adapter) (adapter->num_vfs > 0) ++#define for_all_vfs(adapter, vf_cfg, i) \ ++ for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ ++ i++, vf_cfg++) + + /* BladeEngine Generation numbers */ + #define BE_GEN2 2 +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index f180f49..cf83b33 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -27,13 +27,14 @@ MODULE_DESCRIPTION(DRV_DESC " " DRV_VER); + MODULE_AUTHOR("ServerEngines Corporation"); + MODULE_LICENSE("GPL"); + +-static ushort rx_frag_size = 2048; + static unsigned int num_vfs; +-module_param(rx_frag_size, ushort, S_IRUGO); + module_param(num_vfs, uint, S_IRUGO); +-MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); + MODULE_PARM_DESC(num_vfs, "Number of PCI VFs to initialize"); + ++static ushort rx_frag_size = 2048; ++module_param(rx_frag_size, ushort, S_IRUGO); ++MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data."); ++ + static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { + { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, + { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, +@@ -779,15 +780,15 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu) + */ + static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) + { ++ struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf_num]; + u16 vtag[BE_NUM_VLANS_SUPPORTED]; + u16 ntags = 0, i; + int status = 0; +- u32 if_handle; + + if (vf) { +- if_handle = adapter->vf_cfg[vf_num].vf_if_handle; +- vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag); +- status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0); ++ vtag[0] = cpu_to_le16(vf_cfg->vlan_tag); ++ status = be_cmd_vlan_config(adapter, vf_cfg->if_handle, vtag, ++ 1, 1, 0); + } + + /* No need to further configure vids if in promiscuous mode */ +@@ -873,31 +874,30 @@ done: + static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf]; + int status; + +- if (!adapter->sriov_enabled) ++ if (!sriov_enabled(adapter)) + return -EPERM; + +- if (!is_valid_ether_addr(mac) || (vf >= num_vfs)) ++ if (!is_valid_ether_addr(mac) || vf >= adapter->num_vfs) + return -EINVAL; + + if (lancer_chip(adapter)) { + status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); + } else { +- status = be_cmd_pmac_del(adapter, +- adapter->vf_cfg[vf].vf_if_handle, +- adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ status = be_cmd_pmac_del(adapter, vf_cfg->if_handle, ++ vf_cfg->pmac_id, vf + 1); + +- status = be_cmd_pmac_add(adapter, mac, +- adapter->vf_cfg[vf].vf_if_handle, +- &adapter->vf_cfg[vf].vf_pmac_id, vf + 1); ++ status = be_cmd_pmac_add(adapter, mac, vf_cfg->if_handle, ++ &vf_cfg->pmac_id, vf + 1); + } + + if (status) + dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n", + mac, vf); + else +- memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); ++ memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); + + return status; + } +@@ -906,18 +906,19 @@ static int be_get_vf_config(struct net_device *netdev, int vf, + struct ifla_vf_info *vi) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ struct be_vf_cfg *vf_cfg = &adapter->vf_cfg[vf]; + +- if (!adapter->sriov_enabled) ++ if (!sriov_enabled(adapter)) + return -EPERM; + +- if (vf >= num_vfs) ++ if (vf >= adapter->num_vfs) + return -EINVAL; + + vi->vf = vf; +- vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate; +- vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag; ++ vi->tx_rate = vf_cfg->tx_rate; ++ vi->vlan = vf_cfg->vlan_tag; + vi->qos = 0; +- memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN); ++ memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN); + + return 0; + } +@@ -928,17 +929,17 @@ static int be_set_vf_vlan(struct net_device *netdev, + struct be_adapter *adapter = netdev_priv(netdev); + int status = 0; + +- if (!adapter->sriov_enabled) ++ if (!sriov_enabled(adapter)) + return -EPERM; + +- if ((vf >= num_vfs) || (vlan > 4095)) ++ if (vf >= adapter->num_vfs || vlan > 4095) + return -EINVAL; + + if (vlan) { +- adapter->vf_cfg[vf].vf_vlan_tag = vlan; ++ adapter->vf_cfg[vf].vlan_tag = vlan; + adapter->vlans_added++; + } else { +- adapter->vf_cfg[vf].vf_vlan_tag = 0; ++ adapter->vf_cfg[vf].vlan_tag = 0; + adapter->vlans_added--; + } + +@@ -956,16 +957,16 @@ static int be_set_vf_tx_rate(struct net_device *netdev, + struct be_adapter *adapter = netdev_priv(netdev); + int status = 0; + +- if (!adapter->sriov_enabled) ++ if (!sriov_enabled(adapter)) + return -EPERM; + +- if ((vf >= num_vfs) || (rate < 0)) ++ if (vf >= adapter->num_vfs || rate < 0) + return -EINVAL; + + if (rate > 10000) + rate = 10000; + +- adapter->vf_cfg[vf].vf_tx_rate = rate; ++ adapter->vf_cfg[vf].tx_rate = rate; + status = be_cmd_set_qos(adapter, rate / 10, vf + 1); + + if (status) +@@ -1681,8 +1682,7 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) + + static int be_num_txqs_want(struct be_adapter *adapter) + { +- if ((num_vfs && adapter->sriov_enabled) || +- be_is_mc(adapter) || ++ if (sriov_enabled(adapter) || be_is_mc(adapter) || + lancer_chip(adapter) || !be_physfn(adapter) || + adapter->generation == BE_GEN2) + return 1; +@@ -1764,8 +1764,8 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) + static u32 be_num_rxqs_want(struct be_adapter *adapter) + { + if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && +- !adapter->sriov_enabled && be_physfn(adapter) && +- !be_is_mc(adapter)) { ++ !sriov_enabled(adapter) && be_physfn(adapter) && ++ !be_is_mc(adapter)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, +@@ -2112,27 +2112,28 @@ done: + static int be_sriov_enable(struct be_adapter *adapter) + { + be_check_sriov_fn_type(adapter); ++ + #ifdef CONFIG_PCI_IOV + if (be_physfn(adapter) && num_vfs) { + int status, pos; +- u16 nvfs; ++ u16 dev_vfs; + + pos = pci_find_ext_capability(adapter->pdev, + PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(adapter->pdev, +- pos + PCI_SRIOV_TOTAL_VF, &nvfs); ++ pos + PCI_SRIOV_TOTAL_VF, &dev_vfs); + +- if (num_vfs > nvfs) { ++ adapter->num_vfs = min_t(u16, num_vfs, dev_vfs); ++ if (adapter->num_vfs != num_vfs) + dev_info(&adapter->pdev->dev, +- "Device supports %d VFs and not %d\n", +- nvfs, num_vfs); +- num_vfs = nvfs; +- } ++ "Device supports %d VFs and not %d\n", ++ adapter->num_vfs, num_vfs); + +- status = pci_enable_sriov(adapter->pdev, num_vfs); +- adapter->sriov_enabled = status ? false : true; ++ status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); ++ if (status) ++ adapter->num_vfs = 0; + +- if (adapter->sriov_enabled) { ++ if (adapter->num_vfs) { + adapter->vf_cfg = kcalloc(num_vfs, + sizeof(struct be_vf_cfg), + GFP_KERNEL); +@@ -2147,10 +2148,10 @@ static int be_sriov_enable(struct be_adapter *adapter) + static void be_sriov_disable(struct be_adapter *adapter) + { + #ifdef CONFIG_PCI_IOV +- if (adapter->sriov_enabled) { ++ if (sriov_enabled(adapter)) { + pci_disable_sriov(adapter->pdev); + kfree(adapter->vf_cfg); +- adapter->sriov_enabled = false; ++ adapter->num_vfs = 0; + } + #endif + } +@@ -2462,24 +2463,24 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) + u32 vf; + int status = 0; + u8 mac[ETH_ALEN]; ++ struct be_vf_cfg *vf_cfg; + + be_vf_eth_addr_generate(adapter, mac); + +- for (vf = 0; vf < num_vfs; vf++) { ++ for_all_vfs(adapter, vf_cfg, vf) { + if (lancer_chip(adapter)) { + status = be_cmd_set_mac_list(adapter, mac, 1, vf + 1); + } else { + status = be_cmd_pmac_add(adapter, mac, +- adapter->vf_cfg[vf].vf_if_handle, +- &adapter->vf_cfg[vf].vf_pmac_id, +- vf + 1); ++ vf_cfg->if_handle, ++ &vf_cfg->pmac_id, vf + 1); + } + + if (status) + dev_err(&adapter->pdev->dev, + "Mac address assignment failed for VF %d\n", vf); + else +- memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN); ++ memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); + + mac[5] += 1; + } +@@ -2488,25 +2489,23 @@ static inline int be_vf_eth_addr_config(struct be_adapter *adapter) + + static void be_vf_clear(struct be_adapter *adapter) + { ++ struct be_vf_cfg *vf_cfg; + u32 vf; + +- for (vf = 0; vf < num_vfs; vf++) { ++ for_all_vfs(adapter, vf_cfg, vf) { + if (lancer_chip(adapter)) + be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); + else +- be_cmd_pmac_del(adapter, +- adapter->vf_cfg[vf].vf_if_handle, +- adapter->vf_cfg[vf].vf_pmac_id, vf + 1); +- } ++ be_cmd_pmac_del(adapter, vf_cfg->if_handle, ++ vf_cfg->pmac_id, vf + 1); + +- for (vf = 0; vf < num_vfs; vf++) +- be_cmd_if_destroy(adapter, adapter->vf_cfg[vf].vf_if_handle, +- vf + 1); ++ be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1); ++ } + } + + static int be_clear(struct be_adapter *adapter) + { +- if (be_physfn(adapter) && adapter->sriov_enabled) ++ if (sriov_enabled(adapter)) + be_vf_clear(adapter); + + be_cmd_if_destroy(adapter, adapter->if_handle, 0); +@@ -2522,16 +2521,18 @@ static int be_clear(struct be_adapter *adapter) + + static void be_vf_setup_init(struct be_adapter *adapter) + { ++ struct be_vf_cfg *vf_cfg; + int vf; + +- for (vf = 0; vf < num_vfs; vf++) { +- adapter->vf_cfg[vf].vf_if_handle = -1; +- adapter->vf_cfg[vf].vf_pmac_id = -1; ++ for_all_vfs(adapter, vf_cfg, vf) { ++ vf_cfg->if_handle = -1; ++ vf_cfg->pmac_id = -1; + } + } + + static int be_vf_setup(struct be_adapter *adapter) + { ++ struct be_vf_cfg *vf_cfg; + u32 cap_flags, en_flags, vf; + u16 lnk_speed; + int status; +@@ -2540,11 +2541,9 @@ static int be_vf_setup(struct be_adapter *adapter) + + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST; +- +- for (vf = 0; vf < num_vfs; vf++) { ++ for_all_vfs(adapter, vf_cfg, vf) { + status = be_cmd_if_create(adapter, cap_flags, en_flags, NULL, +- &adapter->vf_cfg[vf].vf_if_handle, +- NULL, vf+1); ++ &vf_cfg->if_handle, NULL, vf + 1); + if (status) + goto err; + } +@@ -2553,12 +2552,12 @@ static int be_vf_setup(struct be_adapter *adapter) + if (status) + goto err; + +- for (vf = 0; vf < num_vfs; vf++) { ++ for_all_vfs(adapter, vf_cfg, vf) { + status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, +- vf + 1); ++ vf + 1); + if (status) + goto err; +- adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10; ++ vf_cfg->tx_rate = lnk_speed * 10; + } + return 0; + err: +@@ -2686,7 +2685,7 @@ static int be_setup(struct be_adapter *adapter) + + pcie_set_readrq(adapter->pdev, 4096); + +- if (be_physfn(adapter) && adapter->sriov_enabled) { ++ if (sriov_enabled(adapter)) { + status = be_vf_setup(adapter); + if (status) + goto err; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0021-be2net-Add-support-for-Skyhawk-cards.patch b/debian/patches/features/all/be2net/0021-be2net-Add-support-for-Skyhawk-cards.patch new file mode 100644 index 000000000..3d077d4b1 --- /dev/null +++ b/debian/patches/features/all/be2net/0021-be2net-Add-support-for-Skyhawk-cards.patch @@ -0,0 +1,65 @@ +From: Ajit Khaparde +Date: Thu, 15 Dec 2011 06:31:38 +0000 +Subject: [PATCH 21/58] be2net: Add support for Skyhawk cards + +commit ecedb6ae908e3a8a19942da921a3ffb1c5a0d6ab upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 4 ++++ + drivers/net/ethernet/emulex/benet/be_main.c | 2 ++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index a3588fb..995198d 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -40,6 +40,7 @@ + #define OC_NAME "Emulex OneConnect 10Gbps NIC" + #define OC_NAME_BE OC_NAME "(be3)" + #define OC_NAME_LANCER OC_NAME "(Lancer)" ++#define OC_NAME_SH OC_NAME "(Skyhawk)" + #define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver" + + #define BE_VENDOR_ID 0x19a2 +@@ -50,6 +51,7 @@ + #define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */ + #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ + #define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ ++#define OC_DEVICE_ID5 0x720 /* Device Id for Skyhawk cards */ + + static inline char *nic_name(struct pci_dev *pdev) + { +@@ -63,6 +65,8 @@ static inline char *nic_name(struct pci_dev *pdev) + return OC_NAME_LANCER; + case BE_DEVICE_ID2: + return BE3_NAME; ++ case OC_DEVICE_ID5: ++ return OC_NAME_SH; + default: + return BE_NAME; + } +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index cf83b33..3ed2987 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -42,6 +42,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = { + { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, + { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)}, + { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)}, ++ { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID5)}, + { 0 } + }; + MODULE_DEVICE_TABLE(pci, be_dev_ids); +@@ -3308,6 +3309,7 @@ static int be_dev_family_check(struct be_adapter *adapter) + break; + case BE_DEVICE_ID2: + case OC_DEVICE_ID2: ++ case OC_DEVICE_ID5: + adapter->generation = BE_GEN3; + break; + case OC_DEVICE_ID3: +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0022-be2net-Fix-INTx-processing-for-Lancer.patch b/debian/patches/features/all/be2net/0022-be2net-Fix-INTx-processing-for-Lancer.patch new file mode 100644 index 000000000..10e8fb054 --- /dev/null +++ b/debian/patches/features/all/be2net/0022-be2net-Fix-INTx-processing-for-Lancer.patch @@ -0,0 +1,53 @@ +From: Padmanabh Ratnakar +Date: Mon, 19 Dec 2011 01:53:35 +0000 +Subject: [PATCH 22/58] be2net: Fix INTx processing for Lancer + +commit 93c86700c0ae3a1407b979073f423e62e29372c1 upstream. + +Lancer does not have HW registers to indicate the EQ causing the INTx +interrupt. As a result EQE entries of one EQ may be consumed when interrupt +is caused by another EQ. Fix this by arming CQs at the end of NAPI poll +routine to regenerate the EQEs. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 3ed2987..a185e61 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1966,6 +1966,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) + struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); + struct be_adapter *adapter = + container_of(tx_eq, struct be_adapter, tx_eq); ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + struct be_tx_obj *txo; + struct be_eth_tx_compl *txcp; + int tx_compl, mcc_compl, status = 0; +@@ -2002,12 +2003,19 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) + mcc_compl = be_process_mcc(adapter, &status); + + if (mcc_compl) { +- struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl); + } + + napi_complete(napi); + ++ /* Arm CQ again to regenerate EQEs for Lancer in INTx mode */ ++ if (lancer_chip(adapter) && !msix_enabled(adapter)) { ++ for_all_tx_queues(adapter, txo, i) ++ be_cq_notify(adapter, txo->cq.id, true, 0); ++ ++ be_cq_notify(adapter, mcc_obj->cq.id, true, 0); ++ } ++ + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + adapter->drv_stats.tx_events++; + return 1; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0023-be2net-fix-be_vlan_add-rem_vid.patch b/debian/patches/features/all/be2net/0023-be2net-fix-be_vlan_add-rem_vid.patch new file mode 100644 index 000000000..8f416aecd --- /dev/null +++ b/debian/patches/features/all/be2net/0023-be2net-fix-be_vlan_add-rem_vid.patch @@ -0,0 +1,65 @@ +From: Ajit Khaparde +Date: Fri, 25 May 2012 21:21:23 +0530 +Subject: [PATCH 23/58] be2net: fix be_vlan_add/rem_vid + +commit 80817cbf5ac13da76f3ee2b9259f26c09b385e84 upstream. + +1) fix be_vlan_add/rem_vid to return proper status +2) perform appropriate housekeeping if firmware command succeeds. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index a185e61..acef082 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -817,28 +817,37 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) + static void be_vlan_add_vid(struct net_device *netdev, u16 vid) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ int status = 0; + +- adapter->vlans_added++; + if (!be_physfn(adapter)) + return; + + adapter->vlan_tag[vid] = 1; + if (adapter->vlans_added <= (adapter->max_vlans + 1)) +- be_vid_config(adapter, false, 0); ++ status = be_vid_config(adapter, false, 0); ++ ++ if (!status) ++ adapter->vlans_added++; ++ else ++ adapter->vlan_tag[vid] = 0; + } + + static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) + { + struct be_adapter *adapter = netdev_priv(netdev); +- +- adapter->vlans_added--; ++ int status = 0; + + if (!be_physfn(adapter)) + return; + + adapter->vlan_tag[vid] = 0; + if (adapter->vlans_added <= adapter->max_vlans) +- be_vid_config(adapter, false, 0); ++ status = be_vid_config(adapter, false, 0); ++ ++ if (!status) ++ adapter->vlans_added--; ++ else ++ adapter->vlan_tag[vid] = 1; + } + + static void be_set_rx_mode(struct net_device *netdev) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0024-be2net-fix-range-check-for-set_qos-for-a-VF.patch b/debian/patches/features/all/be2net/0024-be2net-fix-range-check-for-set_qos-for-a-VF.patch new file mode 100644 index 000000000..f75af073a --- /dev/null +++ b/debian/patches/features/all/be2net/0024-be2net-fix-range-check-for-set_qos-for-a-VF.patch @@ -0,0 +1,47 @@ +From: Ajit Khaparde +Date: Fri, 30 Dec 2011 12:15:30 +0000 +Subject: [PATCH 24/58] be2net: fix range check for set_qos for a VF + +commit 94f434c2055db5fe20f10d4e0ec50ab395e1f62b upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index acef082..cd7f5e3 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -970,18 +970,22 @@ static int be_set_vf_tx_rate(struct net_device *netdev, + if (!sriov_enabled(adapter)) + return -EPERM; + +- if (vf >= adapter->num_vfs || rate < 0) ++ if (vf >= adapter->num_vfs) + return -EINVAL; + +- if (rate > 10000) +- rate = 10000; ++ if (rate < 100 || rate > 10000) { ++ dev_err(&adapter->pdev->dev, ++ "tx rate must be between 100 and 10000 Mbps\n"); ++ return -EINVAL; ++ } + +- adapter->vf_cfg[vf].tx_rate = rate; + status = be_cmd_set_qos(adapter, rate / 10, vf + 1); + + if (status) +- dev_info(&adapter->pdev->dev, ++ dev_err(&adapter->pdev->dev, + "tx rate %d on VF %d failed\n", rate, vf); ++ else ++ adapter->vf_cfg[vf].tx_rate = rate; + return status; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0025-be2net-query-link-status-in-be_open.patch b/debian/patches/features/all/be2net/0025-be2net-query-link-status-in-be_open.patch new file mode 100644 index 000000000..57c542c70 --- /dev/null +++ b/debian/patches/features/all/be2net/0025-be2net-query-link-status-in-be_open.patch @@ -0,0 +1,234 @@ +From: Ajit Khaparde +Date: Fri, 30 Dec 2011 12:15:40 +0000 +Subject: [PATCH 25/58] be2net: query link status in be_open() + +commit b236916a68d923acff15787b5439d7d684c17ae5 upstream. + +be2net gets an async link status notification from the FW when it creates +an MCC queue. There are some cases in which this gratuitous notification +is not received from FW. To cover this explicitly query the link status +in be_open(). + +Signed-off-by: Vasundhara Volam +Signed-off-by: Sathya Perla +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 5 ++++- + drivers/net/ethernet/emulex/benet/be_cmds.c | 21 +++++++++++++++++---- + drivers/net/ethernet/emulex/benet/be_cmds.h | 7 ++++--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 7 +++++-- + drivers/net/ethernet/emulex/benet/be_main.c | 24 +++++++++++++++--------- + 5 files changed, 45 insertions(+), 19 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 995198d..cbdec25 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -299,6 +299,8 @@ struct be_vf_cfg { + u32 tx_rate; + }; + ++#define BE_FLAGS_LINK_STATUS_INIT 1 ++ + struct be_adapter { + struct pci_dev *pdev; + struct net_device *netdev; +@@ -347,6 +349,7 @@ struct be_adapter { + struct delayed_work work; + u16 work_counter; + ++ u32 flags; + /* Ethtool knobs and info */ + char fw_ver[FW_VER_LEN]; + int if_handle; /* Used to configure filtering */ +@@ -538,7 +541,7 @@ static inline bool be_error(struct be_adapter *adapter) + + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, + u16 num_popped); +-extern void be_link_status_update(struct be_adapter *adapter, u32 link_status); ++extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); + extern void be_parse_stats(struct be_adapter *adapter); + extern int be_load_fw(struct be_adapter *adapter, u8 *func); + #endif /* BE_H */ +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 62868ea..0fcb456 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -125,7 +125,14 @@ done: + static void be_async_link_state_process(struct be_adapter *adapter, + struct be_async_event_link_state *evt) + { +- be_link_status_update(adapter, evt->port_link_status); ++ /* When link status changes, link speed must be re-queried from FW */ ++ adapter->link_speed = -1; ++ ++ /* For the initial link status do not rely on the ASYNC event as ++ * it may not be received in some cases. ++ */ ++ if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) ++ be_link_status_update(adapter, evt->port_link_status); + } + + /* Grp5 CoS Priority evt */ +@@ -1232,7 +1239,7 @@ err: + + /* Uses synchronous mcc */ + int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, +- u16 *link_speed, u32 dom) ++ u16 *link_speed, u8 *link_status, u32 dom) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_link_status *req; +@@ -1240,6 +1247,9 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + + spin_lock_bh(&adapter->mcc_lock); + ++ if (link_status) ++ *link_status = LINK_DOWN; ++ + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; +@@ -1247,7 +1257,7 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + } + req = embedded_payload(wrb); + +- if (lancer_chip(adapter)) ++ if (adapter->generation == BE_GEN3 || lancer_chip(adapter)) + req->hdr.version = 1; + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +@@ -1257,10 +1267,13 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + if (!status) { + struct be_cmd_resp_link_status *resp = embedded_payload(wrb); + if (resp->mac_speed != PHY_LINK_SPEED_ZERO) { +- *link_speed = le16_to_cpu(resp->link_speed); ++ if (link_speed) ++ *link_speed = le16_to_cpu(resp->link_speed); + if (mac_speed) + *mac_speed = resp->mac_speed; + } ++ if (link_status) ++ *link_status = resp->logical_link_status; + } + + err: +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 0b694c6..dca8924 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -960,7 +960,8 @@ struct be_cmd_resp_link_status { + u8 mgmt_mac_duplex; + u8 mgmt_mac_speed; + u16 link_speed; +- u32 rsvd0; ++ u8 logical_link_status; ++ u8 rsvd1[3]; + } __packed; + + /******************** Port Identification ***************************/ +@@ -1507,8 +1508,8 @@ extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + int type); + extern int be_cmd_rxq_destroy(struct be_adapter *adapter, + struct be_queue_info *q); +-extern int be_cmd_link_status_query(struct be_adapter *adapter, +- u8 *mac_speed, u16 *link_speed, u32 dom); ++extern int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, ++ u16 *link_speed, u8 *link_status, u32 dom); + extern int be_cmd_reset(struct be_adapter *adapter); + extern int be_cmd_get_stats(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 6ba2dc6..6db6b6a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -429,11 +429,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + struct be_phy_info phy_info; + u8 mac_speed = 0; + u16 link_speed = 0; ++ u8 link_status; + int status; + + if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { + status = be_cmd_link_status_query(adapter, &mac_speed, +- &link_speed, 0); ++ &link_speed, &link_status, 0); ++ if (!status) ++ be_link_status_update(adapter, link_status); + + /* link_speed is in units of 10 Mbps */ + if (link_speed) { +@@ -700,7 +703,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) + } + + if (be_cmd_link_status_query(adapter, &mac_speed, +- &qos_link_speed, 0) != 0) { ++ &qos_link_speed, NULL, 0) != 0) { + test->flags |= ETH_TEST_FL_FAILED; + data[4] = -1; + } else if (!mac_speed) { +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index cd7f5e3..42ee4c9 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -496,19 +496,19 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, + return stats; + } + +-void be_link_status_update(struct be_adapter *adapter, u32 link_status) ++void be_link_status_update(struct be_adapter *adapter, u8 link_status) + { + struct net_device *netdev = adapter->netdev; + +- /* when link status changes, link speed must be re-queried from card */ +- adapter->link_speed = -1; +- if ((link_status & LINK_STATUS_MASK) == LINK_UP) { +- netif_carrier_on(netdev); +- dev_info(&adapter->pdev->dev, "%s: Link up\n", netdev->name); +- } else { ++ if (!(adapter->flags & BE_FLAGS_LINK_STATUS_INIT)) { + netif_carrier_off(netdev); +- dev_info(&adapter->pdev->dev, "%s: Link down\n", netdev->name); ++ adapter->flags |= BE_FLAGS_LINK_STATUS_INIT; + } ++ ++ if ((link_status & LINK_STATUS_MASK) == LINK_UP) ++ netif_carrier_on(netdev); ++ else ++ netif_carrier_off(netdev); + } + + static void be_tx_stats_update(struct be_tx_obj *txo, +@@ -2406,6 +2406,7 @@ static int be_open(struct net_device *netdev) + struct be_adapter *adapter = netdev_priv(netdev); + struct be_eq_obj *tx_eq = &adapter->tx_eq; + struct be_rx_obj *rxo; ++ u8 link_status; + int status, i; + + status = be_rx_queues_setup(adapter); +@@ -2429,6 +2430,11 @@ static int be_open(struct net_device *netdev) + /* Now that interrupts are on we can process async mcc */ + be_async_mcc_enable(adapter); + ++ status = be_cmd_link_status_query(adapter, NULL, NULL, ++ &link_status, 0); ++ if (!status) ++ be_link_status_update(adapter, link_status); ++ + return 0; + err: + be_close(adapter->netdev); +@@ -2576,7 +2582,7 @@ static int be_vf_setup(struct be_adapter *adapter) + + for_all_vfs(adapter, vf_cfg, vf) { + status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, +- vf + 1); ++ NULL, vf + 1); + if (status) + goto err; + vf_cfg->tx_rate = lnk_speed * 10; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0026-netdev-make-net_device_ops-const.patch b/debian/patches/features/all/be2net/0026-netdev-make-net_device_ops-const.patch new file mode 100644 index 000000000..3b0d14740 --- /dev/null +++ b/debian/patches/features/all/be2net/0026-netdev-make-net_device_ops-const.patch @@ -0,0 +1,31 @@ +From: stephen hemminger +Date: Thu, 5 Jan 2012 19:10:25 +0000 +Subject: [PATCH 26/58] netdev: make net_device_ops const + +commit e5686ad82ca2aeed7a8f24ffca115c0b7478dec9 upstream. + +More drivers where net_device_ops should be const. + +Signed-off-by: Stephen Hemminger +Signed-off-by: David S. Miller +[bwh: Restrict to drivers/net/ethernet/emulex/benet/] +--- + drivers/net/ethernet/emulex/benet/be_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 42ee4c9..804ab7e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -3072,7 +3072,7 @@ fw_exit: + return status; + } + +-static struct net_device_ops be_netdev_ops = { ++static const struct net_device_ops be_netdev_ops = { + .ndo_open = be_open, + .ndo_stop = be_close, + .ndo_start_xmit = be_xmit, +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0027-be2net-create-RSS-rings-even-in-multi-channel-config.patch b/debian/patches/features/all/be2net/0027-be2net-create-RSS-rings-even-in-multi-channel-config.patch new file mode 100644 index 000000000..92b230534 --- /dev/null +++ b/debian/patches/features/all/be2net/0027-be2net-create-RSS-rings-even-in-multi-channel-config.patch @@ -0,0 +1,36 @@ +From: Sathya Perla +Date: Thu, 19 Jan 2012 20:34:04 +0000 +Subject: [PATCH 27/58] be2net: create RSS rings even in multi-channel configs + +commit df505eb804d5221c3164ebecd1286cb7fc7f49ba upstream. + +Currently RSS rings are not created in a multi-channel config. +RSS rings can be created on one (out of four) interfaces per port in a +multi-channel config. Doing this insulates the driver from a FW bug wherin +multi-channel config is wrongly reported even when not enabled. This also +helps performance in a multi-channel config, as one interface per port gets +RSS rings. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 804ab7e..adfd66a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1778,8 +1778,7 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) + static u32 be_num_rxqs_want(struct be_adapter *adapter) + { + if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && +- !sriov_enabled(adapter) && be_physfn(adapter) && +- !be_is_mc(adapter)) { ++ !sriov_enabled(adapter) && be_physfn(adapter)) { + return 1 + MAX_RSS_QS; /* one default non-RSS queue */ + } else { + dev_warn(&adapter->pdev->dev, +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0028-be2net-allocate-more-headroom-in-incoming-skbs.patch b/debian/patches/features/all/be2net/0028-be2net-allocate-more-headroom-in-incoming-skbs.patch new file mode 100644 index 000000000..b2b4ffd53 --- /dev/null +++ b/debian/patches/features/all/be2net/0028-be2net-allocate-more-headroom-in-incoming-skbs.patch @@ -0,0 +1,57 @@ +From: Eric Dumazet +Date: Wed, 25 Jan 2012 03:56:30 +0000 +Subject: [PATCH 28/58] be2net: allocate more headroom in incoming skbs + +commit bb349bb4b19b39830e0486aedfd7c7dca23b7baf upstream. + +Allocation of 64 bytes in skb headroom is not enough if we have to pull +ethernet + ipv6 + tcp headers, and/or extra tunneling header. + +Its currently not noticed because netdev_alloc_skb_ip_align(64) give us +more room, thanks to power-of-two kmalloc() roundups. + +Make sure we ask for 128 bytes so that side effects of upcoming patches +from Ian Campbell dont decrease benet rx performance, because of extra +skb head reallocations. + +Signed-off-by: Eric Dumazet +Cc: Ian Campbell +Cc: Vasundhara Volam +Cc: Sathya Perla +Cc: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 3 +++ + drivers/net/ethernet/emulex/benet/be_main.c | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index cbdec25..453d486 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -74,6 +74,9 @@ static inline char *nic_name(struct pci_dev *pdev) + + /* Number of bytes of an RX frame that are copied to skb->data */ + #define BE_HDR_LEN ((u16) 64) ++/* allocate extra space to allow tunneling decapsulation without head reallocation */ ++#define BE_RX_SKB_ALLOC_SIZE (BE_HDR_LEN + 64) ++ + #define BE_MAX_JUMBO_FRAME_SIZE 9018 + #define BE_MIN_MTU 256 + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index adfd66a..860c461 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1181,7 +1181,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, + struct net_device *netdev = adapter->netdev; + struct sk_buff *skb; + +- skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN); ++ skb = netdev_alloc_skb_ip_align(netdev, BE_RX_SKB_ALLOC_SIZE); + if (unlikely(!skb)) { + rx_stats(rxo)->rx_drops_no_skbs++; + be_rx_compl_discard(adapter, rxo, rxcp); +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0029-be2net-add-descriptions-for-stat-counters-reported-v.patch b/debian/patches/features/all/be2net/0029-be2net-add-descriptions-for-stat-counters-reported-v.patch new file mode 100644 index 000000000..471544bec --- /dev/null +++ b/debian/patches/features/all/be2net/0029-be2net-add-descriptions-for-stat-counters-reported-v.patch @@ -0,0 +1,259 @@ +From: Sathya Perla +Date: Sun, 29 Jan 2012 20:17:39 +0000 +Subject: [PATCH 29/58] be2net: add descriptions for stat counters reported + via ethtool + +commit d45b9d39a1aed7851948460d29b843ce70eb0a68 upstream. + +Also rename a few counters appropritely and delete 2 counters that are not +implemented in HW. + +vlan_mismatch_drops does not exist in BE3 and is accounted for in +address_mismatch_drops. Do the same thing for BE2 and Lancer. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 3 +- + drivers/net/ethernet/emulex/benet/be_cmds.h | 10 ++-- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 64 ++++++++++++++++++++++-- + drivers/net/ethernet/emulex/benet/be_main.c | 15 +++--- + 4 files changed, 74 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 453d486..74aa148 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -265,7 +265,6 @@ struct be_drv_stats { + u32 rx_drops_no_erx_descr; + u32 rx_drops_no_tpre_descr; + u32 rx_drops_too_many_frags; +- u32 rx_drops_invalid_ring; + u32 forwarded_packets; + u32 rx_drops_mtu; + u32 rx_crc_errors; +@@ -276,7 +275,7 @@ struct be_drv_stats { + u32 rx_in_range_errors; + u32 rx_out_range_errors; + u32 rx_frame_too_long; +- u32 rx_address_match_errors; ++ u32 rx_address_mismatch_drops; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index dca8924..bbd012b 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -592,8 +592,8 @@ struct be_port_rxf_stats_v0 { + u32 rx_in_range_errors; /* dword 10*/ + u32 rx_out_range_errors; /* dword 11*/ + u32 rx_frame_too_long; /* dword 12*/ +- u32 rx_address_match_errors; /* dword 13*/ +- u32 rx_vlan_mismatch; /* dword 14*/ ++ u32 rx_address_mismatch_drops; /* dword 13*/ ++ u32 rx_vlan_mismatch_drops; /* dword 14*/ + u32 rx_dropped_too_small; /* dword 15*/ + u32 rx_dropped_too_short; /* dword 16*/ + u32 rx_dropped_header_too_small; /* dword 17*/ +@@ -799,8 +799,8 @@ struct lancer_pport_stats { + u32 rx_control_frames_unknown_opcode_hi; + u32 rx_in_range_errors; + u32 rx_out_of_range_errors; +- u32 rx_address_match_errors; +- u32 rx_vlan_mismatch_errors; ++ u32 rx_address_mismatch_drops; ++ u32 rx_vlan_mismatch_drops; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; +@@ -1384,7 +1384,7 @@ struct be_port_rxf_stats_v1 { + u32 rx_in_range_errors; + u32 rx_out_range_errors; + u32 rx_frame_too_long; +- u32 rx_address_match_errors; ++ u32 rx_address_mismatch_drops; + u32 rx_dropped_too_small; + u32 rx_dropped_too_short; + u32 rx_dropped_header_too_small; +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 6db6b6a..0a5ee22 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -42,15 +42,42 @@ static const struct be_ethtool_stat et_stats[] = { + {DRVSTAT_INFO(rx_alignment_symbol_errors)}, + {DRVSTAT_INFO(rx_pause_frames)}, + {DRVSTAT_INFO(rx_control_frames)}, ++ /* Received packets dropped when the Ethernet length field ++ * is not equal to the actual Ethernet data length. ++ */ + {DRVSTAT_INFO(rx_in_range_errors)}, ++ /* Received packets dropped when their length field is >= 1501 bytes ++ * and <= 1535 bytes. ++ */ + {DRVSTAT_INFO(rx_out_range_errors)}, ++ /* Received packets dropped when they are longer than 9216 bytes */ + {DRVSTAT_INFO(rx_frame_too_long)}, +- {DRVSTAT_INFO(rx_address_match_errors)}, ++ /* Received packets dropped when they don't pass the unicast or ++ * multicast address filtering. ++ */ ++ {DRVSTAT_INFO(rx_address_mismatch_drops)}, ++ /* Received packets dropped when IP packet length field is less than ++ * the IP header length field. ++ */ + {DRVSTAT_INFO(rx_dropped_too_small)}, ++ /* Received packets dropped when IP length field is greater than ++ * the actual packet length. ++ */ + {DRVSTAT_INFO(rx_dropped_too_short)}, ++ /* Received packets dropped when the IP header length field is less ++ * than 5. ++ */ + {DRVSTAT_INFO(rx_dropped_header_too_small)}, ++ /* Received packets dropped when the TCP header length field is less ++ * than 5 or the TCP header length + IP header length is more ++ * than IP packet length. ++ */ + {DRVSTAT_INFO(rx_dropped_tcp_length)}, + {DRVSTAT_INFO(rx_dropped_runt)}, ++ /* Number of received packets dropped when a fifo for descriptors going ++ * into the packet demux block overflows. In normal operation, this ++ * fifo must never overflow. ++ */ + {DRVSTAT_INFO(rxpp_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_input_fifo_overflow_drop)}, + {DRVSTAT_INFO(rx_ip_checksum_errs)}, +@@ -59,16 +86,35 @@ static const struct be_ethtool_stat et_stats[] = { + {DRVSTAT_INFO(tx_pauseframes)}, + {DRVSTAT_INFO(tx_controlframes)}, + {DRVSTAT_INFO(rx_priority_pause_frames)}, ++ /* Received packets dropped when an internal fifo going into ++ * main packet buffer tank (PMEM) overflows. ++ */ + {DRVSTAT_INFO(pmem_fifo_overflow_drop)}, + {DRVSTAT_INFO(jabber_events)}, ++ /* Received packets dropped due to lack of available HW packet buffers ++ * used to temporarily hold the received packets. ++ */ + {DRVSTAT_INFO(rx_drops_no_pbuf)}, +- {DRVSTAT_INFO(rx_drops_no_txpb)}, ++ /* Received packets dropped due to input receive buffer ++ * descriptor fifo overflowing. ++ */ + {DRVSTAT_INFO(rx_drops_no_erx_descr)}, ++ /* Packets dropped because the internal FIFO to the offloaded TCP ++ * receive processing block is full. This could happen only for ++ * offloaded iSCSI or FCoE trarffic. ++ */ + {DRVSTAT_INFO(rx_drops_no_tpre_descr)}, ++ /* Received packets dropped when they need more than 8 ++ * receive buffers. This cannot happen as the driver configures ++ * 2048 byte receive buffers. ++ */ + {DRVSTAT_INFO(rx_drops_too_many_frags)}, +- {DRVSTAT_INFO(rx_drops_invalid_ring)}, + {DRVSTAT_INFO(forwarded_packets)}, ++ /* Received packets dropped when the frame length ++ * is more than 9018 bytes ++ */ + {DRVSTAT_INFO(rx_drops_mtu)}, ++ /* Number of packets dropped due to random early drop function */ + {DRVSTAT_INFO(eth_red_drops)}, + {DRVSTAT_INFO(be_on_die_temperature)} + }; +@@ -84,8 +130,15 @@ static const struct be_ethtool_stat et_rx_stats[] = { + {DRVSTAT_RX_INFO(rx_events)}, + {DRVSTAT_RX_INFO(rx_compl)}, + {DRVSTAT_RX_INFO(rx_mcast_pkts)}, ++ /* Number of page allocation failures while posting receive buffers ++ * to HW. ++ */ + {DRVSTAT_RX_INFO(rx_post_fail)}, ++ /* Recevied packets dropped due to skb allocation failure */ + {DRVSTAT_RX_INFO(rx_drops_no_skbs)}, ++ /* Received packets dropped due to lack of available fetched buffers ++ * posted by the driver. ++ */ + {DRVSTAT_RX_INFO(rx_drops_no_frags)} + }; + #define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats)) +@@ -97,9 +150,14 @@ static const struct be_ethtool_stat et_tx_stats[] = { + {DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */ + {DRVSTAT_TX_INFO(tx_bytes)}, + {DRVSTAT_TX_INFO(tx_pkts)}, ++ /* Number of skbs queued for trasmission by the driver */ + {DRVSTAT_TX_INFO(tx_reqs)}, ++ /* Number of TX work request blocks DMAed to HW */ + {DRVSTAT_TX_INFO(tx_wrbs)}, + {DRVSTAT_TX_INFO(tx_compl)}, ++ /* Number of times the TX queue was stopped due to lack ++ * of spaces in the TXQ. ++ */ + {DRVSTAT_TX_INFO(tx_stops)} + }; + #define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats)) +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 860c461..d1536e2 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -286,7 +286,9 @@ static void populate_be2_stats(struct be_adapter *adapter) + drvs->rx_input_fifo_overflow_drop = port_stats->rx_input_fifo_overflow; + drvs->rx_dropped_header_too_small = + port_stats->rx_dropped_header_too_small; +- drvs->rx_address_match_errors = port_stats->rx_address_match_errors; ++ drvs->rx_address_mismatch_drops = ++ port_stats->rx_address_mismatch_drops + ++ port_stats->rx_vlan_mismatch_drops; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + +@@ -298,9 +300,7 @@ static void populate_be2_stats(struct be_adapter *adapter) + else + drvs->jabber_events = rxf_stats->port0_jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; +- drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; +- drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr; +@@ -337,7 +337,7 @@ static void populate_be3_stats(struct be_adapter *adapter) + port_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = + port_stats->rx_input_fifo_overflow_drop; +- drvs->rx_address_match_errors = port_stats->rx_address_match_errors; ++ drvs->rx_address_mismatch_drops = port_stats->rx_address_mismatch_drops; + drvs->rx_alignment_symbol_errors = + port_stats->rx_alignment_symbol_errors; + drvs->rxpp_fifo_overflow_drop = port_stats->rxpp_fifo_overflow_drop; +@@ -345,9 +345,7 @@ static void populate_be3_stats(struct be_adapter *adapter) + drvs->tx_controlframes = port_stats->tx_controlframes; + drvs->jabber_events = port_stats->jabber_events; + drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf; +- drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb; + drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr; +- drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring; + drvs->forwarded_packets = rxf_stats->forwarded_packets; + drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu; + drvs->rx_drops_no_tpre_descr = rxf_stats->rx_drops_no_tpre_descr; +@@ -380,13 +378,14 @@ static void populate_lancer_stats(struct be_adapter *adapter) + drvs->rx_dropped_header_too_small = + pport_stats->rx_dropped_header_too_small; + drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow; +- drvs->rx_address_match_errors = pport_stats->rx_address_match_errors; ++ drvs->rx_address_mismatch_drops = ++ pport_stats->rx_address_mismatch_drops + ++ pport_stats->rx_vlan_mismatch_drops; + drvs->rx_alignment_symbol_errors = pport_stats->rx_symbol_errors_lo; + drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow; + drvs->tx_pauseframes = pport_stats->tx_pause_frames_lo; + drvs->tx_controlframes = pport_stats->tx_control_frames_lo; + drvs->jabber_events = pport_stats->rx_jabbers; +- drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue; + drvs->forwarded_packets = pport_stats->num_forwards_lo; + drvs->rx_drops_mtu = pport_stats->rx_drops_mtu_lo; + drvs->rx_drops_too_many_frags = +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0030-be2net-Fix-link-status-query-command.patch b/debian/patches/features/all/be2net/0030-be2net-Fix-link-status-query-command.patch new file mode 100644 index 000000000..96309581e --- /dev/null +++ b/debian/patches/features/all/be2net/0030-be2net-Fix-link-status-query-command.patch @@ -0,0 +1,39 @@ +From: Padmanabh Ratnakar +Date: Fri, 3 Feb 2012 09:49:46 +0000 +Subject: [PATCH 30/58] be2net: Fix link status query command + +commit 57cd80d4d511748f3973accc6919e7e1e1936ebb upstream. + +Version number in query link status command is getting overwritten in +be_wrb_cmd_hdr_prepare() routine. Move the initialization to fix this +issue. Also initialize the domain field. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 0fcb456..dd6e8e2 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1257,11 +1257,13 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed, + } + req = embedded_payload(wrb); + ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL); ++ + if (adapter->generation == BE_GEN3 || lancer_chip(adapter)) + req->hdr.version = 1; + +- be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +- OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req), wrb, NULL); ++ req->hdr.domain = dom; + + status = be_mcc_notify_wait(adapter); + if (!status) { +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0031-be2net-Use-new-implementation-of-get-mac-list-comman.patch b/debian/patches/features/all/be2net/0031-be2net-Use-new-implementation-of-get-mac-list-comman.patch new file mode 100644 index 000000000..5f3ab3580 --- /dev/null +++ b/debian/patches/features/all/be2net/0031-be2net-Use-new-implementation-of-get-mac-list-comman.patch @@ -0,0 +1,237 @@ +From: Padmanabh Ratnakar +Date: Fri, 3 Feb 2012 09:50:17 +0000 +Subject: [PATCH 31/58] be2net: Use new implementation of get mac list command + +commit e5e1ee89461543043a0144e6dac90547fefe2f89 upstream. + +VFs use get mac list command to get their mac address. The format of +this command has changed. Update driver to use the new format. + +Signed-off-by: Mammatha Edhala +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 67 +++++++++++++++++++-------- + drivers/net/ethernet/emulex/benet/be_cmds.h | 36 +++++++++----- + drivers/net/ethernet/emulex/benet/be_main.c | 29 ++++++++---- + 3 files changed, 92 insertions(+), 40 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index dd6e8e2..29dff7d 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -2300,52 +2300,81 @@ err: + + /* Uses synchronous MCCQ */ + int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, +- u32 *pmac_id) ++ bool *pmac_id_active, u32 *pmac_id, u8 *mac) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_mac_list *req; + int status; + int mac_count; ++ struct be_dma_mem get_mac_list_cmd; ++ int i; ++ ++ memset(&get_mac_list_cmd, 0, sizeof(struct be_dma_mem)); ++ get_mac_list_cmd.size = sizeof(struct be_cmd_resp_get_mac_list); ++ get_mac_list_cmd.va = pci_alloc_consistent(adapter->pdev, ++ get_mac_list_cmd.size, ++ &get_mac_list_cmd.dma); ++ ++ if (!get_mac_list_cmd.va) { ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure during GET_MAC_LIST\n"); ++ return -ENOMEM; ++ } + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; +- goto err; ++ goto out; + } +- req = embedded_payload(wrb); ++ ++ req = get_mac_list_cmd.va; + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_MAC_LIST, sizeof(*req), +- wrb, NULL); ++ wrb, &get_mac_list_cmd); + + req->hdr.domain = domain; ++ req->mac_type = MAC_ADDRESS_TYPE_NETWORK; ++ req->perm_override = 1; + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_mac_list *resp = +- embedded_payload(wrb); +- int i; +- u8 *ctxt = &resp->context[0][0]; +- status = -EIO; +- mac_count = resp->mac_count; +- be_dws_le_to_cpu(&resp->context, sizeof(resp->context)); ++ get_mac_list_cmd.va; ++ mac_count = resp->true_mac_count + resp->pseudo_mac_count; ++ /* Mac list returned could contain one or more active mac_ids ++ * or one or more pseudo permanant mac addresses. If an active ++ * mac_id is present, return first active mac_id found ++ */ + for (i = 0; i < mac_count; i++) { +- if (!AMAP_GET_BITS(struct amap_get_mac_list_context, +- act, ctxt)) { +- *pmac_id = AMAP_GET_BITS +- (struct amap_get_mac_list_context, +- macid, ctxt); +- status = 0; +- break; ++ struct get_list_macaddr *mac_entry; ++ u16 mac_addr_size; ++ u32 mac_id; ++ ++ mac_entry = &resp->macaddr_list[i]; ++ mac_addr_size = le16_to_cpu(mac_entry->mac_addr_size); ++ /* mac_id is a 32 bit value and mac_addr size ++ * is 6 bytes ++ */ ++ if (mac_addr_size == sizeof(u32)) { ++ *pmac_id_active = true; ++ mac_id = mac_entry->mac_addr_id.s_mac_id.mac_id; ++ *pmac_id = le32_to_cpu(mac_id); ++ goto out; + } +- ctxt += sizeof(struct amap_get_mac_list_context) / 8; + } ++ /* If no active mac_id found, return first pseudo mac addr */ ++ *pmac_id_active = false; ++ memcpy(mac, resp->macaddr_list[0].mac_addr_id.macaddr, ++ ETH_ALEN); + } + +-err: ++out: + spin_unlock_bh(&adapter->mcc_lock); ++ pci_free_consistent(adapter->pdev, get_mac_list_cmd.size, ++ get_mac_list_cmd.va, get_mac_list_cmd.dma); + return status; + } + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index bbd012b..5bb66c8 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1346,22 +1346,36 @@ struct be_cmd_resp_set_func_cap { + + /******************** GET/SET_MACLIST **************************/ + #define BE_MAX_MAC 64 +-struct amap_get_mac_list_context { +- u8 macid[31]; +- u8 act; +-} __packed; +- + struct be_cmd_req_get_mac_list { + struct be_cmd_req_hdr hdr; +- u32 rsvd; ++ u8 mac_type; ++ u8 perm_override; ++ u16 iface_id; ++ u32 mac_id; ++ u32 rsvd[3]; ++} __packed; ++ ++struct get_list_macaddr { ++ u16 mac_addr_size; ++ union { ++ u8 macaddr[6]; ++ struct { ++ u8 rsvd[2]; ++ u32 mac_id; ++ } __packed s_mac_id; ++ } __packed mac_addr_id; + } __packed; + + struct be_cmd_resp_get_mac_list { + struct be_cmd_resp_hdr hdr; +- u8 mac_count; +- u8 rsvd1; +- u16 rsvd2; +- u8 context[sizeof(struct amap_get_mac_list_context) / 8][BE_MAX_MAC]; ++ struct get_list_macaddr fd_macaddr; /* Factory default mac */ ++ struct get_list_macaddr macid_macaddr; /* soft mac */ ++ u8 true_mac_count; ++ u8 pseudo_mac_count; ++ u8 mac_list_size; ++ u8 rsvd; ++ /* perm override mac */ ++ struct get_list_macaddr macaddr_list[BE_MAX_MAC]; + } __packed; + + struct be_cmd_req_set_mac_list { +@@ -1575,7 +1589,7 @@ extern int be_cmd_req_native_mode(struct be_adapter *adapter); + extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size); + extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf); + extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, +- u32 *pmac_id); ++ bool *pmac_id_active, u32 *pmac_id, u8 *mac); + extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, + u8 mac_count, u32 domain); + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index d1536e2..4364f01 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2600,19 +2600,28 @@ static void be_setup_init(struct be_adapter *adapter) + adapter->eq_next_idx = 0; + } + +-static int be_configure_mac_from_list(struct be_adapter *adapter, u8 *mac) ++static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) + { + u32 pmac_id; +- int status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id); +- if (status != 0) +- goto do_none; +- status = be_cmd_mac_addr_query(adapter, mac, +- MAC_ADDRESS_TYPE_NETWORK, +- false, adapter->if_handle, pmac_id); ++ int status; ++ bool pmac_id_active; ++ ++ status = be_cmd_get_mac_from_list(adapter, 0, &pmac_id_active, ++ &pmac_id, mac); + if (status != 0) + goto do_none; +- status = be_cmd_pmac_add(adapter, mac, adapter->if_handle, +- &adapter->pmac_id, 0); ++ ++ if (pmac_id_active) { ++ status = be_cmd_mac_addr_query(adapter, mac, ++ MAC_ADDRESS_TYPE_NETWORK, ++ false, adapter->if_handle, pmac_id); ++ ++ if (!status) ++ adapter->pmac_id = pmac_id; ++ } else { ++ status = be_cmd_pmac_add(adapter, mac, ++ adapter->if_handle, &adapter->pmac_id, 0); ++ } + do_none: + return status; + } +@@ -2677,7 +2686,7 @@ static int be_setup(struct be_adapter *adapter) + */ + if (!be_physfn(adapter)) { + if (lancer_chip(adapter)) +- status = be_configure_mac_from_list(adapter, mac); ++ status = be_add_mac_from_list(adapter, mac); + else + status = be_cmd_mac_addr_query(adapter, mac, + MAC_ADDRESS_TYPE_NETWORK, false, +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0032-be2net-event-queue-re-design.patch b/debian/patches/features/all/be2net/0032-be2net-event-queue-re-design.patch new file mode 100644 index 000000000..f9c15c481 --- /dev/null +++ b/debian/patches/features/all/be2net/0032-be2net-event-queue-re-design.patch @@ -0,0 +1,1895 @@ +From: Sathya Perla +Date: Thu, 9 Feb 2012 18:05:27 +0000 +Subject: [PATCH 32/58] be2net: event queue re-design + +commit 10ef9ab4329edd08bccc7a8d34b96b85714195ce upstream. + +v2: Fixed up the bad typecasting pointed out by David... + +In the current design 8 TXQs are serviced by 1 EQ, while each RSS queue +is serviced by a separate EQ. This is being changed as follows: + +- Upto 8 EQs will be used (based on the availabilty of msix vectors). +Each EQ will handle 1 RSS and 1 TX ring. The default non-RSS RX queue and +MCC queue are handled by the last EQ. + +- On cards which provide support, upto 8 RSS rings will be used, instead +of the current limit of 4. + +The new design allows spreading the TX multi-queue completion processing +across multiple CPUs unlike the previous design. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 65 +- + drivers/net/ethernet/emulex/benet/be_cmds.c | 31 +- + drivers/net/ethernet/emulex/benet/be_cmds.h | 8 +- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 96 +-- + drivers/net/ethernet/emulex/benet/be_main.c | 812 +++++++++++------------- + 5 files changed, 434 insertions(+), 578 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 74aa148..86f51de 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -81,7 +81,7 @@ static inline char *nic_name(struct pci_dev *pdev) + #define BE_MIN_MTU 256 + + #define BE_NUM_VLANS_SUPPORTED 64 +-#define BE_MAX_EQD 96 ++#define BE_MAX_EQD 96u + #define BE_MAX_TX_FRAG_COUNT 30 + + #define EVNT_Q_LEN 1024 +@@ -92,12 +92,16 @@ static inline char *nic_name(struct pci_dev *pdev) + #define MCC_Q_LEN 128 /* total size not to exceed 8 pages */ + #define MCC_CQ_LEN 256 + +-#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */ ++#define BE3_MAX_RSS_QS 8 ++#define BE2_MAX_RSS_QS 4 ++#define MAX_RSS_QS BE3_MAX_RSS_QS + #define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */ ++ + #define MAX_TX_QS 8 +-#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */ ++#define MAX_MSIX_VECTORS MAX_RSS_QS ++#define BE_TX_BUDGET 256 + #define BE_NAPI_WEIGHT 64 +-#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ ++#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */ + #define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST) + + #define FW_VER_LEN 32 +@@ -165,13 +169,16 @@ struct be_eq_obj { + + /* Adaptive interrupt coalescing (AIC) info */ + bool enable_aic; +- u16 min_eqd; /* in usecs */ +- u16 max_eqd; /* in usecs */ +- u16 cur_eqd; /* in usecs */ +- u8 eq_idx; ++ u32 min_eqd; /* in usecs */ ++ u32 max_eqd; /* in usecs */ ++ u32 eqd; /* configured val when aic is off */ ++ u32 cur_eqd; /* in usecs */ + ++ u8 idx; /* array index */ ++ u16 tx_budget; + struct napi_struct napi; +-}; ++ struct be_adapter *adapter; ++} ____cacheline_aligned_in_smp; + + struct be_mcc_obj { + struct be_queue_info q; +@@ -197,7 +204,7 @@ struct be_tx_obj { + /* Remember the skbs that were transmitted */ + struct sk_buff *sent_skb_list[TX_Q_LEN]; + struct be_tx_stats stats; +-}; ++} ____cacheline_aligned_in_smp; + + /* Struct to remember the pages posted for rx frags */ + struct be_rx_page_info { +@@ -215,8 +222,6 @@ struct be_rx_stats { + u32 rx_drops_no_skbs; /* skb allocation errors */ + u32 rx_drops_no_frags; /* HW has no fetched frags */ + u32 rx_post_fail; /* page post alloc failures */ +- u32 rx_polls; /* NAPI calls */ +- u32 rx_events; + u32 rx_compl; + u32 rx_mcast_pkts; + u32 rx_compl_err; /* completions with err set */ +@@ -249,16 +254,13 @@ struct be_rx_obj { + struct be_queue_info cq; + struct be_rx_compl_info rxcp; + struct be_rx_page_info page_info_tbl[RX_Q_LEN]; +- struct be_eq_obj rx_eq; + struct be_rx_stats stats; + u8 rss_id; + bool rx_post_starved; /* Zero rx frags have been posted to BE */ +- u32 cache_line_barrier[16]; +-}; ++} ____cacheline_aligned_in_smp; + + struct be_drv_stats { + u32 be_on_die_temperature; +- u32 tx_events; + u32 eth_red_drops; + u32 rx_drops_no_pbuf; + u32 rx_drops_no_txpb; +@@ -320,20 +322,19 @@ struct be_adapter { + spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ + spinlock_t mcc_cq_lock; + +- struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS]; + u32 num_msix_vec; ++ u32 num_evt_qs; ++ struct be_eq_obj eq_obj[MAX_MSIX_VECTORS]; ++ struct msix_entry msix_entries[MAX_MSIX_VECTORS]; + bool isr_registered; + + /* TX Rings */ +- struct be_eq_obj tx_eq; ++ u32 num_tx_qs; + struct be_tx_obj tx_obj[MAX_TX_QS]; +- u8 num_tx_qs; +- +- u32 cache_line_break[8]; + + /* Rx rings */ +- struct be_rx_obj rx_obj[MAX_RX_QS]; + u32 num_rx_qs; ++ struct be_rx_obj rx_obj[MAX_RX_QS]; + u32 big_page_size; /* Compounded page size shared by rx wrbs */ + + u8 eq_next_idx; +@@ -404,24 +405,34 @@ struct be_adapter { + extern const struct ethtool_ops be_ethtool_ops; + + #define msix_enabled(adapter) (adapter->num_msix_vec > 0) +-#define tx_stats(txo) (&txo->stats) +-#define rx_stats(rxo) (&rxo->stats) ++#define num_irqs(adapter) (msix_enabled(adapter) ? \ ++ adapter->num_msix_vec : 1) ++#define tx_stats(txo) (&(txo)->stats) ++#define rx_stats(rxo) (&(rxo)->stats) + +-#define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops) ++/* The default RXQ is the last RXQ */ ++#define default_rxo(adpt) (&adpt->rx_obj[adpt->num_rx_qs - 1]) + + #define for_all_rx_queues(adapter, rxo, i) \ + for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs; \ + i++, rxo++) + +-/* Just skip the first default non-rss queue */ ++/* Skip the default non-rss queue (last one)*/ + #define for_all_rss_queues(adapter, rxo, i) \ +- for (i = 0, rxo = &adapter->rx_obj[i+1]; i < (adapter->num_rx_qs - 1);\ ++ for (i = 0, rxo = &adapter->rx_obj[i]; i < (adapter->num_rx_qs - 1);\ + i++, rxo++) + + #define for_all_tx_queues(adapter, txo, i) \ + for (i = 0, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs; \ + i++, txo++) + ++#define for_all_evt_queues(adapter, eqo, i) \ ++ for (i = 0, eqo = &adapter->eq_obj[i]; i < adapter->num_evt_qs; \ ++ i++, eqo++) ++ ++#define is_mcc_eqo(eqo) (eqo->idx == 0) ++#define mcc_eqo(adapter) (&adapter->eq_obj[0]) ++ + #define PAGE_SHIFT_4K 12 + #define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 29dff7d..6432efa 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -235,10 +235,10 @@ void be_async_mcc_disable(struct be_adapter *adapter) + adapter->mcc_obj.rearm_cq = false; + } + +-int be_process_mcc(struct be_adapter *adapter, int *status) ++int be_process_mcc(struct be_adapter *adapter) + { + struct be_mcc_compl *compl; +- int num = 0; ++ int num = 0, status = 0; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + + spin_lock_bh(&adapter->mcc_cq_lock); +@@ -252,32 +252,32 @@ int be_process_mcc(struct be_adapter *adapter, int *status) + be_async_grp5_evt_process(adapter, + compl->flags, compl); + } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { +- *status = be_mcc_compl_process(adapter, compl); ++ status = be_mcc_compl_process(adapter, compl); + atomic_dec(&mcc_obj->q.used); + } + be_mcc_compl_use(compl); + num++; + } + ++ if (num) ++ be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num); ++ + spin_unlock_bh(&adapter->mcc_cq_lock); +- return num; ++ return status; + } + + /* Wait till no more pending mcc requests are present */ + static int be_mcc_wait_compl(struct be_adapter *adapter) + { + #define mcc_timeout 120000 /* 12s timeout */ +- int i, num, status = 0; ++ int i, status = 0; + struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; + + for (i = 0; i < mcc_timeout; i++) { + if (be_error(adapter)) + return -EIO; + +- num = be_process_mcc(adapter, &status); +- if (num) +- be_cq_notify(adapter, mcc_obj->cq.id, +- mcc_obj->rearm_cq, num); ++ status = be_process_mcc(adapter); + + if (atomic_read(&mcc_obj->q.used) == 0) + break; +@@ -726,9 +726,8 @@ err: + } + + /* Uses Mbox */ +-int be_cmd_cq_create(struct be_adapter *adapter, +- struct be_queue_info *cq, struct be_queue_info *eq, +- bool sol_evts, bool no_delay, int coalesce_wm) ++int be_cmd_cq_create(struct be_adapter *adapter, struct be_queue_info *cq, ++ struct be_queue_info *eq, bool no_delay, int coalesce_wm) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_cq_create *req; +@@ -759,7 +758,6 @@ int be_cmd_cq_create(struct be_adapter *adapter, + ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_lancer, eqid, + ctxt, eq->id); +- AMAP_SET_BITS(struct amap_cq_context_lancer, armed, ctxt, 1); + } else { + AMAP_SET_BITS(struct amap_cq_context_be, coalescwm, ctxt, + coalesce_wm); +@@ -768,11 +766,8 @@ int be_cmd_cq_create(struct be_adapter *adapter, + AMAP_SET_BITS(struct amap_cq_context_be, count, ctxt, + __ilog2_u32(cq->len/256)); + AMAP_SET_BITS(struct amap_cq_context_be, valid, ctxt, 1); +- AMAP_SET_BITS(struct amap_cq_context_be, solevent, +- ctxt, sol_evts); + AMAP_SET_BITS(struct amap_cq_context_be, eventable, ctxt, 1); + AMAP_SET_BITS(struct amap_cq_context_be, eqid, ctxt, eq->id); +- AMAP_SET_BITS(struct amap_cq_context_be, armed, ctxt, 1); + } + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); +@@ -973,7 +968,7 @@ err: + /* Uses MCC */ + int be_cmd_rxq_create(struct be_adapter *adapter, + struct be_queue_info *rxq, u16 cq_id, u16 frag_size, +- u16 max_frame_size, u32 if_id, u32 rss, u8 *rss_id) ++ u32 if_id, u32 rss, u8 *rss_id) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_eth_rx_create *req; +@@ -997,7 +992,7 @@ int be_cmd_rxq_create(struct be_adapter *adapter, + req->num_pages = 2; + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + req->interface_id = cpu_to_le32(if_id); +- req->max_frame_size = cpu_to_le16(max_frame_size); ++ req->max_frame_size = cpu_to_le16(BE_MAX_JUMBO_FRAME_SIZE); + req->rss_queue = cpu_to_le32(rss); + + status = be_mcc_notify_wait(adapter); +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 5bb66c8..687c420 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1506,8 +1506,7 @@ extern int be_cmd_eq_create(struct be_adapter *adapter, + struct be_queue_info *eq, int eq_delay); + extern int be_cmd_cq_create(struct be_adapter *adapter, + struct be_queue_info *cq, struct be_queue_info *eq, +- bool sol_evts, bool no_delay, +- int num_cqe_dma_coalesce); ++ bool no_delay, int num_cqe_dma_coalesce); + extern int be_cmd_mccq_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq); +@@ -1516,8 +1515,7 @@ extern int be_cmd_txq_create(struct be_adapter *adapter, + struct be_queue_info *cq); + extern int be_cmd_rxq_create(struct be_adapter *adapter, + struct be_queue_info *rxq, u16 cq_id, +- u16 frag_size, u16 max_frame_size, u32 if_id, +- u32 rss, u8 *rss_id); ++ u16 frag_size, u32 if_id, u32 rss, u8 *rss_id); + extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, + int type); + extern int be_cmd_rxq_destroy(struct be_adapter *adapter, +@@ -1546,7 +1544,7 @@ extern int be_cmd_query_fw_cfg(struct be_adapter *adapter, + extern int be_cmd_reset_function(struct be_adapter *adapter); + extern int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, + u16 table_size); +-extern int be_process_mcc(struct be_adapter *adapter, int *status); ++extern int be_process_mcc(struct be_adapter *adapter); + extern int be_cmd_set_beacon_state(struct be_adapter *adapter, + u8 port_num, u8 beacon, u8 status, u8 state); + extern int be_cmd_get_beacon_state(struct be_adapter *adapter, +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 0a5ee22..d98ad7e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -37,7 +37,6 @@ enum {DRVSTAT_TX, DRVSTAT_RX, DRVSTAT}; + FIELDINFO(struct be_drv_stats, field) + + static const struct be_ethtool_stat et_stats[] = { +- {DRVSTAT_INFO(tx_events)}, + {DRVSTAT_INFO(rx_crc_errors)}, + {DRVSTAT_INFO(rx_alignment_symbol_errors)}, + {DRVSTAT_INFO(rx_pause_frames)}, +@@ -126,8 +125,6 @@ static const struct be_ethtool_stat et_stats[] = { + static const struct be_ethtool_stat et_rx_stats[] = { + {DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */ + {DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */ +- {DRVSTAT_RX_INFO(rx_polls)}, +- {DRVSTAT_RX_INFO(rx_events)}, + {DRVSTAT_RX_INFO(rx_compl)}, + {DRVSTAT_RX_INFO(rx_mcast_pkts)}, + /* Number of page allocation failures while posting receive buffers +@@ -154,7 +151,6 @@ static const struct be_ethtool_stat et_tx_stats[] = { + {DRVSTAT_TX_INFO(tx_reqs)}, + /* Number of TX work request blocks DMAed to HW */ + {DRVSTAT_TX_INFO(tx_wrbs)}, +- {DRVSTAT_TX_INFO(tx_compl)}, + /* Number of times the TX queue was stopped due to lack + * of spaces in the TXQ. + */ +@@ -290,86 +286,42 @@ be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf) + } + } + +-static int +-be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) ++static int be_get_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *et) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *rx_eq = &adapter->rx_obj[0].rx_eq; +- struct be_eq_obj *tx_eq = &adapter->tx_eq; ++ struct be_eq_obj *eqo = &adapter->eq_obj[0]; ++ + +- coalesce->rx_coalesce_usecs = rx_eq->cur_eqd; +- coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd; +- coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd; ++ et->rx_coalesce_usecs = eqo->cur_eqd; ++ et->rx_coalesce_usecs_high = eqo->max_eqd; ++ et->rx_coalesce_usecs_low = eqo->min_eqd; + +- coalesce->tx_coalesce_usecs = tx_eq->cur_eqd; +- coalesce->tx_coalesce_usecs_high = tx_eq->max_eqd; +- coalesce->tx_coalesce_usecs_low = tx_eq->min_eqd; ++ et->tx_coalesce_usecs = eqo->cur_eqd; ++ et->tx_coalesce_usecs_high = eqo->max_eqd; ++ et->tx_coalesce_usecs_low = eqo->min_eqd; + +- coalesce->use_adaptive_rx_coalesce = rx_eq->enable_aic; +- coalesce->use_adaptive_tx_coalesce = tx_eq->enable_aic; ++ et->use_adaptive_rx_coalesce = eqo->enable_aic; ++ et->use_adaptive_tx_coalesce = eqo->enable_aic; + + return 0; + } + +-/* +- * This routine is used to set interrup coalescing delay ++/* TX attributes are ignored. Only RX attributes are considered ++ * eqd cmd is issued in the worker thread. + */ +-static int +-be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce) ++static int be_set_coalesce(struct net_device *netdev, ++ struct ethtool_coalesce *et) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_rx_obj *rxo; +- struct be_eq_obj *rx_eq; +- struct be_eq_obj *tx_eq = &adapter->tx_eq; +- u32 rx_max, rx_min, rx_cur; +- int status = 0, i; +- u32 tx_cur; +- +- if (coalesce->use_adaptive_tx_coalesce == 1) +- return -EINVAL; +- +- for_all_rx_queues(adapter, rxo, i) { +- rx_eq = &rxo->rx_eq; +- +- if (!rx_eq->enable_aic && coalesce->use_adaptive_rx_coalesce) +- rx_eq->cur_eqd = 0; +- rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce; +- +- rx_max = coalesce->rx_coalesce_usecs_high; +- rx_min = coalesce->rx_coalesce_usecs_low; +- rx_cur = coalesce->rx_coalesce_usecs; +- +- if (rx_eq->enable_aic) { +- if (rx_max > BE_MAX_EQD) +- rx_max = BE_MAX_EQD; +- if (rx_min > rx_max) +- rx_min = rx_max; +- rx_eq->max_eqd = rx_max; +- rx_eq->min_eqd = rx_min; +- if (rx_eq->cur_eqd > rx_max) +- rx_eq->cur_eqd = rx_max; +- if (rx_eq->cur_eqd < rx_min) +- rx_eq->cur_eqd = rx_min; +- } else { +- if (rx_cur > BE_MAX_EQD) +- rx_cur = BE_MAX_EQD; +- if (rx_eq->cur_eqd != rx_cur) { +- status = be_cmd_modify_eqd(adapter, rx_eq->q.id, +- rx_cur); +- if (!status) +- rx_eq->cur_eqd = rx_cur; +- } +- } +- } +- +- tx_cur = coalesce->tx_coalesce_usecs; +- +- if (tx_cur > BE_MAX_EQD) +- tx_cur = BE_MAX_EQD; +- if (tx_eq->cur_eqd != tx_cur) { +- status = be_cmd_modify_eqd(adapter, tx_eq->q.id, tx_cur); +- if (!status) +- tx_eq->cur_eqd = tx_cur; ++ struct be_eq_obj *eqo; ++ int i; ++ ++ for_all_evt_queues(adapter, eqo, i) { ++ eqo->enable_aic = et->use_adaptive_rx_coalesce; ++ eqo->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD); ++ eqo->min_eqd = min(et->rx_coalesce_usecs_low, eqo->max_eqd); ++ eqo->eqd = et->rx_coalesce_usecs; + } + + return 0; +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 4364f01..4a3a186 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -144,7 +144,7 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, + mem->va = dma_alloc_coherent(&adapter->pdev->dev, mem->size, &mem->dma, + GFP_KERNEL); + if (!mem->va) +- return -1; ++ return -ENOMEM; + memset(mem->va, 0, mem->size); + return 0; + } +@@ -988,18 +988,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev, + return status; + } + +-static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) ++static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo) + { +- struct be_eq_obj *rx_eq = &rxo->rx_eq; +- struct be_rx_stats *stats = rx_stats(rxo); ++ struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]); + ulong now = jiffies; + ulong delta = now - stats->rx_jiffies; + u64 pkts; + unsigned int start, eqd; + +- if (!rx_eq->enable_aic) ++ if (!eqo->enable_aic) { ++ eqd = eqo->eqd; ++ goto modify_eqd; ++ } ++ ++ if (eqo->idx >= adapter->num_rx_qs) + return; + ++ stats = rx_stats(&adapter->rx_obj[eqo->idx]); ++ + /* Wrapped around */ + if (time_before(now, stats->rx_jiffies)) { + stats->rx_jiffies = now; +@@ -1018,17 +1024,16 @@ static void be_rx_eqd_update(struct be_adapter *adapter, struct be_rx_obj *rxo) + stats->rx_pps = (unsigned long)(pkts - stats->rx_pkts_prev) / (delta / HZ); + stats->rx_pkts_prev = pkts; + stats->rx_jiffies = now; +- eqd = stats->rx_pps / 110000; +- eqd = eqd << 3; +- if (eqd > rx_eq->max_eqd) +- eqd = rx_eq->max_eqd; +- if (eqd < rx_eq->min_eqd) +- eqd = rx_eq->min_eqd; ++ eqd = (stats->rx_pps / 110000) << 3; ++ eqd = min(eqd, eqo->max_eqd); ++ eqd = max(eqd, eqo->min_eqd); + if (eqd < 10) + eqd = 0; +- if (eqd != rx_eq->cur_eqd) { +- be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); +- rx_eq->cur_eqd = eqd; ++ ++modify_eqd: ++ if (eqd != eqo->cur_eqd) { ++ be_cmd_modify_eqd(adapter, eqo->q.id, eqd); ++ eqo->cur_eqd = eqd; + } + } + +@@ -1056,11 +1061,10 @@ static inline bool csum_passed(struct be_rx_compl_info *rxcp) + (rxcp->ip_csum || rxcp->ipv6); + } + +-static struct be_rx_page_info * +-get_rx_page_info(struct be_adapter *adapter, +- struct be_rx_obj *rxo, +- u16 frag_idx) ++static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo, ++ u16 frag_idx) + { ++ struct be_adapter *adapter = rxo->adapter; + struct be_rx_page_info *rx_page_info; + struct be_queue_info *rxq = &rxo->q; + +@@ -1079,16 +1083,15 @@ get_rx_page_info(struct be_adapter *adapter, + } + + /* Throwaway the data in the Rx completion */ +-static void be_rx_compl_discard(struct be_adapter *adapter, +- struct be_rx_obj *rxo, +- struct be_rx_compl_info *rxcp) ++static void be_rx_compl_discard(struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { + struct be_queue_info *rxq = &rxo->q; + struct be_rx_page_info *page_info; + u16 i, num_rcvd = rxcp->num_rcvd; + + for (i = 0; i < num_rcvd; i++) { +- page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + put_page(page_info->page); + memset(page_info, 0, sizeof(*page_info)); + index_inc(&rxcp->rxq_idx, rxq->len); +@@ -1099,8 +1102,8 @@ static void be_rx_compl_discard(struct be_adapter *adapter, + * skb_fill_rx_data forms a complete skb for an ether frame + * indicated by rxcp. + */ +-static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, +- struct sk_buff *skb, struct be_rx_compl_info *rxcp) ++static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, ++ struct be_rx_compl_info *rxcp) + { + struct be_queue_info *rxq = &rxo->q; + struct be_rx_page_info *page_info; +@@ -1108,7 +1111,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, + u16 hdr_len, curr_frag_len, remaining; + u8 *start; + +- page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + start = page_address(page_info->page) + page_info->page_offset; + prefetch(start); + +@@ -1145,7 +1148,7 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, + index_inc(&rxcp->rxq_idx, rxq->len); + remaining = rxcp->pkt_size - curr_frag_len; + for (i = 1, j = 0; i < rxcp->num_rcvd; i++) { +- page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + curr_frag_len = min(remaining, rx_frag_size); + + /* Coalesce all frags from the same physical page in one slot */ +@@ -1173,21 +1176,21 @@ static void skb_fill_rx_data(struct be_adapter *adapter, struct be_rx_obj *rxo, + } + + /* Process the RX completion indicated by rxcp when GRO is disabled */ +-static void be_rx_compl_process(struct be_adapter *adapter, +- struct be_rx_obj *rxo, +- struct be_rx_compl_info *rxcp) ++static void be_rx_compl_process(struct be_rx_obj *rxo, ++ struct be_rx_compl_info *rxcp) + { ++ struct be_adapter *adapter = rxo->adapter; + struct net_device *netdev = adapter->netdev; + struct sk_buff *skb; + + skb = netdev_alloc_skb_ip_align(netdev, BE_RX_SKB_ALLOC_SIZE); + if (unlikely(!skb)) { + rx_stats(rxo)->rx_drops_no_skbs++; +- be_rx_compl_discard(adapter, rxo, rxcp); ++ be_rx_compl_discard(rxo, rxcp); + return; + } + +- skb_fill_rx_data(adapter, rxo, skb, rxcp); ++ skb_fill_rx_data(rxo, skb, rxcp); + + if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp))) + skb->ip_summed = CHECKSUM_UNNECESSARY; +@@ -1195,7 +1198,7 @@ static void be_rx_compl_process(struct be_adapter *adapter, + skb_checksum_none_assert(skb); + + skb->protocol = eth_type_trans(skb, netdev); +- if (adapter->netdev->features & NETIF_F_RXHASH) ++ if (netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + + +@@ -1206,26 +1209,25 @@ static void be_rx_compl_process(struct be_adapter *adapter, + } + + /* Process the RX completion indicated by rxcp when GRO is enabled */ +-static void be_rx_compl_process_gro(struct be_adapter *adapter, +- struct be_rx_obj *rxo, +- struct be_rx_compl_info *rxcp) ++void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct napi_struct *napi, ++ struct be_rx_compl_info *rxcp) + { ++ struct be_adapter *adapter = rxo->adapter; + struct be_rx_page_info *page_info; + struct sk_buff *skb = NULL; + struct be_queue_info *rxq = &rxo->q; +- struct be_eq_obj *eq_obj = &rxo->rx_eq; + u16 remaining, curr_frag_len; + u16 i, j; + +- skb = napi_get_frags(&eq_obj->napi); ++ skb = napi_get_frags(napi); + if (!skb) { +- be_rx_compl_discard(adapter, rxo, rxcp); ++ be_rx_compl_discard(rxo, rxcp); + return; + } + + remaining = rxcp->pkt_size; + for (i = 0, j = -1; i < rxcp->num_rcvd; i++) { +- page_info = get_rx_page_info(adapter, rxo, rxcp->rxq_idx); ++ page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + + curr_frag_len = min(remaining, rx_frag_size); + +@@ -1258,12 +1260,11 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, + if (rxcp->vlanf) + __vlan_hwaccel_put_tag(skb, rxcp->vlan_tag); + +- napi_gro_frags(&eq_obj->napi); ++ napi_gro_frags(napi); + } + +-static void be_parse_rx_compl_v1(struct be_adapter *adapter, +- struct be_eth_rx_compl *compl, +- struct be_rx_compl_info *rxcp) ++static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl, ++ struct be_rx_compl_info *rxcp) + { + rxcp->pkt_size = + AMAP_GET_BITS(struct amap_eth_rx_compl_v1, pktsize, compl); +@@ -1294,9 +1295,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, + rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl); + } + +-static void be_parse_rx_compl_v0(struct be_adapter *adapter, +- struct be_eth_rx_compl *compl, +- struct be_rx_compl_info *rxcp) ++static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl, ++ struct be_rx_compl_info *rxcp) + { + rxcp->pkt_size = + AMAP_GET_BITS(struct amap_eth_rx_compl_v0, pktsize, compl); +@@ -1342,9 +1342,9 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) + be_dws_le_to_cpu(compl, sizeof(*compl)); + + if (adapter->be3_native) +- be_parse_rx_compl_v1(adapter, compl, rxcp); ++ be_parse_rx_compl_v1(compl, rxcp); + else +- be_parse_rx_compl_v0(adapter, compl, rxcp); ++ be_parse_rx_compl_v0(compl, rxcp); + + if (rxcp->vlanf) { + /* vlanf could be wrongly set in some cards. +@@ -1383,7 +1383,6 @@ static inline struct page *be_alloc_pages(u32 size, gfp_t gfp) + static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) + { + struct be_adapter *adapter = rxo->adapter; +- struct be_rx_page_info *page_info_tbl = rxo->page_info_tbl; + struct be_rx_page_info *page_info = NULL, *prev_page_info = NULL; + struct be_queue_info *rxq = &rxo->q; + struct page *pagep = NULL; +@@ -1425,7 +1424,7 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) + + prev_page_info = page_info; + queue_head_inc(rxq); +- page_info = &page_info_tbl[rxq->head]; ++ page_info = &rxo->page_info_tbl[rxq->head]; + } + if (pagep) + prev_page_info->last_page_user = true; +@@ -1487,62 +1486,51 @@ static u16 be_tx_compl_process(struct be_adapter *adapter, + return num_wrbs; + } + +-static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) ++/* Return the number of events in the event queue */ ++static inline int events_get(struct be_eq_obj *eqo) + { +- struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); ++ struct be_eq_entry *eqe; ++ int num = 0; + +- if (!eqe->evt) +- return NULL; ++ do { ++ eqe = queue_tail_node(&eqo->q); ++ if (eqe->evt == 0) ++ break; + +- rmb(); +- eqe->evt = le32_to_cpu(eqe->evt); +- queue_tail_inc(&eq_obj->q); +- return eqe; ++ rmb(); ++ eqe->evt = 0; ++ num++; ++ queue_tail_inc(&eqo->q); ++ } while (true); ++ ++ return num; + } + +-static int event_handle(struct be_adapter *adapter, +- struct be_eq_obj *eq_obj, +- bool rearm) ++static int event_handle(struct be_eq_obj *eqo) + { +- struct be_eq_entry *eqe; +- u16 num = 0; +- +- while ((eqe = event_get(eq_obj)) != NULL) { +- eqe->evt = 0; +- num++; +- } ++ bool rearm = false; ++ int num = events_get(eqo); + +- /* Deal with any spurious interrupts that come +- * without events +- */ ++ /* Deal with any spurious interrupts that come without events */ + if (!num) + rearm = true; + +- be_eq_notify(adapter, eq_obj->q.id, rearm, true, num); ++ be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num); + if (num) +- napi_schedule(&eq_obj->napi); ++ napi_schedule(&eqo->napi); + + return num; + } + +-/* Just read and notify events without processing them. +- * Used at the time of destroying event queues */ +-static void be_eq_clean(struct be_adapter *adapter, +- struct be_eq_obj *eq_obj) ++/* Leaves the EQ is disarmed state */ ++static void be_eq_clean(struct be_eq_obj *eqo) + { +- struct be_eq_entry *eqe; +- u16 num = 0; +- +- while ((eqe = event_get(eq_obj)) != NULL) { +- eqe->evt = 0; +- num++; +- } ++ int num = events_get(eqo); + +- if (num) +- be_eq_notify(adapter, eq_obj->q.id, false, true, num); ++ be_eq_notify(eqo->adapter, eqo->q.id, false, true, num); + } + +-static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) ++static void be_rx_cq_clean(struct be_rx_obj *rxo) + { + struct be_rx_page_info *page_info; + struct be_queue_info *rxq = &rxo->q; +@@ -1552,14 +1540,14 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo) + + /* First cleanup pending rx completions */ + while ((rxcp = be_rx_compl_get(rxo)) != NULL) { +- be_rx_compl_discard(adapter, rxo, rxcp); +- be_cq_notify(adapter, rx_cq->id, false, 1); ++ be_rx_compl_discard(rxo, rxcp); ++ be_cq_notify(rxo->adapter, rx_cq->id, false, 1); + } + + /* Then free posted rx buffer that were not used */ + tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; + for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { +- page_info = get_rx_page_info(adapter, rxo, tail); ++ page_info = get_rx_page_info(rxo, tail); + put_page(page_info->page); + memset(page_info, 0, sizeof(*page_info)); + } +@@ -1615,6 +1603,47 @@ static void be_tx_compl_clean(struct be_adapter *adapter, + } + } + ++static void be_evt_queues_destroy(struct be_adapter *adapter) ++{ ++ struct be_eq_obj *eqo; ++ int i; ++ ++ for_all_evt_queues(adapter, eqo, i) { ++ be_eq_clean(eqo); ++ if (eqo->q.created) ++ be_cmd_q_destroy(adapter, &eqo->q, QTYPE_EQ); ++ be_queue_free(adapter, &eqo->q); ++ } ++} ++ ++static int be_evt_queues_create(struct be_adapter *adapter) ++{ ++ struct be_queue_info *eq; ++ struct be_eq_obj *eqo; ++ int i, rc; ++ ++ adapter->num_evt_qs = num_irqs(adapter); ++ ++ for_all_evt_queues(adapter, eqo, i) { ++ eqo->adapter = adapter; ++ eqo->tx_budget = BE_TX_BUDGET; ++ eqo->idx = i; ++ eqo->max_eqd = BE_MAX_EQD; ++ eqo->enable_aic = true; ++ ++ eq = &eqo->q; ++ rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, ++ sizeof(struct be_eq_entry)); ++ if (rc) ++ return rc; ++ ++ rc = be_cmd_eq_create(adapter, eq, eqo->cur_eqd); ++ if (rc) ++ return rc; ++ } ++ return rc; ++} ++ + static void be_mcc_queues_destroy(struct be_adapter *adapter) + { + struct be_queue_info *q; +@@ -1635,22 +1664,19 @@ static int be_mcc_queues_create(struct be_adapter *adapter) + { + struct be_queue_info *q, *cq; + +- /* Alloc MCC compl queue */ + cq = &adapter->mcc_obj.cq; + if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, + sizeof(struct be_mcc_compl))) + goto err; + +- /* Ask BE to create MCC compl queue; share TX's eq */ +- if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0)) ++ /* Use the default EQ for MCC completions */ ++ if (be_cmd_cq_create(adapter, cq, &mcc_eqo(adapter)->q, true, 0)) + goto mcc_cq_free; + +- /* Alloc MCC queue */ + q = &adapter->mcc_obj.q; + if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) + goto mcc_cq_destroy; + +- /* Ask BE to create MCC queue */ + if (be_cmd_mccq_create(adapter, q, cq)) + goto mcc_q_free; + +@@ -1683,14 +1709,6 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) + be_cmd_q_destroy(adapter, q, QTYPE_CQ); + be_queue_free(adapter, q); + } +- +- /* Clear any residual events */ +- be_eq_clean(adapter, &adapter->tx_eq); +- +- q = &adapter->tx_eq.q; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_EQ); +- be_queue_free(adapter, q); + } + + static int be_num_txqs_want(struct be_adapter *adapter) +@@ -1703,10 +1721,10 @@ static int be_num_txqs_want(struct be_adapter *adapter) + return MAX_TX_QS; + } + +-/* One TX event queue is shared by all TX compl qs */ +-static int be_tx_queues_create(struct be_adapter *adapter) ++static int be_tx_cqs_create(struct be_adapter *adapter) + { +- struct be_queue_info *eq, *q, *cq; ++ struct be_queue_info *cq, *eq; ++ int status; + struct be_tx_obj *txo; + u8 i; + +@@ -1718,192 +1736,109 @@ static int be_tx_queues_create(struct be_adapter *adapter) + rtnl_unlock(); + } + +- adapter->tx_eq.max_eqd = 0; +- adapter->tx_eq.min_eqd = 0; +- adapter->tx_eq.cur_eqd = 96; +- adapter->tx_eq.enable_aic = false; ++ for_all_tx_queues(adapter, txo, i) { ++ cq = &txo->cq; ++ status = be_queue_alloc(adapter, cq, TX_CQ_LEN, ++ sizeof(struct be_eth_tx_compl)); ++ if (status) ++ return status; + +- eq = &adapter->tx_eq.q; +- if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, +- sizeof(struct be_eq_entry))) +- return -1; ++ /* If num_evt_qs is less than num_tx_qs, then more than ++ * one txq share an eq ++ */ ++ eq = &adapter->eq_obj[i % adapter->num_evt_qs].q; ++ status = be_cmd_cq_create(adapter, cq, eq, false, 3); ++ if (status) ++ return status; ++ } ++ return 0; ++} + +- if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) +- goto err; +- adapter->tx_eq.eq_idx = adapter->eq_next_idx++; ++static int be_tx_qs_create(struct be_adapter *adapter) ++{ ++ struct be_tx_obj *txo; ++ int i, status; + + for_all_tx_queues(adapter, txo, i) { +- cq = &txo->cq; +- if (be_queue_alloc(adapter, cq, TX_CQ_LEN, +- sizeof(struct be_eth_tx_compl))) +- goto err; +- +- if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) +- goto err; ++ status = be_queue_alloc(adapter, &txo->q, TX_Q_LEN, ++ sizeof(struct be_eth_wrb)); ++ if (status) ++ return status; + +- q = &txo->q; +- if (be_queue_alloc(adapter, q, TX_Q_LEN, +- sizeof(struct be_eth_wrb))) +- goto err; ++ status = be_cmd_txq_create(adapter, &txo->q, &txo->cq); ++ if (status) ++ return status; + } +- return 0; + +-err: +- be_tx_queues_destroy(adapter); +- return -1; ++ return 0; + } + +-static void be_rx_queues_destroy(struct be_adapter *adapter) ++static void be_rx_cqs_destroy(struct be_adapter *adapter) + { + struct be_queue_info *q; + struct be_rx_obj *rxo; + int i; + + for_all_rx_queues(adapter, rxo, i) { +- be_queue_free(adapter, &rxo->q); +- + q = &rxo->cq; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_CQ); + be_queue_free(adapter, q); +- +- q = &rxo->rx_eq.q; +- if (q->created) +- be_cmd_q_destroy(adapter, q, QTYPE_EQ); +- be_queue_free(adapter, q); +- } +-} +- +-static u32 be_num_rxqs_want(struct be_adapter *adapter) +-{ +- if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && +- !sriov_enabled(adapter) && be_physfn(adapter)) { +- return 1 + MAX_RSS_QS; /* one default non-RSS queue */ +- } else { +- dev_warn(&adapter->pdev->dev, +- "No support for multiple RX queues\n"); +- return 1; + } + } + +-static int be_rx_queues_create(struct be_adapter *adapter) ++static int be_rx_cqs_create(struct be_adapter *adapter) + { +- struct be_queue_info *eq, *q, *cq; ++ struct be_queue_info *eq, *cq; + struct be_rx_obj *rxo; + int rc, i; + +- adapter->num_rx_qs = min(be_num_rxqs_want(adapter), +- msix_enabled(adapter) ? +- adapter->num_msix_vec - 1 : 1); +- if (adapter->num_rx_qs != MAX_RX_QS) +- dev_warn(&adapter->pdev->dev, +- "Can create only %d RX queues", adapter->num_rx_qs); ++ /* We'll create as many RSS rings as there are irqs. ++ * But when there's only one irq there's no use creating RSS rings ++ */ ++ adapter->num_rx_qs = (num_irqs(adapter) > 1) ? ++ num_irqs(adapter) + 1 : 1; + + adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; + for_all_rx_queues(adapter, rxo, i) { + rxo->adapter = adapter; +- rxo->rx_eq.max_eqd = BE_MAX_EQD; +- rxo->rx_eq.enable_aic = true; +- +- /* EQ */ +- eq = &rxo->rx_eq.q; +- rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN, +- sizeof(struct be_eq_entry)); +- if (rc) +- goto err; +- +- rc = be_cmd_eq_create(adapter, eq, rxo->rx_eq.cur_eqd); +- if (rc) +- goto err; +- +- rxo->rx_eq.eq_idx = adapter->eq_next_idx++; +- +- /* CQ */ + cq = &rxo->cq; + rc = be_queue_alloc(adapter, cq, RX_CQ_LEN, + sizeof(struct be_eth_rx_compl)); + if (rc) +- goto err; ++ return rc; + +- rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); ++ eq = &adapter->eq_obj[i % adapter->num_evt_qs].q; ++ rc = be_cmd_cq_create(adapter, cq, eq, false, 3); + if (rc) +- goto err; +- +- /* Rx Q - will be created in be_open() */ +- q = &rxo->q; +- rc = be_queue_alloc(adapter, q, RX_Q_LEN, +- sizeof(struct be_eth_rx_d)); +- if (rc) +- goto err; +- ++ return rc; + } + +- return 0; +-err: +- be_rx_queues_destroy(adapter); +- return -1; +-} ++ if (adapter->num_rx_qs != MAX_RX_QS) ++ dev_info(&adapter->pdev->dev, ++ "Created only %d receive queues", adapter->num_rx_qs); + +-static bool event_peek(struct be_eq_obj *eq_obj) +-{ +- struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); +- if (!eqe->evt) +- return false; +- else +- return true; ++ return 0; + } + + static irqreturn_t be_intx(int irq, void *dev) + { + struct be_adapter *adapter = dev; +- struct be_rx_obj *rxo; +- int isr, i, tx = 0 , rx = 0; +- +- if (lancer_chip(adapter)) { +- if (event_peek(&adapter->tx_eq)) +- tx = event_handle(adapter, &adapter->tx_eq, false); +- for_all_rx_queues(adapter, rxo, i) { +- if (event_peek(&rxo->rx_eq)) +- rx |= event_handle(adapter, &rxo->rx_eq, true); +- } +- +- if (!(tx || rx)) +- return IRQ_NONE; +- +- } else { +- isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + +- (adapter->tx_eq.q.id / 8) * CEV_ISR_SIZE); +- if (!isr) +- return IRQ_NONE; +- +- if ((1 << adapter->tx_eq.eq_idx & isr)) +- event_handle(adapter, &adapter->tx_eq, false); +- +- for_all_rx_queues(adapter, rxo, i) { +- if ((1 << rxo->rx_eq.eq_idx & isr)) +- event_handle(adapter, &rxo->rx_eq, true); +- } +- } +- +- return IRQ_HANDLED; +-} +- +-static irqreturn_t be_msix_rx(int irq, void *dev) +-{ +- struct be_rx_obj *rxo = dev; +- struct be_adapter *adapter = rxo->adapter; ++ int num_evts; + +- event_handle(adapter, &rxo->rx_eq, true); +- +- return IRQ_HANDLED; ++ /* With INTx only one EQ is used */ ++ num_evts = event_handle(&adapter->eq_obj[0]); ++ if (num_evts) ++ return IRQ_HANDLED; ++ else ++ return IRQ_NONE; + } + +-static irqreturn_t be_msix_tx_mcc(int irq, void *dev) ++static irqreturn_t be_msix(int irq, void *dev) + { +- struct be_adapter *adapter = dev; +- +- event_handle(adapter, &adapter->tx_eq, false); ++ struct be_eq_obj *eqo = dev; + ++ event_handle(eqo); + return IRQ_HANDLED; + } + +@@ -1912,16 +1847,14 @@ static inline bool do_gro(struct be_rx_compl_info *rxcp) + return (rxcp->tcpf && !rxcp->err) ? true : false; + } + +-static int be_poll_rx(struct napi_struct *napi, int budget) ++static int be_process_rx(struct be_rx_obj *rxo, struct napi_struct *napi, ++ int budget) + { +- struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi); +- struct be_rx_obj *rxo = container_of(rx_eq, struct be_rx_obj, rx_eq); + struct be_adapter *adapter = rxo->adapter; + struct be_queue_info *rx_cq = &rxo->cq; + struct be_rx_compl_info *rxcp; + u32 work_done; + +- rx_stats(rxo)->rx_polls++; + for (work_done = 0; work_done < budget; work_done++) { + rxcp = be_rx_compl_get(rxo); + if (!rxcp) +@@ -1933,7 +1866,7 @@ static int be_poll_rx(struct napi_struct *napi, int budget) + + /* Discard compl with partial DMA Lancer B0 */ + if (unlikely(!rxcp->pkt_size)) { +- be_rx_compl_discard(adapter, rxo, rxcp); ++ be_rx_compl_discard(rxo, rxcp); + goto loop_continue; + } + +@@ -1942,94 +1875,96 @@ static int be_poll_rx(struct napi_struct *napi, int budget) + */ + if (unlikely(rxcp->port != adapter->port_num && + !lancer_chip(adapter))) { +- be_rx_compl_discard(adapter, rxo, rxcp); ++ be_rx_compl_discard(rxo, rxcp); + goto loop_continue; + } + + if (do_gro(rxcp)) +- be_rx_compl_process_gro(adapter, rxo, rxcp); ++ be_rx_compl_process_gro(rxo, napi, rxcp); + else +- be_rx_compl_process(adapter, rxo, rxcp); ++ be_rx_compl_process(rxo, rxcp); + loop_continue: + be_rx_stats_update(rxo, rxcp); + } + +- be_cq_notify(adapter, rx_cq->id, false, work_done); ++ if (work_done) { ++ be_cq_notify(adapter, rx_cq->id, true, work_done); + +- /* Refill the queue */ +- if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM) +- be_post_rx_frags(rxo, GFP_ATOMIC); +- +- /* All consumed */ +- if (work_done < budget) { +- napi_complete(napi); +- /* Arm CQ */ +- be_cq_notify(adapter, rx_cq->id, true, 0); ++ if (atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM) ++ be_post_rx_frags(rxo, GFP_ATOMIC); + } ++ + return work_done; + } + +-/* As TX and MCC share the same EQ check for both TX and MCC completions. +- * For TX/MCC we don't honour budget; consume everything +- */ +-static int be_poll_tx_mcc(struct napi_struct *napi, int budget) ++static bool be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo, ++ int budget, int idx) + { +- struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); +- struct be_adapter *adapter = +- container_of(tx_eq, struct be_adapter, tx_eq); +- struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; +- struct be_tx_obj *txo; + struct be_eth_tx_compl *txcp; +- int tx_compl, mcc_compl, status = 0; +- u8 i; +- u16 num_wrbs; ++ int num_wrbs = 0, work_done; + +- for_all_tx_queues(adapter, txo, i) { +- tx_compl = 0; +- num_wrbs = 0; +- while ((txcp = be_tx_compl_get(&txo->cq))) { +- num_wrbs += be_tx_compl_process(adapter, txo, ++ for (work_done = 0; work_done < budget; work_done++) { ++ txcp = be_tx_compl_get(&txo->cq); ++ if (!txcp) ++ break; ++ num_wrbs += be_tx_compl_process(adapter, txo, + AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp)); +- tx_compl++; +- } +- if (tx_compl) { +- be_cq_notify(adapter, txo->cq.id, true, tx_compl); +- +- atomic_sub(num_wrbs, &txo->q.used); ++ } + +- /* As Tx wrbs have been freed up, wake up netdev queue +- * if it was stopped due to lack of tx wrbs. */ +- if (__netif_subqueue_stopped(adapter->netdev, i) && +- atomic_read(&txo->q.used) < txo->q.len / 2) { +- netif_wake_subqueue(adapter->netdev, i); +- } ++ if (work_done) { ++ be_cq_notify(adapter, txo->cq.id, true, work_done); ++ atomic_sub(num_wrbs, &txo->q.used); + +- u64_stats_update_begin(&tx_stats(txo)->sync_compl); +- tx_stats(txo)->tx_compl += tx_compl; +- u64_stats_update_end(&tx_stats(txo)->sync_compl); ++ /* As Tx wrbs have been freed up, wake up netdev queue ++ * if it was stopped due to lack of tx wrbs. */ ++ if (__netif_subqueue_stopped(adapter->netdev, idx) && ++ atomic_read(&txo->q.used) < txo->q.len / 2) { ++ netif_wake_subqueue(adapter->netdev, idx); + } ++ ++ u64_stats_update_begin(&tx_stats(txo)->sync_compl); ++ tx_stats(txo)->tx_compl += work_done; ++ u64_stats_update_end(&tx_stats(txo)->sync_compl); + } ++ return (work_done < budget); /* Done */ ++} + +- mcc_compl = be_process_mcc(adapter, &status); ++int be_poll(struct napi_struct *napi, int budget) ++{ ++ struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi); ++ struct be_adapter *adapter = eqo->adapter; ++ int max_work = 0, work, i; ++ bool tx_done; + +- if (mcc_compl) { +- be_cq_notify(adapter, mcc_obj->cq.id, true, mcc_compl); ++ /* Process all TXQs serviced by this EQ */ ++ for (i = eqo->idx; i < adapter->num_tx_qs; i += adapter->num_evt_qs) { ++ tx_done = be_process_tx(adapter, &adapter->tx_obj[i], ++ eqo->tx_budget, i); ++ if (!tx_done) ++ max_work = budget; + } + +- napi_complete(napi); ++ /* This loop will iterate twice for EQ0 in which ++ * completions of the last RXQ (default one) are also processed ++ * For other EQs the loop iterates only once ++ */ ++ for (i = eqo->idx; i < adapter->num_rx_qs; i += adapter->num_evt_qs) { ++ work = be_process_rx(&adapter->rx_obj[i], napi, budget); ++ max_work = max(work, max_work); ++ } + +- /* Arm CQ again to regenerate EQEs for Lancer in INTx mode */ +- if (lancer_chip(adapter) && !msix_enabled(adapter)) { +- for_all_tx_queues(adapter, txo, i) +- be_cq_notify(adapter, txo->cq.id, true, 0); ++ if (is_mcc_eqo(eqo)) ++ be_process_mcc(adapter); + +- be_cq_notify(adapter, mcc_obj->cq.id, true, 0); ++ if (max_work < budget) { ++ napi_complete(napi); ++ be_eq_notify(adapter, eqo->q.id, true, false, 0); ++ } else { ++ /* As we'll continue in polling mode, count and clear events */ ++ be_eq_notify(adapter, eqo->q.id, false, false, events_get(eqo)); + } +- +- be_eq_notify(adapter, tx_eq->q.id, true, false, 0); +- adapter->drv_stats.tx_events++; +- return 1; ++ return max_work; + } + + void be_detect_dump_ue(struct be_adapter *adapter) +@@ -2104,12 +2039,24 @@ static void be_msix_disable(struct be_adapter *adapter) + } + } + ++static uint be_num_rss_want(struct be_adapter *adapter) ++{ ++ if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && ++ adapter->num_vfs == 0 && be_physfn(adapter) && ++ !be_is_mc(adapter)) ++ return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS; ++ else ++ return 0; ++} ++ + static void be_msix_enable(struct be_adapter *adapter) + { +-#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */ ++#define BE_MIN_MSIX_VECTORS 1 + int i, status, num_vec; + +- num_vec = be_num_rxqs_want(adapter) + 1; ++ /* If RSS queues are not used, need a vec for default RX Q */ ++ num_vec = min(be_num_rss_want(adapter), num_online_cpus()); ++ num_vec = max(num_vec, BE_MIN_MSIX_VECTORS); + + for (i = 0; i < num_vec; i++) + adapter->msix_entries[i].entry = i; +@@ -2177,60 +2124,31 @@ static void be_sriov_disable(struct be_adapter *adapter) + } + + static inline int be_msix_vec_get(struct be_adapter *adapter, +- struct be_eq_obj *eq_obj) +-{ +- return adapter->msix_entries[eq_obj->eq_idx].vector; +-} +- +-static int be_request_irq(struct be_adapter *adapter, +- struct be_eq_obj *eq_obj, +- void *handler, char *desc, void *context) +-{ +- struct net_device *netdev = adapter->netdev; +- int vec; +- +- sprintf(eq_obj->desc, "%s-%s", netdev->name, desc); +- vec = be_msix_vec_get(adapter, eq_obj); +- return request_irq(vec, handler, 0, eq_obj->desc, context); +-} +- +-static void be_free_irq(struct be_adapter *adapter, struct be_eq_obj *eq_obj, +- void *context) ++ struct be_eq_obj *eqo) + { +- int vec = be_msix_vec_get(adapter, eq_obj); +- free_irq(vec, context); ++ return adapter->msix_entries[eqo->idx].vector; + } + + static int be_msix_register(struct be_adapter *adapter) + { +- struct be_rx_obj *rxo; +- int status, i; +- char qname[10]; +- +- status = be_request_irq(adapter, &adapter->tx_eq, be_msix_tx_mcc, "tx", +- adapter); +- if (status) +- goto err; ++ struct net_device *netdev = adapter->netdev; ++ struct be_eq_obj *eqo; ++ int status, i, vec; + +- for_all_rx_queues(adapter, rxo, i) { +- sprintf(qname, "rxq%d", i); +- status = be_request_irq(adapter, &rxo->rx_eq, be_msix_rx, +- qname, rxo); ++ for_all_evt_queues(adapter, eqo, i) { ++ sprintf(eqo->desc, "%s-q%d", netdev->name, i); ++ vec = be_msix_vec_get(adapter, eqo); ++ status = request_irq(vec, be_msix, 0, eqo->desc, eqo); + if (status) + goto err_msix; + } + + return 0; +- + err_msix: +- be_free_irq(adapter, &adapter->tx_eq, adapter); +- +- for (i--, rxo = &adapter->rx_obj[i]; i >= 0; i--, rxo--) +- be_free_irq(adapter, &rxo->rx_eq, rxo); +- +-err: +- dev_warn(&adapter->pdev->dev, +- "MSIX Request IRQ failed - err %d\n", status); ++ for (i--, eqo = &adapter->eq_obj[i]; i >= 0; i--, eqo--) ++ free_irq(be_msix_vec_get(adapter, eqo), eqo); ++ dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n", ++ status); + be_msix_disable(adapter); + return status; + } +@@ -2266,7 +2184,7 @@ done: + static void be_irq_unregister(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; +- struct be_rx_obj *rxo; ++ struct be_eq_obj *eqo; + int i; + + if (!adapter->isr_registered) +@@ -2279,16 +2197,14 @@ static void be_irq_unregister(struct be_adapter *adapter) + } + + /* MSIx */ +- be_free_irq(adapter, &adapter->tx_eq, adapter); +- +- for_all_rx_queues(adapter, rxo, i) +- be_free_irq(adapter, &rxo->rx_eq, rxo); ++ for_all_evt_queues(adapter, eqo, i) ++ free_irq(be_msix_vec_get(adapter, eqo), eqo); + + done: + adapter->isr_registered = false; + } + +-static void be_rx_queues_clear(struct be_adapter *adapter) ++static void be_rx_qs_destroy(struct be_adapter *adapter) + { + struct be_queue_info *q; + struct be_rx_obj *rxo; +@@ -2303,53 +2219,33 @@ static void be_rx_queues_clear(struct be_adapter *adapter) + * arrive + */ + mdelay(1); +- be_rx_q_clean(adapter, rxo); ++ be_rx_cq_clean(rxo); + } +- +- /* Clear any residual events */ +- q = &rxo->rx_eq.q; +- if (q->created) +- be_eq_clean(adapter, &rxo->rx_eq); ++ be_queue_free(adapter, q); + } + } + + static int be_close(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_rx_obj *rxo; + struct be_tx_obj *txo; +- struct be_eq_obj *tx_eq = &adapter->tx_eq; +- int vec, i; ++ struct be_eq_obj *eqo; ++ int i; + + be_async_mcc_disable(adapter); + + if (!lancer_chip(adapter)) + be_intr_set(adapter, false); + +- for_all_rx_queues(adapter, rxo, i) +- napi_disable(&rxo->rx_eq.napi); +- +- napi_disable(&tx_eq->napi); +- +- if (lancer_chip(adapter)) { +- be_cq_notify(adapter, adapter->mcc_obj.cq.id, false, 0); +- for_all_rx_queues(adapter, rxo, i) +- be_cq_notify(adapter, rxo->cq.id, false, 0); +- for_all_tx_queues(adapter, txo, i) +- be_cq_notify(adapter, txo->cq.id, false, 0); ++ for_all_evt_queues(adapter, eqo, i) { ++ napi_disable(&eqo->napi); ++ if (msix_enabled(adapter)) ++ synchronize_irq(be_msix_vec_get(adapter, eqo)); ++ else ++ synchronize_irq(netdev->irq); ++ be_eq_clean(eqo); + } + +- if (msix_enabled(adapter)) { +- vec = be_msix_vec_get(adapter, tx_eq); +- synchronize_irq(vec); +- +- for_all_rx_queues(adapter, rxo, i) { +- vec = be_msix_vec_get(adapter, &rxo->rx_eq); +- synchronize_irq(vec); +- } +- } else { +- synchronize_irq(netdev->irq); +- } + be_irq_unregister(adapter); + + /* Wait for all pending tx completions to arrive so that +@@ -2358,21 +2254,34 @@ static int be_close(struct net_device *netdev) + for_all_tx_queues(adapter, txo, i) + be_tx_compl_clean(adapter, txo); + +- be_rx_queues_clear(adapter); ++ be_rx_qs_destroy(adapter); + return 0; + } + +-static int be_rx_queues_setup(struct be_adapter *adapter) ++static int be_rx_qs_create(struct be_adapter *adapter) + { + struct be_rx_obj *rxo; + int rc, i, j; + u8 rsstable[128]; + + for_all_rx_queues(adapter, rxo, i) { ++ rc = be_queue_alloc(adapter, &rxo->q, RX_Q_LEN, ++ sizeof(struct be_eth_rx_d)); ++ if (rc) ++ return rc; ++ } ++ ++ /* The FW would like the default RXQ to be created first */ ++ rxo = default_rxo(adapter); ++ rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, rx_frag_size, ++ adapter->if_handle, false, &rxo->rss_id); ++ if (rc) ++ return rc; ++ ++ for_all_rss_queues(adapter, rxo, i) { + rc = be_cmd_rxq_create(adapter, &rxo->q, rxo->cq.id, +- rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, +- adapter->if_handle, +- (i > 0) ? 1 : 0/* rss enable */, &rxo->rss_id); ++ rx_frag_size, adapter->if_handle, ++ true, &rxo->rss_id); + if (rc) + return rc; + } +@@ -2386,48 +2295,47 @@ static int be_rx_queues_setup(struct be_adapter *adapter) + } + } + rc = be_cmd_rss_config(adapter, rsstable, 128); +- + if (rc) + return rc; + } + + /* First time posting */ +- for_all_rx_queues(adapter, rxo, i) { ++ for_all_rx_queues(adapter, rxo, i) + be_post_rx_frags(rxo, GFP_KERNEL); +- napi_enable(&rxo->rx_eq.napi); +- } + return 0; + } + + static int be_open(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_eq_obj *tx_eq = &adapter->tx_eq; ++ struct be_eq_obj *eqo; + struct be_rx_obj *rxo; ++ struct be_tx_obj *txo; + u8 link_status; + int status, i; + +- status = be_rx_queues_setup(adapter); ++ status = be_rx_qs_create(adapter); + if (status) + goto err; + +- napi_enable(&tx_eq->napi); +- + be_irq_register(adapter); + + if (!lancer_chip(adapter)) + be_intr_set(adapter, true); + +- /* The evt queues are created in unarmed state; arm them */ +- for_all_rx_queues(adapter, rxo, i) { +- be_eq_notify(adapter, rxo->rx_eq.q.id, true, false, 0); ++ for_all_rx_queues(adapter, rxo, i) + be_cq_notify(adapter, rxo->cq.id, true, 0); +- } +- be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + +- /* Now that interrupts are on we can process async mcc */ ++ for_all_tx_queues(adapter, txo, i) ++ be_cq_notify(adapter, txo->cq.id, true, 0); ++ + be_async_mcc_enable(adapter); + ++ for_all_evt_queues(adapter, eqo, i) { ++ napi_enable(&eqo->napi); ++ be_eq_notify(adapter, eqo->q.id, true, false, 0); ++ } ++ + status = be_cmd_link_status_query(adapter, NULL, NULL, + &link_status, 0); + if (!status) +@@ -2537,11 +2445,14 @@ static int be_clear(struct be_adapter *adapter) + be_cmd_if_destroy(adapter, adapter->if_handle, 0); + + be_mcc_queues_destroy(adapter); +- be_rx_queues_destroy(adapter); ++ be_rx_cqs_destroy(adapter); + be_tx_queues_destroy(adapter); ++ be_evt_queues_destroy(adapter); + + /* tell fw we're done with firing cmds */ + be_cmd_fw_clean(adapter); ++ ++ be_msix_disable(adapter); + return 0; + } + +@@ -2631,24 +2542,29 @@ static int be_setup(struct be_adapter *adapter) + struct net_device *netdev = adapter->netdev; + u32 cap_flags, en_flags; + u32 tx_fc, rx_fc; +- int status, i; ++ int status; + u8 mac[ETH_ALEN]; +- struct be_tx_obj *txo; + + be_setup_init(adapter); + + be_cmd_req_native_mode(adapter); + +- status = be_tx_queues_create(adapter); +- if (status != 0) ++ be_msix_enable(adapter); ++ ++ status = be_evt_queues_create(adapter); ++ if (status) + goto err; + +- status = be_rx_queues_create(adapter); +- if (status != 0) ++ status = be_tx_cqs_create(adapter); ++ if (status) ++ goto err; ++ ++ status = be_rx_cqs_create(adapter); ++ if (status) + goto err; + + status = be_mcc_queues_create(adapter); +- if (status != 0) ++ if (status) + goto err; + + memset(mac, 0, ETH_ALEN); +@@ -2674,12 +2590,6 @@ static int be_setup(struct be_adapter *adapter) + if (status != 0) + goto err; + +- for_all_tx_queues(adapter, txo, i) { +- status = be_cmd_txq_create(adapter, &txo->q, &txo->cq); +- if (status) +- goto err; +- } +- + /* The VF's permanent mac queried from card is incorrect. + * For BEx: Query the mac configued by the PF using if_handle + * For Lancer: Get and use mac_list to obtain mac address. +@@ -2697,6 +2607,10 @@ static int be_setup(struct be_adapter *adapter) + } + } + ++ status = be_tx_qs_create(adapter); ++ if (status) ++ goto err; ++ + be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); + + status = be_vid_config(adapter, false, 0); +@@ -2736,12 +2650,13 @@ err: + static void be_netpoll(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_rx_obj *rxo; ++ struct be_eq_obj *eqo; + int i; + +- event_handle(adapter, &adapter->tx_eq, false); +- for_all_rx_queues(adapter, rxo, i) +- event_handle(adapter, &rxo->rx_eq, true); ++ for_all_evt_queues(adapter, eqo, i) ++ event_handle(eqo); ++ ++ return; + } + #endif + +@@ -3102,7 +3017,7 @@ static const struct net_device_ops be_netdev_ops = { + static void be_netdev_init(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_rx_obj *rxo; ++ struct be_eq_obj *eqo; + int i; + + netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | +@@ -3121,16 +3036,12 @@ static void be_netdev_init(struct net_device *netdev) + + netif_set_gso_max_size(netdev, 65535); + +- BE_SET_NETDEV_OPS(netdev, &be_netdev_ops); ++ netdev->netdev_ops = &be_netdev_ops; + + SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); + +- for_all_rx_queues(adapter, rxo, i) +- netif_napi_add(netdev, &rxo->rx_eq.napi, be_poll_rx, +- BE_NAPI_WEIGHT); +- +- netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, +- BE_NAPI_WEIGHT); ++ for_all_evt_queues(adapter, eqo, i) ++ netif_napi_add(netdev, &eqo->napi, be_poll, BE_NAPI_WEIGHT); + } + + static void be_unmap_pci_bars(struct be_adapter *adapter) +@@ -3301,8 +3212,6 @@ static void __devexit be_remove(struct pci_dev *pdev) + + be_sriov_disable(adapter); + +- be_msix_disable(adapter); +- + pci_set_drvdata(pdev, NULL); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -3469,6 +3378,7 @@ static void be_worker(struct work_struct *work) + struct be_adapter *adapter = + container_of(work, struct be_adapter, work.work); + struct be_rx_obj *rxo; ++ struct be_eq_obj *eqo; + int i; + + if (lancer_chip(adapter)) +@@ -3479,15 +3389,7 @@ static void be_worker(struct work_struct *work) + /* when interrupts are not yet enabled, just reap any pending + * mcc completions */ + if (!netif_running(adapter->netdev)) { +- int mcc_compl, status = 0; +- +- mcc_compl = be_process_mcc(adapter, &status); +- +- if (mcc_compl) { +- struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; +- be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl); +- } +- ++ be_process_mcc(adapter); + goto reschedule; + } + +@@ -3500,14 +3402,15 @@ static void be_worker(struct work_struct *work) + } + + for_all_rx_queues(adapter, rxo, i) { +- be_rx_eqd_update(adapter, rxo); +- + if (rxo->rx_post_starved) { + rxo->rx_post_starved = false; + be_post_rx_frags(rxo, GFP_KERNEL); + } + } + ++ for_all_evt_queues(adapter, eqo, i) ++ be_eqd_update(adapter, eqo); ++ + reschedule: + adapter->work_counter++; + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); +@@ -3593,6 +3496,12 @@ static int __devinit be_probe(struct pci_dev *pdev, + if (status) + goto ctrl_clean; + ++ /* The INTR bit may be set in the card when probed by a kdump kernel ++ * after a crash. ++ */ ++ if (!lancer_chip(adapter)) ++ be_intr_set(adapter, false); ++ + status = be_stats_init(adapter); + if (status) + goto ctrl_clean; +@@ -3601,14 +3510,6 @@ static int __devinit be_probe(struct pci_dev *pdev, + if (status) + goto stats_clean; + +- /* The INTR bit may be set in the card when probed by a kdump kernel +- * after a crash. +- */ +- if (!lancer_chip(adapter)) +- be_intr_set(adapter, false); +- +- be_msix_enable(adapter); +- + INIT_DELAYED_WORK(&adapter->work, be_worker); + adapter->rx_fc = adapter->tx_fc = true; + +@@ -3621,7 +3522,8 @@ static int __devinit be_probe(struct pci_dev *pdev, + if (status != 0) + goto unsetup; + +- dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); ++ dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), ++ adapter->port_num); + + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; +@@ -3665,7 +3567,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) + } + be_clear(adapter); + +- be_msix_disable(adapter); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +@@ -3687,7 +3588,6 @@ static int be_resume(struct pci_dev *pdev) + pci_set_power_state(pdev, 0); + pci_restore_state(pdev); + +- be_msix_enable(adapter); + /* tell fw we're ready to fire cmds */ + status = be_cmd_fw_init(adapter); + if (status) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0033-be2net-cancel-be_worker-during-EEH-recovery.patch b/debian/patches/features/all/be2net/0033-be2net-cancel-be_worker-during-EEH-recovery.patch new file mode 100644 index 000000000..a8ce85ea7 --- /dev/null +++ b/debian/patches/features/all/be2net/0033-be2net-cancel-be_worker-during-EEH-recovery.patch @@ -0,0 +1,90 @@ +From: Sathya Perla +Date: Thu, 23 Feb 2012 18:50:13 +0000 +Subject: [PATCH 33/58] be2net: cancel be_worker during EEH recovery + +commit 191eb7563164529bc7d6a693742fe5bed33cf004 upstream. + +EEH recovery involves ring cleanup and re-creation. The worker +thread must not run during EEH cleanup/resume. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 1 + + drivers/net/ethernet/emulex/benet/be_main.c | 13 ++++++++----- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 86f51de..4b1994d 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -304,6 +304,7 @@ struct be_vf_cfg { + }; + + #define BE_FLAGS_LINK_STATUS_INIT 1 ++#define BE_FLAGS_WORKER_SCHEDULED (1 << 3) + + struct be_adapter { + struct pci_dev *pdev; +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 4a3a186..2c146ac 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2439,6 +2439,11 @@ static void be_vf_clear(struct be_adapter *adapter) + + static int be_clear(struct be_adapter *adapter) + { ++ if (adapter->flags & BE_FLAGS_WORKER_SCHEDULED) { ++ cancel_delayed_work_sync(&adapter->work); ++ adapter->flags &= ~BE_FLAGS_WORKER_SCHEDULED; ++ } ++ + if (sriov_enabled(adapter)) + be_vf_clear(adapter); + +@@ -2640,6 +2645,9 @@ static int be_setup(struct be_adapter *adapter) + goto err; + } + ++ schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); ++ adapter->flags |= BE_FLAGS_WORKER_SCHEDULED; ++ + return 0; + err: + be_clear(adapter); +@@ -3200,8 +3208,6 @@ static void __devexit be_remove(struct pci_dev *pdev) + if (!adapter) + return; + +- cancel_delayed_work_sync(&adapter->work); +- + unregister_netdev(adapter->netdev); + + be_clear(adapter); +@@ -3525,7 +3531,6 @@ static int __devinit be_probe(struct pci_dev *pdev, + dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev), + adapter->port_num); + +- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; + + unsetup: +@@ -3555,7 +3560,6 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) + struct be_adapter *adapter = pci_get_drvdata(pdev); + struct net_device *netdev = adapter->netdev; + +- cancel_delayed_work_sync(&adapter->work); + if (adapter->wol) + be_setup_wol(adapter, true); + +@@ -3604,7 +3608,6 @@ static int be_resume(struct pci_dev *pdev) + if (adapter->wol) + be_setup_wol(adapter, false); + +- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0034-be2net-fix-tx-completion-cleanup.patch b/debian/patches/features/all/be2net/0034-be2net-fix-tx-completion-cleanup.patch new file mode 100644 index 000000000..5e0575a8c --- /dev/null +++ b/debian/patches/features/all/be2net/0034-be2net-fix-tx-completion-cleanup.patch @@ -0,0 +1,133 @@ +From: Sathya Perla +Date: Thu, 23 Feb 2012 18:50:14 +0000 +Subject: [PATCH 34/58] be2net: fix tx completion cleanup + +commit 0ae57bb3df562e57ac89ad7bc524b6f2e83235f9 upstream. + +As a part of be_close(), instead of waiting for a max of 200ms for each TXQ, +wait for a total of 200ms for completions from all TXQs to arrive. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 75 +++++++++++++++------------ + 1 file changed, 42 insertions(+), 33 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 2c146ac..dce97dc 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1555,51 +1555,62 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) + rxq->tail = rxq->head = 0; + } + +-static void be_tx_compl_clean(struct be_adapter *adapter, +- struct be_tx_obj *txo) ++static void be_tx_compl_clean(struct be_adapter *adapter) + { +- struct be_queue_info *tx_cq = &txo->cq; +- struct be_queue_info *txq = &txo->q; ++ struct be_tx_obj *txo; ++ struct be_queue_info *txq; + struct be_eth_tx_compl *txcp; + u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0; +- struct sk_buff **sent_skbs = txo->sent_skb_list; + struct sk_buff *sent_skb; + bool dummy_wrb; ++ int i, pending_txqs; + + /* Wait for a max of 200ms for all the tx-completions to arrive. */ + do { +- while ((txcp = be_tx_compl_get(tx_cq))) { +- end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, +- wrb_index, txcp); +- num_wrbs += be_tx_compl_process(adapter, txo, end_idx); +- cmpl++; +- } +- if (cmpl) { +- be_cq_notify(adapter, tx_cq->id, false, cmpl); +- atomic_sub(num_wrbs, &txq->used); +- cmpl = 0; +- num_wrbs = 0; ++ pending_txqs = adapter->num_tx_qs; ++ ++ for_all_tx_queues(adapter, txo, i) { ++ txq = &txo->q; ++ while ((txcp = be_tx_compl_get(&txo->cq))) { ++ end_idx = ++ AMAP_GET_BITS(struct amap_eth_tx_compl, ++ wrb_index, txcp); ++ num_wrbs += be_tx_compl_process(adapter, txo, ++ end_idx); ++ cmpl++; ++ } ++ if (cmpl) { ++ be_cq_notify(adapter, txo->cq.id, false, cmpl); ++ atomic_sub(num_wrbs, &txq->used); ++ cmpl = 0; ++ num_wrbs = 0; ++ } ++ if (atomic_read(&txq->used) == 0) ++ pending_txqs--; + } + +- if (atomic_read(&txq->used) == 0 || ++timeo > 200) ++ if (pending_txqs == 0 || ++timeo > 200) + break; + + mdelay(1); + } while (true); + +- if (atomic_read(&txq->used)) +- dev_err(&adapter->pdev->dev, "%d pending tx-completions\n", +- atomic_read(&txq->used)); +- +- /* free posted tx for which compls will never arrive */ +- while (atomic_read(&txq->used)) { +- sent_skb = sent_skbs[txq->tail]; +- end_idx = txq->tail; +- index_adv(&end_idx, +- wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1, +- txq->len); +- num_wrbs = be_tx_compl_process(adapter, txo, end_idx); +- atomic_sub(num_wrbs, &txq->used); ++ for_all_tx_queues(adapter, txo, i) { ++ txq = &txo->q; ++ if (atomic_read(&txq->used)) ++ dev_err(&adapter->pdev->dev, "%d pending tx-compls\n", ++ atomic_read(&txq->used)); ++ ++ /* free posted tx for which compls will never arrive */ ++ while (atomic_read(&txq->used)) { ++ sent_skb = txo->sent_skb_list[txq->tail]; ++ end_idx = txq->tail; ++ num_wrbs = wrb_cnt_for_skb(adapter, sent_skb, ++ &dummy_wrb); ++ index_adv(&end_idx, num_wrbs - 1, txq->len); ++ num_wrbs = be_tx_compl_process(adapter, txo, end_idx); ++ atomic_sub(num_wrbs, &txq->used); ++ } + } + } + +@@ -2228,7 +2239,6 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) + static int be_close(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_tx_obj *txo; + struct be_eq_obj *eqo; + int i; + +@@ -2251,8 +2261,7 @@ static int be_close(struct net_device *netdev) + /* Wait for all pending tx completions to arrive so that + * all tx skbs are freed. + */ +- for_all_tx_queues(adapter, txo, i) +- be_tx_compl_clean(adapter, txo); ++ be_tx_compl_clean(adapter); + + be_rx_qs_destroy(adapter); + return 0; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0035-be2net-reset-queue-address-after-freeing.patch b/debian/patches/features/all/be2net/0035-be2net-reset-queue-address-after-freeing.patch new file mode 100644 index 000000000..4164b289c --- /dev/null +++ b/debian/patches/features/all/be2net/0035-be2net-reset-queue-address-after-freeing.patch @@ -0,0 +1,44 @@ +From: Sathya Perla +Date: Thu, 23 Feb 2012 18:50:15 +0000 +Subject: [PATCH 35/58] be2net: reset queue address after freeing + +commit 1cfafab965198bc0d9cb794af5065d0797969727 upstream. + +This will prevent double free in some cases where be_clear() is called +for cleanup when be_setup() fails half-way. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index dce97dc..c1b9cdf 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -127,9 +127,11 @@ static inline bool be_is_mc(struct be_adapter *adapter) { + static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) + { + struct be_dma_mem *mem = &q->dma_mem; +- if (mem->va) ++ if (mem->va) { + dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va, + mem->dma); ++ mem->va = NULL; ++ } + } + + static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, +@@ -1652,7 +1654,7 @@ static int be_evt_queues_create(struct be_adapter *adapter) + if (rc) + return rc; + } +- return rc; ++ return 0; + } + + static void be_mcc_queues_destroy(struct be_adapter *adapter) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0036-be2net-enable-RSS-for-ipv6-pkts.patch b/debian/patches/features/all/be2net/0036-be2net-enable-RSS-for-ipv6-pkts.patch new file mode 100644 index 000000000..0d03b030f --- /dev/null +++ b/debian/patches/features/all/be2net/0036-be2net-enable-RSS-for-ipv6-pkts.patch @@ -0,0 +1,29 @@ +From: Sathya Perla +Date: Thu, 23 Feb 2012 18:50:16 +0000 +Subject: [PATCH 36/58] be2net: enable RSS for ipv6 pkts + +commit 1ca7ba921e8af04266881bc485be08d4fac5f1bc upstream. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 6432efa..398fb5c 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1694,7 +1694,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size) + OPCODE_ETH_RSS_CONFIG, sizeof(*req), wrb, NULL); + + req->if_id = cpu_to_le32(adapter->if_handle); +- req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4); ++ req->enable_rss = cpu_to_le16(RSS_ENABLE_TCP_IPV4 | RSS_ENABLE_IPV4 | ++ RSS_ENABLE_TCP_IPV6 | RSS_ENABLE_IPV6); + req->cpu_table_size_log2 = cpu_to_le16(fls(table_size) - 1); + memcpy(req->cpu_table, rsstable, table_size); + memcpy(req->hash, myhash, sizeof(myhash)); +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0037-be2net-update-driver-version.patch b/debian/patches/features/all/be2net/0037-be2net-update-driver-version.patch new file mode 100644 index 000000000..5e0e822de --- /dev/null +++ b/debian/patches/features/all/be2net/0037-be2net-update-driver-version.patch @@ -0,0 +1,28 @@ +From: Sathya Perla +Date: Thu, 23 Feb 2012 18:50:17 +0000 +Subject: [PATCH 37/58] be2net: update driver version + +commit d708f6039b21ca8f0508ba1da1aaf3d00a36446f upstream. + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 4b1994d..c357172 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -33,7 +33,7 @@ + + #include "be_hw.h" + +-#define DRV_VER "4.0.100u" ++#define DRV_VER "4.2.116u" + #define DRV_NAME "be2net" + #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" + #define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0038-be2net-Remove-unused-OFFSET_IN_PAGE-macro.patch b/debian/patches/features/all/be2net/0038-be2net-Remove-unused-OFFSET_IN_PAGE-macro.patch new file mode 100644 index 000000000..7c696874a --- /dev/null +++ b/debian/patches/features/all/be2net/0038-be2net-Remove-unused-OFFSET_IN_PAGE-macro.patch @@ -0,0 +1,30 @@ +From: Roland Dreier +Date: Wed, 29 Feb 2012 20:40:46 +0000 +Subject: [PATCH 38/58] be2net: Remove unused OFFSET_IN_PAGE() macro + +commit 97767a87f3be8834192dc3fc9412aaccf708d87f upstream. + +Signed-off-by: Roland Dreier +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index c357172..ab24e46 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -442,10 +442,6 @@ extern const struct ethtool_ops be_ethtool_ops; + ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ + (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) + +-/* Byte offset into the page corresponding to given address */ +-#define OFFSET_IN_PAGE(addr) \ +- ((size_t)(addr) & (PAGE_SIZE_4K-1)) +- + /* Returns bit offset within a DWORD of a bitfield */ + #define AMAP_BIT_OFFSET(_struct, field) \ + (((size_t)&(((_struct *)0)->field))%32) +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0039-be2net-enable-WOL-by-default-if-h-w-supports-it.patch b/debian/patches/features/all/be2net/0039-be2net-enable-WOL-by-default-if-h-w-supports-it.patch new file mode 100644 index 000000000..eda742bc2 --- /dev/null +++ b/debian/patches/features/all/be2net/0039-be2net-enable-WOL-by-default-if-h-w-supports-it.patch @@ -0,0 +1,274 @@ +From: Ajit Khaparde +Date: Sun, 18 Mar 2012 06:23:11 +0000 +Subject: [PATCH 39/58] be2net: enable WOL by default if h/w supports it + +commit 4762f6cec4455f3bbe4ca82c100fe5d85d3c02a2 upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 26 ++++++++++- + drivers/net/ethernet/emulex/benet/be_cmds.c | 55 ++++++++++++++++++++++++ + drivers/net/ethernet/emulex/benet/be_cmds.h | 28 ++++++++++++ + drivers/net/ethernet/emulex/benet/be_ethtool.c | 27 +++++------- + drivers/net/ethernet/emulex/benet/be_main.c | 17 ++++++++ + 5 files changed, 136 insertions(+), 17 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index ab24e46..cabe1b8 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -52,6 +52,10 @@ + #define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */ + #define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */ + #define OC_DEVICE_ID5 0x720 /* Device Id for Skyhawk cards */ ++#define OC_SUBSYS_DEVICE_ID1 0xE602 ++#define OC_SUBSYS_DEVICE_ID2 0xE642 ++#define OC_SUBSYS_DEVICE_ID3 0xE612 ++#define OC_SUBSYS_DEVICE_ID4 0xE652 + + static inline char *nic_name(struct pci_dev *pdev) + { +@@ -365,7 +369,6 @@ struct be_adapter { + bool fw_timeout; + u32 port_num; + bool promiscuous; +- bool wol; + u32 function_mode; + u32 function_caps; + u32 rx_fc; /* Rx flow control */ +@@ -386,6 +389,8 @@ struct be_adapter { + u32 sli_family; + u8 hba_port_num; + u16 pvid; ++ u8 wol_cap; ++ bool wol; + }; + + #define be_physfn(adapter) (!adapter->is_virtfn) +@@ -549,9 +554,28 @@ static inline bool be_error(struct be_adapter *adapter) + return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout; + } + ++static inline bool be_is_wol_excluded(struct be_adapter *adapter) ++{ ++ struct pci_dev *pdev = adapter->pdev; ++ ++ if (!be_physfn(adapter)) ++ return true; ++ ++ switch (pdev->subsystem_device) { ++ case OC_SUBSYS_DEVICE_ID1: ++ case OC_SUBSYS_DEVICE_ID2: ++ case OC_SUBSYS_DEVICE_ID3: ++ case OC_SUBSYS_DEVICE_ID4: ++ return true; ++ default: ++ return false; ++ } ++} ++ + extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, + u16 num_popped); + extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); + extern void be_parse_stats(struct be_adapter *adapter); + extern int be_load_fw(struct be_adapter *adapter, u8 *func); ++extern bool be_is_wol_supported(struct be_adapter *adapter); + #endif /* BE_H */ +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 398fb5c..d72c2b4 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -2418,3 +2418,58 @@ err: + spin_unlock_bh(&adapter->mcc_lock); + return status; + } ++ ++int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_acpi_wol_magic_config_v1 *req; ++ int status; ++ int payload_len = sizeof(*req); ++ struct be_dma_mem cmd; ++ ++ memset(&cmd, 0, sizeof(struct be_dma_mem)); ++ cmd.size = sizeof(struct be_cmd_resp_acpi_wol_magic_config_v1); ++ cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, ++ &cmd.dma); ++ if (!cmd.va) { ++ dev_err(&adapter->pdev->dev, ++ "Memory allocation failure\n"); ++ return -ENOMEM; ++ } ++ ++ if (mutex_lock_interruptible(&adapter->mbox_lock)) ++ return -1; ++ ++ wrb = wrb_from_mbox(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = cmd.va; ++ ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, ++ OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, ++ payload_len, wrb, &cmd); ++ ++ req->hdr.version = 1; ++ req->query_options = BE_GET_WOL_CAP; ++ ++ status = be_mbox_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; ++ resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *) cmd.va; ++ ++ /* the command could succeed misleadingly on old f/w ++ * which is not aware of the V1 version. fake an error. */ ++ if (resp->hdr.response_length < payload_len) { ++ status = -1; ++ goto err; ++ } ++ adapter->wol_cap = resp->wol_settings; ++ } ++err: ++ mutex_unlock(&adapter->mbox_lock); ++ pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); ++ return status; ++} +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 687c420..345d49e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1206,6 +1206,33 @@ struct be_cmd_req_acpi_wol_magic_config{ + u8 rsvd2[2]; + } __packed; + ++struct be_cmd_req_acpi_wol_magic_config_v1 { ++ struct be_cmd_req_hdr hdr; ++ u8 rsvd0[2]; ++ u8 query_options; ++ u8 rsvd1[5]; ++ u32 rsvd2[288]; ++ u8 magic_mac[6]; ++ u8 rsvd3[22]; ++} __packed; ++ ++struct be_cmd_resp_acpi_wol_magic_config_v1 { ++ struct be_cmd_resp_hdr hdr; ++ u8 rsvd0[2]; ++ u8 wol_settings; ++ u8 rsvd1[5]; ++ u32 rsvd2[295]; ++} __packed; ++ ++#define BE_GET_WOL_CAP 2 ++ ++#define BE_WOL_CAP 0x1 ++#define BE_PME_D0_CAP 0x8 ++#define BE_PME_D1_CAP 0x10 ++#define BE_PME_D2_CAP 0x20 ++#define BE_PME_D3HOT_CAP 0x40 ++#define BE_PME_D3COLD_CAP 0x80 ++ + /********************** LoopBack test *********************/ + struct be_cmd_req_loopback_test { + struct be_cmd_req_hdr hdr; +@@ -1590,4 +1617,5 @@ extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, + bool *pmac_id_active, u32 *pmac_id, u8 *mac); + extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, + u8 mac_count, u32 domain); ++extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index d98ad7e..e0eb995 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -600,26 +600,16 @@ be_set_phys_id(struct net_device *netdev, + return 0; + } + +-static bool +-be_is_wol_supported(struct be_adapter *adapter) +-{ +- if (!be_physfn(adapter)) +- return false; +- else +- return true; +-} + + static void + be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) + { + struct be_adapter *adapter = netdev_priv(netdev); + +- if (be_is_wol_supported(adapter)) +- wol->supported = WAKE_MAGIC; +- +- if (adapter->wol) +- wol->wolopts = WAKE_MAGIC; +- else ++ if (be_is_wol_supported(adapter)) { ++ wol->supported |= WAKE_MAGIC; ++ wol->wolopts |= WAKE_MAGIC; ++ } else + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); + } +@@ -630,9 +620,14 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) + struct be_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & ~WAKE_MAGIC) +- return -EINVAL; ++ return -EOPNOTSUPP; ++ ++ if (!be_is_wol_supported(adapter)) { ++ dev_warn(&adapter->pdev->dev, "WOL not supported\n"); ++ return -EOPNOTSUPP; ++ } + +- if ((wol->wolopts & WAKE_MAGIC) && be_is_wol_supported(adapter)) ++ if (wol->wolopts & WAKE_MAGIC) + adapter->wol = true; + else + adapter->wol = false; +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index c1b9cdf..70b138f 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -3236,6 +3236,12 @@ static void __devexit be_remove(struct pci_dev *pdev) + free_netdev(adapter->netdev); + } + ++bool be_is_wol_supported(struct be_adapter *adapter) ++{ ++ return ((adapter->wol_cap & BE_WOL_CAP) && ++ !be_is_wol_excluded(adapter)) ? true : false; ++} ++ + static int be_get_config(struct be_adapter *adapter) + { + int status; +@@ -3254,6 +3260,17 @@ static int be_get_config(struct be_adapter *adapter) + if (status) + return status; + ++ status = be_cmd_get_acpi_wol_cap(adapter); ++ if (status) { ++ /* in case of a failure to get wol capabillities ++ * check the exclusion list to determine WOL capability */ ++ if (!be_is_wol_excluded(adapter)) ++ adapter->wol_cap |= BE_WOL_CAP; ++ } ++ ++ if (be_is_wol_supported(adapter)) ++ adapter->wol = true; ++ + return 0; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0040-be2net-Program-secondary-UC-MAC-address-into-MAC-fil.patch b/debian/patches/features/all/be2net/0040-be2net-Program-secondary-UC-MAC-address-into-MAC-fil.patch new file mode 100644 index 000000000..935bc3e45 --- /dev/null +++ b/debian/patches/features/all/be2net/0040-be2net-Program-secondary-UC-MAC-address-into-MAC-fil.patch @@ -0,0 +1,177 @@ +From: Ajit Khaparde +Date: Sun, 18 Mar 2012 06:23:21 +0000 +Subject: [PATCH 40/58] be2net: Program secondary UC MAC address into MAC + filter + +commit fbc13f018c0043146f8eccc7d6a6c0e66339e2d5 upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 6 ++- + drivers/net/ethernet/emulex/benet/be_main.c | 53 ++++++++++++++++++++++++--- + 2 files changed, 53 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index cabe1b8..03fc3db 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -309,6 +309,8 @@ struct be_vf_cfg { + + #define BE_FLAGS_LINK_STATUS_INIT 1 + #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) ++#define BE_UC_PMAC_COUNT 30 ++#define BE_VF_UC_PMAC_COUNT 2 + + struct be_adapter { + struct pci_dev *pdev; +@@ -361,7 +363,7 @@ struct be_adapter { + /* Ethtool knobs and info */ + char fw_ver[FW_VER_LEN]; + int if_handle; /* Used to configure filtering */ +- u32 pmac_id; /* MAC addr handle used by BE card */ ++ u32 *pmac_id; /* MAC addr handle used by BE card */ + u32 beacon_state; /* for set_phys_id */ + + bool eeh_err; +@@ -391,6 +393,8 @@ struct be_adapter { + u16 pvid; + u8 wol_cap; + bool wol; ++ u32 max_pmac_cnt; /* Max secondary UC MACs programmable */ ++ u32 uc_macs; /* Count of secondary UC MAC programmed */ + }; + + #define be_physfn(adapter) (!adapter->is_virtfn) +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 70b138f..b8b34f5 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -235,7 +235,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) + struct sockaddr *addr = p; + int status = 0; + u8 current_mac[ETH_ALEN]; +- u32 pmac_id = adapter->pmac_id; ++ u32 pmac_id = adapter->pmac_id[0]; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; +@@ -248,7 +248,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) + + if (memcmp(addr->sa_data, current_mac, ETH_ALEN)) { + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, +- adapter->if_handle, &adapter->pmac_id, 0); ++ adapter->if_handle, &adapter->pmac_id[0], 0); + if (status) + goto err; + +@@ -877,6 +877,29 @@ static void be_set_rx_mode(struct net_device *netdev) + goto done; + } + ++ if (netdev_uc_count(netdev) != adapter->uc_macs) { ++ struct netdev_hw_addr *ha; ++ int i = 1; /* First slot is claimed by the Primary MAC */ ++ ++ for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) { ++ be_cmd_pmac_del(adapter, adapter->if_handle, ++ adapter->pmac_id[i], 0); ++ } ++ ++ if (netdev_uc_count(netdev) > adapter->max_pmac_cnt) { ++ be_cmd_rx_filter(adapter, IFF_PROMISC, ON); ++ adapter->promiscuous = true; ++ goto done; ++ } ++ ++ netdev_for_each_uc_addr(ha, adapter->netdev) { ++ adapter->uc_macs++; /* First slot is for Primary MAC */ ++ be_cmd_pmac_add(adapter, (u8 *)ha->addr, ++ adapter->if_handle, ++ &adapter->pmac_id[adapter->uc_macs], 0); ++ } ++ } ++ + be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); + done: + return; +@@ -2450,6 +2473,8 @@ static void be_vf_clear(struct be_adapter *adapter) + + static int be_clear(struct be_adapter *adapter) + { ++ int i = 1; ++ + if (adapter->flags & BE_FLAGS_WORKER_SCHEDULED) { + cancel_delayed_work_sync(&adapter->work); + adapter->flags &= ~BE_FLAGS_WORKER_SCHEDULED; +@@ -2458,6 +2483,10 @@ static int be_clear(struct be_adapter *adapter) + if (sriov_enabled(adapter)) + be_vf_clear(adapter); + ++ for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) ++ be_cmd_pmac_del(adapter, adapter->if_handle, ++ adapter->pmac_id[i], 0); ++ + be_cmd_if_destroy(adapter, adapter->if_handle, 0); + + be_mcc_queues_destroy(adapter); +@@ -2469,6 +2498,7 @@ static int be_clear(struct be_adapter *adapter) + be_cmd_fw_clean(adapter); + + be_msix_disable(adapter); ++ kfree(adapter->pmac_id); + return 0; + } + +@@ -2544,10 +2574,10 @@ static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) + false, adapter->if_handle, pmac_id); + + if (!status) +- adapter->pmac_id = pmac_id; ++ adapter->pmac_id[0] = pmac_id; + } else { + status = be_cmd_pmac_add(adapter, mac, +- adapter->if_handle, &adapter->pmac_id, 0); ++ adapter->if_handle, &adapter->pmac_id[0], 0); + } + do_none: + return status; +@@ -2602,7 +2632,7 @@ static int be_setup(struct be_adapter *adapter) + } + status = be_cmd_if_create(adapter, cap_flags, en_flags, + netdev->dev_addr, &adapter->if_handle, +- &adapter->pmac_id, 0); ++ &adapter->pmac_id[0], 0); + if (status != 0) + goto err; + +@@ -3051,6 +3081,8 @@ static void be_netdev_init(struct net_device *netdev) + netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + ++ netdev->priv_flags |= IFF_UNICAST_FLT; ++ + netdev->flags |= IFF_MULTICAST; + + netif_set_gso_max_size(netdev, 65535); +@@ -3256,6 +3288,17 @@ static int be_get_config(struct be_adapter *adapter) + else + adapter->max_vlans = BE_NUM_VLANS_SUPPORTED; + ++ if (be_physfn(adapter)) ++ adapter->max_pmac_cnt = BE_UC_PMAC_COUNT; ++ else ++ adapter->max_pmac_cnt = BE_VF_UC_PMAC_COUNT; ++ ++ /* primary mac needs 1 pmac entry */ ++ adapter->pmac_id = kcalloc(adapter->max_pmac_cnt + 1, ++ sizeof(u32), GFP_KERNEL); ++ if (!adapter->pmac_id) ++ return -ENOMEM; ++ + status = be_cmd_get_cntl_attributes(adapter); + if (status) + return status; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0041-be2net-Fix-number-of-vlan-slots-in-flex-mode.patch b/debian/patches/features/all/be2net/0041-be2net-Fix-number-of-vlan-slots-in-flex-mode.patch new file mode 100644 index 000000000..f95dc38ac --- /dev/null +++ b/debian/patches/features/all/be2net/0041-be2net-Fix-number-of-vlan-slots-in-flex-mode.patch @@ -0,0 +1,30 @@ +From: Ajit Khaparde +Date: Sun, 18 Mar 2012 06:23:31 +0000 +Subject: [PATCH 41/58] be2net: Fix number of vlan slots in flex mode + +commit 456d9c962bb5824423fa93277c8f7f5b2e3d5e1c upstream. + +In flex10 mode the number of vlan slots supported is halved. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index b8b34f5..c9a9bf0 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -3284,7 +3284,7 @@ static int be_get_config(struct be_adapter *adapter) + return status; + + if (adapter->function_mode & FLEX10_MODE) +- adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4; ++ adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/8; + else + adapter->max_vlans = BE_NUM_VLANS_SUPPORTED; + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0042-be2net-fix-programming-of-VLAN-tags-for-VF.patch b/debian/patches/features/all/be2net/0042-be2net-fix-programming-of-VLAN-tags-for-VF.patch new file mode 100644 index 000000000..c8e86963b --- /dev/null +++ b/debian/patches/features/all/be2net/0042-be2net-fix-programming-of-VLAN-tags-for-VF.patch @@ -0,0 +1,255 @@ +From: Ajit Khaparde +Date: Sun, 18 Mar 2012 06:23:41 +0000 +Subject: [PATCH 42/58] be2net: fix programming of VLAN tags for VF + +commit f1f3ee1bcc996e21f122442fd8c34de51622c76a upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 1 + + drivers/net/ethernet/emulex/benet/be_cmds.c | 83 +++++++++++++++++++++++++++ + drivers/net/ethernet/emulex/benet/be_cmds.h | 55 ++++++++++++++++++ + drivers/net/ethernet/emulex/benet/be_main.c | 23 ++++++-- + 4 files changed, 157 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 03fc3db..9576ac0 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -303,6 +303,7 @@ struct be_vf_cfg { + unsigned char mac_addr[ETH_ALEN]; + int if_handle; + int pmac_id; ++ u16 def_vid; + u16 vlan_tag; + u32 tx_rate; + }; +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index d72c2b4..67b030d 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -2419,6 +2419,89 @@ err: + return status; + } + ++int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, ++ u32 domain, u16 intf_id) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_set_hsw_config *req; ++ void *ctxt; ++ int status; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ctxt = &req->context; ++ ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_SET_HSW_CONFIG, sizeof(*req), wrb, NULL); ++ ++ req->hdr.domain = domain; ++ AMAP_SET_BITS(struct amap_set_hsw_context, interface_id, ctxt, intf_id); ++ if (pvid) { ++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid_valid, ctxt, 1); ++ AMAP_SET_BITS(struct amap_set_hsw_context, pvid, ctxt, pvid); ++ } ++ ++ be_dws_cpu_to_le(req->context, sizeof(req->context)); ++ status = be_mcc_notify_wait(adapter); ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ ++/* Get Hyper switch config */ ++int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, ++ u32 domain, u16 intf_id) ++{ ++ struct be_mcc_wrb *wrb; ++ struct be_cmd_req_get_hsw_config *req; ++ void *ctxt; ++ int status; ++ u16 vid; ++ ++ spin_lock_bh(&adapter->mcc_lock); ++ ++ wrb = wrb_from_mccq(adapter); ++ if (!wrb) { ++ status = -EBUSY; ++ goto err; ++ } ++ ++ req = embedded_payload(wrb); ++ ctxt = &req->context; ++ ++ be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, ++ OPCODE_COMMON_GET_HSW_CONFIG, sizeof(*req), wrb, NULL); ++ ++ req->hdr.domain = domain; ++ AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt, ++ intf_id); ++ AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); ++ be_dws_cpu_to_le(req->context, sizeof(req->context)); ++ ++ status = be_mcc_notify_wait(adapter); ++ if (!status) { ++ struct be_cmd_resp_get_hsw_config *resp = ++ embedded_payload(wrb); ++ be_dws_le_to_cpu(&resp->context, ++ sizeof(resp->context)); ++ vid = AMAP_GET_BITS(struct amap_get_hsw_resp_context, ++ pvid, &resp->context); ++ *pvid = le16_to_cpu(vid); ++ } ++ ++err: ++ spin_unlock_bh(&adapter->mcc_lock); ++ return status; ++} ++ + int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) + { + struct be_mcc_wrb *wrb; +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 345d49e..d5b680c 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -191,6 +191,8 @@ struct be_mcc_mailbox { + #define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121 + #define OPCODE_COMMON_GET_MAC_LIST 147 + #define OPCODE_COMMON_SET_MAC_LIST 148 ++#define OPCODE_COMMON_GET_HSW_CONFIG 152 ++#define OPCODE_COMMON_SET_HSW_CONFIG 153 + #define OPCODE_COMMON_READ_OBJECT 171 + #define OPCODE_COMMON_WRITE_OBJECT 172 + +@@ -1413,6 +1415,55 @@ struct be_cmd_req_set_mac_list { + struct macaddr mac[BE_MAX_MAC]; + } __packed; + ++/*********************** HSW Config ***********************/ ++struct amap_set_hsw_context { ++ u8 interface_id[16]; ++ u8 rsvd0[14]; ++ u8 pvid_valid; ++ u8 rsvd1; ++ u8 rsvd2[16]; ++ u8 pvid[16]; ++ u8 rsvd3[32]; ++ u8 rsvd4[32]; ++ u8 rsvd5[32]; ++} __packed; ++ ++struct be_cmd_req_set_hsw_config { ++ struct be_cmd_req_hdr hdr; ++ u8 context[sizeof(struct amap_set_hsw_context) / 8]; ++} __packed; ++ ++struct be_cmd_resp_set_hsw_config { ++ struct be_cmd_resp_hdr hdr; ++ u32 rsvd; ++}; ++ ++struct amap_get_hsw_req_context { ++ u8 interface_id[16]; ++ u8 rsvd0[14]; ++ u8 pvid_valid; ++ u8 pport; ++} __packed; ++ ++struct amap_get_hsw_resp_context { ++ u8 rsvd1[16]; ++ u8 pvid[16]; ++ u8 rsvd2[32]; ++ u8 rsvd3[32]; ++ u8 rsvd4[32]; ++} __packed; ++ ++struct be_cmd_req_get_hsw_config { ++ struct be_cmd_req_hdr hdr; ++ u8 context[sizeof(struct amap_get_hsw_req_context) / 8]; ++} __packed; ++ ++struct be_cmd_resp_get_hsw_config { ++ struct be_cmd_resp_hdr hdr; ++ u8 context[sizeof(struct amap_get_hsw_resp_context) / 8]; ++ u32 rsvd; ++}; ++ + /*************** HW Stats Get v1 **********************************/ + #define BE_TXP_SW_SZ 48 + struct be_port_rxf_stats_v1 { +@@ -1617,5 +1668,9 @@ extern int be_cmd_get_mac_from_list(struct be_adapter *adapter, u32 domain, + bool *pmac_id_active, u32 *pmac_id, u8 *mac); + extern int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, + u8 mac_count, u32 domain); ++extern int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, ++ u32 domain, u16 intf_id); ++extern int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, ++ u32 domain, u16 intf_id); + extern int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index c9a9bf0..2e54335 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -970,14 +970,21 @@ static int be_set_vf_vlan(struct net_device *netdev, + return -EINVAL; + + if (vlan) { +- adapter->vf_cfg[vf].vlan_tag = vlan; +- adapter->vlans_added++; ++ if (adapter->vf_cfg[vf].vlan_tag != vlan) { ++ /* If this is new value, program it. Else skip. */ ++ adapter->vf_cfg[vf].vlan_tag = vlan; ++ ++ status = be_cmd_set_hsw_config(adapter, vlan, ++ vf + 1, adapter->vf_cfg[vf].if_handle); ++ } + } else { ++ /* Reset Transparent Vlan Tagging. */ + adapter->vf_cfg[vf].vlan_tag = 0; +- adapter->vlans_added--; ++ vlan = adapter->vf_cfg[vf].def_vid; ++ status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, ++ adapter->vf_cfg[vf].if_handle); + } + +- status = be_vid_config(adapter, true, vf); + + if (status) + dev_info(&adapter->pdev->dev, +@@ -2517,7 +2524,7 @@ static int be_vf_setup(struct be_adapter *adapter) + { + struct be_vf_cfg *vf_cfg; + u32 cap_flags, en_flags, vf; +- u16 lnk_speed; ++ u16 def_vlan, lnk_speed; + int status; + + be_vf_setup_init(adapter); +@@ -2541,6 +2548,12 @@ static int be_vf_setup(struct be_adapter *adapter) + if (status) + goto err; + vf_cfg->tx_rate = lnk_speed * 10; ++ ++ status = be_cmd_get_hsw_config(adapter, &def_vlan, ++ vf + 1, vf_cfg->if_handle); ++ if (status) ++ goto err; ++ vf_cfg->def_vid = def_vlan; + } + return 0; + err: +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0043-be2net-fix-ethtool-get-settings.patch b/debian/patches/features/all/be2net/0043-be2net-fix-ethtool-get-settings.patch new file mode 100644 index 000000000..96364e7d4 --- /dev/null +++ b/debian/patches/features/all/be2net/0043-be2net-fix-ethtool-get-settings.patch @@ -0,0 +1,521 @@ +From: Ajit Khaparde +Date: Sat, 21 Apr 2012 18:53:22 +0000 +Subject: [PATCH 43/58] be2net: fix ethtool get settings + +commit 42f11cf20cc5b76766fd1f0e591eda26283a38ec upstream. + +ethtool get settings was not displaying all the settings correctly. +use the get_phy_info to get more information about the PHY to fix this. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 23 ++- + drivers/net/ethernet/emulex/benet/be_cmds.c | 17 +- + drivers/net/ethernet/emulex/benet/be_cmds.h | 36 +++- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 245 ++++++++++++++++-------- + drivers/net/ethernet/emulex/benet/be_main.c | 20 +- + 5 files changed, 239 insertions(+), 102 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 9576ac0..ad69cf8 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -313,6 +313,23 @@ struct be_vf_cfg { + #define BE_UC_PMAC_COUNT 30 + #define BE_VF_UC_PMAC_COUNT 2 + ++struct phy_info { ++ u8 transceiver; ++ u8 autoneg; ++ u8 fc_autoneg; ++ u8 port_type; ++ u16 phy_type; ++ u16 interface_type; ++ u32 misc_params; ++ u16 auto_speeds_supported; ++ u16 fixed_speeds_supported; ++ int link_speed; ++ int forced_port_speed; ++ u32 dac_cable_len; ++ u32 advertising; ++ u32 supported; ++}; ++ + struct be_adapter { + struct pci_dev *pdev; + struct net_device *netdev; +@@ -377,10 +394,6 @@ struct be_adapter { + u32 rx_fc; /* Rx flow control */ + u32 tx_fc; /* Tx flow control */ + bool stats_cmd_sent; +- int link_speed; +- u8 port_type; +- u8 transceiver; +- u8 autoneg; + u8 generation; /* BladeEngine ASIC generation */ + u32 flash_status; + struct completion flash_compl; +@@ -392,6 +405,7 @@ struct be_adapter { + u32 sli_family; + u8 hba_port_num; + u16 pvid; ++ struct phy_info phy; + u8 wol_cap; + bool wol; + u32 max_pmac_cnt; /* Max secondary UC MACs programmable */ +@@ -583,4 +597,5 @@ extern void be_link_status_update(struct be_adapter *adapter, u8 link_status); + extern void be_parse_stats(struct be_adapter *adapter); + extern int be_load_fw(struct be_adapter *adapter, u8 *func); + extern bool be_is_wol_supported(struct be_adapter *adapter); ++extern bool be_pause_supported(struct be_adapter *adapter); + #endif /* BE_H */ +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 67b030d..22be08c 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -126,7 +126,7 @@ static void be_async_link_state_process(struct be_adapter *adapter, + struct be_async_event_link_state *evt) + { + /* When link status changes, link speed must be re-queried from FW */ +- adapter->link_speed = -1; ++ adapter->phy.link_speed = -1; + + /* For the initial link status do not rely on the ASYNC event as + * it may not be received in some cases. +@@ -153,7 +153,7 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, + { + if (evt->physical_port == adapter->port_num) { + /* qos_link_speed is in units of 10 Mbps */ +- adapter->link_speed = evt->qos_link_speed * 10; ++ adapter->phy.link_speed = evt->qos_link_speed * 10; + } + } + +@@ -2136,8 +2136,7 @@ err: + return status; + } + +-int be_cmd_get_phy_info(struct be_adapter *adapter, +- struct be_phy_info *phy_info) ++int be_cmd_get_phy_info(struct be_adapter *adapter) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_phy_info *req; +@@ -2170,9 +2169,15 @@ int be_cmd_get_phy_info(struct be_adapter *adapter, + if (!status) { + struct be_phy_info *resp_phy_info = + cmd.va + sizeof(struct be_cmd_req_hdr); +- phy_info->phy_type = le16_to_cpu(resp_phy_info->phy_type); +- phy_info->interface_type = ++ adapter->phy.phy_type = le16_to_cpu(resp_phy_info->phy_type); ++ adapter->phy.interface_type = + le16_to_cpu(resp_phy_info->interface_type); ++ adapter->phy.auto_speeds_supported = ++ le16_to_cpu(resp_phy_info->auto_speeds_supported); ++ adapter->phy.fixed_speeds_supported = ++ le16_to_cpu(resp_phy_info->fixed_speeds_supported); ++ adapter->phy.misc_params = ++ le32_to_cpu(resp_phy_info->misc_params); + } + pci_free_consistent(adapter->pdev, cmd.size, + cmd.va, cmd.dma); +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index d5b680c..3c54361 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -1309,9 +1309,36 @@ enum { + PHY_TYPE_KX4_10GB, + PHY_TYPE_BASET_10GB, + PHY_TYPE_BASET_1GB, ++ PHY_TYPE_BASEX_1GB, ++ PHY_TYPE_SGMII, + PHY_TYPE_DISABLED = 255 + }; + ++#define BE_SUPPORTED_SPEED_NONE 0 ++#define BE_SUPPORTED_SPEED_10MBPS 1 ++#define BE_SUPPORTED_SPEED_100MBPS 2 ++#define BE_SUPPORTED_SPEED_1GBPS 4 ++#define BE_SUPPORTED_SPEED_10GBPS 8 ++ ++#define BE_AN_EN 0x2 ++#define BE_PAUSE_SYM_EN 0x80 ++ ++/* MAC speed valid values */ ++#define SPEED_DEFAULT 0x0 ++#define SPEED_FORCED_10GB 0x1 ++#define SPEED_FORCED_1GB 0x2 ++#define SPEED_AUTONEG_10GB 0x3 ++#define SPEED_AUTONEG_1GB 0x4 ++#define SPEED_AUTONEG_100MB 0x5 ++#define SPEED_AUTONEG_10GB_1GB 0x6 ++#define SPEED_AUTONEG_10GB_1GB_100MB 0x7 ++#define SPEED_AUTONEG_1GB_100MB 0x8 ++#define SPEED_AUTONEG_10MB 0x9 ++#define SPEED_AUTONEG_1GB_100MB_10MB 0xa ++#define SPEED_AUTONEG_100MB_10MB 0xb ++#define SPEED_FORCED_100MB 0xc ++#define SPEED_FORCED_10MB 0xd ++ + struct be_cmd_req_get_phy_info { + struct be_cmd_req_hdr hdr; + u8 rsvd0[24]; +@@ -1321,7 +1348,11 @@ struct be_phy_info { + u16 phy_type; + u16 interface_type; + u32 misc_params; +- u32 future_use[4]; ++ u16 ext_phy_details; ++ u16 rsvd; ++ u16 auto_speeds_supported; ++ u16 fixed_speeds_supported; ++ u32 future_use[2]; + }; + + struct be_cmd_resp_get_phy_info { +@@ -1655,8 +1686,7 @@ extern int be_cmd_get_seeprom_data(struct be_adapter *adapter, + struct be_dma_mem *nonemb_cmd); + extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, + u8 loopback_type, u8 enable); +-extern int be_cmd_get_phy_info(struct be_adapter *adapter, +- struct be_phy_info *phy_info); ++extern int be_cmd_get_phy_info(struct be_adapter *adapter); + extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain); + extern void be_detect_dump_ue(struct be_adapter *adapter); + extern int be_cmd_get_die_temperature(struct be_adapter *adapter); +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index e0eb995..076adeb 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -433,102 +433,193 @@ static int be_get_sset_count(struct net_device *netdev, int stringset) + } + } + ++static u32 be_get_port_type(u32 phy_type, u32 dac_cable_len) ++{ ++ u32 port; ++ ++ switch (phy_type) { ++ case PHY_TYPE_BASET_1GB: ++ case PHY_TYPE_BASEX_1GB: ++ case PHY_TYPE_SGMII: ++ port = PORT_TP; ++ break; ++ case PHY_TYPE_SFP_PLUS_10GB: ++ port = dac_cable_len ? PORT_DA : PORT_FIBRE; ++ break; ++ case PHY_TYPE_XFP_10GB: ++ case PHY_TYPE_SFP_1GB: ++ port = PORT_FIBRE; ++ break; ++ case PHY_TYPE_BASET_10GB: ++ port = PORT_TP; ++ break; ++ default: ++ port = PORT_OTHER; ++ } ++ ++ return port; ++} ++ ++static u32 convert_to_et_setting(u32 if_type, u32 if_speeds) ++{ ++ u32 val = 0; ++ ++ switch (if_type) { ++ case PHY_TYPE_BASET_1GB: ++ case PHY_TYPE_BASEX_1GB: ++ case PHY_TYPE_SGMII: ++ val |= SUPPORTED_TP; ++ if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) ++ val |= SUPPORTED_1000baseT_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_100MBPS) ++ val |= SUPPORTED_100baseT_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_10MBPS) ++ val |= SUPPORTED_10baseT_Full; ++ break; ++ case PHY_TYPE_KX4_10GB: ++ val |= SUPPORTED_Backplane; ++ if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) ++ val |= SUPPORTED_1000baseKX_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) ++ val |= SUPPORTED_10000baseKX4_Full; ++ break; ++ case PHY_TYPE_KR_10GB: ++ val |= SUPPORTED_Backplane | ++ SUPPORTED_10000baseKR_Full; ++ break; ++ case PHY_TYPE_SFP_PLUS_10GB: ++ case PHY_TYPE_XFP_10GB: ++ case PHY_TYPE_SFP_1GB: ++ val |= SUPPORTED_FIBRE; ++ if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) ++ val |= SUPPORTED_10000baseT_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) ++ val |= SUPPORTED_1000baseT_Full; ++ break; ++ case PHY_TYPE_BASET_10GB: ++ val |= SUPPORTED_TP; ++ if (if_speeds & BE_SUPPORTED_SPEED_10GBPS) ++ val |= SUPPORTED_10000baseT_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_1GBPS) ++ val |= SUPPORTED_1000baseT_Full; ++ if (if_speeds & BE_SUPPORTED_SPEED_100MBPS) ++ val |= SUPPORTED_100baseT_Full; ++ break; ++ default: ++ val |= SUPPORTED_TP; ++ } ++ ++ return val; ++} ++ ++static int convert_to_et_speed(u32 be_speed) ++{ ++ int et_speed = SPEED_10000; ++ ++ switch (be_speed) { ++ case PHY_LINK_SPEED_10MBPS: ++ et_speed = SPEED_10; ++ break; ++ case PHY_LINK_SPEED_100MBPS: ++ et_speed = SPEED_100; ++ break; ++ case PHY_LINK_SPEED_1GBPS: ++ et_speed = SPEED_1000; ++ break; ++ case PHY_LINK_SPEED_10GBPS: ++ et_speed = SPEED_10000; ++ break; ++ } ++ ++ return et_speed; ++} ++ ++bool be_pause_supported(struct be_adapter *adapter) ++{ ++ return (adapter->phy.interface_type == PHY_TYPE_SFP_PLUS_10GB || ++ adapter->phy.interface_type == PHY_TYPE_XFP_10GB) ? ++ false : true; ++} ++ + static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + { + struct be_adapter *adapter = netdev_priv(netdev); +- struct be_phy_info phy_info; +- u8 mac_speed = 0; ++ u8 port_speed = 0; + u16 link_speed = 0; + u8 link_status; ++ u32 et_speed = 0; + int status; + +- if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) { +- status = be_cmd_link_status_query(adapter, &mac_speed, +- &link_speed, &link_status, 0); +- if (!status) +- be_link_status_update(adapter, link_status); +- +- /* link_speed is in units of 10 Mbps */ +- if (link_speed) { +- ethtool_cmd_speed_set(ecmd, link_speed*10); ++ if (adapter->phy.link_speed < 0 || !(netdev->flags & IFF_UP)) { ++ if (adapter->phy.forced_port_speed < 0) { ++ status = be_cmd_link_status_query(adapter, &port_speed, ++ &link_speed, &link_status, 0); ++ if (!status) ++ be_link_status_update(adapter, link_status); ++ if (link_speed) ++ et_speed = link_speed; ++ else ++ et_speed = convert_to_et_speed(port_speed); + } else { +- switch (mac_speed) { +- case PHY_LINK_SPEED_10MBPS: +- ethtool_cmd_speed_set(ecmd, SPEED_10); +- break; +- case PHY_LINK_SPEED_100MBPS: +- ethtool_cmd_speed_set(ecmd, SPEED_100); +- break; +- case PHY_LINK_SPEED_1GBPS: +- ethtool_cmd_speed_set(ecmd, SPEED_1000); +- break; +- case PHY_LINK_SPEED_10GBPS: +- ethtool_cmd_speed_set(ecmd, SPEED_10000); +- break; +- case PHY_LINK_SPEED_ZERO: +- ethtool_cmd_speed_set(ecmd, 0); +- break; +- } ++ et_speed = adapter->phy.forced_port_speed; + } + +- status = be_cmd_get_phy_info(adapter, &phy_info); +- if (!status) { +- switch (phy_info.interface_type) { +- case PHY_TYPE_XFP_10GB: +- case PHY_TYPE_SFP_1GB: +- case PHY_TYPE_SFP_PLUS_10GB: +- ecmd->port = PORT_FIBRE; +- break; +- default: +- ecmd->port = PORT_TP; +- break; +- } ++ ethtool_cmd_speed_set(ecmd, et_speed); ++ ++ status = be_cmd_get_phy_info(adapter); ++ if (status) ++ return status; ++ ++ ecmd->supported = ++ convert_to_et_setting(adapter->phy.interface_type, ++ adapter->phy.auto_speeds_supported | ++ adapter->phy.fixed_speeds_supported); ++ ecmd->advertising = ++ convert_to_et_setting(adapter->phy.interface_type, ++ adapter->phy.auto_speeds_supported); + +- switch (phy_info.interface_type) { +- case PHY_TYPE_KR_10GB: +- case PHY_TYPE_KX4_10GB: +- ecmd->autoneg = AUTONEG_ENABLE; ++ ecmd->port = be_get_port_type(adapter->phy.interface_type, ++ adapter->phy.dac_cable_len); ++ ++ if (adapter->phy.auto_speeds_supported) { ++ ecmd->supported |= SUPPORTED_Autoneg; ++ ecmd->autoneg = AUTONEG_ENABLE; ++ ecmd->advertising |= ADVERTISED_Autoneg; ++ } ++ ++ if (be_pause_supported(adapter)) { ++ ecmd->supported |= SUPPORTED_Pause; ++ ecmd->advertising |= ADVERTISED_Pause; ++ } ++ ++ switch (adapter->phy.interface_type) { ++ case PHY_TYPE_KR_10GB: ++ case PHY_TYPE_KX4_10GB: + ecmd->transceiver = XCVR_INTERNAL; +- break; +- default: +- ecmd->autoneg = AUTONEG_DISABLE; +- ecmd->transceiver = XCVR_EXTERNAL; +- break; +- } ++ break; ++ default: ++ ecmd->transceiver = XCVR_EXTERNAL; ++ break; + } + + /* Save for future use */ +- adapter->link_speed = ethtool_cmd_speed(ecmd); +- adapter->port_type = ecmd->port; +- adapter->transceiver = ecmd->transceiver; +- adapter->autoneg = ecmd->autoneg; ++ adapter->phy.link_speed = ethtool_cmd_speed(ecmd); ++ adapter->phy.port_type = ecmd->port; ++ adapter->phy.transceiver = ecmd->transceiver; ++ adapter->phy.autoneg = ecmd->autoneg; ++ adapter->phy.advertising = ecmd->advertising; ++ adapter->phy.supported = ecmd->supported; + } else { +- ethtool_cmd_speed_set(ecmd, adapter->link_speed); +- ecmd->port = adapter->port_type; +- ecmd->transceiver = adapter->transceiver; +- ecmd->autoneg = adapter->autoneg; ++ ethtool_cmd_speed_set(ecmd, adapter->phy.link_speed); ++ ecmd->port = adapter->phy.port_type; ++ ecmd->transceiver = adapter->phy.transceiver; ++ ecmd->autoneg = adapter->phy.autoneg; ++ ecmd->advertising = adapter->phy.advertising; ++ ecmd->supported = adapter->phy.supported; + } + + ecmd->duplex = DUPLEX_FULL; + ecmd->phy_address = adapter->port_num; +- switch (ecmd->port) { +- case PORT_FIBRE: +- ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); +- break; +- case PORT_TP: +- ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); +- break; +- case PORT_AUI: +- ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_AUI); +- break; +- } +- +- if (ecmd->autoneg) { +- ecmd->supported |= SUPPORTED_1000baseT_Full; +- ecmd->supported |= SUPPORTED_Autoneg; +- ecmd->advertising |= (ADVERTISED_10000baseT_Full | +- ADVERTISED_1000baseT_Full); +- } + + return 0; + } +@@ -548,7 +639,7 @@ be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd) + struct be_adapter *adapter = netdev_priv(netdev); + + be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause); +- ecmd->autoneg = 0; ++ ecmd->autoneg = adapter->phy.fc_autoneg; + } + + static int +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 2e54335..376a2fa 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2563,11 +2563,12 @@ err: + static void be_setup_init(struct be_adapter *adapter) + { + adapter->vlan_prio_bmap = 0xff; +- adapter->link_speed = -1; ++ adapter->phy.link_speed = -1; + adapter->if_handle = -1; + adapter->be3_native = false; + adapter->promiscuous = false; + adapter->eq_next_idx = 0; ++ adapter->phy.forced_port_speed = -1; + } + + static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) +@@ -2699,6 +2700,10 @@ static int be_setup(struct be_adapter *adapter) + goto err; + } + ++ be_cmd_get_phy_info(adapter); ++ if (be_pause_supported(adapter)) ++ adapter->phy.fc_autoneg = 1; ++ + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); + adapter->flags |= BE_FLAGS_WORKER_SCHEDULED; + +@@ -2752,17 +2757,8 @@ static bool be_flash_redboot(struct be_adapter *adapter, + + static bool phy_flashing_required(struct be_adapter *adapter) + { +- int status = 0; +- struct be_phy_info phy_info; +- +- status = be_cmd_get_phy_info(adapter, &phy_info); +- if (status) +- return false; +- if ((phy_info.phy_type == TN_8022) && +- (phy_info.interface_type == PHY_TYPE_BASET_10GB)) { +- return true; +- } +- return false; ++ return (adapter->phy.phy_type == TN_8022 && ++ adapter->phy.interface_type == PHY_TYPE_BASET_10GB); + } + + static int be_flash_data(struct be_adapter *adapter, +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0044-be2net-Fix-VLAN-multicast-packet-reception.patch b/debian/patches/features/all/be2net/0044-be2net-Fix-VLAN-multicast-packet-reception.patch new file mode 100644 index 000000000..a49ecf62c --- /dev/null +++ b/debian/patches/features/all/be2net/0044-be2net-Fix-VLAN-multicast-packet-reception.patch @@ -0,0 +1,94 @@ +From: Padmanabh Ratnakar +Date: Fri, 25 May 2012 21:28:09 +0530 +Subject: [PATCH 44/58] be2net: Fix VLAN/multicast packet reception + +commit 0fc16ebf69fc57b42110712eaaf8a6aa2492afbe upstream. + +VLAN and multicast hardware filters are limited and can get +exhausted in adapters with many PCI functions. If setting +a VLAN or multicast filter fails due to lack of sufficient +hardware resources, these packets get dropped. Fix this by +switching to VLAN or multicast promiscous mode so that these +packets are not dropped. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 44 ++++++++++++++++++--------- + 1 file changed, 30 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 376a2fa..34b8ad2 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -797,22 +797,30 @@ static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num) + if (adapter->promiscuous) + return 0; + +- if (adapter->vlans_added <= adapter->max_vlans) { +- /* Construct VLAN Table to give to HW */ +- for (i = 0; i < VLAN_N_VID; i++) { +- if (adapter->vlan_tag[i]) { +- vtag[ntags] = cpu_to_le16(i); +- ntags++; +- } +- } +- status = be_cmd_vlan_config(adapter, adapter->if_handle, +- vtag, ntags, 1, 0); +- } else { +- status = be_cmd_vlan_config(adapter, adapter->if_handle, +- NULL, 0, 1, 1); ++ if (adapter->vlans_added > adapter->max_vlans) ++ goto set_vlan_promisc; ++ ++ /* Construct VLAN Table to give to HW */ ++ for (i = 0; i < VLAN_N_VID; i++) ++ if (adapter->vlan_tag[i]) ++ vtag[ntags++] = cpu_to_le16(i); ++ ++ status = be_cmd_vlan_config(adapter, adapter->if_handle, ++ vtag, ntags, 1, 0); ++ ++ /* Set to VLAN promisc mode as setting VLAN filter failed */ ++ if (status) { ++ dev_info(&adapter->pdev->dev, "Exhausted VLAN HW filters.\n"); ++ dev_info(&adapter->pdev->dev, "Disabling HW VLAN filtering.\n"); ++ goto set_vlan_promisc; + } + + return status; ++ ++set_vlan_promisc: ++ status = be_cmd_vlan_config(adapter, adapter->if_handle, ++ NULL, 0, 1, 1); ++ return status; + } + + static void be_vlan_add_vid(struct net_device *netdev, u16 vid) +@@ -854,6 +862,7 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) + static void be_set_rx_mode(struct net_device *netdev) + { + struct be_adapter *adapter = netdev_priv(netdev); ++ int status; + + if (netdev->flags & IFF_PROMISC) { + be_cmd_rx_filter(adapter, IFF_PROMISC, ON); +@@ -900,7 +909,14 @@ static void be_set_rx_mode(struct net_device *netdev) + } + } + +- be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); ++ status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); ++ ++ /* Set to MCAST promisc mode if setting MULTICAST address fails */ ++ if (status) { ++ dev_info(&adapter->pdev->dev, "Exhausted multicast HW filters.\n"); ++ dev_info(&adapter->pdev->dev, "Disabling HW multicast filtering.\n"); ++ be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON); ++ } + done: + return; + } +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0045-be2net-Fix-FW-download-in-Lancer.patch b/debian/patches/features/all/be2net/0045-be2net-Fix-FW-download-in-Lancer.patch new file mode 100644 index 000000000..8a5f30e4e --- /dev/null +++ b/debian/patches/features/all/be2net/0045-be2net-Fix-FW-download-in-Lancer.patch @@ -0,0 +1,44 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:46:18 +0000 +Subject: [PATCH 45/58] be2net: Fix FW download in Lancer + +commit 804c751599855a83efdc781cd9a2bda725d1391c upstream. + +Increase time given by driver to adapter for completing FW download +to 30 seconds. Also return correct status when FW download times out. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 22be08c..3ba4aed 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1824,18 +1824,16 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->flash_compl, +- msecs_to_jiffies(12000))) ++ msecs_to_jiffies(30000))) + status = -1; + else + status = adapter->flash_status; + + resp = embedded_payload(wrb); +- if (!status) { ++ if (!status) + *data_written = le32_to_cpu(resp->actual_write_len); +- } else { ++ else + *addn_status = resp->additional_status; +- status = resp->status; +- } + + return status; + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0046-be2net-Fix-ethtool-self-test-for-Lancer.patch b/debian/patches/features/all/be2net/0046-be2net-Fix-ethtool-self-test-for-Lancer.patch new file mode 100644 index 000000000..589d83892 --- /dev/null +++ b/debian/patches/features/all/be2net/0046-be2net-Fix-ethtool-self-test-for-Lancer.patch @@ -0,0 +1,31 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:46:28 +0000 +Subject: [PATCH 46/58] be2net: Fix ethtool self test for Lancer + +commit a70473949698c1c46e5523e1810a0a0f904a1fd2 upstream. + +Lancer does not support DDR self test. Fix ethtool self test by +skipping this test for Lancer. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 076adeb..9d71bad 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -793,7 +793,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) + } + } + +- if (be_test_ddr_dma(adapter) != 0) { ++ if (!lancer_chip(adapter) && be_test_ddr_dma(adapter) != 0) { + data[3] = 1; + test->flags |= ETH_TEST_FL_FAILED; + } +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0047-be2net-Fix-traffic-stall-INTx-mode.patch b/debian/patches/features/all/be2net/0047-be2net-Fix-traffic-stall-INTx-mode.patch new file mode 100644 index 000000000..fd6dd0d08 --- /dev/null +++ b/debian/patches/features/all/be2net/0047-be2net-Fix-traffic-stall-INTx-mode.patch @@ -0,0 +1,36 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:46:39 +0000 +Subject: [PATCH 47/58] be2net: Fix traffic stall INTx mode + +commit af311fe31015e2b27bd65e22fc103230fb3a78b7 upstream. + +EQ is getting armed wrongly in INTx mode as INTx interrupt is taking +some time to deassert. This can cause another interrupt while NAPI is +scheduled and scheduling a NAPI in interrupt does not take effect. +This causes interrupt to be missed and traffic stalls. Fixing this by +preventing wrong arming of EQ. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 34b8ad2..915b95e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1563,7 +1563,9 @@ static int event_handle(struct be_eq_obj *eqo) + if (!num) + rearm = true; + +- be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num); ++ if (num || msix_enabled(eqo->adapter)) ++ be_eq_notify(eqo->adapter, eqo->q.id, rearm, true, num); ++ + if (num) + napi_schedule(&eqo->napi); + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0048-be2net-Fix-Lancer-statistics.patch b/debian/patches/features/all/be2net/0048-be2net-Fix-Lancer-statistics.patch new file mode 100644 index 000000000..2eacf504b --- /dev/null +++ b/debian/patches/features/all/be2net/0048-be2net-Fix-Lancer-statistics.patch @@ -0,0 +1,55 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:46:52 +0000 +Subject: [PATCH 48/58] be2net: Fix Lancer statistics + +commit d51ebd331166e102591e5c25805d8015df0e1e21 upstream. + +Fix port num sent in command to get stats. Also skip unnecessary +parsing of stats for Lancer. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- + drivers/net/ethernet/emulex/benet/be_main.c | 5 +++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 3ba4aed..4e07e58 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1221,7 +1221,7 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter, + OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size, wrb, + nonemb_cmd); + +- req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num); ++ req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); + req->cmd_params.params.reset_stats = 0; + + be_mcc_notify(adapter); +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 915b95e..9b1c03e 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -421,6 +421,9 @@ void be_parse_stats(struct be_adapter *adapter) + populate_be2_stats(adapter); + } + ++ if (lancer_chip(adapter)) ++ goto done; ++ + /* as erx_v1 is longer than v0, ok to use v1 defn for v0 access */ + for_all_rx_queues(adapter, rxo, i) { + /* below erx HW counter can actually wrap around after +@@ -429,6 +432,8 @@ void be_parse_stats(struct be_adapter *adapter) + accumulate_16bit_val(&rx_stats(rxo)->rx_drops_no_frags, + (u16)erx->rx_drops_no_fragments[rxo->q.id]); + } ++done: ++ return; + } + + static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev, +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0049-be2net-Fix-wrong-status-getting-returned-for-MCC-com.patch b/debian/patches/features/all/be2net/0049-be2net-Fix-wrong-status-getting-returned-for-MCC-com.patch new file mode 100644 index 000000000..f899b3ca3 --- /dev/null +++ b/debian/patches/features/all/be2net/0049-be2net-Fix-wrong-status-getting-returned-for-MCC-com.patch @@ -0,0 +1,232 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:47:03 +0000 +Subject: [PATCH 49/58] be2net: Fix wrong status getting returned for MCC + commands + +commit 652bf64622f32c938dd4a8738ba12d51dc9fbdd4 upstream. + +MCC Response CQEs are processed as part of NAPI poll routine and +also synchronously. If MCC completions are consumed by NAPI poll +routine, wrong status is returned to synchronously waiting routine. +Fix this by getting status of MCC command from command response +instead of response CQEs. + +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 5 ++ + drivers/net/ethernet/emulex/benet/be_cmds.c | 81 ++++++++++++++++++--------- + drivers/net/ethernet/emulex/benet/be_cmds.h | 8 ++- + 3 files changed, 67 insertions(+), 27 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index ad69cf8..4bc18ef 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -162,6 +162,11 @@ static inline void queue_head_inc(struct be_queue_info *q) + index_inc(&q->head, q->len); + } + ++static inline void index_dec(u16 *index, u16 limit) ++{ ++ *index = MODULO((*index - 1), limit); ++} ++ + static inline void queue_tail_inc(struct be_queue_info *q) + { + index_inc(&q->tail, q->len); +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 4e07e58..2673081 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -61,10 +61,21 @@ static inline void be_mcc_compl_use(struct be_mcc_compl *compl) + compl->flags = 0; + } + ++static struct be_cmd_resp_hdr *be_decode_resp_hdr(u32 tag0, u32 tag1) ++{ ++ unsigned long addr; ++ ++ addr = tag1; ++ addr = ((addr << 16) << 16) | tag0; ++ return (void *)addr; ++} ++ + static int be_mcc_compl_process(struct be_adapter *adapter, +- struct be_mcc_compl *compl) ++ struct be_mcc_compl *compl) + { + u16 compl_status, extd_status; ++ struct be_cmd_resp_hdr *resp_hdr; ++ u8 opcode = 0, subsystem = 0; + + /* Just swap the status to host endian; mcc tag is opaquely copied + * from mcc_wrb */ +@@ -73,32 +84,36 @@ static int be_mcc_compl_process(struct be_adapter *adapter, + compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & + CQE_STATUS_COMPL_MASK; + +- if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) || +- (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) && +- (compl->tag1 == CMD_SUBSYSTEM_COMMON)) { ++ resp_hdr = be_decode_resp_hdr(compl->tag0, compl->tag1); ++ ++ if (resp_hdr) { ++ opcode = resp_hdr->opcode; ++ subsystem = resp_hdr->subsystem; ++ } ++ ++ if (((opcode == OPCODE_COMMON_WRITE_FLASHROM) || ++ (opcode == OPCODE_COMMON_WRITE_OBJECT)) && ++ (subsystem == CMD_SUBSYSTEM_COMMON)) { + adapter->flash_status = compl_status; + complete(&adapter->flash_compl); + } + + if (compl_status == MCC_STATUS_SUCCESS) { +- if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) || +- (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) && +- (compl->tag1 == CMD_SUBSYSTEM_ETH)) { ++ if (((opcode == OPCODE_ETH_GET_STATISTICS) || ++ (opcode == OPCODE_ETH_GET_PPORT_STATS)) && ++ (subsystem == CMD_SUBSYSTEM_ETH)) { + be_parse_stats(adapter); + adapter->stats_cmd_sent = false; + } +- if (compl->tag0 == +- OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) { +- struct be_mcc_wrb *mcc_wrb = +- queue_index_node(&adapter->mcc_obj.q, +- compl->tag1); ++ if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES && ++ subsystem == CMD_SUBSYSTEM_COMMON) { + struct be_cmd_resp_get_cntl_addnl_attribs *resp = +- embedded_payload(mcc_wrb); ++ (void *)resp_hdr; + adapter->drv_stats.be_on_die_temperature = + resp->on_die_temperature; + } + } else { +- if (compl->tag0 == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) ++ if (opcode == OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES) + be_get_temp_freq = 0; + + if (compl_status == MCC_STATUS_NOT_SUPPORTED || +@@ -108,13 +123,13 @@ static int be_mcc_compl_process(struct be_adapter *adapter, + if (compl_status == MCC_STATUS_UNAUTHORIZED_REQUEST) { + dev_warn(&adapter->pdev->dev, "This domain(VM) is not " + "permitted to execute this cmd (opcode %d)\n", +- compl->tag0); ++ opcode); + } else { + extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & + CQE_STATUS_EXTD_MASK; + dev_err(&adapter->pdev->dev, "Cmd (opcode %d) failed:" + "status %d, extd-status %d\n", +- compl->tag0, compl_status, extd_status); ++ opcode, compl_status, extd_status); + } + } + done: +@@ -286,7 +301,7 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) + if (i == mcc_timeout) { + dev_err(&adapter->pdev->dev, "FW not responding\n"); + adapter->fw_timeout = true; +- return -1; ++ return -EIO; + } + return status; + } +@@ -294,8 +309,26 @@ static int be_mcc_wait_compl(struct be_adapter *adapter) + /* Notify MCC requests and wait for completion */ + static int be_mcc_notify_wait(struct be_adapter *adapter) + { ++ int status; ++ struct be_mcc_wrb *wrb; ++ struct be_mcc_obj *mcc_obj = &adapter->mcc_obj; ++ u16 index = mcc_obj->q.head; ++ struct be_cmd_resp_hdr *resp; ++ ++ index_dec(&index, mcc_obj->q.len); ++ wrb = queue_index_node(&mcc_obj->q, index); ++ ++ resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1); ++ + be_mcc_notify(adapter); +- return be_mcc_wait_compl(adapter); ++ ++ status = be_mcc_wait_compl(adapter); ++ if (status == -EIO) ++ goto out; ++ ++ status = resp->status; ++out: ++ return status; + } + + static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) +@@ -435,14 +468,17 @@ static void be_wrb_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, + struct be_mcc_wrb *wrb, struct be_dma_mem *mem) + { + struct be_sge *sge; ++ unsigned long addr = (unsigned long)req_hdr; ++ u64 req_addr = addr; + + req_hdr->opcode = opcode; + req_hdr->subsystem = subsystem; + req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); + req_hdr->version = 0; + +- wrb->tag0 = opcode; +- wrb->tag1 = subsystem; ++ wrb->tag0 = req_addr & 0xFFFFFFFF; ++ wrb->tag1 = upper_32_bits(req_addr); ++ + wrb->payload_length = cmd_len; + if (mem) { + wrb->embedded |= (1 & MCC_WRB_SGE_CNT_MASK) << +@@ -1283,13 +1319,10 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) + { + struct be_mcc_wrb *wrb; + struct be_cmd_req_get_cntl_addnl_attribs *req; +- u16 mccq_index; + int status; + + spin_lock_bh(&adapter->mcc_lock); + +- mccq_index = adapter->mcc_obj.q.head; +- + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; +@@ -1301,8 +1334,6 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) + OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req), + wrb, NULL); + +- wrb->tag1 = mccq_index; +- + be_mcc_notify(adapter); + + err: +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h +index 3c54361..944f031 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.h ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.h +@@ -225,8 +225,12 @@ struct be_cmd_req_hdr { + #define RESP_HDR_INFO_OPCODE_SHIFT 0 /* bits 0 - 7 */ + #define RESP_HDR_INFO_SUBSYS_SHIFT 8 /* bits 8 - 15 */ + struct be_cmd_resp_hdr { +- u32 info; /* dword 0 */ +- u32 status; /* dword 1 */ ++ u8 opcode; /* dword 0 */ ++ u8 subsystem; /* dword 0 */ ++ u8 rsvd[2]; /* dword 0 */ ++ u8 status; /* dword 1 */ ++ u8 add_status; /* dword 1 */ ++ u8 rsvd1[2]; /* dword 1 */ + u32 response_length; /* dword 2 */ + u32 actual_resp_len; /* dword 3 */ + }; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0050-be2net-Fix-FW-download-for-BE.patch b/debian/patches/features/all/be2net/0050-be2net-Fix-FW-download-for-BE.patch new file mode 100644 index 000000000..1f344a742 --- /dev/null +++ b/debian/patches/features/all/be2net/0050-be2net-Fix-FW-download-for-BE.patch @@ -0,0 +1,383 @@ +From: Padmanabh Ratnakar +Date: Wed, 25 Apr 2012 01:47:15 +0000 +Subject: [PATCH 50/58] be2net: Fix FW download for BE + +commit c165541efc4d1024d7db22ecdf64359b1f6107fc upstream. + +Skip flashing a FW component if that component is not present in a +particular FW UFI image. + +Signed-off-by: Somnath Kotur +Signed-off-by: Padmanabh Ratnakar +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- + drivers/net/ethernet/emulex/benet/be_hw.h | 74 ++++++++---- + drivers/net/ethernet/emulex/benet/be_main.c | 168 ++++++++++++++++++--------- + 3 files changed, 166 insertions(+), 78 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c +index 2673081..43167e8 100644 +--- a/drivers/net/ethernet/emulex/benet/be_cmds.c ++++ b/drivers/net/ethernet/emulex/benet/be_cmds.c +@@ -1979,7 +1979,7 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc, + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4, wrb, NULL); + +- req->params.op_type = cpu_to_le32(IMG_TYPE_REDBOOT); ++ req->params.op_type = cpu_to_le32(OPTYPE_REDBOOT); + req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT); + req->params.offset = cpu_to_le32(offset); + req->params.data_buf_size = cpu_to_le32(0x4); +diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h +index f2c89e3..0949aa6 100644 +--- a/drivers/net/ethernet/emulex/benet/be_hw.h ++++ b/drivers/net/ethernet/emulex/benet/be_hw.h +@@ -162,22 +162,23 @@ + #define QUERY_FAT 1 + + /* Flashrom related descriptors */ ++#define MAX_FLASH_COMP 32 + #define IMAGE_TYPE_FIRMWARE 160 + #define IMAGE_TYPE_BOOTCODE 224 + #define IMAGE_TYPE_OPTIONROM 32 + + #define NUM_FLASHDIR_ENTRIES 32 + +-#define IMG_TYPE_ISCSI_ACTIVE 0 +-#define IMG_TYPE_REDBOOT 1 +-#define IMG_TYPE_BIOS 2 +-#define IMG_TYPE_PXE_BIOS 3 +-#define IMG_TYPE_FCOE_BIOS 8 +-#define IMG_TYPE_ISCSI_BACKUP 9 +-#define IMG_TYPE_FCOE_FW_ACTIVE 10 +-#define IMG_TYPE_FCOE_FW_BACKUP 11 +-#define IMG_TYPE_NCSI_FW 13 +-#define IMG_TYPE_PHY_FW 99 ++#define OPTYPE_ISCSI_ACTIVE 0 ++#define OPTYPE_REDBOOT 1 ++#define OPTYPE_BIOS 2 ++#define OPTYPE_PXE_BIOS 3 ++#define OPTYPE_FCOE_BIOS 8 ++#define OPTYPE_ISCSI_BACKUP 9 ++#define OPTYPE_FCOE_FW_ACTIVE 10 ++#define OPTYPE_FCOE_FW_BACKUP 11 ++#define OPTYPE_NCSI_FW 13 ++#define OPTYPE_PHY_FW 99 + #define TN_8022 13 + + #define ILLEGAL_IOCTL_REQ 2 +@@ -223,6 +224,24 @@ + #define FLASH_REDBOOT_START_g3 (262144) + #define FLASH_PHY_FW_START_g3 1310720 + ++#define IMAGE_NCSI 16 ++#define IMAGE_OPTION_ROM_PXE 32 ++#define IMAGE_OPTION_ROM_FCoE 33 ++#define IMAGE_OPTION_ROM_ISCSI 34 ++#define IMAGE_FLASHISM_JUMPVECTOR 48 ++#define IMAGE_FLASH_ISM 49 ++#define IMAGE_JUMP_VECTOR 50 ++#define IMAGE_FIRMWARE_iSCSI 160 ++#define IMAGE_FIRMWARE_COMP_iSCSI 161 ++#define IMAGE_FIRMWARE_FCoE 162 ++#define IMAGE_FIRMWARE_COMP_FCoE 163 ++#define IMAGE_FIRMWARE_BACKUP_iSCSI 176 ++#define IMAGE_FIRMWARE_BACKUP_COMP_iSCSI 177 ++#define IMAGE_FIRMWARE_BACKUP_FCoE 178 ++#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179 ++#define IMAGE_FIRMWARE_PHY 192 ++#define IMAGE_BOOT_CODE 224 ++ + /************* Rx Packet Type Encoding **************/ + #define BE_UNICAST_PACKET 0 + #define BE_MULTICAST_PACKET 1 +@@ -445,6 +464,7 @@ struct flash_comp { + unsigned long offset; + int optype; + int size; ++ int img_type; + }; + + struct image_hdr { +@@ -481,17 +501,19 @@ struct flash_section_hdr { + u32 format_rev; + u32 cksum; + u32 antidote; +- u32 build_no; +- u8 id_string[64]; +- u32 active_entry_mask; +- u32 valid_entry_mask; +- u32 org_content_mask; +- u32 rsvd0; +- u32 rsvd1; +- u32 rsvd2; +- u32 rsvd3; +- u32 rsvd4; +-}; ++ u32 num_images; ++ u8 id_string[128]; ++ u32 rsvd[4]; ++} __packed; ++ ++struct flash_section_hdr_g2 { ++ u32 format_rev; ++ u32 cksum; ++ u32 antidote; ++ u32 build_num; ++ u8 id_string[128]; ++ u32 rsvd[8]; ++} __packed; + + struct flash_section_entry { + u32 type; +@@ -503,10 +525,16 @@ struct flash_section_entry { + u32 rsvd0; + u32 rsvd1; + u8 ver_data[32]; +-}; ++} __packed; + + struct flash_section_info { + u8 cookie[32]; + struct flash_section_hdr fsec_hdr; + struct flash_section_entry fsec_entry[32]; +-}; ++} __packed; ++ ++struct flash_section_info_g2 { ++ u8 cookie[32]; ++ struct flash_section_hdr_g2 fsec_hdr; ++ struct flash_section_entry fsec_entry[32]; ++} __packed; +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 9b1c03e..730fb1b 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2751,6 +2751,8 @@ static void be_netpoll(struct net_device *netdev) + #endif + + #define FW_FILE_HDR_SIGN "ServerEngines Corp. " ++char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "}; ++ + static bool be_flash_redboot(struct be_adapter *adapter, + const u8 *p, u32 img_start, int image_size, + int hdr_size) +@@ -2784,58 +2786,101 @@ static bool phy_flashing_required(struct be_adapter *adapter) + adapter->phy.interface_type == PHY_TYPE_BASET_10GB); + } + ++static bool is_comp_in_ufi(struct be_adapter *adapter, ++ struct flash_section_info *fsec, int type) ++{ ++ int i = 0, img_type = 0; ++ struct flash_section_info_g2 *fsec_g2 = NULL; ++ ++ if (adapter->generation != BE_GEN3) ++ fsec_g2 = (struct flash_section_info_g2 *)fsec; ++ ++ for (i = 0; i < MAX_FLASH_COMP; i++) { ++ if (fsec_g2) ++ img_type = le32_to_cpu(fsec_g2->fsec_entry[i].type); ++ else ++ img_type = le32_to_cpu(fsec->fsec_entry[i].type); ++ ++ if (img_type == type) ++ return true; ++ } ++ return false; ++ ++} ++ ++struct flash_section_info *get_fsec_info(struct be_adapter *adapter, ++ int header_size, ++ const struct firmware *fw) ++{ ++ struct flash_section_info *fsec = NULL; ++ const u8 *p = fw->data; ++ ++ p += header_size; ++ while (p < (fw->data + fw->size)) { ++ fsec = (struct flash_section_info *)p; ++ if (!memcmp(flash_cookie, fsec->cookie, sizeof(flash_cookie))) ++ return fsec; ++ p += 32; ++ } ++ return NULL; ++} ++ + static int be_flash_data(struct be_adapter *adapter, +- const struct firmware *fw, +- struct be_dma_mem *flash_cmd, int num_of_images) ++ const struct firmware *fw, ++ struct be_dma_mem *flash_cmd, ++ int num_of_images) + + { + int status = 0, i, filehdr_size = 0; ++ int img_hdrs_size = (num_of_images * sizeof(struct image_hdr)); + u32 total_bytes = 0, flash_op; + int num_bytes; + const u8 *p = fw->data; + struct be_cmd_write_flashrom *req = flash_cmd->va; + const struct flash_comp *pflashcomp; +- int num_comp; +- +- static const struct flash_comp gen3_flash_types[10] = { +- { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, IMG_TYPE_ISCSI_ACTIVE, +- FLASH_IMAGE_MAX_SIZE_g3}, +- { FLASH_REDBOOT_START_g3, IMG_TYPE_REDBOOT, +- FLASH_REDBOOT_IMAGE_MAX_SIZE_g3}, +- { FLASH_iSCSI_BIOS_START_g3, IMG_TYPE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g3}, +- { FLASH_PXE_BIOS_START_g3, IMG_TYPE_PXE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g3}, +- { FLASH_FCoE_BIOS_START_g3, IMG_TYPE_FCOE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g3}, +- { FLASH_iSCSI_BACKUP_IMAGE_START_g3, IMG_TYPE_ISCSI_BACKUP, +- FLASH_IMAGE_MAX_SIZE_g3}, +- { FLASH_FCoE_PRIMARY_IMAGE_START_g3, IMG_TYPE_FCOE_FW_ACTIVE, +- FLASH_IMAGE_MAX_SIZE_g3}, +- { FLASH_FCoE_BACKUP_IMAGE_START_g3, IMG_TYPE_FCOE_FW_BACKUP, +- FLASH_IMAGE_MAX_SIZE_g3}, +- { FLASH_NCSI_START_g3, IMG_TYPE_NCSI_FW, +- FLASH_NCSI_IMAGE_MAX_SIZE_g3}, +- { FLASH_PHY_FW_START_g3, IMG_TYPE_PHY_FW, +- FLASH_PHY_FW_IMAGE_MAX_SIZE_g3} ++ int num_comp, hdr_size; ++ struct flash_section_info *fsec = NULL; ++ ++ struct flash_comp gen3_flash_types[] = { ++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g3, OPTYPE_ISCSI_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_iSCSI}, ++ { FLASH_REDBOOT_START_g3, OPTYPE_REDBOOT, ++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g3, IMAGE_BOOT_CODE}, ++ { FLASH_iSCSI_BIOS_START_g3, OPTYPE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_ISCSI}, ++ { FLASH_PXE_BIOS_START_g3, OPTYPE_PXE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_PXE}, ++ { FLASH_FCoE_BIOS_START_g3, OPTYPE_FCOE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g3, IMAGE_OPTION_ROM_FCoE}, ++ { FLASH_iSCSI_BACKUP_IMAGE_START_g3, OPTYPE_ISCSI_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_BACKUP_iSCSI}, ++ { FLASH_FCoE_PRIMARY_IMAGE_START_g3, OPTYPE_FCOE_FW_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_FCoE}, ++ { FLASH_FCoE_BACKUP_IMAGE_START_g3, OPTYPE_FCOE_FW_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_BACKUP_FCoE}, ++ { FLASH_NCSI_START_g3, OPTYPE_NCSI_FW, ++ FLASH_NCSI_IMAGE_MAX_SIZE_g3, IMAGE_NCSI}, ++ { FLASH_PHY_FW_START_g3, OPTYPE_PHY_FW, ++ FLASH_PHY_FW_IMAGE_MAX_SIZE_g3, IMAGE_FIRMWARE_PHY} + }; +- static const struct flash_comp gen2_flash_types[8] = { +- { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, IMG_TYPE_ISCSI_ACTIVE, +- FLASH_IMAGE_MAX_SIZE_g2}, +- { FLASH_REDBOOT_START_g2, IMG_TYPE_REDBOOT, +- FLASH_REDBOOT_IMAGE_MAX_SIZE_g2}, +- { FLASH_iSCSI_BIOS_START_g2, IMG_TYPE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g2}, +- { FLASH_PXE_BIOS_START_g2, IMG_TYPE_PXE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g2}, +- { FLASH_FCoE_BIOS_START_g2, IMG_TYPE_FCOE_BIOS, +- FLASH_BIOS_IMAGE_MAX_SIZE_g2}, +- { FLASH_iSCSI_BACKUP_IMAGE_START_g2, IMG_TYPE_ISCSI_BACKUP, +- FLASH_IMAGE_MAX_SIZE_g2}, +- { FLASH_FCoE_PRIMARY_IMAGE_START_g2, IMG_TYPE_FCOE_FW_ACTIVE, +- FLASH_IMAGE_MAX_SIZE_g2}, +- { FLASH_FCoE_BACKUP_IMAGE_START_g2, IMG_TYPE_FCOE_FW_BACKUP, +- FLASH_IMAGE_MAX_SIZE_g2} ++ ++ struct flash_comp gen2_flash_types[] = { ++ { FLASH_iSCSI_PRIMARY_IMAGE_START_g2, OPTYPE_ISCSI_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_iSCSI}, ++ { FLASH_REDBOOT_START_g2, OPTYPE_REDBOOT, ++ FLASH_REDBOOT_IMAGE_MAX_SIZE_g2, IMAGE_BOOT_CODE}, ++ { FLASH_iSCSI_BIOS_START_g2, OPTYPE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_ISCSI}, ++ { FLASH_PXE_BIOS_START_g2, OPTYPE_PXE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_PXE}, ++ { FLASH_FCoE_BIOS_START_g2, OPTYPE_FCOE_BIOS, ++ FLASH_BIOS_IMAGE_MAX_SIZE_g2, IMAGE_OPTION_ROM_FCoE}, ++ { FLASH_iSCSI_BACKUP_IMAGE_START_g2, OPTYPE_ISCSI_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_BACKUP_iSCSI}, ++ { FLASH_FCoE_PRIMARY_IMAGE_START_g2, OPTYPE_FCOE_FW_ACTIVE, ++ FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_FCoE}, ++ { FLASH_FCoE_BACKUP_IMAGE_START_g2, OPTYPE_FCOE_FW_BACKUP, ++ FLASH_IMAGE_MAX_SIZE_g2, IMAGE_FIRMWARE_BACKUP_FCoE} + }; + + if (adapter->generation == BE_GEN3) { +@@ -2847,22 +2892,37 @@ static int be_flash_data(struct be_adapter *adapter, + filehdr_size = sizeof(struct flash_file_hdr_g2); + num_comp = ARRAY_SIZE(gen2_flash_types); + } ++ /* Get flash section info*/ ++ fsec = get_fsec_info(adapter, filehdr_size + img_hdrs_size, fw); ++ if (!fsec) { ++ dev_err(&adapter->pdev->dev, ++ "Invalid Cookie. UFI corrupted ?\n"); ++ return -1; ++ } + for (i = 0; i < num_comp; i++) { +- if ((pflashcomp[i].optype == IMG_TYPE_NCSI_FW) && +- memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) ++ if (!is_comp_in_ufi(adapter, fsec, pflashcomp[i].img_type)) + continue; +- if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) { ++ ++ if ((pflashcomp[i].optype == OPTYPE_NCSI_FW) && ++ memcmp(adapter->fw_ver, "3.102.148.0", 11) < 0) ++ continue; ++ ++ if (pflashcomp[i].optype == OPTYPE_PHY_FW) { + if (!phy_flashing_required(adapter)) + continue; + } +- if ((pflashcomp[i].optype == IMG_TYPE_REDBOOT) && +- (!be_flash_redboot(adapter, fw->data, +- pflashcomp[i].offset, pflashcomp[i].size, filehdr_size + +- (num_of_images * sizeof(struct image_hdr))))) ++ ++ hdr_size = filehdr_size + ++ (num_of_images * sizeof(struct image_hdr)); ++ ++ if ((pflashcomp[i].optype == OPTYPE_REDBOOT) && ++ (!be_flash_redboot(adapter, fw->data, pflashcomp[i].offset, ++ pflashcomp[i].size, hdr_size))) + continue; ++ ++ /* Flash the component */ + p = fw->data; +- p += filehdr_size + pflashcomp[i].offset +- + (num_of_images * sizeof(struct image_hdr)); ++ p += filehdr_size + pflashcomp[i].offset + img_hdrs_size; + if (p + pflashcomp[i].size > fw->data + fw->size) + return -1; + total_bytes = pflashcomp[i].size; +@@ -2873,12 +2933,12 @@ static int be_flash_data(struct be_adapter *adapter, + num_bytes = total_bytes; + total_bytes -= num_bytes; + if (!total_bytes) { +- if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) ++ if (pflashcomp[i].optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_FLASH; + else + flash_op = FLASHROM_OPER_FLASH; + } else { +- if (pflashcomp[i].optype == IMG_TYPE_PHY_FW) ++ if (pflashcomp[i].optype == OPTYPE_PHY_FW) + flash_op = FLASHROM_OPER_PHY_SAVE; + else + flash_op = FLASHROM_OPER_SAVE; +@@ -2890,7 +2950,7 @@ static int be_flash_data(struct be_adapter *adapter, + if (status) { + if ((status == ILLEGAL_IOCTL_REQ) && + (pflashcomp[i].optype == +- IMG_TYPE_PHY_FW)) ++ OPTYPE_PHY_FW)) + break; + dev_err(&adapter->pdev->dev, + "cmd to write to flash rom failed.\n"); +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0051-be2net-Ignore-status-of-some-ioctls-during-driver-lo.patch b/debian/patches/features/all/be2net/0051-be2net-Ignore-status-of-some-ioctls-during-driver-lo.patch new file mode 100644 index 000000000..c80cab68c --- /dev/null +++ b/debian/patches/features/all/be2net/0051-be2net-Ignore-status-of-some-ioctls-during-driver-lo.patch @@ -0,0 +1,49 @@ +From: Ajit Khaparde +Date: Thu, 26 Apr 2012 15:42:31 +0000 +Subject: [PATCH 51/58] be2net: Ignore status of some ioctls during driver + load + +commit ddc3f5cbaf1ddea122ec1d51c1cce97482b4d0c2 upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 17 ++++------------- + 1 file changed, 4 insertions(+), 13 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 730fb1b..9effea4 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -2696,24 +2696,15 @@ static int be_setup(struct be_adapter *adapter) + + be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL); + +- status = be_vid_config(adapter, false, 0); +- if (status) +- goto err; ++ be_vid_config(adapter, false, 0); + + be_set_rx_mode(adapter->netdev); + +- status = be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); +- /* For Lancer: It is legal for this cmd to fail on VF */ +- if (status && (be_physfn(adapter) || !lancer_chip(adapter))) +- goto err; ++ be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); + +- if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) { +- status = be_cmd_set_flow_control(adapter, adapter->tx_fc, ++ if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) ++ be_cmd_set_flow_control(adapter, adapter->tx_fc, + adapter->rx_fc); +- /* For Lancer: It is legal for this cmd to fail on VF */ +- if (status && (be_physfn(adapter) || !lancer_chip(adapter))) +- goto err; +- } + + pcie_set_readrq(adapter->pdev, 4096); + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0052-be2net-fix-speed-displayed-by-ethtool-on-certain-SKU.patch b/debian/patches/features/all/be2net/0052-be2net-fix-speed-displayed-by-ethtool-on-certain-SKU.patch new file mode 100644 index 000000000..7be6beee2 --- /dev/null +++ b/debian/patches/features/all/be2net/0052-be2net-fix-speed-displayed-by-ethtool-on-certain-SKU.patch @@ -0,0 +1,30 @@ +From: Ajit Khaparde +Date: Thu, 26 Apr 2012 15:42:39 +0000 +Subject: [PATCH 52/58] be2net: fix speed displayed by ethtool on certain SKUs + +commit 2a89611a051cdcfcf4a7ae21d18eef64fab517b4 upstream. + +logical speed returned by link_status_query needs to be multiplied by 10. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 9d71bad..b3b5fae 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -557,7 +557,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + if (!status) + be_link_status_update(adapter, link_status); + if (link_speed) +- et_speed = link_speed; ++ et_speed = link_speed * 10; + else + et_speed = convert_to_et_speed(port_speed); + } else { +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0053-be2net-update-the-driver-version.patch b/debian/patches/features/all/be2net/0053-be2net-update-the-driver-version.patch new file mode 100644 index 000000000..d59371e45 --- /dev/null +++ b/debian/patches/features/all/be2net/0053-be2net-update-the-driver-version.patch @@ -0,0 +1,28 @@ +From: Ajit Khaparde +Date: Thu, 26 Apr 2012 15:42:46 +0000 +Subject: [PATCH 53/58] be2net: update the driver version + +commit 06b0ab373df74f7916282b452b35d6389a605b8a upstream. + +Signed-off-by: Ajit Khaparde +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index 4bc18ef..c3ee910 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -33,7 +33,7 @@ + + #include "be_hw.h" + +-#define DRV_VER "4.2.116u" ++#define DRV_VER "4.2.220u" + #define DRV_NAME "be2net" + #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" + #define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0054-be2net-Fix-to-not-set-link-speed-for-disabled-functi.patch b/debian/patches/features/all/be2net/0054-be2net-Fix-to-not-set-link-speed-for-disabled-functi.patch new file mode 100644 index 000000000..0a3677df4 --- /dev/null +++ b/debian/patches/features/all/be2net/0054-be2net-Fix-to-not-set-link-speed-for-disabled-functi.patch @@ -0,0 +1,33 @@ +From: Somnath Kotur +Date: Wed, 2 May 2012 03:40:16 +0000 +Subject: [PATCH 54/58] be2net: Fix to not set link speed for disabled + functions of a UMC card + +commit 22ca7a6e9a68a7e0c149b22ebed9dcd106245bb7 upstream. + +This renders the interface view somewhat inconsistent from the Host OS POV +considering the rest of the interfaces are showing their respective speeds +based on the bandwidth assigned to them. + +Signed-off-by: Somnath Kotur +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index b3b5fae..1763836 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -558,7 +558,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + be_link_status_update(adapter, link_status); + if (link_speed) + et_speed = link_speed * 10; +- else ++ else if (link_status) + et_speed = convert_to_et_speed(port_speed); + } else { + et_speed = adapter->phy.forced_port_speed; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0055-be2net-Fix-to-apply-duplex-value-as-unknown-when-lin.patch b/debian/patches/features/all/be2net/0055-be2net-Fix-to-apply-duplex-value-as-unknown-when-lin.patch new file mode 100644 index 000000000..3e3774c6b --- /dev/null +++ b/debian/patches/features/all/be2net/0055-be2net-Fix-to-apply-duplex-value-as-unknown-when-lin.patch @@ -0,0 +1,31 @@ +From: Somnath Kotur +Date: Wed, 2 May 2012 03:40:32 +0000 +Subject: [PATCH 55/58] be2net: Fix to apply duplex value as unknown when link + is down. + +commit 682256dbef8e827385cf214f3ada8b62f6c227ed upstream. + +Suggested-by: Ben Hutchings +Signed-off-by: Sarveshwar Bandi +Signed-off-by: Somnath Kotur +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_ethtool.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c +index 1763836..730e96a 100644 +--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c ++++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c +@@ -618,7 +618,7 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) + ecmd->supported = adapter->phy.supported; + } + +- ecmd->duplex = DUPLEX_FULL; ++ ecmd->duplex = netif_carrier_ok(netdev) ? DUPLEX_FULL : DUPLEX_UNKNOWN; + ecmd->phy_address = adapter->port_num; + + return 0; +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch b/debian/patches/features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch new file mode 100644 index 000000000..4024f1f3d --- /dev/null +++ b/debian/patches/features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch @@ -0,0 +1,36 @@ +From: Somnath Kotur +Date: Wed, 2 May 2012 03:40:49 +0000 +Subject: [PATCH 56/58] be2net: Record receive queue index in skb to aid RPS. + +commit aaa6daec586cd39a6cd44b3d0ab91a84b0e3d53a upstream. + +Signed-off-by: Sarveshwar Bandi +Signed-off-by: Somnath Kotur +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 9effea4..0dd4b88 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1251,6 +1251,7 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, + skb_checksum_none_assert(skb); + + skb->protocol = eth_type_trans(skb, netdev); ++ skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]); + if (netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + +@@ -1307,6 +1308,7 @@ void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct napi_struct *napi, + skb->len = rxcp->pkt_size; + skb->data_len = rxcp->pkt_size; + skb->ip_summed = CHECKSUM_UNNECESSARY; ++ skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]); + if (adapter->netdev->features & NETIF_F_RXHASH) + skb->rxhash = rxcp->rss_hash; + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch b/debian/patches/features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch new file mode 100644 index 000000000..51e6a13f3 --- /dev/null +++ b/debian/patches/features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch @@ -0,0 +1,37 @@ +From: Somnath Kotur +Date: Wed, 2 May 2012 03:41:01 +0000 +Subject: [PATCH 57/58] be2net: Fix EEH error reset before a flash dump + completes + +commit eeb7fc7bc095546b21188e8e076a59bce73f9ca6 upstream. + +An EEH error can cause the FW to trigger a flash debug dump. +Resetting the card while flash dump is in progress can cause it not to recover. +Wait for it to finish before letting EEH flow to reset the card. + +Signed-off-by: Sathya Perla +Signed-off-by: Somnath Kotur +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be_main.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 0dd4b88..3492dc8 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -3813,6 +3813,11 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev, + + pci_disable_device(pdev); + ++ /* The error could cause the FW to trigger a flash debug dump. ++ * Resetting the card while flash dump is in progress ++ * can cause it not to recover; wait for it to finish ++ */ ++ ssleep(30); + return PCI_ERS_RESULT_NEED_RESET; + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch b/debian/patches/features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch new file mode 100644 index 000000000..841e66a8e --- /dev/null +++ b/debian/patches/features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch @@ -0,0 +1,473 @@ +From: Sathya Perla +Date: Tue, 8 May 2012 19:41:24 +0000 +Subject: [PATCH 58/58] be2net: avoid disabling sriov while VFs are assigned + +commit 39f1d94d300a58eb3e9b851d077cada4e2fa9d46 upstream. + +Calling pci_disable_sriov() while VFs are assigned to VMs causes +kernel panic. This patch uses PCI_DEV_FLAGS_ASSIGNED bit state of the +VF's pci_dev to avoid this. Also, the unconditional function reset cmd +issued on a PF probe can delete the VF configuration for the +previously enabled VFs. A scratchpad register is now used to issue a +function reset only when needed (i.e., in a crash dump scenario.) + +Signed-off-by: Sathya Perla +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/emulex/benet/be.h | 22 +-- + drivers/net/ethernet/emulex/benet/be_hw.h | 2 + + drivers/net/ethernet/emulex/benet/be_main.c | 199 ++++++++++++++++----------- + 3 files changed, 134 insertions(+), 89 deletions(-) + +diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h +index c3ee910..ecf1a81 100644 +--- a/drivers/net/ethernet/emulex/benet/be.h ++++ b/drivers/net/ethernet/emulex/benet/be.h +@@ -313,6 +313,11 @@ struct be_vf_cfg { + u32 tx_rate; + }; + ++enum vf_state { ++ ENABLED = 0, ++ ASSIGNED = 1 ++}; ++ + #define BE_FLAGS_LINK_STATUS_INIT 1 + #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) + #define BE_UC_PMAC_COUNT 30 +@@ -403,8 +408,9 @@ struct be_adapter { + u32 flash_status; + struct completion flash_compl; + +- u32 num_vfs; +- u8 is_virtfn; ++ u32 num_vfs; /* Number of VFs provisioned by PF driver */ ++ u32 dev_num_vfs; /* Number of VFs supported by HW */ ++ u8 virtfn; + struct be_vf_cfg *vf_cfg; + bool be3_native; + u32 sli_family; +@@ -417,8 +423,10 @@ struct be_adapter { + u32 uc_macs; /* Count of secondary UC MAC programmed */ + }; + +-#define be_physfn(adapter) (!adapter->is_virtfn) ++#define be_physfn(adapter) (!adapter->virtfn) + #define sriov_enabled(adapter) (adapter->num_vfs > 0) ++#define sriov_want(adapter) (adapter->dev_num_vfs && num_vfs && \ ++ be_physfn(adapter)) + #define for_all_vfs(adapter, vf_cfg, i) \ + for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \ + i++, vf_cfg++) +@@ -547,14 +555,6 @@ static inline u8 is_udp_pkt(struct sk_buff *skb) + return val; + } + +-static inline void be_check_sriov_fn_type(struct be_adapter *adapter) +-{ +- u32 sli_intf; +- +- pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); +- adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; +-} +- + static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac) + { + u32 addr; +diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h +index 0949aa6..f38b58c 100644 +--- a/drivers/net/ethernet/emulex/benet/be_hw.h ++++ b/drivers/net/ethernet/emulex/benet/be_hw.h +@@ -58,6 +58,8 @@ + + #define SLI_PORT_CONTROL_IP_MASK 0x08000000 + ++#define PCICFG_CUST_SCRATCHPAD_CSR 0x1EC ++ + /********* Memory BAR register ************/ + #define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc + /* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt +diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c +index 3492dc8..910bae8 100644 +--- a/drivers/net/ethernet/emulex/benet/be_main.c ++++ b/drivers/net/ethernet/emulex/benet/be_main.c +@@ -1041,6 +1041,29 @@ static int be_set_vf_tx_rate(struct net_device *netdev, + return status; + } + ++static int be_find_vfs(struct be_adapter *adapter, int vf_state) ++{ ++ struct pci_dev *dev, *pdev = adapter->pdev; ++ int vfs = 0, assigned_vfs = 0, pos, vf_fn; ++ u16 offset, stride; ++ ++ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); ++ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset); ++ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride); ++ ++ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL); ++ while (dev) { ++ vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF; ++ if (dev->is_virtfn && dev->devfn == vf_fn) { ++ vfs++; ++ if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) ++ assigned_vfs++; ++ } ++ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, dev); ++ } ++ return (vf_state == ASSIGNED) ? assigned_vfs : vfs; ++} ++ + static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo) + { + struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]); +@@ -1781,9 +1804,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) + + static int be_num_txqs_want(struct be_adapter *adapter) + { +- if (sriov_enabled(adapter) || be_is_mc(adapter) || +- lancer_chip(adapter) || !be_physfn(adapter) || +- adapter->generation == BE_GEN2) ++ if (sriov_want(adapter) || be_is_mc(adapter) || ++ lancer_chip(adapter) || !be_physfn(adapter) || ++ adapter->generation == BE_GEN2) + return 1; + else + return MAX_TX_QS; +@@ -2110,7 +2133,7 @@ static void be_msix_disable(struct be_adapter *adapter) + static uint be_num_rss_want(struct be_adapter *adapter) + { + if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) && +- adapter->num_vfs == 0 && be_physfn(adapter) && ++ !sriov_want(adapter) && be_physfn(adapter) && + !be_is_mc(adapter)) + return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS; + else +@@ -2144,53 +2167,6 @@ done: + return; + } + +-static int be_sriov_enable(struct be_adapter *adapter) +-{ +- be_check_sriov_fn_type(adapter); +- +-#ifdef CONFIG_PCI_IOV +- if (be_physfn(adapter) && num_vfs) { +- int status, pos; +- u16 dev_vfs; +- +- pos = pci_find_ext_capability(adapter->pdev, +- PCI_EXT_CAP_ID_SRIOV); +- pci_read_config_word(adapter->pdev, +- pos + PCI_SRIOV_TOTAL_VF, &dev_vfs); +- +- adapter->num_vfs = min_t(u16, num_vfs, dev_vfs); +- if (adapter->num_vfs != num_vfs) +- dev_info(&adapter->pdev->dev, +- "Device supports %d VFs and not %d\n", +- adapter->num_vfs, num_vfs); +- +- status = pci_enable_sriov(adapter->pdev, adapter->num_vfs); +- if (status) +- adapter->num_vfs = 0; +- +- if (adapter->num_vfs) { +- adapter->vf_cfg = kcalloc(num_vfs, +- sizeof(struct be_vf_cfg), +- GFP_KERNEL); +- if (!adapter->vf_cfg) +- return -ENOMEM; +- } +- } +-#endif +- return 0; +-} +- +-static void be_sriov_disable(struct be_adapter *adapter) +-{ +-#ifdef CONFIG_PCI_IOV +- if (sriov_enabled(adapter)) { +- pci_disable_sriov(adapter->pdev); +- kfree(adapter->vf_cfg); +- adapter->num_vfs = 0; +- } +-#endif +-} +- + static inline int be_msix_vec_get(struct be_adapter *adapter, + struct be_eq_obj *eqo) + { +@@ -2492,6 +2468,11 @@ static void be_vf_clear(struct be_adapter *adapter) + struct be_vf_cfg *vf_cfg; + u32 vf; + ++ if (be_find_vfs(adapter, ASSIGNED)) { ++ dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n"); ++ goto done; ++ } ++ + for_all_vfs(adapter, vf_cfg, vf) { + if (lancer_chip(adapter)) + be_cmd_set_mac_list(adapter, NULL, 0, vf + 1); +@@ -2501,6 +2482,10 @@ static void be_vf_clear(struct be_adapter *adapter) + + be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1); + } ++ pci_disable_sriov(adapter->pdev); ++done: ++ kfree(adapter->vf_cfg); ++ adapter->num_vfs = 0; + } + + static int be_clear(struct be_adapter *adapter) +@@ -2530,29 +2515,60 @@ static int be_clear(struct be_adapter *adapter) + be_cmd_fw_clean(adapter); + + be_msix_disable(adapter); +- kfree(adapter->pmac_id); ++ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0); + return 0; + } + +-static void be_vf_setup_init(struct be_adapter *adapter) ++static int be_vf_setup_init(struct be_adapter *adapter) + { + struct be_vf_cfg *vf_cfg; + int vf; + ++ adapter->vf_cfg = kcalloc(adapter->num_vfs, sizeof(*vf_cfg), ++ GFP_KERNEL); ++ if (!adapter->vf_cfg) ++ return -ENOMEM; ++ + for_all_vfs(adapter, vf_cfg, vf) { + vf_cfg->if_handle = -1; + vf_cfg->pmac_id = -1; + } ++ return 0; + } + + static int be_vf_setup(struct be_adapter *adapter) + { + struct be_vf_cfg *vf_cfg; ++ struct device *dev = &adapter->pdev->dev; + u32 cap_flags, en_flags, vf; + u16 def_vlan, lnk_speed; +- int status; ++ int status, enabled_vfs; ++ ++ enabled_vfs = be_find_vfs(adapter, ENABLED); ++ if (enabled_vfs) { ++ dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs); ++ dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs); ++ return 0; ++ } + +- be_vf_setup_init(adapter); ++ if (num_vfs > adapter->dev_num_vfs) { ++ dev_warn(dev, "Device supports %d VFs and not %d\n", ++ adapter->dev_num_vfs, num_vfs); ++ num_vfs = adapter->dev_num_vfs; ++ } ++ ++ status = pci_enable_sriov(adapter->pdev, num_vfs); ++ if (!status) { ++ adapter->num_vfs = num_vfs; ++ } else { ++ /* Platform doesn't support SRIOV though device supports it */ ++ dev_warn(dev, "SRIOV enable failed\n"); ++ return 0; ++ } ++ ++ status = be_vf_setup_init(adapter); ++ if (status) ++ goto err; + + cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST | + BE_IF_FLAGS_MULTICAST; +@@ -2563,9 +2579,11 @@ static int be_vf_setup(struct be_adapter *adapter) + goto err; + } + +- status = be_vf_eth_addr_config(adapter); +- if (status) +- goto err; ++ if (!enabled_vfs) { ++ status = be_vf_eth_addr_config(adapter); ++ if (status) ++ goto err; ++ } + + for_all_vfs(adapter, vf_cfg, vf) { + status = be_cmd_link_status_query(adapter, NULL, &lnk_speed, +@@ -2622,9 +2640,25 @@ do_none: + return status; + } + ++/* Routine to query per function resource limits */ ++static int be_get_config(struct be_adapter *adapter) ++{ ++ int pos; ++ u16 dev_num_vfs; ++ ++ pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV); ++ if (pos) { ++ pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF, ++ &dev_num_vfs); ++ adapter->dev_num_vfs = dev_num_vfs; ++ } ++ return 0; ++} ++ + static int be_setup(struct be_adapter *adapter) + { + struct net_device *netdev = adapter->netdev; ++ struct device *dev = &adapter->pdev->dev; + u32 cap_flags, en_flags; + u32 tx_fc, rx_fc; + int status; +@@ -2632,6 +2666,8 @@ static int be_setup(struct be_adapter *adapter) + + be_setup_init(adapter); + ++ be_get_config(adapter); ++ + be_cmd_req_native_mode(adapter); + + be_msix_enable(adapter); +@@ -2710,10 +2746,11 @@ static int be_setup(struct be_adapter *adapter) + + pcie_set_readrq(adapter->pdev, 4096); + +- if (sriov_enabled(adapter)) { +- status = be_vf_setup(adapter); +- if (status) +- goto err; ++ if (be_physfn(adapter) && num_vfs) { ++ if (adapter->dev_num_vfs) ++ be_vf_setup(adapter); ++ else ++ dev_warn(dev, "device doesn't support SRIOV\n"); + } + + be_cmd_get_phy_info(adapter); +@@ -2723,6 +2760,7 @@ static int be_setup(struct be_adapter *adapter) + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); + adapter->flags |= BE_FLAGS_WORKER_SCHEDULED; + ++ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1); + return 0; + err: + be_clear(adapter); +@@ -3344,8 +3382,6 @@ static void __devexit be_remove(struct pci_dev *pdev) + + be_ctrl_cleanup(adapter); + +- be_sriov_disable(adapter); +- + pci_set_drvdata(pdev, NULL); + pci_release_regions(pdev); + pci_disable_device(pdev); +@@ -3359,7 +3395,7 @@ bool be_is_wol_supported(struct be_adapter *adapter) + !be_is_wol_excluded(adapter)) ? true : false; + } + +-static int be_get_config(struct be_adapter *adapter) ++static int be_get_initial_config(struct be_adapter *adapter) + { + int status; + +@@ -3402,7 +3438,7 @@ static int be_get_config(struct be_adapter *adapter) + return 0; + } + +-static int be_dev_family_check(struct be_adapter *adapter) ++static int be_dev_type_check(struct be_adapter *adapter) + { + struct pci_dev *pdev = adapter->pdev; + u32 sli_intf = 0, if_type; +@@ -3435,6 +3471,9 @@ static int be_dev_family_check(struct be_adapter *adapter) + default: + adapter->generation = 0; + } ++ ++ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf); ++ adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0; + return 0; + } + +@@ -3578,6 +3617,14 @@ reschedule: + schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); + } + ++static bool be_reset_required(struct be_adapter *adapter) ++{ ++ u32 reg; ++ ++ pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, ®); ++ return reg; ++} ++ + static int __devinit be_probe(struct pci_dev *pdev, + const struct pci_device_id *pdev_id) + { +@@ -3603,7 +3650,7 @@ static int __devinit be_probe(struct pci_dev *pdev, + adapter->pdev = pdev; + pci_set_drvdata(pdev, adapter); + +- status = be_dev_family_check(adapter); ++ status = be_dev_type_check(adapter); + if (status) + goto free_netdev; + +@@ -3621,13 +3668,9 @@ static int __devinit be_probe(struct pci_dev *pdev, + } + } + +- status = be_sriov_enable(adapter); +- if (status) +- goto free_netdev; +- + status = be_ctrl_init(adapter); + if (status) +- goto disable_sriov; ++ goto free_netdev; + + if (lancer_chip(adapter)) { + status = lancer_wait_ready(adapter); +@@ -3654,9 +3697,11 @@ static int __devinit be_probe(struct pci_dev *pdev, + if (status) + goto ctrl_clean; + +- status = be_cmd_reset_function(adapter); +- if (status) +- goto ctrl_clean; ++ if (be_reset_required(adapter)) { ++ status = be_cmd_reset_function(adapter); ++ if (status) ++ goto ctrl_clean; ++ } + + /* The INTR bit may be set in the card when probed by a kdump kernel + * after a crash. +@@ -3668,7 +3713,7 @@ static int __devinit be_probe(struct pci_dev *pdev, + if (status) + goto ctrl_clean; + +- status = be_get_config(adapter); ++ status = be_get_initial_config(adapter); + if (status) + goto stats_clean; + +@@ -3697,8 +3742,6 @@ stats_clean: + be_stats_cleanup(adapter); + ctrl_clean: + be_ctrl_cleanup(adapter); +-disable_sriov: +- be_sriov_disable(adapter); + free_netdev: + free_netdev(netdev); + pci_set_drvdata(pdev, NULL); +-- +1.7.10 + diff --git a/debian/patches/series/base b/debian/patches/series/base index 63a90ccf1..f5300548d 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -232,3 +232,64 @@ + features/all/rt2x00-add-rt5372-chipset-support.patch + bugfix/all/acpi-battery-only-refresh-the-sysfs-files-when-pertinent.patch ++ bugfix/all/ethtool-null-terminate-filename-passed-to.patch + +# Update be2net driver to 3.5ish ++ features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch ++ features/all/be2net/0002-be2net-init-vf-_if_handle-vf_pmac_id-to-handle-failu.patch ++ features/all/be2net/0003-be2net-stop-checking-the-UE-registers-after-an-EEH-e.patch ++ features/all/be2net/0004-be2net-don-t-log-more-than-one-error-on-detecting-EE.patch ++ features/all/be2net/0005-be2net-stop-issuing-FW-cmds-if-any-cmd-times-out.patch ++ features/all/be2net/0006-be2net-Fix-TX-queue-create-for-Lancer.patch ++ features/all/be2net/0007-be2net-add-register-dump-feature-for-Lancer.patch ++ features/all/be2net/0008-be2net-Add-EEPROM-dump-feature-for-Lancer.patch ++ features/all/be2net/0009-be2net-Fix-VLAN-promiscous-mode-for-Lancer.patch ++ features/all/be2net/0010-be2net-Use-V1-query-link-status-command-for-lancer.patch ++ features/all/be2net/0011-be2net-Move-to-new-SR-IOV-implementation-in-Lancer.patch ++ features/all/be2net/0012-be2net-Fix-error-recovery-paths.patch ++ features/all/be2net/0013-be2net-Add-error-handling-for-Lancer.patch ++ features/all/be2net/0014-be2net-Use-new-hash-key.patch ++ features/all/be2net/0015-be2net-Fix-non-utilization-of-RX-queues.patch ++ features/all/be2net/0016-be2net-netpoll-support.patch ++ features/all/be2net/0017-be2net-update-some-counters-to-display-via-ethtool.patch ++ features/all/be2net/0018-be2net-workaround-to-fix-a-bug-in-BE.patch ++ features/all/be2net/0019-be2net-fix-ethtool-ringparam-reporting.patch ++ features/all/be2net/0020-be2net-refactor-cleanup-vf-configuration-code.patch ++ features/all/be2net/0021-be2net-Add-support-for-Skyhawk-cards.patch ++ features/all/be2net/0022-be2net-Fix-INTx-processing-for-Lancer.patch ++ features/all/be2net/0023-be2net-fix-be_vlan_add-rem_vid.patch ++ features/all/be2net/0024-be2net-fix-range-check-for-set_qos-for-a-VF.patch ++ features/all/be2net/0025-be2net-query-link-status-in-be_open.patch ++ features/all/be2net/0026-netdev-make-net_device_ops-const.patch ++ features/all/be2net/0027-be2net-create-RSS-rings-even-in-multi-channel-config.patch ++ features/all/be2net/0028-be2net-allocate-more-headroom-in-incoming-skbs.patch ++ features/all/be2net/0029-be2net-add-descriptions-for-stat-counters-reported-v.patch ++ features/all/be2net/0030-be2net-Fix-link-status-query-command.patch ++ features/all/be2net/0031-be2net-Use-new-implementation-of-get-mac-list-comman.patch ++ features/all/be2net/0032-be2net-event-queue-re-design.patch ++ features/all/be2net/0033-be2net-cancel-be_worker-during-EEH-recovery.patch ++ features/all/be2net/0034-be2net-fix-tx-completion-cleanup.patch ++ features/all/be2net/0035-be2net-reset-queue-address-after-freeing.patch ++ features/all/be2net/0036-be2net-enable-RSS-for-ipv6-pkts.patch ++ features/all/be2net/0037-be2net-update-driver-version.patch ++ features/all/be2net/0038-be2net-Remove-unused-OFFSET_IN_PAGE-macro.patch ++ features/all/be2net/0039-be2net-enable-WOL-by-default-if-h-w-supports-it.patch ++ features/all/be2net/0040-be2net-Program-secondary-UC-MAC-address-into-MAC-fil.patch ++ features/all/be2net/0041-be2net-Fix-number-of-vlan-slots-in-flex-mode.patch ++ features/all/be2net/0042-be2net-fix-programming-of-VLAN-tags-for-VF.patch ++ features/all/be2net/0043-be2net-fix-ethtool-get-settings.patch ++ features/all/be2net/0044-be2net-Fix-VLAN-multicast-packet-reception.patch ++ features/all/be2net/0045-be2net-Fix-FW-download-in-Lancer.patch ++ features/all/be2net/0046-be2net-Fix-ethtool-self-test-for-Lancer.patch ++ features/all/be2net/0047-be2net-Fix-traffic-stall-INTx-mode.patch ++ features/all/be2net/0048-be2net-Fix-Lancer-statistics.patch ++ features/all/be2net/0049-be2net-Fix-wrong-status-getting-returned-for-MCC-com.patch ++ features/all/be2net/0050-be2net-Fix-FW-download-for-BE.patch ++ features/all/be2net/0051-be2net-Ignore-status-of-some-ioctls-during-driver-lo.patch ++ features/all/be2net/0052-be2net-fix-speed-displayed-by-ethtool-on-certain-SKU.patch ++ features/all/be2net/0053-be2net-update-the-driver-version.patch ++ features/all/be2net/0054-be2net-Fix-to-not-set-link-speed-for-disabled-functi.patch ++ features/all/be2net/0055-be2net-Fix-to-apply-duplex-value-as-unknown-when-lin.patch ++ features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch ++ features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch ++ features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch From f27223075db8b43f56c285b03b4e80a5217d4b30 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 27 May 2012 21:32:18 +0000 Subject: [PATCH 02/13] Add credit for be2net backport svn path=/dists/sid/linux-2.6/; revision=19039 --- debian/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 0c136dc8c..e3446c9e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,8 @@ linux-2.6 (3.2.18-2) UNRELEASED; urgency=low [ Ben Hutchings ] - * be2net: Backport most changes up to Linux 3.5-rc1 (Closes: #673391) + * be2net: Backport most changes up to Linux 3.5-rc1, thanks to + Sarveshwar Bandi (Closes: #673391) - Add support for Skyhawk cards -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 From ec8c372709a2c0beabc726049cd38d3078765891 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 28 May 2012 01:50:18 +0000 Subject: [PATCH 03/13] net/sched: Add codel and fq_codel from Linux 3.5-rc1 svn path=/dists/sid/linux-2.6/; revision=19042 --- debian/changelog | 1 + debian/config/config | 2 + .../0001-codel-Controlled-Delay-AQM.patch | 771 ++++++++++++++++ ...n-method-instead-of-sqrt-and-divides.patch | 189 ++++ .../0003-fq_codel-Fair-Queue-Codel-AQM.patch | 850 ++++++++++++++++++ ...Add-missing-include-linux-prefetch.h.patch | 37 + .../0005-net-codel-fix-build-errors.patch | 55 ++ ...eld-instead-of-31bits-for-rec_inv_sq.patch | 90 ++ ...hould-use-qdisc-backlog-as-threshold.patch | 140 +++ ...low_dissector-use-a-64bit-load-store.patch | 90 ++ ...tor.c-missing-include-linux-export.h.patch | 25 + .../all/net-introduce-skb_flow_dissect.patch | 195 ++++ debian/patches/series/base | 12 + 13 files changed, 2457 insertions(+) create mode 100644 debian/patches/features/all/codel/0001-codel-Controlled-Delay-AQM.patch create mode 100644 debian/patches/features/all/codel/0002-codel-use-Newton-method-instead-of-sqrt-and-divides.patch create mode 100644 debian/patches/features/all/codel/0003-fq_codel-Fair-Queue-Codel-AQM.patch create mode 100644 debian/patches/features/all/codel/0004-net-codel-Add-missing-include-linux-prefetch.h.patch create mode 100644 debian/patches/features/all/codel/0005-net-codel-fix-build-errors.patch create mode 100644 debian/patches/features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch create mode 100644 debian/patches/features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch create mode 100644 debian/patches/features/all/flow_dissector-use-a-64bit-load-store.patch create mode 100644 debian/patches/features/all/net-flow_dissector.c-missing-include-linux-export.h.patch create mode 100644 debian/patches/features/all/net-introduce-skb_flow_dissect.patch diff --git a/debian/changelog b/debian/changelog index e3446c9e7..a52b30b8f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ linux-2.6 (3.2.18-2) UNRELEASED; urgency=low * be2net: Backport most changes up to Linux 3.5-rc1, thanks to Sarveshwar Bandi (Closes: #673391) - Add support for Skyhawk cards + * net/sched: Add codel and fq_codel from Linux 3.5-rc1 -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/config/config b/debian/config/config index fd240bf1c..90459d49a 100644 --- a/debian/config/config +++ b/debian/config/config @@ -4554,6 +4554,8 @@ CONFIG_NET_SCH_DRR=m CONFIG_NET_SCH_MQPRIO=m CONFIG_NET_SCH_CHOKE=m CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_CLS_BASIC=m CONFIG_NET_CLS_TCINDEX=m diff --git a/debian/patches/features/all/codel/0001-codel-Controlled-Delay-AQM.patch b/debian/patches/features/all/codel/0001-codel-Controlled-Delay-AQM.patch new file mode 100644 index 000000000..0d8d18b57 --- /dev/null +++ b/debian/patches/features/all/codel/0001-codel-Controlled-Delay-AQM.patch @@ -0,0 +1,771 @@ +From: Eric Dumazet +Date: Thu, 10 May 2012 07:51:25 +0000 +Subject: [PATCH 1/7] codel: Controlled Delay AQM + +commit 76e3cc126bb223013a6b9a0e2a51238d1ef2e409 upstream. + +An implementation of CoDel AQM, from Kathleen Nichols and Van Jacobson. + +http://queue.acm.org/detail.cfm?id=2209336 + +This AQM main input is no longer queue size in bytes or packets, but the +delay packets stay in (FIFO) queue. + +As we don't have infinite memory, we still can drop packets in enqueue() +in case of massive load, but mean of CoDel is to drop packets in +dequeue(), using a control law based on two simple parameters : + +target : target sojourn time (default 5ms) +interval : width of moving time window (default 100ms) + +Based on initial work from Dave Taht. + +Refactored to help future codel inclusion as a plugin for other linux +qdisc (FQ_CODEL, ...), like RED. + +include/net/codel.h contains codel algorithm as close as possible than +Kathleen reference. + +net/sched/sch_codel.c contains the linux qdisc specific glue. + +Separate structures permit a memory efficient implementation of fq_codel +(to be sent as a separate work) : Each flow has its own struct +codel_vars. + +timestamps are taken at enqueue() time with 1024 ns precision, allowing +a range of 2199 seconds in queue, and 100Gb links support. iproute2 uses +usec as base unit. + +Selected packets are dropped, unless ECN is enabled and packets can get +ECN mark instead. + +Tested from 2Mb to 10Gb speeds with no particular problems, on ixgbe and +tg3 drivers (BQL enabled). + +Usage: tc qdisc ... codel [ limit PACKETS ] [ target TIME ] + [ interval TIME ] [ ecn ] + +qdisc codel 10: parent 1:1 limit 2000p target 3.0ms interval 60.0ms ecn + Sent 13347099587 bytes 8815805 pkt (dropped 0, overlimits 0 requeues 0) + rate 202365Kbit 16708pps backlog 113550b 75p requeues 0 + count 116 lastcount 98 ldelay 4.3ms dropping drop_next 816us + maxpacket 1514 ecn_mark 84399 drop_overlimit 0 + +CoDel must be seen as a base module, and should be used keeping in mind +there is still a FIFO queue. So a typical setup will probably need a +hierarchy of several qdiscs and packet classifiers to be able to meet +whatever constraints a user might have. + +One possible example would be to use fq_codel, which combines Fair +Queueing and CoDel, in replacement of sfq / sfq_red. + +Signed-off-by: Eric Dumazet +Signed-off-by: Dave Taht +Cc: Kathleen Nichols +Cc: Van Jacobson +Cc: Tom Herbert +Cc: Matt Mathis +Cc: Yuchung Cheng +Cc: Stephen Hemminger +Signed-off-by: David S. Miller +--- + include/linux/pkt_sched.h | 26 ++++ + include/net/codel.h | 332 +++++++++++++++++++++++++++++++++++++++++++++ + net/sched/Kconfig | 11 ++ + net/sched/Makefile | 1 + + net/sched/sch_codel.c | 275 +++++++++++++++++++++++++++++++++++++ + 5 files changed, 645 insertions(+) + create mode 100644 include/net/codel.h + create mode 100644 net/sched/sch_codel.c + +diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h +index ffe975c..cde56c2 100644 +--- a/include/linux/pkt_sched.h ++++ b/include/linux/pkt_sched.h +@@ -655,4 +655,30 @@ struct tc_qfq_stats { + __u32 lmax; + }; + ++/* CODEL */ ++ ++enum { ++ TCA_CODEL_UNSPEC, ++ TCA_CODEL_TARGET, ++ TCA_CODEL_LIMIT, ++ TCA_CODEL_INTERVAL, ++ TCA_CODEL_ECN, ++ __TCA_CODEL_MAX ++}; ++ ++#define TCA_CODEL_MAX (__TCA_CODEL_MAX - 1) ++ ++struct tc_codel_xstats { ++ __u32 maxpacket; /* largest packet we've seen so far */ ++ __u32 count; /* how many drops we've done since the last time we ++ * entered dropping state ++ */ ++ __u32 lastcount; /* count at entry to dropping state */ ++ __u32 ldelay; /* in-queue delay seen by most recently dequeued packet */ ++ __s32 drop_next; /* time to drop next packet */ ++ __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ ++ __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ ++ __u32 dropping; /* are we in dropping state ? */ ++}; ++ + #endif +diff --git a/include/net/codel.h b/include/net/codel.h +new file mode 100644 +index 0000000..bce2cef +--- /dev/null ++++ b/include/net/codel.h +@@ -0,0 +1,332 @@ ++#ifndef __NET_SCHED_CODEL_H ++#define __NET_SCHED_CODEL_H ++ ++/* ++ * Codel - The Controlled-Delay Active Queue Management algorithm ++ * ++ * Copyright (C) 2011-2012 Kathleen Nichols ++ * Copyright (C) 2011-2012 Van Jacobson ++ * Copyright (C) 2012 Michael D. Taht ++ * Copyright (C) 2012 Eric Dumazet ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the authors may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * Alternatively, provided that this notice is retained in full, this ++ * software may be distributed under the terms of the GNU General ++ * Public License ("GPL") version 2, in which case the provisions of the ++ * GPL apply INSTEAD OF those given above. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Controlling Queue Delay (CoDel) algorithm ++ * ========================================= ++ * Source : Kathleen Nichols and Van Jacobson ++ * http://queue.acm.org/detail.cfm?id=2209336 ++ * ++ * Implemented on linux by Dave Taht and Eric Dumazet ++ */ ++ ++ ++/* CoDel uses a 1024 nsec clock, encoded in u32 ++ * This gives a range of 2199 seconds, because of signed compares ++ */ ++typedef u32 codel_time_t; ++typedef s32 codel_tdiff_t; ++#define CODEL_SHIFT 10 ++#define MS2TIME(a) ((a * NSEC_PER_MSEC) >> CODEL_SHIFT) ++ ++static inline codel_time_t codel_get_time(void) ++{ ++ u64 ns = ktime_to_ns(ktime_get()); ++ ++ return ns >> CODEL_SHIFT; ++} ++ ++#define codel_time_after(a, b) ((s32)(a) - (s32)(b) > 0) ++#define codel_time_after_eq(a, b) ((s32)(a) - (s32)(b) >= 0) ++#define codel_time_before(a, b) ((s32)(a) - (s32)(b) < 0) ++#define codel_time_before_eq(a, b) ((s32)(a) - (s32)(b) <= 0) ++ ++/* Qdiscs using codel plugin must use codel_skb_cb in their own cb[] */ ++struct codel_skb_cb { ++ codel_time_t enqueue_time; ++}; ++ ++static struct codel_skb_cb *get_codel_cb(const struct sk_buff *skb) ++{ ++ qdisc_cb_private_validate(skb, sizeof(struct codel_skb_cb)); ++ return (struct codel_skb_cb *)qdisc_skb_cb(skb)->data; ++} ++ ++static codel_time_t codel_get_enqueue_time(const struct sk_buff *skb) ++{ ++ return get_codel_cb(skb)->enqueue_time; ++} ++ ++static void codel_set_enqueue_time(struct sk_buff *skb) ++{ ++ get_codel_cb(skb)->enqueue_time = codel_get_time(); ++} ++ ++static inline u32 codel_time_to_us(codel_time_t val) ++{ ++ u64 valns = ((u64)val << CODEL_SHIFT); ++ ++ do_div(valns, NSEC_PER_USEC); ++ return (u32)valns; ++} ++ ++/** ++ * struct codel_params - contains codel parameters ++ * @target: target queue size (in time units) ++ * @interval: width of moving time window ++ * @ecn: is Explicit Congestion Notification enabled ++ */ ++struct codel_params { ++ codel_time_t target; ++ codel_time_t interval; ++ bool ecn; ++}; ++ ++/** ++ * struct codel_vars - contains codel variables ++ * @count: how many drops we've done since the last time we ++ * entered dropping state ++ * @lastcount: count at entry to dropping state ++ * @dropping: set to true if in dropping state ++ * @first_above_time: when we went (or will go) continuously above target ++ * for interval ++ * @drop_next: time to drop next packet, or when we dropped last ++ * @ldelay: sojourn time of last dequeued packet ++ */ ++struct codel_vars { ++ u32 count; ++ u32 lastcount; ++ bool dropping; ++ codel_time_t first_above_time; ++ codel_time_t drop_next; ++ codel_time_t ldelay; ++}; ++ ++/** ++ * struct codel_stats - contains codel shared variables and stats ++ * @maxpacket: largest packet we've seen so far ++ * @drop_count: temp count of dropped packets in dequeue() ++ * ecn_mark: number of packets we ECN marked instead of dropping ++ */ ++struct codel_stats { ++ u32 maxpacket; ++ u32 drop_count; ++ u32 ecn_mark; ++}; ++ ++static void codel_params_init(struct codel_params *params) ++{ ++ params->interval = MS2TIME(100); ++ params->target = MS2TIME(5); ++ params->ecn = false; ++} ++ ++static void codel_vars_init(struct codel_vars *vars) ++{ ++ vars->drop_next = 0; ++ vars->first_above_time = 0; ++ vars->dropping = false; /* exit dropping state */ ++ vars->count = 0; ++ vars->lastcount = 0; ++} ++ ++static void codel_stats_init(struct codel_stats *stats) ++{ ++ stats->maxpacket = 256; ++} ++ ++/* return interval/sqrt(x) with good precision ++ * relies on int_sqrt(unsigned long x) kernel implementation ++ */ ++static u32 codel_inv_sqrt(u32 _interval, u32 _x) ++{ ++ u64 interval = _interval; ++ unsigned long x = _x; ++ ++ /* Scale operands for max precision */ ++ ++#if BITS_PER_LONG == 64 ++ x <<= 32; /* On 64bit arches, we can prescale x by 32bits */ ++ interval <<= 16; ++#endif ++ ++ while (x < (1UL << (BITS_PER_LONG - 2))) { ++ x <<= 2; ++ interval <<= 1; ++ } ++ do_div(interval, int_sqrt(x)); ++ return (u32)interval; ++} ++ ++static codel_time_t codel_control_law(codel_time_t t, ++ codel_time_t interval, ++ u32 count) ++{ ++ return t + codel_inv_sqrt(interval, count); ++} ++ ++ ++static bool codel_should_drop(struct sk_buff *skb, ++ unsigned int *backlog, ++ struct codel_vars *vars, ++ struct codel_params *params, ++ struct codel_stats *stats, ++ codel_time_t now) ++{ ++ bool ok_to_drop; ++ ++ if (!skb) { ++ vars->first_above_time = 0; ++ return false; ++ } ++ ++ vars->ldelay = now - codel_get_enqueue_time(skb); ++ *backlog -= qdisc_pkt_len(skb); ++ ++ if (unlikely(qdisc_pkt_len(skb) > stats->maxpacket)) ++ stats->maxpacket = qdisc_pkt_len(skb); ++ ++ if (codel_time_before(vars->ldelay, params->target) || ++ *backlog <= stats->maxpacket) { ++ /* went below - stay below for at least interval */ ++ vars->first_above_time = 0; ++ return false; ++ } ++ ok_to_drop = false; ++ if (vars->first_above_time == 0) { ++ /* just went above from below. If we stay above ++ * for at least interval we'll say it's ok to drop ++ */ ++ vars->first_above_time = now + params->interval; ++ } else if (codel_time_after(now, vars->first_above_time)) { ++ ok_to_drop = true; ++ } ++ return ok_to_drop; ++} ++ ++typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *vars, ++ struct Qdisc *sch); ++ ++static struct sk_buff *codel_dequeue(struct Qdisc *sch, ++ struct codel_params *params, ++ struct codel_vars *vars, ++ struct codel_stats *stats, ++ codel_skb_dequeue_t dequeue_func, ++ u32 *backlog) ++{ ++ struct sk_buff *skb = dequeue_func(vars, sch); ++ codel_time_t now; ++ bool drop; ++ ++ if (!skb) { ++ vars->dropping = false; ++ return skb; ++ } ++ now = codel_get_time(); ++ drop = codel_should_drop(skb, backlog, vars, params, stats, now); ++ if (vars->dropping) { ++ if (!drop) { ++ /* sojourn time below target - leave dropping state */ ++ vars->dropping = false; ++ } else if (codel_time_after_eq(now, vars->drop_next)) { ++ /* It's time for the next drop. Drop the current ++ * packet and dequeue the next. The dequeue might ++ * take us out of dropping state. ++ * If not, schedule the next drop. ++ * A large backlog might result in drop rates so high ++ * that the next drop should happen now, ++ * hence the while loop. ++ */ ++ while (vars->dropping && ++ codel_time_after_eq(now, vars->drop_next)) { ++ if (++vars->count == 0) /* avoid zero divides */ ++ vars->count = ~0U; ++ if (params->ecn && INET_ECN_set_ce(skb)) { ++ stats->ecn_mark++; ++ vars->drop_next = ++ codel_control_law(vars->drop_next, ++ params->interval, ++ vars->count); ++ goto end; ++ } ++ qdisc_drop(skb, sch); ++ stats->drop_count++; ++ skb = dequeue_func(vars, sch); ++ if (!codel_should_drop(skb, backlog, ++ vars, params, stats, now)) { ++ /* leave dropping state */ ++ vars->dropping = false; ++ } else { ++ /* and schedule the next drop */ ++ vars->drop_next = ++ codel_control_law(vars->drop_next, ++ params->interval, ++ vars->count); ++ } ++ } ++ } ++ } else if (drop) { ++ if (params->ecn && INET_ECN_set_ce(skb)) { ++ stats->ecn_mark++; ++ } else { ++ qdisc_drop(skb, sch); ++ stats->drop_count++; ++ ++ skb = dequeue_func(vars, sch); ++ drop = codel_should_drop(skb, backlog, vars, params, ++ stats, now); ++ } ++ vars->dropping = true; ++ /* if min went above target close to when we last went below it ++ * assume that the drop rate that controlled the queue on the ++ * last cycle is a good starting point to control it now. ++ */ ++ if (codel_time_before(now - vars->drop_next, ++ 16 * params->interval)) { ++ vars->count = (vars->count - vars->lastcount) | 1; ++ } else { ++ vars->count = 1; ++ } ++ vars->lastcount = vars->count; ++ vars->drop_next = codel_control_law(now, params->interval, ++ vars->count); ++ } ++end: ++ return skb; ++} ++#endif +diff --git a/net/sched/Kconfig b/net/sched/Kconfig +index 75b58f8..fadd252 100644 +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -250,6 +250,17 @@ config NET_SCH_QFQ + + If unsure, say N. + ++config NET_SCH_CODEL ++ tristate "Controlled Delay AQM (CODEL)" ++ help ++ Say Y here if you want to use the Controlled Delay (CODEL) ++ packet scheduling algorithm. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called sch_codel. ++ ++ If unsure, say N. ++ + config NET_SCH_INGRESS + tristate "Ingress Qdisc" + depends on NET_CLS_ACT +diff --git a/net/sched/Makefile b/net/sched/Makefile +index 8cdf4e2..30fab03 100644 +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_NET_SCH_PLUG) += sch_plug.o + obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o + obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o + obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o ++obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o + + obj-$(CONFIG_NET_CLS_U32) += cls_u32.o + obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +new file mode 100644 +index 0000000..b4a1a81 +--- /dev/null ++++ b/net/sched/sch_codel.c +@@ -0,0 +1,275 @@ ++/* ++ * Codel - The Controlled-Delay Active Queue Management algorithm ++ * ++ * Copyright (C) 2011-2012 Kathleen Nichols ++ * Copyright (C) 2011-2012 Van Jacobson ++ * ++ * Implemented on linux by : ++ * Copyright (C) 2012 Michael D. Taht ++ * Copyright (C) 2012 Eric Dumazet ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions, and the following disclaimer, ++ * without modification. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * 3. The names of the authors may not be used to endorse or promote products ++ * derived from this software without specific prior written permission. ++ * ++ * Alternatively, provided that this notice is retained in full, this ++ * software may be distributed under the terms of the GNU General ++ * Public License ("GPL") version 2, in which case the provisions of the ++ * GPL apply INSTEAD OF those given above. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DEFAULT_CODEL_LIMIT 1000 ++ ++struct codel_sched_data { ++ struct codel_params params; ++ struct codel_vars vars; ++ struct codel_stats stats; ++ u32 drop_overlimit; ++}; ++ ++/* This is the specific function called from codel_dequeue() ++ * to dequeue a packet from queue. Note: backlog is handled in ++ * codel, we dont need to reduce it here. ++ */ ++static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) ++{ ++ struct sk_buff *skb = __skb_dequeue(&sch->q); ++ ++ prefetch(&skb->end); /* we'll need skb_shinfo() */ ++ return skb; ++} ++ ++static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) ++{ ++ struct codel_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ ++ skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, ++ dequeue, &sch->qstats.backlog); ++ /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, ++ * or HTB crashes. Defer it for next round. ++ */ ++ if (q->stats.drop_count && sch->q.qlen) { ++ qdisc_tree_decrease_qlen(sch, q->stats.drop_count); ++ q->stats.drop_count = 0; ++ } ++ if (skb) ++ qdisc_bstats_update(sch, skb); ++ return skb; ++} ++ ++static int codel_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch) ++{ ++ struct codel_sched_data *q; ++ ++ if (likely(qdisc_qlen(sch) < sch->limit)) { ++ codel_set_enqueue_time(skb); ++ return qdisc_enqueue_tail(skb, sch); ++ } ++ q = qdisc_priv(sch); ++ q->drop_overlimit++; ++ return qdisc_drop(skb, sch); ++} ++ ++static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = { ++ [TCA_CODEL_TARGET] = { .type = NLA_U32 }, ++ [TCA_CODEL_LIMIT] = { .type = NLA_U32 }, ++ [TCA_CODEL_INTERVAL] = { .type = NLA_U32 }, ++ [TCA_CODEL_ECN] = { .type = NLA_U32 }, ++}; ++ ++static int codel_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct codel_sched_data *q = qdisc_priv(sch); ++ struct nlattr *tb[TCA_CODEL_MAX + 1]; ++ unsigned int qlen; ++ int err; ++ ++ if (!opt) ++ return -EINVAL; ++ ++ err = nla_parse_nested(tb, TCA_CODEL_MAX, opt, codel_policy); ++ if (err < 0) ++ return err; ++ ++ sch_tree_lock(sch); ++ ++ if (tb[TCA_CODEL_TARGET]) { ++ u32 target = nla_get_u32(tb[TCA_CODEL_TARGET]); ++ ++ q->params.target = ((u64)target * NSEC_PER_USEC) >> CODEL_SHIFT; ++ } ++ ++ if (tb[TCA_CODEL_INTERVAL]) { ++ u32 interval = nla_get_u32(tb[TCA_CODEL_INTERVAL]); ++ ++ q->params.interval = ((u64)interval * NSEC_PER_USEC) >> CODEL_SHIFT; ++ } ++ ++ if (tb[TCA_CODEL_LIMIT]) ++ sch->limit = nla_get_u32(tb[TCA_CODEL_LIMIT]); ++ ++ if (tb[TCA_CODEL_ECN]) ++ q->params.ecn = !!nla_get_u32(tb[TCA_CODEL_ECN]); ++ ++ qlen = sch->q.qlen; ++ while (sch->q.qlen > sch->limit) { ++ struct sk_buff *skb = __skb_dequeue(&sch->q); ++ ++ sch->qstats.backlog -= qdisc_pkt_len(skb); ++ qdisc_drop(skb, sch); ++ } ++ qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); ++ ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++static int codel_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct codel_sched_data *q = qdisc_priv(sch); ++ ++ sch->limit = DEFAULT_CODEL_LIMIT; ++ ++ codel_params_init(&q->params); ++ codel_vars_init(&q->vars); ++ codel_stats_init(&q->stats); ++ ++ if (opt) { ++ int err = codel_change(sch, opt); ++ ++ if (err) ++ return err; ++ } ++ ++ if (sch->limit >= 1) ++ sch->flags |= TCQ_F_CAN_BYPASS; ++ else ++ sch->flags &= ~TCQ_F_CAN_BYPASS; ++ ++ return 0; ++} ++ ++static int codel_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct codel_sched_data *q = qdisc_priv(sch); ++ struct nlattr *opts; ++ ++ opts = nla_nest_start(skb, TCA_OPTIONS); ++ if (opts == NULL) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(skb, TCA_CODEL_TARGET, ++ codel_time_to_us(q->params.target)) || ++ nla_put_u32(skb, TCA_CODEL_LIMIT, ++ sch->limit) || ++ nla_put_u32(skb, TCA_CODEL_INTERVAL, ++ codel_time_to_us(q->params.interval)) || ++ nla_put_u32(skb, TCA_CODEL_ECN, ++ q->params.ecn)) ++ goto nla_put_failure; ++ ++ return nla_nest_end(skb, opts); ++ ++nla_put_failure: ++ nla_nest_cancel(skb, opts); ++ return -1; ++} ++ ++static int codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) ++{ ++ const struct codel_sched_data *q = qdisc_priv(sch); ++ struct tc_codel_xstats st = { ++ .maxpacket = q->stats.maxpacket, ++ .count = q->vars.count, ++ .lastcount = q->vars.lastcount, ++ .drop_overlimit = q->drop_overlimit, ++ .ldelay = codel_time_to_us(q->vars.ldelay), ++ .dropping = q->vars.dropping, ++ .ecn_mark = q->stats.ecn_mark, ++ }; ++ ++ if (q->vars.dropping) { ++ codel_tdiff_t delta = q->vars.drop_next - codel_get_time(); ++ ++ if (delta >= 0) ++ st.drop_next = codel_time_to_us(delta); ++ else ++ st.drop_next = -codel_time_to_us(-delta); ++ } ++ ++ return gnet_stats_copy_app(d, &st, sizeof(st)); ++} ++ ++static void codel_reset(struct Qdisc *sch) ++{ ++ struct codel_sched_data *q = qdisc_priv(sch); ++ ++ qdisc_reset_queue(sch); ++ codel_vars_init(&q->vars); ++} ++ ++static struct Qdisc_ops codel_qdisc_ops __read_mostly = { ++ .id = "codel", ++ .priv_size = sizeof(struct codel_sched_data), ++ ++ .enqueue = codel_qdisc_enqueue, ++ .dequeue = codel_qdisc_dequeue, ++ .peek = qdisc_peek_dequeued, ++ .init = codel_init, ++ .reset = codel_reset, ++ .change = codel_change, ++ .dump = codel_dump, ++ .dump_stats = codel_dump_stats, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init codel_module_init(void) ++{ ++ return register_qdisc(&codel_qdisc_ops); ++} ++ ++static void __exit codel_module_exit(void) ++{ ++ unregister_qdisc(&codel_qdisc_ops); ++} ++ ++module_init(codel_module_init) ++module_exit(codel_module_exit) ++ ++MODULE_DESCRIPTION("Controlled Delay queue discipline"); ++MODULE_AUTHOR("Dave Taht"); ++MODULE_AUTHOR("Eric Dumazet"); ++MODULE_LICENSE("Dual BSD/GPL"); +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0002-codel-use-Newton-method-instead-of-sqrt-and-divides.patch b/debian/patches/features/all/codel/0002-codel-use-Newton-method-instead-of-sqrt-and-divides.patch new file mode 100644 index 000000000..954d05044 --- /dev/null +++ b/debian/patches/features/all/codel/0002-codel-use-Newton-method-instead-of-sqrt-and-divides.patch @@ -0,0 +1,189 @@ +From: Eric Dumazet +Date: Sat, 12 May 2012 03:32:13 +0000 +Subject: [PATCH 2/7] codel: use Newton method instead of sqrt() and divides + +commit 536edd67109df5e0cdb2c4ee759e9bade7976367 upstream. + +As Van pointed out, interval/sqrt(count) can be implemented using +multiplies only. + +http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots + +This patch implements the Newton method and reciprocal divide. + +Total cost is 15 cycles instead of 120 on my Corei5 machine (64bit +kernel). + +There is a small 'error' for count values < 5, but we don't really care. + +I reuse a hole in struct codel_vars : + - pack the dropping boolean into one bit + - use 31bit to store the reciprocal value of sqrt(count). + +Suggested-by: Van Jacobson +Signed-off-by: Eric Dumazet +Cc: Dave Taht +Cc: Kathleen Nichols +Cc: Tom Herbert +Cc: Matt Mathis +Cc: Yuchung Cheng +Cc: Nandita Dukkipati +Cc: Stephen Hemminger +Signed-off-by: David S. Miller +--- + include/net/codel.h | 68 ++++++++++++++++++++++++++++----------------------- + 1 file changed, 37 insertions(+), 31 deletions(-) + +diff --git a/include/net/codel.h b/include/net/codel.h +index bce2cef..bd8747c 100644 +--- a/include/net/codel.h ++++ b/include/net/codel.h +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + + /* Controlling Queue Delay (CoDel) algorithm + * ========================================= +@@ -123,6 +124,7 @@ struct codel_params { + * entered dropping state + * @lastcount: count at entry to dropping state + * @dropping: set to true if in dropping state ++ * @rec_inv_sqrt: reciprocal value of sqrt(count) >> 1 + * @first_above_time: when we went (or will go) continuously above target + * for interval + * @drop_next: time to drop next packet, or when we dropped last +@@ -131,7 +133,8 @@ struct codel_params { + struct codel_vars { + u32 count; + u32 lastcount; +- bool dropping; ++ bool dropping:1; ++ u32 rec_inv_sqrt:31; + codel_time_t first_above_time; + codel_time_t drop_next; + codel_time_t ldelay; +@@ -158,11 +161,7 @@ static void codel_params_init(struct codel_params *params) + + static void codel_vars_init(struct codel_vars *vars) + { +- vars->drop_next = 0; +- vars->first_above_time = 0; +- vars->dropping = false; /* exit dropping state */ +- vars->count = 0; +- vars->lastcount = 0; ++ memset(vars, 0, sizeof(*vars)); + } + + static void codel_stats_init(struct codel_stats *stats) +@@ -170,38 +169,37 @@ static void codel_stats_init(struct codel_stats *stats) + stats->maxpacket = 256; + } + +-/* return interval/sqrt(x) with good precision +- * relies on int_sqrt(unsigned long x) kernel implementation ++/* ++ * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots ++ * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2) ++ * ++ * Here, invsqrt is a fixed point number (< 1.0), 31bit mantissa) + */ +-static u32 codel_inv_sqrt(u32 _interval, u32 _x) ++static void codel_Newton_step(struct codel_vars *vars) + { +- u64 interval = _interval; +- unsigned long x = _x; ++ u32 invsqrt = vars->rec_inv_sqrt; ++ u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 31; ++ u64 val = (3LL << 31) - ((u64)vars->count * invsqrt2); + +- /* Scale operands for max precision */ +- +-#if BITS_PER_LONG == 64 +- x <<= 32; /* On 64bit arches, we can prescale x by 32bits */ +- interval <<= 16; +-#endif ++ val = (val * invsqrt) >> 32; + +- while (x < (1UL << (BITS_PER_LONG - 2))) { +- x <<= 2; +- interval <<= 1; +- } +- do_div(interval, int_sqrt(x)); +- return (u32)interval; ++ vars->rec_inv_sqrt = val; + } + ++/* ++ * CoDel control_law is t + interval/sqrt(count) ++ * We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid ++ * both sqrt() and divide operation. ++ */ + static codel_time_t codel_control_law(codel_time_t t, + codel_time_t interval, +- u32 count) ++ u32 rec_inv_sqrt) + { +- return t + codel_inv_sqrt(interval, count); ++ return t + reciprocal_divide(interval, rec_inv_sqrt << 1); + } + + +-static bool codel_should_drop(struct sk_buff *skb, ++static bool codel_should_drop(const struct sk_buff *skb, + unsigned int *backlog, + struct codel_vars *vars, + struct codel_params *params, +@@ -274,14 +272,16 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + */ + while (vars->dropping && + codel_time_after_eq(now, vars->drop_next)) { +- if (++vars->count == 0) /* avoid zero divides */ +- vars->count = ~0U; ++ vars->count++; /* dont care of possible wrap ++ * since there is no more divide ++ */ ++ codel_Newton_step(vars); + if (params->ecn && INET_ECN_set_ce(skb)) { + stats->ecn_mark++; + vars->drop_next = + codel_control_law(vars->drop_next, + params->interval, +- vars->count); ++ vars->rec_inv_sqrt); + goto end; + } + qdisc_drop(skb, sch); +@@ -296,7 +296,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + vars->drop_next = + codel_control_law(vars->drop_next, + params->interval, +- vars->count); ++ vars->rec_inv_sqrt); + } + } + } +@@ -319,12 +319,18 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + if (codel_time_before(now - vars->drop_next, + 16 * params->interval)) { + vars->count = (vars->count - vars->lastcount) | 1; ++ /* we dont care if rec_inv_sqrt approximation ++ * is not very precise : ++ * Next Newton steps will correct it quadratically. ++ */ ++ codel_Newton_step(vars); + } else { + vars->count = 1; ++ vars->rec_inv_sqrt = 0x7fffffff; + } + vars->lastcount = vars->count; + vars->drop_next = codel_control_law(now, params->interval, +- vars->count); ++ vars->rec_inv_sqrt); + } + end: + return skb; +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0003-fq_codel-Fair-Queue-Codel-AQM.patch b/debian/patches/features/all/codel/0003-fq_codel-Fair-Queue-Codel-AQM.patch new file mode 100644 index 000000000..e1d2260b9 --- /dev/null +++ b/debian/patches/features/all/codel/0003-fq_codel-Fair-Queue-Codel-AQM.patch @@ -0,0 +1,850 @@ +From: Eric Dumazet +Date: Fri, 11 May 2012 09:30:50 +0000 +Subject: [PATCH 3/7] fq_codel: Fair Queue Codel AQM + +commit 4b549a2ef4bef9965d97cbd992ba67930cd3e0fe upstream. + +Fair Queue Codel packet scheduler + +Principles : + +- Packets are classified (internal classifier or external) on flows. +- This is a Stochastic model (as we use a hash, several flows might + be hashed on same slot) +- Each flow has a CoDel managed queue. +- Flows are linked onto two (Round Robin) lists, + so that new flows have priority on old ones. + +- For a given flow, packets are not reordered (CoDel uses a FIFO) +- head drops only. +- ECN capability is on by default. +- Very low memory footprint (64 bytes per flow) + +tc qdisc ... fq_codel [ limit PACKETS ] [ flows number ] + [ target TIME ] [ interval TIME ] [ noecn ] + [ quantum BYTES ] + +defaults : 1024 flows, 10240 packets limit, quantum : device MTU + target : 5ms (CoDel default) + interval : 100ms (CoDel default) + +Impressive results on load : + +class htb 1:1 root leaf 10: prio 0 quantum 1514 rate 200000Kbit ceil 200000Kbit burst 1475b/8 mpu 0b overhead 0b cburst 1475b/8 mpu 0b overhead 0b level 0 + Sent 43304920109 bytes 33063109 pkt (dropped 0, overlimits 0 requeues 0) + rate 201691Kbit 28595pps backlog 0b 312p requeues 0 + lended: 33063109 borrowed: 0 giants: 0 + tokens: -912 ctokens: -912 + +class fq_codel 10:1735 parent 10: + (dropped 1292, overlimits 0 requeues 0) + backlog 15140b 10p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.1ms +class fq_codel 10:4524 parent 10: + (dropped 1291, overlimits 0 requeues 0) + backlog 16654b 11p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.1ms +class fq_codel 10:4e74 parent 10: + (dropped 1290, overlimits 0 requeues 0) + backlog 6056b 4p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 6.4ms dropping drop_next 92.0ms +class fq_codel 10:628a parent 10: + (dropped 1289, overlimits 0 requeues 0) + backlog 7570b 5p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 5.4ms dropping drop_next 90.9ms +class fq_codel 10:a4b3 parent 10: + (dropped 302, overlimits 0 requeues 0) + backlog 16654b 11p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.1ms +class fq_codel 10:c3c2 parent 10: + (dropped 1284, overlimits 0 requeues 0) + backlog 13626b 9p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 5.9ms +class fq_codel 10:d331 parent 10: + (dropped 299, overlimits 0 requeues 0) + backlog 15140b 10p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.0ms +class fq_codel 10:d526 parent 10: + (dropped 12160, overlimits 0 requeues 0) + backlog 35870b 211p requeues 0 + deficit 1508 count 12160 lastcount 1 ldelay 15.3ms dropping drop_next 247us +class fq_codel 10:e2c6 parent 10: + (dropped 1288, overlimits 0 requeues 0) + backlog 15140b 10p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.1ms +class fq_codel 10:eab5 parent 10: + (dropped 1285, overlimits 0 requeues 0) + backlog 16654b 11p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 5.9ms +class fq_codel 10:f220 parent 10: + (dropped 1289, overlimits 0 requeues 0) + backlog 15140b 10p requeues 0 + deficit 1514 count 1 lastcount 1 ldelay 7.1ms + +qdisc htb 1: root refcnt 6 r2q 10 default 1 direct_packets_stat 0 ver 3.17 + Sent 43331086547 bytes 33092812 pkt (dropped 0, overlimits 66063544 requeues 71) + rate 201697Kbit 28602pps backlog 0b 260p requeues 71 +qdisc fq_codel 10: parent 1:1 limit 10240p flows 65536 target 5.0ms interval 100.0ms ecn + Sent 43331086547 bytes 33092812 pkt (dropped 949359, overlimits 0 requeues 0) + rate 201697Kbit 28602pps backlog 189352b 260p requeues 0 + maxpacket 1514 drop_overlimit 0 new_flow_count 5582 ecn_mark 125593 + new_flows_len 0 old_flows_len 11 + +PING 172.30.42.18 (172.30.42.18) 56(84) bytes of data. +64 bytes from 172.30.42.18: icmp_req=1 ttl=64 time=0.227 ms +64 bytes from 172.30.42.18: icmp_req=2 ttl=64 time=0.165 ms +64 bytes from 172.30.42.18: icmp_req=3 ttl=64 time=0.166 ms +64 bytes from 172.30.42.18: icmp_req=4 ttl=64 time=0.151 ms +64 bytes from 172.30.42.18: icmp_req=5 ttl=64 time=0.164 ms +64 bytes from 172.30.42.18: icmp_req=6 ttl=64 time=0.172 ms +64 bytes from 172.30.42.18: icmp_req=7 ttl=64 time=0.175 ms +64 bytes from 172.30.42.18: icmp_req=8 ttl=64 time=0.183 ms +64 bytes from 172.30.42.18: icmp_req=9 ttl=64 time=0.158 ms +64 bytes from 172.30.42.18: icmp_req=10 ttl=64 time=0.200 ms + +10 packets transmitted, 10 received, 0% packet loss, time 8999ms +rtt min/avg/max/mdev = 0.151/0.176/0.227/0.022 ms + +Much better than SFQ because of priority given to new flows, and fast +path dirtying less cache lines. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + include/linux/pkt_sched.h | 54 ++++ + net/sched/Kconfig | 11 + + net/sched/Makefile | 1 + + net/sched/sch_fq_codel.c | 624 +++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 690 insertions(+) + create mode 100644 net/sched/sch_fq_codel.c + +diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h +index cde56c2..32aef0a 100644 +--- a/include/linux/pkt_sched.h ++++ b/include/linux/pkt_sched.h +@@ -681,4 +681,58 @@ struct tc_codel_xstats { + __u32 dropping; /* are we in dropping state ? */ + }; + ++/* FQ_CODEL */ ++ ++enum { ++ TCA_FQ_CODEL_UNSPEC, ++ TCA_FQ_CODEL_TARGET, ++ TCA_FQ_CODEL_LIMIT, ++ TCA_FQ_CODEL_INTERVAL, ++ TCA_FQ_CODEL_ECN, ++ TCA_FQ_CODEL_FLOWS, ++ TCA_FQ_CODEL_QUANTUM, ++ __TCA_FQ_CODEL_MAX ++}; ++ ++#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1) ++ ++enum { ++ TCA_FQ_CODEL_XSTATS_QDISC, ++ TCA_FQ_CODEL_XSTATS_CLASS, ++}; ++ ++struct tc_fq_codel_qd_stats { ++ __u32 maxpacket; /* largest packet we've seen so far */ ++ __u32 drop_overlimit; /* number of time max qdisc ++ * packet limit was hit ++ */ ++ __u32 ecn_mark; /* number of packets we ECN marked ++ * instead of being dropped ++ */ ++ __u32 new_flow_count; /* number of time packets ++ * created a 'new flow' ++ */ ++ __u32 new_flows_len; /* count of flows in new list */ ++ __u32 old_flows_len; /* count of flows in old list */ ++}; ++ ++struct tc_fq_codel_cl_stats { ++ __s32 deficit; ++ __u32 ldelay; /* in-queue delay seen by most recently ++ * dequeued packet ++ */ ++ __u32 count; ++ __u32 lastcount; ++ __u32 dropping; ++ __s32 drop_next; ++}; ++ ++struct tc_fq_codel_xstats { ++ __u32 type; ++ union { ++ struct tc_fq_codel_qd_stats qdisc_stats; ++ struct tc_fq_codel_cl_stats class_stats; ++ }; ++}; ++ + #endif +diff --git a/net/sched/Kconfig b/net/sched/Kconfig +index fadd252..e7a8976 100644 +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -261,6 +261,17 @@ config NET_SCH_CODEL + + If unsure, say N. + ++config NET_SCH_FQ_CODEL ++ tristate "Fair Queue Controlled Delay AQM (FQ_CODEL)" ++ help ++ Say Y here if you want to use the FQ Controlled Delay (FQ_CODEL) ++ packet scheduling algorithm. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called sch_fq_codel. ++ ++ If unsure, say N. ++ + config NET_SCH_INGRESS + tristate "Ingress Qdisc" + depends on NET_CLS_ACT +diff --git a/net/sched/Makefile b/net/sched/Makefile +index 30fab03..5940a19 100644 +--- a/net/sched/Makefile ++++ b/net/sched/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o + obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o + obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o + obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o ++obj-$(CONFIG_NET_SCH_FQ_CODEL) += sch_fq_codel.o + + obj-$(CONFIG_NET_CLS_U32) += cls_u32.o + obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +new file mode 100644 +index 0000000..a7b3754 +--- /dev/null ++++ b/net/sched/sch_fq_codel.c +@@ -0,0 +1,624 @@ ++/* ++ * Fair Queue CoDel discipline ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Copyright (C) 2012 Eric Dumazet ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Fair Queue CoDel. ++ * ++ * Principles : ++ * Packets are classified (internal classifier or external) on flows. ++ * This is a Stochastic model (as we use a hash, several flows ++ * might be hashed on same slot) ++ * Each flow has a CoDel managed queue. ++ * Flows are linked onto two (Round Robin) lists, ++ * so that new flows have priority on old ones. ++ * ++ * For a given flow, packets are not reordered (CoDel uses a FIFO) ++ * head drops only. ++ * ECN capability is on by default. ++ * Low memory footprint (64 bytes per flow) ++ */ ++ ++struct fq_codel_flow { ++ struct sk_buff *head; ++ struct sk_buff *tail; ++ struct list_head flowchain; ++ int deficit; ++ u32 dropped; /* number of drops (or ECN marks) on this flow */ ++ struct codel_vars cvars; ++}; /* please try to keep this structure <= 64 bytes */ ++ ++struct fq_codel_sched_data { ++ struct tcf_proto *filter_list; /* optional external classifier */ ++ struct fq_codel_flow *flows; /* Flows table [flows_cnt] */ ++ u32 *backlogs; /* backlog table [flows_cnt] */ ++ u32 flows_cnt; /* number of flows */ ++ u32 perturbation; /* hash perturbation */ ++ u32 quantum; /* psched_mtu(qdisc_dev(sch)); */ ++ struct codel_params cparams; ++ struct codel_stats cstats; ++ u32 drop_overlimit; ++ u32 new_flow_count; ++ ++ struct list_head new_flows; /* list of new flows */ ++ struct list_head old_flows; /* list of old flows */ ++}; ++ ++static unsigned int fq_codel_hash(const struct fq_codel_sched_data *q, ++ const struct sk_buff *skb) ++{ ++ struct flow_keys keys; ++ unsigned int hash; ++ ++ skb_flow_dissect(skb, &keys); ++ hash = jhash_3words((__force u32)keys.dst, ++ (__force u32)keys.src ^ keys.ip_proto, ++ (__force u32)keys.ports, q->perturbation); ++ return ((u64)hash * q->flows_cnt) >> 32; ++} ++ ++static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch, ++ int *qerr) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct tcf_result res; ++ int result; ++ ++ if (TC_H_MAJ(skb->priority) == sch->handle && ++ TC_H_MIN(skb->priority) > 0 && ++ TC_H_MIN(skb->priority) <= q->flows_cnt) ++ return TC_H_MIN(skb->priority); ++ ++ if (!q->filter_list) ++ return fq_codel_hash(q, skb) + 1; ++ ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; ++ result = tc_classify(skb, q->filter_list, &res); ++ if (result >= 0) { ++#ifdef CONFIG_NET_CLS_ACT ++ switch (result) { ++ case TC_ACT_STOLEN: ++ case TC_ACT_QUEUED: ++ *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; ++ case TC_ACT_SHOT: ++ return 0; ++ } ++#endif ++ if (TC_H_MIN(res.classid) <= q->flows_cnt) ++ return TC_H_MIN(res.classid); ++ } ++ return 0; ++} ++ ++/* helper functions : might be changed when/if skb use a standard list_head */ ++ ++/* remove one skb from head of slot queue */ ++static inline struct sk_buff *dequeue_head(struct fq_codel_flow *flow) ++{ ++ struct sk_buff *skb = flow->head; ++ ++ flow->head = skb->next; ++ skb->next = NULL; ++ return skb; ++} ++ ++/* add skb to flow queue (tail add) */ ++static inline void flow_queue_add(struct fq_codel_flow *flow, ++ struct sk_buff *skb) ++{ ++ if (flow->head == NULL) ++ flow->head = skb; ++ else ++ flow->tail->next = skb; ++ flow->tail = skb; ++ skb->next = NULL; ++} ++ ++static unsigned int fq_codel_drop(struct Qdisc *sch) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ unsigned int maxbacklog = 0, idx = 0, i, len; ++ struct fq_codel_flow *flow; ++ ++ /* Queue is full! Find the fat flow and drop packet from it. ++ * This might sound expensive, but with 1024 flows, we scan ++ * 4KB of memory, and we dont need to handle a complex tree ++ * in fast path (packet queue/enqueue) with many cache misses. ++ */ ++ for (i = 0; i < q->flows_cnt; i++) { ++ if (q->backlogs[i] > maxbacklog) { ++ maxbacklog = q->backlogs[i]; ++ idx = i; ++ } ++ } ++ flow = &q->flows[idx]; ++ skb = dequeue_head(flow); ++ len = qdisc_pkt_len(skb); ++ q->backlogs[idx] -= len; ++ kfree_skb(skb); ++ sch->q.qlen--; ++ sch->qstats.drops++; ++ sch->qstats.backlog -= len; ++ flow->dropped++; ++ return idx; ++} ++ ++static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ unsigned int idx; ++ struct fq_codel_flow *flow; ++ int uninitialized_var(ret); ++ ++ idx = fq_codel_classify(skb, sch, &ret); ++ if (idx == 0) { ++ if (ret & __NET_XMIT_BYPASS) ++ sch->qstats.drops++; ++ kfree_skb(skb); ++ return ret; ++ } ++ idx--; ++ ++ codel_set_enqueue_time(skb); ++ flow = &q->flows[idx]; ++ flow_queue_add(flow, skb); ++ q->backlogs[idx] += qdisc_pkt_len(skb); ++ sch->qstats.backlog += qdisc_pkt_len(skb); ++ ++ if (list_empty(&flow->flowchain)) { ++ list_add_tail(&flow->flowchain, &q->new_flows); ++ codel_vars_init(&flow->cvars); ++ q->new_flow_count++; ++ flow->deficit = q->quantum; ++ flow->dropped = 0; ++ } ++ if (++sch->q.qlen < sch->limit) ++ return NET_XMIT_SUCCESS; ++ ++ q->drop_overlimit++; ++ /* Return Congestion Notification only if we dropped a packet ++ * from this flow. ++ */ ++ if (fq_codel_drop(sch) == idx) ++ return NET_XMIT_CN; ++ ++ /* As we dropped a packet, better let upper stack know this */ ++ qdisc_tree_decrease_qlen(sch, 1); ++ return NET_XMIT_SUCCESS; ++} ++ ++/* This is the specific function called from codel_dequeue() ++ * to dequeue a packet from queue. Note: backlog is handled in ++ * codel, we dont need to reduce it here. ++ */ ++static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) ++{ ++ struct fq_codel_flow *flow; ++ struct sk_buff *skb = NULL; ++ ++ flow = container_of(vars, struct fq_codel_flow, cvars); ++ if (flow->head) { ++ skb = dequeue_head(flow); ++ sch->qstats.backlog -= qdisc_pkt_len(skb); ++ sch->q.qlen--; ++ } ++ return skb; ++} ++ ++static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct sk_buff *skb; ++ struct fq_codel_flow *flow; ++ struct list_head *head; ++ u32 prev_drop_count, prev_ecn_mark; ++ ++begin: ++ head = &q->new_flows; ++ if (list_empty(head)) { ++ head = &q->old_flows; ++ if (list_empty(head)) ++ return NULL; ++ } ++ flow = list_first_entry(head, struct fq_codel_flow, flowchain); ++ ++ if (flow->deficit <= 0) { ++ flow->deficit += q->quantum; ++ list_move_tail(&flow->flowchain, &q->old_flows); ++ goto begin; ++ } ++ ++ prev_drop_count = q->cstats.drop_count; ++ prev_ecn_mark = q->cstats.ecn_mark; ++ ++ skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats, ++ dequeue, &q->backlogs[flow - q->flows]); ++ ++ flow->dropped += q->cstats.drop_count - prev_drop_count; ++ flow->dropped += q->cstats.ecn_mark - prev_ecn_mark; ++ ++ if (!skb) { ++ /* force a pass through old_flows to prevent starvation */ ++ if ((head == &q->new_flows) && !list_empty(&q->old_flows)) ++ list_move_tail(&flow->flowchain, &q->old_flows); ++ else ++ list_del_init(&flow->flowchain); ++ goto begin; ++ } ++ qdisc_bstats_update(sch, skb); ++ flow->deficit -= qdisc_pkt_len(skb); ++ /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, ++ * or HTB crashes. Defer it for next round. ++ */ ++ if (q->cstats.drop_count && sch->q.qlen) { ++ qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); ++ q->cstats.drop_count = 0; ++ } ++ return skb; ++} ++ ++static void fq_codel_reset(struct Qdisc *sch) ++{ ++ struct sk_buff *skb; ++ ++ while ((skb = fq_codel_dequeue(sch)) != NULL) ++ kfree_skb(skb); ++} ++ ++static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { ++ [TCA_FQ_CODEL_TARGET] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_LIMIT] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_INTERVAL] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_ECN] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_FLOWS] = { .type = NLA_U32 }, ++ [TCA_FQ_CODEL_QUANTUM] = { .type = NLA_U32 }, ++}; ++ ++static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct nlattr *tb[TCA_FQ_CODEL_MAX + 1]; ++ int err; ++ ++ if (!opt) ++ return -EINVAL; ++ ++ err = nla_parse_nested(tb, TCA_FQ_CODEL_MAX, opt, fq_codel_policy); ++ if (err < 0) ++ return err; ++ if (tb[TCA_FQ_CODEL_FLOWS]) { ++ if (q->flows) ++ return -EINVAL; ++ q->flows_cnt = nla_get_u32(tb[TCA_FQ_CODEL_FLOWS]); ++ if (!q->flows_cnt || ++ q->flows_cnt > 65536) ++ return -EINVAL; ++ } ++ sch_tree_lock(sch); ++ ++ if (tb[TCA_FQ_CODEL_TARGET]) { ++ u64 target = nla_get_u32(tb[TCA_FQ_CODEL_TARGET]); ++ ++ q->cparams.target = (target * NSEC_PER_USEC) >> CODEL_SHIFT; ++ } ++ ++ if (tb[TCA_FQ_CODEL_INTERVAL]) { ++ u64 interval = nla_get_u32(tb[TCA_FQ_CODEL_INTERVAL]); ++ ++ q->cparams.interval = (interval * NSEC_PER_USEC) >> CODEL_SHIFT; ++ } ++ ++ if (tb[TCA_FQ_CODEL_LIMIT]) ++ sch->limit = nla_get_u32(tb[TCA_FQ_CODEL_LIMIT]); ++ ++ if (tb[TCA_FQ_CODEL_ECN]) ++ q->cparams.ecn = !!nla_get_u32(tb[TCA_FQ_CODEL_ECN]); ++ ++ if (tb[TCA_FQ_CODEL_QUANTUM]) ++ q->quantum = max(256U, nla_get_u32(tb[TCA_FQ_CODEL_QUANTUM])); ++ ++ while (sch->q.qlen > sch->limit) { ++ struct sk_buff *skb = fq_codel_dequeue(sch); ++ ++ kfree_skb(skb); ++ q->cstats.drop_count++; ++ } ++ qdisc_tree_decrease_qlen(sch, q->cstats.drop_count); ++ q->cstats.drop_count = 0; ++ ++ sch_tree_unlock(sch); ++ return 0; ++} ++ ++static void *fq_codel_zalloc(size_t sz) ++{ ++ void *ptr = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN); ++ ++ if (!ptr) ++ ptr = vzalloc(sz); ++ return ptr; ++} ++ ++static void fq_codel_free(void *addr) ++{ ++ if (addr) { ++ if (is_vmalloc_addr(addr)) ++ vfree(addr); ++ else ++ kfree(addr); ++ } ++} ++ ++static void fq_codel_destroy(struct Qdisc *sch) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ ++ tcf_destroy_chain(&q->filter_list); ++ fq_codel_free(q->backlogs); ++ fq_codel_free(q->flows); ++} ++ ++static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ int i; ++ ++ sch->limit = 10*1024; ++ q->flows_cnt = 1024; ++ q->quantum = psched_mtu(qdisc_dev(sch)); ++ q->perturbation = net_random(); ++ INIT_LIST_HEAD(&q->new_flows); ++ INIT_LIST_HEAD(&q->old_flows); ++ codel_params_init(&q->cparams); ++ codel_stats_init(&q->cstats); ++ q->cparams.ecn = true; ++ ++ if (opt) { ++ int err = fq_codel_change(sch, opt); ++ if (err) ++ return err; ++ } ++ ++ if (!q->flows) { ++ q->flows = fq_codel_zalloc(q->flows_cnt * ++ sizeof(struct fq_codel_flow)); ++ if (!q->flows) ++ return -ENOMEM; ++ q->backlogs = fq_codel_zalloc(q->flows_cnt * sizeof(u32)); ++ if (!q->backlogs) { ++ fq_codel_free(q->flows); ++ return -ENOMEM; ++ } ++ for (i = 0; i < q->flows_cnt; i++) { ++ struct fq_codel_flow *flow = q->flows + i; ++ ++ INIT_LIST_HEAD(&flow->flowchain); ++ } ++ } ++ if (sch->limit >= 1) ++ sch->flags |= TCQ_F_CAN_BYPASS; ++ else ++ sch->flags &= ~TCQ_F_CAN_BYPASS; ++ return 0; ++} ++ ++static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct nlattr *opts; ++ ++ opts = nla_nest_start(skb, TCA_OPTIONS); ++ if (opts == NULL) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(skb, TCA_FQ_CODEL_TARGET, ++ codel_time_to_us(q->cparams.target)) || ++ nla_put_u32(skb, TCA_FQ_CODEL_LIMIT, ++ sch->limit) || ++ nla_put_u32(skb, TCA_FQ_CODEL_INTERVAL, ++ codel_time_to_us(q->cparams.interval)) || ++ nla_put_u32(skb, TCA_FQ_CODEL_ECN, ++ q->cparams.ecn) || ++ nla_put_u32(skb, TCA_FQ_CODEL_QUANTUM, ++ q->quantum) || ++ nla_put_u32(skb, TCA_FQ_CODEL_FLOWS, ++ q->flows_cnt)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, opts); ++ return skb->len; ++ ++nla_put_failure: ++ return -1; ++} ++ ++static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ struct tc_fq_codel_xstats st = { ++ .type = TCA_FQ_CODEL_XSTATS_QDISC, ++ .qdisc_stats.maxpacket = q->cstats.maxpacket, ++ .qdisc_stats.drop_overlimit = q->drop_overlimit, ++ .qdisc_stats.ecn_mark = q->cstats.ecn_mark, ++ .qdisc_stats.new_flow_count = q->new_flow_count, ++ }; ++ struct list_head *pos; ++ ++ list_for_each(pos, &q->new_flows) ++ st.qdisc_stats.new_flows_len++; ++ ++ list_for_each(pos, &q->old_flows) ++ st.qdisc_stats.old_flows_len++; ++ ++ return gnet_stats_copy_app(d, &st, sizeof(st)); ++} ++ ++static struct Qdisc *fq_codel_leaf(struct Qdisc *sch, unsigned long arg) ++{ ++ return NULL; ++} ++ ++static unsigned long fq_codel_get(struct Qdisc *sch, u32 classid) ++{ ++ return 0; ++} ++ ++static unsigned long fq_codel_bind(struct Qdisc *sch, unsigned long parent, ++ u32 classid) ++{ ++ /* we cannot bypass queue discipline anymore */ ++ sch->flags &= ~TCQ_F_CAN_BYPASS; ++ return 0; ++} ++ ++static void fq_codel_put(struct Qdisc *q, unsigned long cl) ++{ ++} ++ ++static struct tcf_proto **fq_codel_find_tcf(struct Qdisc *sch, unsigned long cl) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ ++ if (cl) ++ return NULL; ++ return &q->filter_list; ++} ++ ++static int fq_codel_dump_class(struct Qdisc *sch, unsigned long cl, ++ struct sk_buff *skb, struct tcmsg *tcm) ++{ ++ tcm->tcm_handle |= TC_H_MIN(cl); ++ return 0; ++} ++ ++static int fq_codel_dump_class_stats(struct Qdisc *sch, unsigned long cl, ++ struct gnet_dump *d) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ u32 idx = cl - 1; ++ struct gnet_stats_queue qs = { 0 }; ++ struct tc_fq_codel_xstats xstats; ++ ++ if (idx < q->flows_cnt) { ++ const struct fq_codel_flow *flow = &q->flows[idx]; ++ const struct sk_buff *skb = flow->head; ++ ++ memset(&xstats, 0, sizeof(xstats)); ++ xstats.type = TCA_FQ_CODEL_XSTATS_CLASS; ++ xstats.class_stats.deficit = flow->deficit; ++ xstats.class_stats.ldelay = ++ codel_time_to_us(flow->cvars.ldelay); ++ xstats.class_stats.count = flow->cvars.count; ++ xstats.class_stats.lastcount = flow->cvars.lastcount; ++ xstats.class_stats.dropping = flow->cvars.dropping; ++ if (flow->cvars.dropping) { ++ codel_tdiff_t delta = flow->cvars.drop_next - ++ codel_get_time(); ++ ++ xstats.class_stats.drop_next = (delta >= 0) ? ++ codel_time_to_us(delta) : ++ -codel_time_to_us(-delta); ++ } ++ while (skb) { ++ qs.qlen++; ++ skb = skb->next; ++ } ++ qs.backlog = q->backlogs[idx]; ++ qs.drops = flow->dropped; ++ } ++ if (gnet_stats_copy_queue(d, &qs) < 0) ++ return -1; ++ if (idx < q->flows_cnt) ++ return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); ++ return 0; ++} ++ ++static void fq_codel_walk(struct Qdisc *sch, struct qdisc_walker *arg) ++{ ++ struct fq_codel_sched_data *q = qdisc_priv(sch); ++ unsigned int i; ++ ++ if (arg->stop) ++ return; ++ ++ for (i = 0; i < q->flows_cnt; i++) { ++ if (list_empty(&q->flows[i].flowchain) || ++ arg->count < arg->skip) { ++ arg->count++; ++ continue; ++ } ++ if (arg->fn(sch, i + 1, arg) < 0) { ++ arg->stop = 1; ++ break; ++ } ++ arg->count++; ++ } ++} ++ ++static const struct Qdisc_class_ops fq_codel_class_ops = { ++ .leaf = fq_codel_leaf, ++ .get = fq_codel_get, ++ .put = fq_codel_put, ++ .tcf_chain = fq_codel_find_tcf, ++ .bind_tcf = fq_codel_bind, ++ .unbind_tcf = fq_codel_put, ++ .dump = fq_codel_dump_class, ++ .dump_stats = fq_codel_dump_class_stats, ++ .walk = fq_codel_walk, ++}; ++ ++static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { ++ .cl_ops = &fq_codel_class_ops, ++ .id = "fq_codel", ++ .priv_size = sizeof(struct fq_codel_sched_data), ++ .enqueue = fq_codel_enqueue, ++ .dequeue = fq_codel_dequeue, ++ .peek = qdisc_peek_dequeued, ++ .drop = fq_codel_drop, ++ .init = fq_codel_init, ++ .reset = fq_codel_reset, ++ .destroy = fq_codel_destroy, ++ .change = fq_codel_change, ++ .dump = fq_codel_dump, ++ .dump_stats = fq_codel_dump_stats, ++ .owner = THIS_MODULE, ++}; ++ ++static int __init fq_codel_module_init(void) ++{ ++ return register_qdisc(&fq_codel_qdisc_ops); ++} ++ ++static void __exit fq_codel_module_exit(void) ++{ ++ unregister_qdisc(&fq_codel_qdisc_ops); ++} ++ ++module_init(fq_codel_module_init) ++module_exit(fq_codel_module_exit) ++MODULE_AUTHOR("Eric Dumazet"); ++MODULE_LICENSE("GPL"); +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0004-net-codel-Add-missing-include-linux-prefetch.h.patch b/debian/patches/features/all/codel/0004-net-codel-Add-missing-include-linux-prefetch.h.patch new file mode 100644 index 000000000..0d3a88677 --- /dev/null +++ b/debian/patches/features/all/codel/0004-net-codel-Add-missing-include-linux-prefetch.h.patch @@ -0,0 +1,37 @@ +From: Geert Uytterhoeven +Date: Mon, 14 May 2012 09:47:05 +0000 +Subject: [PATCH 4/7] net/codel: Add missing #include +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit ce5b4b977127ee20c3f9c3fd3637cd3796f649f5 upstream. + +m68k allmodconfig: + +net/sched/sch_codel.c: In function ‘dequeue’: +net/sched/sch_codel.c:70: error: implicit declaration of function ‘prefetch’ +make[1]: *** [net/sched/sch_codel.o] Error 1 + +Signed-off-by: Geert Uytterhoeven +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + net/sched/sch_codel.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +index b4a1a81..213ef60 100644 +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -46,6 +46,7 @@ + #include + #include + #include ++#include + #include + #include + +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0005-net-codel-fix-build-errors.patch b/debian/patches/features/all/codel/0005-net-codel-fix-build-errors.patch new file mode 100644 index 000000000..728c12c2a --- /dev/null +++ b/debian/patches/features/all/codel/0005-net-codel-fix-build-errors.patch @@ -0,0 +1,55 @@ +From: Sasha Levin +Date: Mon, 14 May 2012 11:57:06 +0000 +Subject: [PATCH 5/7] net: codel: fix build errors + +commit 669d67bf777def468970f2dcba1537edf3b2d329 upstream. + +Fix the following build error: + +net/sched/sch_fq_codel.c: In function 'fq_codel_dump_stats': +net/sched/sch_fq_codel.c:464:3: error: unknown field 'qdisc_stats' specified in initializer +net/sched/sch_fq_codel.c:464:3: warning: missing braces around initializer +net/sched/sch_fq_codel.c:464:3: warning: (near initialization for 'st.') +net/sched/sch_fq_codel.c:465:3: error: unknown field 'qdisc_stats' specified in initializer +net/sched/sch_fq_codel.c:465:3: warning: excess elements in struct initializer +net/sched/sch_fq_codel.c:465:3: warning: (near initialization for 'st') +net/sched/sch_fq_codel.c:466:3: error: unknown field 'qdisc_stats' specified in initializer +net/sched/sch_fq_codel.c:466:3: warning: excess elements in struct initializer +net/sched/sch_fq_codel.c:466:3: warning: (near initialization for 'st') +net/sched/sch_fq_codel.c:467:3: error: unknown field 'qdisc_stats' specified in initializer +net/sched/sch_fq_codel.c:467:3: warning: excess elements in struct initializer +net/sched/sch_fq_codel.c:467:3: warning: (near initialization for 'st') +make[1]: *** [net/sched/sch_fq_codel.o] Error 1 + +Signed-off-by: Sasha Levin +Signed-off-by: David S. Miller +--- + net/sched/sch_fq_codel.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index a7b3754..337ff20 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -461,13 +461,14 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) + struct fq_codel_sched_data *q = qdisc_priv(sch); + struct tc_fq_codel_xstats st = { + .type = TCA_FQ_CODEL_XSTATS_QDISC, +- .qdisc_stats.maxpacket = q->cstats.maxpacket, +- .qdisc_stats.drop_overlimit = q->drop_overlimit, +- .qdisc_stats.ecn_mark = q->cstats.ecn_mark, +- .qdisc_stats.new_flow_count = q->new_flow_count, + }; + struct list_head *pos; + ++ st.qdisc_stats.maxpacket = q->cstats.maxpacket; ++ st.qdisc_stats.drop_overlimit = q->drop_overlimit; ++ st.qdisc_stats.ecn_mark = q->cstats.ecn_mark; ++ st.qdisc_stats.new_flow_count = q->new_flow_count; ++ + list_for_each(pos, &q->new_flows) + st.qdisc_stats.new_flows_len++; + +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch b/debian/patches/features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch new file mode 100644 index 000000000..67bb75028 --- /dev/null +++ b/debian/patches/features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch @@ -0,0 +1,90 @@ +From: Eric Dumazet +Date: Sat, 12 May 2012 21:23:23 +0000 +Subject: [PATCH 6/7] codel: use u16 field instead of 31bits for rec_inv_sqrt + +commit 6ff272c9ad65eda219cd975b9da2dbc31cc812ee upstream. + +David pointed out gcc might generate poor code with 31bit fields. + +Using u16 is more than enough and permits a better code output. + +Also make the code intent more readable using constants, fixed point arithmetic +not being trivial for everybody. + +Suggested-by: David Miller +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +--- + include/net/codel.h | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/include/net/codel.h b/include/net/codel.h +index bd8747c..7546517 100644 +--- a/include/net/codel.h ++++ b/include/net/codel.h +@@ -133,13 +133,17 @@ struct codel_params { + struct codel_vars { + u32 count; + u32 lastcount; +- bool dropping:1; +- u32 rec_inv_sqrt:31; ++ bool dropping; ++ u16 rec_inv_sqrt; + codel_time_t first_above_time; + codel_time_t drop_next; + codel_time_t ldelay; + }; + ++#define REC_INV_SQRT_BITS (8 * sizeof(u16)) /* or sizeof_in_bits(rec_inv_sqrt) */ ++/* needed shift to get a Q0.32 number from rec_inv_sqrt */ ++#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS) ++ + /** + * struct codel_stats - contains codel shared variables and stats + * @maxpacket: largest packet we've seen so far +@@ -173,17 +177,18 @@ static void codel_stats_init(struct codel_stats *stats) + * http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Iterative_methods_for_reciprocal_square_roots + * new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2) + * +- * Here, invsqrt is a fixed point number (< 1.0), 31bit mantissa) ++ * Here, invsqrt is a fixed point number (< 1.0), 32bit mantissa, aka Q0.32 + */ + static void codel_Newton_step(struct codel_vars *vars) + { +- u32 invsqrt = vars->rec_inv_sqrt; +- u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 31; +- u64 val = (3LL << 31) - ((u64)vars->count * invsqrt2); ++ u32 invsqrt = ((u32)vars->rec_inv_sqrt) << REC_INV_SQRT_SHIFT; ++ u32 invsqrt2 = ((u64)invsqrt * invsqrt) >> 32; ++ u64 val = (3LL << 32) - ((u64)vars->count * invsqrt2); + +- val = (val * invsqrt) >> 32; ++ val >>= 2; /* avoid overflow in following multiply */ ++ val = (val * invsqrt) >> (32 - 2 + 1); + +- vars->rec_inv_sqrt = val; ++ vars->rec_inv_sqrt = val >> REC_INV_SQRT_SHIFT; + } + + /* +@@ -195,7 +200,7 @@ static codel_time_t codel_control_law(codel_time_t t, + codel_time_t interval, + u32 rec_inv_sqrt) + { +- return t + reciprocal_divide(interval, rec_inv_sqrt << 1); ++ return t + reciprocal_divide(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT); + } + + +@@ -326,7 +331,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + codel_Newton_step(vars); + } else { + vars->count = 1; +- vars->rec_inv_sqrt = 0x7fffffff; ++ vars->rec_inv_sqrt = ~0U >> REC_INV_SQRT_SHIFT; + } + vars->lastcount = vars->count; + vars->drop_next = codel_control_law(now, params->interval, +-- +1.7.10 + diff --git a/debian/patches/features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch b/debian/patches/features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch new file mode 100644 index 000000000..0195fdfd0 --- /dev/null +++ b/debian/patches/features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch @@ -0,0 +1,140 @@ +From: Eric Dumazet +Date: Wed, 16 May 2012 04:39:09 +0000 +Subject: [PATCH 7/7] fq_codel: should use qdisc backlog as threshold + +commit 865ec5523dadbedefbc5710a68969f686a28d928 upstream. + +codel_should_drop() logic allows a packet being not dropped if queue +size is under max packet size. + +In fq_codel, we have two possible backlogs : The qdisc global one, and +the flow local one. + +The meaningful one for codel_should_drop() should be the global backlog, +not the per flow one, so that thin flows can have a non zero drop/mark +probability. + +Signed-off-by: Eric Dumazet +Cc: Dave Taht +Cc: Kathleen Nichols +Cc: Van Jacobson +Signed-off-by: David S. Miller +--- + include/net/codel.h | 15 +++++++-------- + net/sched/sch_codel.c | 4 ++-- + net/sched/sch_fq_codel.c | 5 +++-- + 3 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/include/net/codel.h b/include/net/codel.h +index 7546517..550debf 100644 +--- a/include/net/codel.h ++++ b/include/net/codel.h +@@ -205,7 +205,7 @@ static codel_time_t codel_control_law(codel_time_t t, + + + static bool codel_should_drop(const struct sk_buff *skb, +- unsigned int *backlog, ++ struct Qdisc *sch, + struct codel_vars *vars, + struct codel_params *params, + struct codel_stats *stats, +@@ -219,13 +219,13 @@ static bool codel_should_drop(const struct sk_buff *skb, + } + + vars->ldelay = now - codel_get_enqueue_time(skb); +- *backlog -= qdisc_pkt_len(skb); ++ sch->qstats.backlog -= qdisc_pkt_len(skb); + + if (unlikely(qdisc_pkt_len(skb) > stats->maxpacket)) + stats->maxpacket = qdisc_pkt_len(skb); + + if (codel_time_before(vars->ldelay, params->target) || +- *backlog <= stats->maxpacket) { ++ sch->qstats.backlog <= stats->maxpacket) { + /* went below - stay below for at least interval */ + vars->first_above_time = 0; + return false; +@@ -249,8 +249,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + struct codel_params *params, + struct codel_vars *vars, + struct codel_stats *stats, +- codel_skb_dequeue_t dequeue_func, +- u32 *backlog) ++ codel_skb_dequeue_t dequeue_func) + { + struct sk_buff *skb = dequeue_func(vars, sch); + codel_time_t now; +@@ -261,7 +260,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + return skb; + } + now = codel_get_time(); +- drop = codel_should_drop(skb, backlog, vars, params, stats, now); ++ drop = codel_should_drop(skb, sch, vars, params, stats, now); + if (vars->dropping) { + if (!drop) { + /* sojourn time below target - leave dropping state */ +@@ -292,7 +291,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + qdisc_drop(skb, sch); + stats->drop_count++; + skb = dequeue_func(vars, sch); +- if (!codel_should_drop(skb, backlog, ++ if (!codel_should_drop(skb, sch, + vars, params, stats, now)) { + /* leave dropping state */ + vars->dropping = false; +@@ -313,7 +312,7 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch, + stats->drop_count++; + + skb = dequeue_func(vars, sch); +- drop = codel_should_drop(skb, backlog, vars, params, ++ drop = codel_should_drop(skb, sch, vars, params, + stats, now); + } + vars->dropping = true; +diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c +index 213ef60..2f9ab17 100644 +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -77,8 +77,8 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) + struct codel_sched_data *q = qdisc_priv(sch); + struct sk_buff *skb; + +- skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, +- dequeue, &sch->qstats.backlog); ++ skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue); ++ + /* We cant call qdisc_tree_decrease_qlen() if our qlen is 0, + * or HTB crashes. Defer it for next round. + */ +diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c +index 337ff20..9fc1c62 100644 +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -217,13 +217,14 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch) + */ + static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) + { ++ struct fq_codel_sched_data *q = qdisc_priv(sch); + struct fq_codel_flow *flow; + struct sk_buff *skb = NULL; + + flow = container_of(vars, struct fq_codel_flow, cvars); + if (flow->head) { + skb = dequeue_head(flow); +- sch->qstats.backlog -= qdisc_pkt_len(skb); ++ q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb); + sch->q.qlen--; + } + return skb; +@@ -256,7 +257,7 @@ begin: + prev_ecn_mark = q->cstats.ecn_mark; + + skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats, +- dequeue, &q->backlogs[flow - q->flows]); ++ dequeue); + + flow->dropped += q->cstats.drop_count - prev_drop_count; + flow->dropped += q->cstats.ecn_mark - prev_ecn_mark; +-- +1.7.10 + diff --git a/debian/patches/features/all/flow_dissector-use-a-64bit-load-store.patch b/debian/patches/features/all/flow_dissector-use-a-64bit-load-store.patch new file mode 100644 index 000000000..c88f253ac --- /dev/null +++ b/debian/patches/features/all/flow_dissector-use-a-64bit-load-store.patch @@ -0,0 +1,90 @@ +From: Eric Dumazet +Date: Mon, 28 Nov 2011 20:30:35 +0000 +Subject: [PATCH 2/3] flow_dissector: use a 64bit load/store +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 4d77d2b567ec66a443792d99e96ac760991d80d0 upstream. + +Le lundi 28 novembre 2011 à 19:06 -0500, David Miller a écrit : +> From: Dimitris Michailidis +> Date: Mon, 28 Nov 2011 08:25:39 -0800 +> +> >> +bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys +> >> *flow) +> >> +{ +> >> + int poff, nhoff = skb_network_offset(skb); +> >> + u8 ip_proto; +> >> + u16 proto = skb->protocol; +> > +> > __be16 instead of u16 for proto? +> +> I'll take care of this when I apply these patches. + +( CC trimmed ) + +Thanks David ! + +Here is a small patch to use one 64bit load/store on x86_64 instead of +two 32bit load/stores. + +[PATCH net-next] flow_dissector: use a 64bit load/store + +gcc compiler is smart enough to use a single load/store if we +memcpy(dptr, sptr, 8) on x86_64, regardless of +CONFIG_CC_OPTIMIZE_FOR_SIZE + +In IP header, daddr immediately follows saddr, this wont change in the +future. We only need to make sure our flow_keys (src,dst) fields wont +break the rule. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller + +diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h +index e4cb285..80461c1 100644 +--- a/include/net/flow_keys.h ++++ b/include/net/flow_keys.h +@@ -2,6 +2,7 @@ + #define _NET_FLOW_KEYS_H + + struct flow_keys { ++ /* (src,dst) must be grouped, in the same way than in IP header */ + __be32 src; + __be32 dst; + union { +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index f0516d9..0985b9b 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -8,6 +8,16 @@ + #include + #include + ++/* copy saddr & daddr, possibly using 64bit load/store ++ * Equivalent to : flow->src = iph->saddr; ++ * flow->dst = iph->daddr; ++ */ ++static void iph_to_flow_copy_addrs(struct flow_keys *flow, const struct iphdr *iph) ++{ ++ BUILD_BUG_ON(offsetof(typeof(*flow), dst) != ++ offsetof(typeof(*flow), src) + sizeof(flow->src)); ++ memcpy(&flow->src, &iph->saddr, sizeof(flow->src) + sizeof(flow->dst)); ++} + + bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) + { +@@ -31,8 +41,7 @@ ip: + ip_proto = 0; + else + ip_proto = iph->protocol; +- flow->src = iph->saddr; +- flow->dst = iph->daddr; ++ iph_to_flow_copy_addrs(flow, iph); + nhoff += iph->ihl * 4; + break; + } +-- +1.7.10 + diff --git a/debian/patches/features/all/net-flow_dissector.c-missing-include-linux-export.h.patch b/debian/patches/features/all/net-flow_dissector.c-missing-include-linux-export.h.patch new file mode 100644 index 000000000..ae4521dc8 --- /dev/null +++ b/debian/patches/features/all/net-flow_dissector.c-missing-include-linux-export.h.patch @@ -0,0 +1,25 @@ +From: Jesper Dangaard Brouer +Date: Tue, 24 Jan 2012 16:03:33 -0500 +Subject: [PATCH 3/3] net: flow_dissector.c missing include linux/export.h + +commit c452ed70771cea3af73d21a5914989137fbd28b8 upstream. + +The file net/core/flow_dissector.c seems to be missing +including linux/export.h. + +Signed-off-by: Jesper Dangaard Brouer +Signed-off-by: David S. Miller + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index 0985b9b..a225089 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -1,4 +1,5 @@ + #include ++#include + #include + #include + #include +-- +1.7.10 + diff --git a/debian/patches/features/all/net-introduce-skb_flow_dissect.patch b/debian/patches/features/all/net-introduce-skb_flow_dissect.patch new file mode 100644 index 000000000..a749507b2 --- /dev/null +++ b/debian/patches/features/all/net-introduce-skb_flow_dissect.patch @@ -0,0 +1,195 @@ +From: Eric Dumazet +Date: Mon, 28 Nov 2011 05:22:18 +0000 +Subject: [PATCH 1/3] net: introduce skb_flow_dissect() + +commit 0744dd00c1b1be99a25b62b1b48df440e82e57e0 upstream. + +We use at least two flow dissectors in network stack, with known +limitations and code duplication. + +Introduce skb_flow_dissect() to factorize this, highly inspired from +existing dissector from __skb_get_rxhash() + +Note : We extensively use skb_header_pointer(), this permits us to not +touch skb at all. + +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller + +diff --git a/include/net/flow_keys.h b/include/net/flow_keys.h +new file mode 100644 +index 0000000..e4cb285 +--- /dev/null ++++ b/include/net/flow_keys.h +@@ -0,0 +1,15 @@ ++#ifndef _NET_FLOW_KEYS_H ++#define _NET_FLOW_KEYS_H ++ ++struct flow_keys { ++ __be32 src; ++ __be32 dst; ++ union { ++ __be32 ports; ++ __be16 port16[2]; ++ }; ++ u8 ip_proto; ++}; ++ ++extern bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow); ++#endif +diff --git a/net/core/Makefile b/net/core/Makefile +index 3606d40..c4ecc86 100644 +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -3,7 +3,7 @@ + # + + obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ +- gen_stats.o gen_estimator.o net_namespace.o secure_seq.o ++ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o + + obj-$(CONFIG_SYSCTL) += sysctl_net_core.o + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +new file mode 100644 +index 0000000..f0516d9 +--- /dev/null ++++ b/net/core/flow_dissector.c +@@ -0,0 +1,134 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow) ++{ ++ int poff, nhoff = skb_network_offset(skb); ++ u8 ip_proto; ++ __be16 proto = skb->protocol; ++ ++ memset(flow, 0, sizeof(*flow)); ++ ++again: ++ switch (proto) { ++ case __constant_htons(ETH_P_IP): { ++ const struct iphdr *iph; ++ struct iphdr _iph; ++ip: ++ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); ++ if (!iph) ++ return false; ++ ++ if (ip_is_fragment(iph)) ++ ip_proto = 0; ++ else ++ ip_proto = iph->protocol; ++ flow->src = iph->saddr; ++ flow->dst = iph->daddr; ++ nhoff += iph->ihl * 4; ++ break; ++ } ++ case __constant_htons(ETH_P_IPV6): { ++ const struct ipv6hdr *iph; ++ struct ipv6hdr _iph; ++ipv6: ++ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); ++ if (!iph) ++ return false; ++ ++ ip_proto = iph->nexthdr; ++ flow->src = iph->saddr.s6_addr32[3]; ++ flow->dst = iph->daddr.s6_addr32[3]; ++ nhoff += sizeof(struct ipv6hdr); ++ break; ++ } ++ case __constant_htons(ETH_P_8021Q): { ++ const struct vlan_hdr *vlan; ++ struct vlan_hdr _vlan; ++ ++ vlan = skb_header_pointer(skb, nhoff, sizeof(_vlan), &_vlan); ++ if (!vlan) ++ return false; ++ ++ proto = vlan->h_vlan_encapsulated_proto; ++ nhoff += sizeof(*vlan); ++ goto again; ++ } ++ case __constant_htons(ETH_P_PPP_SES): { ++ struct { ++ struct pppoe_hdr hdr; ++ __be16 proto; ++ } *hdr, _hdr; ++ hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); ++ if (!hdr) ++ return false; ++ proto = hdr->proto; ++ nhoff += PPPOE_SES_HLEN; ++ switch (proto) { ++ case __constant_htons(PPP_IP): ++ goto ip; ++ case __constant_htons(PPP_IPV6): ++ goto ipv6; ++ default: ++ return false; ++ } ++ } ++ default: ++ return false; ++ } ++ ++ switch (ip_proto) { ++ case IPPROTO_GRE: { ++ struct gre_hdr { ++ __be16 flags; ++ __be16 proto; ++ } *hdr, _hdr; ++ ++ hdr = skb_header_pointer(skb, nhoff, sizeof(_hdr), &_hdr); ++ if (!hdr) ++ return false; ++ /* ++ * Only look inside GRE if version zero and no ++ * routing ++ */ ++ if (!(hdr->flags & (GRE_VERSION|GRE_ROUTING))) { ++ proto = hdr->proto; ++ nhoff += 4; ++ if (hdr->flags & GRE_CSUM) ++ nhoff += 4; ++ if (hdr->flags & GRE_KEY) ++ nhoff += 4; ++ if (hdr->flags & GRE_SEQ) ++ nhoff += 4; ++ goto again; ++ } ++ break; ++ } ++ case IPPROTO_IPIP: ++ goto again; ++ default: ++ break; ++ } ++ ++ flow->ip_proto = ip_proto; ++ poff = proto_ports_offset(ip_proto); ++ if (poff >= 0) { ++ __be32 *ports, _ports; ++ ++ nhoff += poff; ++ ports = skb_header_pointer(skb, nhoff, sizeof(_ports), &_ports); ++ if (ports) ++ flow->ports = *ports; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL(skb_flow_dissect); +-- +1.7.10 + diff --git a/debian/patches/series/base b/debian/patches/series/base index f5300548d..2f2437bed 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -293,3 +293,15 @@ + features/all/be2net/0056-be2net-Record-receive-queue-index-in-skb-to-aid-RPS.patch + features/all/be2net/0057-be2net-Fix-EEH-error-reset-before-a-flash-dump-compl.patch + features/all/be2net/0058-be2net-avoid-disabling-sriov-while-VFs-are-assigned.patch + +# Add CoDel from 3.5, and prerequisites ++ features/all/net-introduce-skb_flow_dissect.patch ++ features/all/flow_dissector-use-a-64bit-load-store.patch ++ features/all/net-flow_dissector.c-missing-include-linux-export.h.patch ++ features/all/codel/0001-codel-Controlled-Delay-AQM.patch ++ features/all/codel/0002-codel-use-Newton-method-instead-of-sqrt-and-divides.patch ++ features/all/codel/0003-fq_codel-Fair-Queue-Codel-AQM.patch ++ features/all/codel/0004-net-codel-Add-missing-include-linux-prefetch.h.patch ++ features/all/codel/0005-net-codel-fix-build-errors.patch ++ features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch ++ features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch From c2c3e14c9ac904da28490b4a50f4b2bea673d3c9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 30 May 2012 12:48:01 +0000 Subject: [PATCH 04/13] [x86] udeb: Add hyperv-modules containing Hyper-V paravirtualised drivers svn path=/dists/sid/linux-2.6/; revision=19044 --- debian/changelog | 1 + debian/installer/amd64/modules/amd64/hyperv-modules | 1 + debian/installer/i386/modules/i386/hyperv-modules | 1 + debian/installer/modules/hyperv-modules | 6 ++++++ debian/installer/package-list | 6 ++++++ 5 files changed, 15 insertions(+) create mode 100644 debian/installer/amd64/modules/amd64/hyperv-modules create mode 100644 debian/installer/i386/modules/i386/hyperv-modules create mode 100644 debian/installer/modules/hyperv-modules diff --git a/debian/changelog b/debian/changelog index a52b30b8f..a5ff2b901 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ linux-2.6 (3.2.18-2) UNRELEASED; urgency=low Sarveshwar Bandi (Closes: #673391) - Add support for Skyhawk cards * net/sched: Add codel and fq_codel from Linux 3.5-rc1 + * [x86] udeb: Add hyperv-modules containing Hyper-V paravirtualised drivers -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/installer/amd64/modules/amd64/hyperv-modules b/debian/installer/amd64/modules/amd64/hyperv-modules new file mode 100644 index 000000000..69fdd5d22 --- /dev/null +++ b/debian/installer/amd64/modules/amd64/hyperv-modules @@ -0,0 +1 @@ +#include diff --git a/debian/installer/i386/modules/i386/hyperv-modules b/debian/installer/i386/modules/i386/hyperv-modules new file mode 100644 index 000000000..69fdd5d22 --- /dev/null +++ b/debian/installer/i386/modules/i386/hyperv-modules @@ -0,0 +1 @@ +#include diff --git a/debian/installer/modules/hyperv-modules b/debian/installer/modules/hyperv-modules new file mode 100644 index 000000000..f40837f41 --- /dev/null +++ b/debian/installer/modules/hyperv-modules @@ -0,0 +1,6 @@ +# All Hyper-V paravirtual drivers +hid-hyperv +hv_netvsc +hv_storvsc +hv_utils +hv_vmbus diff --git a/debian/installer/package-list b/debian/installer/package-list index 1bde8a815..1ce053036 100644 --- a/debian/installer/package-list +++ b/debian/installer/package-list @@ -478,3 +478,9 @@ Depends: kernel-image Priority: extra Description: LED modules This package contains LED modules. + +Package: hyperv-modules +Depends: kernel-image +Priority: extra +Description: Hyper-V modules + This package contains Hyper-V paravirtualised drivers for the kernel. From bf73f974c973d33f7b9a519900ee05e8e0e5cc87 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 30 May 2012 12:49:00 +0000 Subject: [PATCH 05/13] [x86] ata_piix: defer disks to the Hyper-V drivers by default svn path=/dists/sid/linux-2.6/; revision=19045 --- debian/changelog | 1 + ...t-flag-to-ignore-detected-ATA-device.patch | 49 +++++++++++ ...isks-to-the-Hyper-V-drivers-by-defau.patch | 82 +++++++++++++++++++ debian/patches/series/base | 2 + 4 files changed, 134 insertions(+) create mode 100644 debian/patches/features/x86/hyperv/0078-libata-add-a-host-flag-to-ignore-detected-ATA-device.patch create mode 100644 debian/patches/features/x86/hyperv/0079-ata_piix-defer-disks-to-the-Hyper-V-drivers-by-defau.patch diff --git a/debian/changelog b/debian/changelog index a5ff2b901..e7796c8ea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,7 @@ linux-2.6 (3.2.18-2) UNRELEASED; urgency=low - Add support for Skyhawk cards * net/sched: Add codel and fq_codel from Linux 3.5-rc1 * [x86] udeb: Add hyperv-modules containing Hyper-V paravirtualised drivers + * [x86] ata_piix: defer disks to the Hyper-V drivers by default -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/patches/features/x86/hyperv/0078-libata-add-a-host-flag-to-ignore-detected-ATA-device.patch b/debian/patches/features/x86/hyperv/0078-libata-add-a-host-flag-to-ignore-detected-ATA-device.patch new file mode 100644 index 000000000..f26a0de96 --- /dev/null +++ b/debian/patches/features/x86/hyperv/0078-libata-add-a-host-flag-to-ignore-detected-ATA-device.patch @@ -0,0 +1,49 @@ +From: Andy Whitcroft +Date: Fri, 4 May 2012 22:15:10 +0100 +Subject: [PATCH 78/79] libata: add a host flag to ignore detected ATA devices + +commit db63a4c8115a0bb904496e1cdd3e7488e68b0d06 upstream. + +Where devices are visible via more than one host we sometimes wish to +indicate that cirtain devices should be ignored on a specific host. Add a +host flag indicating that this host wishes to ignore ATA specific devices. + +Signed-off-by: Andy Whitcroft +Signed-off-by: Jeff Garzik +--- + drivers/ata/libata-core.c | 6 ++++++ + include/linux/libata.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c +index 23763a1..d31ee55 100644 +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -1973,6 +1973,12 @@ retry: + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; ++ if (ap->host->flags & ATA_HOST_IGNORE_ATA && ++ ata_id_is_ata(id)) { ++ ata_dev_dbg(dev, ++ "host indicates ignore ATA devices, ignored\n"); ++ return -ENOENT; ++ } + } else { + if (ata_id_is_ata(id)) + goto err_out; +diff --git a/include/linux/libata.h b/include/linux/libata.h +index e926df7..6e887c7 100644 +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -247,6 +247,7 @@ enum { + ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ + ATA_HOST_STARTED = (1 << 1), /* Host started */ + ATA_HOST_PARALLEL_SCAN = (1 << 2), /* Ports on this host can be scanned in parallel */ ++ ATA_HOST_IGNORE_ATA = (1 << 3), /* Ignore ATA devices on this host. */ + + /* bits 24:31 of host->flags are reserved for LLD specific flags */ + +-- +1.7.10 + diff --git a/debian/patches/features/x86/hyperv/0079-ata_piix-defer-disks-to-the-Hyper-V-drivers-by-defau.patch b/debian/patches/features/x86/hyperv/0079-ata_piix-defer-disks-to-the-Hyper-V-drivers-by-defau.patch new file mode 100644 index 000000000..0ebfd3777 --- /dev/null +++ b/debian/patches/features/x86/hyperv/0079-ata_piix-defer-disks-to-the-Hyper-V-drivers-by-defau.patch @@ -0,0 +1,82 @@ +From: Andy Whitcroft +Date: Fri, 4 May 2012 22:15:11 +0100 +Subject: [PATCH 79/79] ata_piix: defer disks to the Hyper-V drivers by + default + +commit cd006086fa5d91414d8ff9ff2b78fbb593878e3c upstream. + +When we are hosted on a Microsoft Hyper-V hypervisor the guest disks +are exposed both via the Hyper-V paravirtualised drivers and via an +emulated SATA disk drive. In this case we want to use the paravirtualised +drivers if we can as they are much more efficient. Note that the Hyper-V +paravirtualised drivers only expose the virtual hard disk devices, the +CDROM/DVD devices must still be enumerated. + +Mark the host controller ATA_HOST_IGNORE_ATA to prevent enumeration of +disk devices. + +BugLink: http://bugs.launchpad.net/bugs/929545 +BugLink: http://bugs.launchpad.net/bugs/942316 +Signed-off-by: Andy Whitcroft +Signed-off-by: Jeff Garzik +--- + drivers/ata/ata_piix.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c +index 7857e8f..3c809bf 100644 +--- a/drivers/ata/ata_piix.c ++++ b/drivers/ata/ata_piix.c +@@ -1554,6 +1554,39 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev) + return false; + } + ++static int prefer_ms_hyperv = 1; ++module_param(prefer_ms_hyperv, int, 0); ++ ++static void piix_ignore_devices_quirk(struct ata_host *host) ++{ ++#if IS_ENABLED(CONFIG_HYPERV_STORAGE) ++ static const struct dmi_system_id ignore_hyperv[] = { ++ { ++ /* On Hyper-V hypervisors the disks are exposed on ++ * both the emulated SATA controller and on the ++ * paravirtualised drivers. The CD/DVD devices ++ * are only exposed on the emulated controller. ++ * Request we ignore ATA devices on this host. ++ */ ++ .ident = "Hyper-V Virtual Machine", ++ .matches = { ++ DMI_MATCH(DMI_SYS_VENDOR, ++ "Microsoft Corporation"), ++ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), ++ }, ++ }, ++ { } /* terminate list */ ++ }; ++ const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv); ++ ++ if (dmi && prefer_ms_hyperv) { ++ host->flags |= ATA_HOST_IGNORE_ATA; ++ dev_info(host->dev, "%s detected, ATA device ignore set\n", ++ dmi->ident); ++ } ++#endif ++} ++ + /** + * piix_init_one - Register PIIX ATA PCI device with kernel services + * @pdev: PCI device to register +@@ -1669,6 +1702,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev, + } + host->flags |= ATA_HOST_PARALLEL_SCAN; + ++ /* Allow hosts to specify device types to ignore when scanning. */ ++ piix_ignore_devices_quirk(host); ++ + pci_set_master(pdev); + return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); + } +-- +1.7.10 + diff --git a/debian/patches/series/base b/debian/patches/series/base index 2f2437bed..478372fb3 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -158,6 +158,8 @@ + features/x86/hyperv/0075-Tools-hv-Support-enumeration-from-all-the-pools.patch + features/x86/hyperv/0076-net-hyperv-Fix-the-code-handling-tx-busy.patch + features/x86/hyperv/0077-hv-remove-the-second-argument-of-k-un-map_atomic.patch ++ features/x86/hyperv/0078-libata-add-a-host-flag-to-ignore-detected-ATA-device.patch ++ features/x86/hyperv/0079-ata_piix-defer-disks-to-the-Hyper-V-drivers-by-defau.patch + features/x86/efi-stub/0001-x86-Add-missing-bzImage-fields-to-struct-setup_heade.patch + features/x86/efi-stub/0002-x86-Don-t-use-magic-strings-for-EFI-loader-signature.patch From ca018e7e1277d602e4303c8f75df1973865f9205 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 30 May 2012 13:46:01 +0000 Subject: [PATCH 06/13] [x86] drm/i915:: Disable FBC on SandyBridge (Closes: #675022) svn path=/dists/sid/linux-2.6/; revision=19046 --- debian/changelog | 1 + .../drm-i915-Disable-FBC-on-SandyBridge.patch | 32 +++++++++++++++++++ debian/patches/series/base | 2 ++ 3 files changed, 35 insertions(+) create mode 100644 debian/patches/bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch diff --git a/debian/changelog b/debian/changelog index e7796c8ea..df5869d3b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,7 @@ linux-2.6 (3.2.18-2) UNRELEASED; urgency=low * net/sched: Add codel and fq_codel from Linux 3.5-rc1 * [x86] udeb: Add hyperv-modules containing Hyper-V paravirtualised drivers * [x86] ata_piix: defer disks to the Hyper-V drivers by default + * [x86] drm/i915:: Disable FBC on SandyBridge (Closes: #675022) -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/patches/bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch b/debian/patches/bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch new file mode 100644 index 000000000..a05704fe8 --- /dev/null +++ b/debian/patches/bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch @@ -0,0 +1,32 @@ +From: Chris Wilson +Date: Tue, 8 Nov 2011 23:17:34 +0000 +Subject: [PATCH] drm/i915:: Disable FBC on SandyBridge + +commit d56d8b28e9247e7e35e02fbb12b12239a2c33ad1 upstream. + +Enabling FBC is causing the BLT ring to run between 10-100x slower than +normal and frequently lockup. The interim solution is disable FBC once +more until we know why. + +Signed-off-by: Chris Wilson +Signed-off-by: Keith Packard +--- + drivers/gpu/drm/i915/intel_display.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c +index b3b51c4..19f35ec 100644 +--- a/drivers/gpu/drm/i915/intel_display.c ++++ b/drivers/gpu/drm/i915/intel_display.c +@@ -1872,7 +1872,7 @@ static void intel_update_fbc(struct drm_device *dev) + if (enable_fbc < 0) { + DRM_DEBUG_KMS("fbc set to per-chip default\n"); + enable_fbc = 1; +- if (INTEL_INFO(dev)->gen <= 5) ++ if (INTEL_INFO(dev)->gen <= 6) + enable_fbc = 0; + } + if (!enable_fbc) { +-- +1.7.10 + diff --git a/debian/patches/series/base b/debian/patches/series/base index 478372fb3..520a90397 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -307,3 +307,5 @@ + features/all/codel/0005-net-codel-fix-build-errors.patch + features/all/codel/0006-codel-use-u16-field-instead-of-31bits-for-rec_inv_sq.patch + features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch + ++ bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch From 681f694b3a9a1f44458444e767fd513c50e44867 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 31 May 2012 03:08:09 +0000 Subject: [PATCH 07/13] Update to 3.2.19 Drop patches included in it. Defer an ABI change in mmc for now. For the PREEMPT_RT featureset, revert one conflicting change in 3.2.19. svn path=/dists/sid/linux-2.6/; revision=19047 --- debian/changelog | 20 +++- ...ol-null-terminate-filename-passed-to.patch | 53 --------- ...re-consistent-with-in-kernel-irqchip.patch | 107 ------------------ ...-slots_lock-around-device-assignment.patch | 80 ------------- ...flush-tlbs-before-releasing-mmu_lock.patch | 85 -------------- ...atus-after-handling-stop_on_stop-bit.patch | 71 ------------ ...nitize-fpc-registers-for-kvm_set_fpu.patch | 43 ------- ...fix-erroneous-exception-bitmap-check.patch | 43 ------- ...-vmx_set_cr0-expects-kvm-srcu-locked.patch | 40 ------- .../mmc-Avoid-ABI-change-in-3.2.19.patch | 34 ++++++ ...-skip-nr_running-sanity-check-in-wor.patch | 35 ++++++ ...t-wacom-relax-Bamboo-stylus-ID-check.patch | 41 ------- debian/patches/series/base | 12 +- debian/patches/series/base-extra | 1 + 14 files changed, 90 insertions(+), 575 deletions(-) delete mode 100644 debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch delete mode 100644 debian/patches/bugfix/all/kvm-ensure-all-vcpus-are-consistent-with-in-kernel-irqchip.patch delete mode 100644 debian/patches/bugfix/all/kvm-lock-slots_lock-around-device-assignment.patch delete mode 100644 debian/patches/bugfix/all/kvm-mmu_notifier-flush-tlbs-before-releasing-mmu_lock.patch delete mode 100644 debian/patches/bugfix/s390/kvm-s390-do-store-status-after-handling-stop_on_stop-bit.patch delete mode 100644 debian/patches/bugfix/s390/kvm-s390-sanitize-fpc-registers-for-kvm_set_fpu.patch delete mode 100644 debian/patches/bugfix/x86/kvm-nvmx-fix-erroneous-exception-bitmap-check.patch delete mode 100644 debian/patches/bugfix/x86/kvm-vmx-vmx_set_cr0-expects-kvm-srcu-locked.patch create mode 100644 debian/patches/debian/mmc-Avoid-ABI-change-in-3.2.19.patch create mode 100644 debian/patches/features/all/rt/revert-workqueue-skip-nr_running-sanity-check-in-wor.patch delete mode 100644 debian/patches/features/all/wacom/0004-Input-wacom-relax-Bamboo-stylus-ID-check.patch diff --git a/debian/changelog b/debian/changelog index df5869d3b..f978aa3d8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,22 @@ -linux-2.6 (3.2.18-2) UNRELEASED; urgency=low +linux-2.6 (3.2.19-1) UNRELEASED; urgency=low + + * New upstream stable update: + http://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.2.19 + - hpsa: Fix problem with MSA2xxx devices (Closes: #661057) + - IB/core: Fix mismatch between locked and pinned pages + - iommu: Fix off by one in dmar_get_fault_reason() + - vfs: make AIO use the proper rw_verify_area() area helpers + - HID: logitech: read all 32 bits of report type bitfield (Closes: #671292) + - USB: Remove races in devio.c + - ext{3,4}: Fix error handling on inode bitmap corruption + - uvcvideo: Fix ENUMINPUT handling + - dl2k: Clean up rio_ioctl (CVE-2012-2313) + - [x86] MCE: Fix vm86 handling for 32bit mce handler + - [x86] mce: Fix check for processor context when machine check was taken. + - ethtool: Null-terminate filename passed to ethtool_ops::flash_device + - NFSv4: Fix buffer overflows in ACL support (CVE-2012-2375) + + Avoid reading past buffer when calling GETACL + + Avoid beyond bounds copy while caching ACL [ Ben Hutchings ] * be2net: Backport most changes up to Linux 3.5-rc1, thanks to diff --git a/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch b/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch deleted file mode 100644 index 22b472be7..000000000 --- a/debian/patches/bugfix/all/ethtool-null-terminate-filename-passed-to.patch +++ /dev/null @@ -1,53 +0,0 @@ -From: Ben Hutchings -Date: Wed, 1 Feb 2012 09:32:25 +0000 -Subject: [PATCH] ethtool: Null-terminate filename passed to - ethtool_ops::flash_device - -commit 786f528119722f564a22ad953411374e06116333 upstream. - -The parameters for ETHTOOL_FLASHDEV include a filename, which ought to -be null-terminated. Currently the only driver that implements -ethtool_ops::flash_device attempts to add a null terminator if -necessary, but does it wrongly. Do it in the ethtool core instead. - -Signed-off-by: Ben Hutchings -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/emulex/benet/be_ethtool.c | 6 +----- - net/core/ethtool.c | 2 ++ - 2 files changed, 3 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c -index 6db6b6a..802e5dd 100644 ---- a/drivers/net/ethernet/emulex/benet/be_ethtool.c -+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c -@@ -716,12 +716,8 @@ static int - be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) - { - struct be_adapter *adapter = netdev_priv(netdev); -- char file_name[ETHTOOL_FLASH_MAX_FILENAME]; - -- file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; -- strcpy(file_name, efl->data); -- -- return be_load_fw(adapter, file_name); -+ return be_load_fw(adapter, efl->data); - } - - static int -diff --git a/net/core/ethtool.c b/net/core/ethtool.c -index 369b418..3f79db1 100644 ---- a/net/core/ethtool.c -+++ b/net/core/ethtool.c -@@ -1190,6 +1190,8 @@ static noinline_for_stack int ethtool_flash_device(struct net_device *dev, - if (!dev->ethtool_ops->flash_device) - return -EOPNOTSUPP; - -+ efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; -+ - return dev->ethtool_ops->flash_device(dev, &efl); - } - --- -1.7.10 - diff --git a/debian/patches/bugfix/all/kvm-ensure-all-vcpus-are-consistent-with-in-kernel-irqchip.patch b/debian/patches/bugfix/all/kvm-ensure-all-vcpus-are-consistent-with-in-kernel-irqchip.patch deleted file mode 100644 index 3059ac98e..000000000 --- a/debian/patches/bugfix/all/kvm-ensure-all-vcpus-are-consistent-with-in-kernel-irqchip.patch +++ /dev/null @@ -1,107 +0,0 @@ -From: Avi Kivity -Date: Mon, 5 Mar 2012 14:23:29 +0200 -Subject: [PATCH] KVM: Ensure all vcpus are consistent with in-kernel irqchip - settings - -commit 3e515705a1f46beb1c942bb8043c16f8ac7b1e9e upstream. - -If some vcpus are created before KVM_CREATE_IRQCHIP, then -irqchip_in_kernel() and vcpu->arch.apic will be inconsistent, leading -to potential NULL pointer dereferences. - -Fix by: -- ensuring that no vcpus are installed when KVM_CREATE_IRQCHIP is called -- ensuring that a vcpu has an apic if it is installed after KVM_CREATE_IRQCHIP - -This is somewhat long winded because vcpu->arch.apic is created without -kvm->lock held. - -Based on earlier patch by Michael Ellerman. - -Signed-off-by: Michael Ellerman -Signed-off-by: Avi Kivity ---- - arch/ia64/kvm/kvm-ia64.c | 5 +++++ - arch/x86/kvm/x86.c | 8 ++++++++ - include/linux/kvm_host.h | 7 +++++++ - virt/kvm/kvm_main.c | 4 ++++ - 4 files changed, 24 insertions(+) - -diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c -index d8ddbba..f5104b7 100644 ---- a/arch/ia64/kvm/kvm-ia64.c -+++ b/arch/ia64/kvm/kvm-ia64.c -@@ -1172,6 +1172,11 @@ out: - - #define PALE_RESET_ENTRY 0x80000000ffffffb0UL - -+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) -+{ -+ return irqchip_in_kernel(vcpu->kcm) == (vcpu->arch.apic != NULL); -+} -+ - int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) - { - struct kvm_vcpu *v; -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index 03a1fd4..9477dc6 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -3199,6 +3199,9 @@ long kvm_arch_vm_ioctl(struct file *filp, - r = -EEXIST; - if (kvm->arch.vpic) - goto create_irqchip_unlock; -+ r = -EINVAL; -+ if (atomic_read(&kvm->online_vcpus)) -+ goto create_irqchip_unlock; - r = -ENOMEM; - vpic = kvm_create_pic(kvm); - if (vpic) { -@@ -6107,6 +6110,11 @@ void kvm_arch_check_processor_compat(void *rtn) - kvm_x86_ops->check_processor_compatibility(rtn); - } - -+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) -+{ -+ return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL); -+} -+ - int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) - { - struct page *page; -diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h -index 355e445..e42d85a 100644 ---- a/include/linux/kvm_host.h -+++ b/include/linux/kvm_host.h -@@ -805,6 +805,13 @@ static inline bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu) - { - return vcpu->kvm->bsp_vcpu_id == vcpu->vcpu_id; - } -+ -+bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu); -+ -+#else -+ -+static inline bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu) { return true; } -+ - #endif - - #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT -diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c -index e4431ad..94e148e 100644 ---- a/virt/kvm/kvm_main.c -+++ b/virt/kvm/kvm_main.c -@@ -1651,6 +1651,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) - goto vcpu_destroy; - - mutex_lock(&kvm->lock); -+ if (!kvm_vcpu_compatible(vcpu)) { -+ r = -EINVAL; -+ goto unlock_vcpu_destroy; -+ } - if (atomic_read(&kvm->online_vcpus) == KVM_MAX_VCPUS) { - r = -EINVAL; - goto unlock_vcpu_destroy; --- -1.7.10 - diff --git a/debian/patches/bugfix/all/kvm-lock-slots_lock-around-device-assignment.patch b/debian/patches/bugfix/all/kvm-lock-slots_lock-around-device-assignment.patch deleted file mode 100644 index 8c23d61db..000000000 --- a/debian/patches/bugfix/all/kvm-lock-slots_lock-around-device-assignment.patch +++ /dev/null @@ -1,80 +0,0 @@ -From: Alex Williamson -Date: Tue, 17 Apr 2012 21:46:44 -0600 -Subject: [PATCH] KVM: lock slots_lock around device assignment - -commit 21a1416a1c945c5aeaeaf791b63c64926018eb77 upstream. - -As pointed out by Jason Baron, when assigning a device to a guest -we first set the iommu domain pointer, which enables mapping -and unmapping of memory slots to the iommu. This leaves a window -where this path is enabled, but we haven't synchronized the iommu -mappings to the existing memory slots. Thus a slot being removed -at that point could send us down unexpected code paths removing -non-existent pinnings and iommu mappings. Take the slots_lock -around creating the iommu domain and initial mappings as well as -around iommu teardown to avoid this race. - -Signed-off-by: Alex Williamson -Signed-off-by: Marcelo Tosatti ---- - virt/kvm/iommu.c | 23 +++++++++++++++-------- - 1 file changed, 15 insertions(+), 8 deletions(-) - -diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c -index fec1723..e9fff98 100644 ---- a/virt/kvm/iommu.c -+++ b/virt/kvm/iommu.c -@@ -240,9 +240,13 @@ int kvm_iommu_map_guest(struct kvm *kvm) - return -ENODEV; - } - -+ mutex_lock(&kvm->slots_lock); -+ - kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type); -- if (!kvm->arch.iommu_domain) -- return -ENOMEM; -+ if (!kvm->arch.iommu_domain) { -+ r = -ENOMEM; -+ goto out_unlock; -+ } - - if (!allow_unsafe_assigned_interrupts && - !iommu_domain_has_cap(kvm->arch.iommu_domain, -@@ -253,17 +257,16 @@ int kvm_iommu_map_guest(struct kvm *kvm) - " module option.\n", __func__); - iommu_domain_free(kvm->arch.iommu_domain); - kvm->arch.iommu_domain = NULL; -- return -EPERM; -+ r = -EPERM; -+ goto out_unlock; - } - - r = kvm_iommu_map_memslots(kvm); - if (r) -- goto out_unmap; -- -- return 0; -+ kvm_iommu_unmap_memslots(kvm); - --out_unmap: -- kvm_iommu_unmap_memslots(kvm); -+out_unlock: -+ mutex_unlock(&kvm->slots_lock); - return r; - } - -@@ -340,7 +343,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm) - if (!domain) - return 0; - -+ mutex_lock(&kvm->slots_lock); - kvm_iommu_unmap_memslots(kvm); -+ kvm->arch.iommu_domain = NULL; -+ mutex_unlock(&kvm->slots_lock); -+ - iommu_domain_free(domain); - return 0; - } --- -1.7.10 - diff --git a/debian/patches/bugfix/all/kvm-mmu_notifier-flush-tlbs-before-releasing-mmu_lock.patch b/debian/patches/bugfix/all/kvm-mmu_notifier-flush-tlbs-before-releasing-mmu_lock.patch deleted file mode 100644 index 00c6c7b65..000000000 --- a/debian/patches/bugfix/all/kvm-mmu_notifier-flush-tlbs-before-releasing-mmu_lock.patch +++ /dev/null @@ -1,85 +0,0 @@ -From: Marcelo Tosatti -Date: Fri, 18 May 2012 17:58:45 -0300 -Subject: KVM: mmu_notifier: Flush TLBs before releasing mmu_lock - -From: Takuya Yoshikawa - -(cherry picked from commit 565f3be2174611f364405bbea2d86e153c2e7e78 - -Other threads may process the same page in that small window and skip -TLB flush and then return before these functions do flush. - -Signed-off-by: Takuya Yoshikawa -Signed-off-by: Marcelo Tosatti -Signed-off-by: Avi Kivity -Signed-off-by: Ben Hutchings ---- - virt/kvm/kvm_main.c | 19 ++++++++++--------- - 1 files changed, 10 insertions(+), 9 deletions(-) - -diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c -index e401c1b..9ffac2e 100644 ---- a/virt/kvm/kvm_main.c -+++ b/virt/kvm/kvm_main.c -@@ -289,15 +289,15 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn, - */ - idx = srcu_read_lock(&kvm->srcu); - spin_lock(&kvm->mmu_lock); -+ - kvm->mmu_notifier_seq++; - need_tlb_flush = kvm_unmap_hva(kvm, address) | kvm->tlbs_dirty; -- spin_unlock(&kvm->mmu_lock); -- srcu_read_unlock(&kvm->srcu, idx); -- - /* we've to flush the tlb before the pages can be freed */ - if (need_tlb_flush) - kvm_flush_remote_tlbs(kvm); - -+ spin_unlock(&kvm->mmu_lock); -+ srcu_read_unlock(&kvm->srcu, idx); - } - - static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn, -@@ -335,12 +335,12 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, - for (; start < end; start += PAGE_SIZE) - need_tlb_flush |= kvm_unmap_hva(kvm, start); - need_tlb_flush |= kvm->tlbs_dirty; -- spin_unlock(&kvm->mmu_lock); -- srcu_read_unlock(&kvm->srcu, idx); -- - /* we've to flush the tlb before the pages can be freed */ - if (need_tlb_flush) - kvm_flush_remote_tlbs(kvm); -+ -+ spin_unlock(&kvm->mmu_lock); -+ srcu_read_unlock(&kvm->srcu, idx); - } - - static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, -@@ -378,13 +378,14 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, - - idx = srcu_read_lock(&kvm->srcu); - spin_lock(&kvm->mmu_lock); -- young = kvm_age_hva(kvm, address); -- spin_unlock(&kvm->mmu_lock); -- srcu_read_unlock(&kvm->srcu, idx); - -+ young = kvm_age_hva(kvm, address); - if (young) - kvm_flush_remote_tlbs(kvm); - -+ spin_unlock(&kvm->mmu_lock); -+ srcu_read_unlock(&kvm->srcu, idx); -+ - return young; - } - --- -1.7.6.4 - --- -To unsubscribe from this list: send the line "unsubscribe stable" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - - diff --git a/debian/patches/bugfix/s390/kvm-s390-do-store-status-after-handling-stop_on_stop-bit.patch b/debian/patches/bugfix/s390/kvm-s390-do-store-status-after-handling-stop_on_stop-bit.patch deleted file mode 100644 index 82c8a6bb2..000000000 --- a/debian/patches/bugfix/s390/kvm-s390-do-store-status-after-handling-stop_on_stop-bit.patch +++ /dev/null @@ -1,71 +0,0 @@ -From: Marcelo Tosatti -Date: Fri, 18 May 2012 17:58:50 -0300 -Subject: KVM: s390: do store status after handling STOP_ON_STOP bit - -From: Jens Freimann - -(cherry picked from commit 9e0d5473e2f0ba2d2fe9dab9408edef3060b710e) - -In handle_stop() handle the stop bit before doing the store status as -described for "Stop and Store Status" in the Principles of Operation. -We have to give up the local_int.lock before calling kvm store status -since it calls gmap_fault() which might sleep. Since local_int.lock -only protects local_int.* and not guest memory we can give up the lock. - -Signed-off-by: Jens Freimann -Signed-off-by: Christian Borntraeger -Signed-off-by: Marcelo Tosatti -Signed-off-by: Avi Kivity -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Ben Hutchings ---- - arch/s390/kvm/intercept.c | 20 ++++++++++++-------- - 1 files changed, 12 insertions(+), 8 deletions(-) - -diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c -index 0243454..a5f6eff 100644 ---- a/arch/s390/kvm/intercept.c -+++ b/arch/s390/kvm/intercept.c -@@ -133,13 +133,6 @@ static int handle_stop(struct kvm_vcpu *vcpu) - - vcpu->stat.exit_stop_request++; - spin_lock_bh(&vcpu->arch.local_int.lock); -- if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { -- vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; -- rc = kvm_s390_vcpu_store_status(vcpu, -- KVM_S390_STORE_STATUS_NOADDR); -- if (rc >= 0) -- rc = -EOPNOTSUPP; -- } - - if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) { - vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP; -@@ -155,7 +148,18 @@ static int handle_stop(struct kvm_vcpu *vcpu) - rc = -EOPNOTSUPP; - } - -- spin_unlock_bh(&vcpu->arch.local_int.lock); -+ if (vcpu->arch.local_int.action_bits & ACTION_STORE_ON_STOP) { -+ vcpu->arch.local_int.action_bits &= ~ACTION_STORE_ON_STOP; -+ /* store status must be called unlocked. Since local_int.lock -+ * only protects local_int.* and not guest memory we can give -+ * up the lock here */ -+ spin_unlock_bh(&vcpu->arch.local_int.lock); -+ rc = kvm_s390_vcpu_store_status(vcpu, -+ KVM_S390_STORE_STATUS_NOADDR); -+ if (rc >= 0) -+ rc = -EOPNOTSUPP; -+ } else -+ spin_unlock_bh(&vcpu->arch.local_int.lock); - return rc; - } - --- -1.7.6.4 - --- -To unsubscribe from this list: send the line "unsubscribe stable" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - - diff --git a/debian/patches/bugfix/s390/kvm-s390-sanitize-fpc-registers-for-kvm_set_fpu.patch b/debian/patches/bugfix/s390/kvm-s390-sanitize-fpc-registers-for-kvm_set_fpu.patch deleted file mode 100644 index 9cab1c80e..000000000 --- a/debian/patches/bugfix/s390/kvm-s390-sanitize-fpc-registers-for-kvm_set_fpu.patch +++ /dev/null @@ -1,43 +0,0 @@ -From: Marcelo Tosatti -Date: Fri, 18 May 2012 17:58:51 -0300 -Subject: KVM: s390: Sanitize fpc registers for KVM_SET_FPU - -From: Christian Borntraeger - -(cherry picked from commit 851755871c1f3184f4124c466e85881f17fa3226) - -commit 7eef87dc99e419b1cc051e4417c37e4744d7b661 (KVM: s390: fix -register setting) added a load of the floating point control register -to the KVM_SET_FPU path. Lets make sure that the fpc is valid. - -Signed-off-by: Christian Borntraeger -Signed-off-by: Marcelo Tosatti -Signed-off-by: Avi Kivity -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Ben Hutchings ---- - arch/s390/kvm/kvm-s390.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c -index d1c44573..d3cb86c 100644 ---- a/arch/s390/kvm/kvm-s390.c -+++ b/arch/s390/kvm/kvm-s390.c -@@ -418,7 +418,7 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, - int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) - { - memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); -- vcpu->arch.guest_fpregs.fpc = fpu->fpc; -+ vcpu->arch.guest_fpregs.fpc = fpu->fpc & FPC_VALID_MASK; - restore_fp_regs(&vcpu->arch.guest_fpregs); - return 0; - } --- -1.7.6.4 - --- -To unsubscribe from this list: send the line "unsubscribe stable" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - - diff --git a/debian/patches/bugfix/x86/kvm-nvmx-fix-erroneous-exception-bitmap-check.patch b/debian/patches/bugfix/x86/kvm-nvmx-fix-erroneous-exception-bitmap-check.patch deleted file mode 100644 index fd839a0d6..000000000 --- a/debian/patches/bugfix/x86/kvm-nvmx-fix-erroneous-exception-bitmap-check.patch +++ /dev/null @@ -1,43 +0,0 @@ -From: Marcelo Tosatti -Date: Fri, 18 May 2012 17:58:48 -0300 -Subject: KVM: nVMX: Fix erroneous exception bitmap check - -From: Nadav Har'El - -(cherry picked from commit 9587190107d0c0cbaccbf7bf6b0245d29095a9ae) - -The code which checks whether to inject a pagefault to L1 or L2 (in -nested VMX) was wrong, incorrect in how it checked the PF_VECTOR bit. -Thanks to Dan Carpenter for spotting this. - -Signed-off-by: Nadav Har'El -Reported-by: Dan Carpenter -Signed-off-by: Avi Kivity -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Ben Hutchings ---- - arch/x86/kvm/vmx.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c -index 4ea7678..7ac5993 100644 ---- a/arch/x86/kvm/vmx.c -+++ b/arch/x86/kvm/vmx.c -@@ -1677,7 +1677,7 @@ static int nested_pf_handled(struct kvm_vcpu *vcpu) - struct vmcs12 *vmcs12 = get_vmcs12(vcpu); - - /* TODO: also check PFEC_MATCH/MASK, not just EB.PF. */ -- if (!(vmcs12->exception_bitmap & PF_VECTOR)) -+ if (!(vmcs12->exception_bitmap & (1u << PF_VECTOR))) - return 0; - - nested_vmx_vmexit(vcpu); --- -1.7.6.4 - --- -To unsubscribe from this list: send the line "unsubscribe stable" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - - diff --git a/debian/patches/bugfix/x86/kvm-vmx-vmx_set_cr0-expects-kvm-srcu-locked.patch b/debian/patches/bugfix/x86/kvm-vmx-vmx_set_cr0-expects-kvm-srcu-locked.patch deleted file mode 100644 index e68e23368..000000000 --- a/debian/patches/bugfix/x86/kvm-vmx-vmx_set_cr0-expects-kvm-srcu-locked.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Marcelo Tosatti -Date: Fri, 18 May 2012 17:58:49 -0300 -Subject: KVM: VMX: vmx_set_cr0 expects kvm->srcu locked - -(cherry picked from commit 7a4f5ad051e02139a9f1c0f7f4b1acb88915852b) - -vmx_set_cr0 is called from vcpu run context, therefore it expects -kvm->srcu to be held (for setting up the real-mode TSS). - -Signed-off-by: Marcelo Tosatti -Signed-off-by: Avi Kivity -Signed-off-by: Greg Kroah-Hartman -Signed-off-by: Ben Hutchings ---- - arch/x86/kvm/vmx.c | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) - -diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c -index 7ac5993..7315488 100644 ---- a/arch/x86/kvm/vmx.c -+++ b/arch/x86/kvm/vmx.c -@@ -3915,7 +3915,9 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu) - vmcs_write16(VIRTUAL_PROCESSOR_ID, vmx->vpid); - - vmx->vcpu.arch.cr0 = X86_CR0_NW | X86_CR0_CD | X86_CR0_ET; -+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); - vmx_set_cr0(&vmx->vcpu, kvm_read_cr0(vcpu)); /* enter rmode */ -+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); - vmx_set_cr4(&vmx->vcpu, 0); - vmx_set_efer(&vmx->vcpu, 0); - vmx_fpu_activate(&vmx->vcpu); --- -1.7.6.4 - --- -To unsubscribe from this list: send the line "unsubscribe stable" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html - - diff --git a/debian/patches/debian/mmc-Avoid-ABI-change-in-3.2.19.patch b/debian/patches/debian/mmc-Avoid-ABI-change-in-3.2.19.patch new file mode 100644 index 000000000..b6654de89 --- /dev/null +++ b/debian/patches/debian/mmc-Avoid-ABI-change-in-3.2.19.patch @@ -0,0 +1,34 @@ +From: Ben Hutchings +Date: Thu, 31 May 2012 04:04:55 +0100 +Subject: [PATCH] mmc: Avoid ABI change in 3.2.19 + +--- + include/linux/mmc/host.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index deb6282..20caeb0 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -303,7 +303,6 @@ struct mmc_host { + + unsigned int sdio_irqs; + struct task_struct *sdio_irq_thread; +- bool sdio_irq_pending; + atomic_t sdio_irq_thread_abort; + + mmc_pm_flag_t pm_flags; /* requested pm features */ +@@ -315,6 +314,10 @@ struct mmc_host { + #ifdef CONFIG_REGULATOR + bool regulator_enabled; /* regulator state */ + #endif ++#if !(defined(__GENKSYMS__) && defined(CONFIG_REGULATOR)) ++ /* Use the hole after regulator_enabled to avoid an ABI change */ ++ bool sdio_irq_pending; ++#endif + + struct dentry *debugfs_root; + +-- +1.7.10 + diff --git a/debian/patches/features/all/rt/revert-workqueue-skip-nr_running-sanity-check-in-wor.patch b/debian/patches/features/all/rt/revert-workqueue-skip-nr_running-sanity-check-in-wor.patch new file mode 100644 index 000000000..8dec2548c --- /dev/null +++ b/debian/patches/features/all/rt/revert-workqueue-skip-nr_running-sanity-check-in-wor.patch @@ -0,0 +1,35 @@ +From: Ben Hutchings +Date: Thu, 31 May 2012 02:58:44 +0100 +Subject: [PATCH] Revert "workqueue: skip nr_running sanity check in + worker_enter_idle() if trustee is active" + +This reverts commit 5d79c6f64a904afc92a329f80abe693e3ae105fe. +It conflicts with, and appears to be unnecessary for, the PREEMPT_RT +series. +--- + kernel/workqueue.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/kernel/workqueue.c b/kernel/workqueue.c +index 7947e16..bb425b1 100644 +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -1215,13 +1215,8 @@ static void worker_enter_idle(struct worker *worker) + } else + wake_up_all(&gcwq->trustee_wait); + +- /* +- * Sanity check nr_running. Because trustee releases gcwq->lock +- * between setting %WORKER_ROGUE and zapping nr_running, the +- * warning may trigger spuriously. Check iff trustee is idle. +- */ +- WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE && +- gcwq->nr_workers == gcwq->nr_idle && ++ /* sanity check nr_running */ ++ WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle && + atomic_read(get_gcwq_nr_running(gcwq->cpu))); + } + +-- +1.7.10 + diff --git a/debian/patches/features/all/wacom/0004-Input-wacom-relax-Bamboo-stylus-ID-check.patch b/debian/patches/features/all/wacom/0004-Input-wacom-relax-Bamboo-stylus-ID-check.patch deleted file mode 100644 index b2f78555c..000000000 --- a/debian/patches/features/all/wacom/0004-Input-wacom-relax-Bamboo-stylus-ID-check.patch +++ /dev/null @@ -1,41 +0,0 @@ -From: Chris Bagwell -Date: Wed, 26 Oct 2011 22:28:34 -0700 -Subject: Input: wacom - relax Bamboo stylus ID check - -commit c5981411f60c31f0dff6f0f98d2d3711384badaf upstream. - -Bit 0x02 always means tip versus eraser. Bit 0x01 is something related -to version of stylus and different values are starting to be used. - -Relaxing proximity check is required to be used with 3rd generation -Bamboo Pen and Touch tablets. - -Signed-off-by: Chris Bagwell -Acked-by: Ping Cheng -Signed-off-by: Dmitry Torokhov -Signed-off-by: Jonathan Nieder ---- - drivers/input/tablet/wacom_wac.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c -index 2ee47d01a3b4..f00c70e1adb0 100644 ---- a/drivers/input/tablet/wacom_wac.c -+++ b/drivers/input/tablet/wacom_wac.c -@@ -843,12 +843,7 @@ static int wacom_bpt_pen(struct wacom_wac *wacom) - unsigned char *data = wacom->data; - int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0; - -- /* -- * Similar to Graphire protocol, data[1] & 0x20 is proximity and -- * data[1] & 0x18 is tool ID. 0x30 is safety check to ignore -- * 2 unused tool ID's. -- */ -- prox = (data[1] & 0x30) == 0x30; -+ prox = (data[1] & 0x20) == 0x20; - - /* - * All reports shared between PEN and RUBBER tool must be --- -1.7.10.1 - diff --git a/debian/patches/series/base b/debian/patches/series/base index 520a90397..6ec769faf 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -189,23 +189,14 @@ + debian/skbuff-avoid-ABI-change-in-3.2.17.patch + debian/usb-hcd-avoid-ABI-change-in-3.2.17.patch + debian/fork-avoid-ABI-change-in-3.2.18.patch ++ debian/mmc-Avoid-ABI-change-in-3.2.19.patch + bugfix/all/ext4-Report-max_batch_time-option-correctly.patch -# KVM fixes queued for 3.2.19 -+ bugfix/all/kvm-mmu_notifier-flush-tlbs-before-releasing-mmu_lock.patch -+ bugfix/all/kvm-ensure-all-vcpus-are-consistent-with-in-kernel-irqchip.patch -+ bugfix/all/kvm-lock-slots_lock-around-device-assignment.patch -+ bugfix/x86/kvm-nvmx-fix-erroneous-exception-bitmap-check.patch -+ bugfix/x86/kvm-vmx-vmx_set_cr0-expects-kvm-srcu-locked.patch -+ bugfix/s390/kvm-s390-do-store-status-after-handling-stop_on_stop-bit.patch -+ bugfix/s390/kvm-s390-sanitize-fpc-registers-for-kvm_set_fpu.patch - # Update wacom driver to 3.5ish + features/all/wacom/0001-Input-wacom-cleanup-feature-report-for-bamboos.patch + features/all/wacom/0002-Input-wacom-remove-unused-bamboo-HID-parsing.patch + features/all/wacom/0003-Input-wacom-add-some-comments-to-wacom_parse_hid.patch -+ features/all/wacom/0004-Input-wacom-relax-Bamboo-stylus-ID-check.patch + features/all/wacom/0005-Input-wacom-read-3rd-gen-Bamboo-Touch-HID-data.patch + features/all/wacom/0006-Input-wacom-3rd-gen-Bamboo-P-Touch-packet-support.patch + features/all/wacom/0007-Input-wacom-ignore-unwanted-bamboo-packets.patch @@ -234,7 +225,6 @@ + features/all/rt2x00-add-rt5372-chipset-support.patch + bugfix/all/acpi-battery-only-refresh-the-sysfs-files-when-pertinent.patch -+ bugfix/all/ethtool-null-terminate-filename-passed-to.patch # Update be2net driver to 3.5ish + features/all/be2net/0001-sweep-the-floors-and-convert-some-.get_drvinfo-routi.patch diff --git a/debian/patches/series/base-extra b/debian/patches/series/base-extra index 490c4dd57..dbe4f961f 100644 --- a/debian/patches/series/base-extra +++ b/debian/patches/series/base-extra @@ -222,6 +222,7 @@ + features/all/rt/0223-workqueue-use-get-cpu-light.patch.patch featureset=rt + features/all/rt/0224-epoll.patch.patch featureset=rt + features/all/rt/0225-mm-vmalloc.patch.patch featureset=rt ++ features/all/rt/revert-workqueue-skip-nr_running-sanity-check-in-wor.patch featureset=rt + features/all/rt/0226-workqueue-Fix-cpuhotplug-trainwreck.patch featureset=rt + features/all/rt/0227-workqueue-Fix-PF_THREAD_BOUND-abuse.patch featureset=rt + features/all/rt/0228-workqueue-Use-get_cpu_light-in-flush_gcwq.patch featureset=rt From 3aecedc12393867b27b0c8ae1fe776d68a17b5b6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 31 May 2012 03:19:00 +0000 Subject: [PATCH 08/13] AppArmor: compatibility patch for v5 interface (Closes: #661151) svn path=/dists/sid/linux-2.6/; revision=19048 --- debian/changelog | 1 + debian/config/config | 1 + ...compatibility-patch-for-v5-interface.patch | 381 ++++++++++++++++++ debian/patches/series/base | 3 + 4 files changed, 386 insertions(+) create mode 100644 debian/patches/features/all/AppArmor-compatibility-patch-for-v5-interface.patch diff --git a/debian/changelog b/debian/changelog index f978aa3d8..95fcff5af 100644 --- a/debian/changelog +++ b/debian/changelog @@ -26,6 +26,7 @@ linux-2.6 (3.2.19-1) UNRELEASED; urgency=low * [x86] udeb: Add hyperv-modules containing Hyper-V paravirtualised drivers * [x86] ata_piix: defer disks to the Hyper-V drivers by default * [x86] drm/i915:: Disable FBC on SandyBridge (Closes: #675022) + * AppArmor: compatibility patch for v5 interface (Closes: #661151) -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/config/config b/debian/config/config index 90459d49a..e62fda784 100644 --- a/debian/config/config +++ b/debian/config/config @@ -4680,6 +4680,7 @@ CONFIG_DEFAULT_SECURITY_DAC=y ## CONFIG_SECURITY_APPARMOR=y CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_APPARMOR_COMPAT_24=y ## ## file: security/integrity/ima/Kconfig diff --git a/debian/patches/features/all/AppArmor-compatibility-patch-for-v5-interface.patch b/debian/patches/features/all/AppArmor-compatibility-patch-for-v5-interface.patch new file mode 100644 index 000000000..b8d1f1aac --- /dev/null +++ b/debian/patches/features/all/AppArmor-compatibility-patch-for-v5-interface.patch @@ -0,0 +1,381 @@ +From: John Johansen +Date: Wed, 10 Aug 2011 22:02:40 -0700 +Subject: AppArmor: compatibility patch for v5 interface + +commit 004192fb5223c7b81a949e36a080a5da56132826 in +git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor + +Signed-off-by: John Johansen +[bwh: Fix up context to apply without the v5 network control interface; + fix unmatched aafs_create() when CONFIG_SECURITY_APPARMOR_COMPAT_24 not set] +--- + security/apparmor/Kconfig | 9 + + security/apparmor/Makefile | 1 + + security/apparmor/apparmorfs-24.c | 287 ++++++++++++++++++++++++++++++++ + security/apparmor/apparmorfs.c | 18 +- + security/apparmor/include/apparmorfs.h | 6 + + 5 files changed, 319 insertions(+), 2 deletions(-) + create mode 100644 security/apparmor/apparmorfs-24.c + +--- a/security/apparmor/Kconfig ++++ b/security/apparmor/Kconfig +@@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE + boot. + + If you are unsure how to answer this question, answer 1. ++ ++config SECURITY_APPARMOR_COMPAT_24 ++ bool "Enable AppArmor 2.4 compatability" ++ depends on SECURITY_APPARMOR ++ default y ++ help ++ This option enables compatability with AppArmor 2.4. It is ++ recommended if compatability with older versions of AppArmor ++ is desired. +--- a/security/apparmor/Makefile ++++ b/security/apparmor/Makefile +@@ -5,6 +5,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o + apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ + path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ + resource.o sid.o file.o ++apparmor-$(CONFIG_SECURITY_APPARMOR_COMPAT_24) += apparmorfs-24.o + + clean-files := capability_names.h rlim_names.h + +--- /dev/null ++++ b/security/apparmor/apparmorfs-24.c +@@ -0,0 +1,287 @@ ++/* ++ * AppArmor security module ++ * ++ * This file contains AppArmor /sys/kernel/secrutiy/apparmor interface functions ++ * ++ * Copyright (C) 1998-2008 Novell/SUSE ++ * Copyright 2009-2010 Canonical Ltd. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation, version 2 of the ++ * License. ++ * ++ * ++ * This file contain functions providing an interface for <= AppArmor 2.4 ++ * compatibility. It is dependent on CONFIG_SECURITY_APPARMOR_COMPAT_24 ++ * being set (see Makefile). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "include/apparmor.h" ++#include "include/audit.h" ++#include "include/context.h" ++#include "include/policy.h" ++ ++ ++/* apparmor/matching */ ++static ssize_t aa_matching_read(struct file *file, char __user *buf, ++ size_t size, loff_t *ppos) ++{ ++ const char matching[] = "pattern=aadfa audit perms=crwxamlk/ " ++ "user::other"; ++ ++ return simple_read_from_buffer(buf, size, ppos, matching, ++ sizeof(matching) - 1); ++} ++ ++const struct file_operations aa_fs_matching_fops = { ++ .read = aa_matching_read, ++}; ++ ++/* apparmor/features */ ++static ssize_t aa_features_read(struct file *file, char __user *buf, ++ size_t size, loff_t *ppos) ++{ ++ const char features[] = "file=3.1 capability=2.0 network=1.0 " ++ "change_hat=1.5 change_profile=1.1 " "aanamespaces=1.1 rlimit=1.1"; ++ ++ return simple_read_from_buffer(buf, size, ppos, features, ++ sizeof(features) - 1); ++} ++ ++const struct file_operations aa_fs_features_fops = { ++ .read = aa_features_read, ++}; ++ ++/** ++ * __next_namespace - find the next namespace to list ++ * @root: root namespace to stop search at (NOT NULL) ++ * @ns: current ns position (NOT NULL) ++ * ++ * Find the next namespace from @ns under @root and handle all locking needed ++ * while switching current namespace. ++ * ++ * Returns: next namespace or NULL if at last namespace under @root ++ * NOTE: will not unlock root->lock ++ */ ++static struct aa_namespace *__next_namespace(struct aa_namespace *root, ++ struct aa_namespace *ns) ++{ ++ struct aa_namespace *parent; ++ ++ /* is next namespace a child */ ++ if (!list_empty(&ns->sub_ns)) { ++ struct aa_namespace *next; ++ next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); ++ read_lock(&next->lock); ++ return next; ++ } ++ ++ /* check if the next ns is a sibling, parent, gp, .. */ ++ parent = ns->parent; ++ while (parent) { ++ read_unlock(&ns->lock); ++ list_for_each_entry_continue(ns, &parent->sub_ns, base.list) { ++ read_lock(&ns->lock); ++ return ns; ++ } ++ if (parent == root) ++ return NULL; ++ ns = parent; ++ parent = parent->parent; ++ } ++ ++ return NULL; ++} ++ ++/** ++ * __first_profile - find the first profile in a namespace ++ * @root: namespace that is root of profiles being displayed (NOT NULL) ++ * @ns: namespace to start in (NOT NULL) ++ * ++ * Returns: unrefcounted profile or NULL if no profile ++ */ ++static struct aa_profile *__first_profile(struct aa_namespace *root, ++ struct aa_namespace *ns) ++{ ++ for ( ; ns; ns = __next_namespace(root, ns)) { ++ if (!list_empty(&ns->base.profiles)) ++ return list_first_entry(&ns->base.profiles, ++ struct aa_profile, base.list); ++ } ++ return NULL; ++} ++ ++/** ++ * __next_profile - step to the next profile in a profile tree ++ * @profile: current profile in tree (NOT NULL) ++ * ++ * Perform a depth first taversal on the profile tree in a namespace ++ * ++ * Returns: next profile or NULL if done ++ * Requires: profile->ns.lock to be held ++ */ ++static struct aa_profile *__next_profile(struct aa_profile *p) ++{ ++ struct aa_profile *parent; ++ struct aa_namespace *ns = p->ns; ++ ++ /* is next profile a child */ ++ if (!list_empty(&p->base.profiles)) ++ return list_first_entry(&p->base.profiles, typeof(*p), ++ base.list); ++ ++ /* is next profile a sibling, parent sibling, gp, subling, .. */ ++ parent = p->parent; ++ while (parent) { ++ list_for_each_entry_continue(p, &parent->base.profiles, ++ base.list) ++ return p; ++ p = parent; ++ parent = parent->parent; ++ } ++ ++ /* is next another profile in the namespace */ ++ list_for_each_entry_continue(p, &ns->base.profiles, base.list) ++ return p; ++ ++ return NULL; ++} ++ ++/** ++ * next_profile - step to the next profile in where ever it may be ++ * @root: root namespace (NOT NULL) ++ * @profile: current profile (NOT NULL) ++ * ++ * Returns: next profile or NULL if there isn't one ++ */ ++static struct aa_profile *next_profile(struct aa_namespace *root, ++ struct aa_profile *profile) ++{ ++ struct aa_profile *next = __next_profile(profile); ++ if (next) ++ return next; ++ ++ /* finished all profiles in namespace move to next namespace */ ++ return __first_profile(root, __next_namespace(root, profile->ns)); ++} ++ ++/** ++ * p_start - start a depth first traversal of profile tree ++ * @f: seq_file to fill ++ * @pos: current position ++ * ++ * Returns: first profile under current namespace or NULL if none found ++ * ++ * acquires first ns->lock ++ */ ++static void *p_start(struct seq_file *f, loff_t *pos) ++ __acquires(root->lock) ++{ ++ struct aa_profile *profile = NULL; ++ struct aa_namespace *root = aa_current_profile()->ns; ++ loff_t l = *pos; ++ f->private = aa_get_namespace(root); ++ ++ ++ /* find the first profile */ ++ read_lock(&root->lock); ++ profile = __first_profile(root, root); ++ ++ /* skip to position */ ++ for (; profile && l > 0; l--) ++ profile = next_profile(root, profile); ++ ++ return profile; ++} ++ ++/** ++ * p_next - read the next profile entry ++ * @f: seq_file to fill ++ * @p: profile previously returned ++ * @pos: current position ++ * ++ * Returns: next profile after @p or NULL if none ++ * ++ * may acquire/release locks in namespace tree as necessary ++ */ ++static void *p_next(struct seq_file *f, void *p, loff_t *pos) ++{ ++ struct aa_profile *profile = p; ++ struct aa_namespace *root = f->private; ++ (*pos)++; ++ ++ return next_profile(root, profile); ++} ++ ++/** ++ * p_stop - stop depth first traversal ++ * @f: seq_file we are filling ++ * @p: the last profile writen ++ * ++ * Release all locking done by p_start/p_next on namespace tree ++ */ ++static void p_stop(struct seq_file *f, void *p) ++ __releases(root->lock) ++{ ++ struct aa_profile *profile = p; ++ struct aa_namespace *root = f->private, *ns; ++ ++ if (profile) { ++ for (ns = profile->ns; ns && ns != root; ns = ns->parent) ++ read_unlock(&ns->lock); ++ } ++ read_unlock(&root->lock); ++ aa_put_namespace(root); ++} ++ ++/** ++ * seq_show_profile - show a profile entry ++ * @f: seq_file to file ++ * @p: current position (profile) (NOT NULL) ++ * ++ * Returns: error on failure ++ */ ++static int seq_show_profile(struct seq_file *f, void *p) ++{ ++ struct aa_profile *profile = (struct aa_profile *)p; ++ struct aa_namespace *root = f->private; ++ ++ if (profile->ns != root) ++ seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); ++ seq_printf(f, "%s (%s)\n", profile->base.hname, ++ COMPLAIN_MODE(profile) ? "complain" : "enforce"); ++ ++ return 0; ++} ++ ++static const struct seq_operations aa_fs_profiles_op = { ++ .start = p_start, ++ .next = p_next, ++ .stop = p_stop, ++ .show = seq_show_profile, ++}; ++ ++static int profiles_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &aa_fs_profiles_op); ++} ++ ++static int profiles_release(struct inode *inode, struct file *file) ++{ ++ return seq_release(inode, file); ++} ++ ++const struct file_operations aa_fs_profiles_fops = { ++ .open = profiles_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = profiles_release, ++}; +--- a/security/apparmor/apparmorfs.c ++++ b/security/apparmor/apparmorfs.c +@@ -187,7 +187,11 @@ void __init aa_destroy_aafs(void) + aafs_remove(".remove"); + aafs_remove(".replace"); + aafs_remove(".load"); +- ++#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 ++ aafs_remove("profiles"); ++ aafs_remove("matching"); ++ aafs_remove("features"); ++#endif + securityfs_remove(aa_fs_dentry); + aa_fs_dentry = NULL; + } +@@ -218,7 +222,17 @@ static int __init aa_create_aafs(void) + aa_fs_dentry = NULL; + goto error; + } +- ++#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 ++ error = aafs_create("matching", 0444, &aa_fs_matching_fops); ++ if (error) ++ goto error; ++ error = aafs_create("features", 0444, &aa_fs_features_fops); ++ if (error) ++ goto error; ++ error = aafs_create("profiles", 0440, &aa_fs_profiles_fops); ++ if (error) ++ goto error; ++#endif + error = aafs_create(".load", 0640, &aa_fs_profile_load); + if (error) + goto error; +--- a/security/apparmor/include/apparmorfs.h ++++ b/security/apparmor/include/apparmorfs.h +@@ -17,4 +17,10 @@ + + extern void __init aa_destroy_aafs(void); + ++#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 ++extern const struct file_operations aa_fs_matching_fops; ++extern const struct file_operations aa_fs_features_fops; ++extern const struct file_operations aa_fs_profiles_fops; ++#endif ++ + #endif /* __AA_APPARMORFS_H */ diff --git a/debian/patches/series/base b/debian/patches/series/base index 6ec769faf..ff71984dd 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -299,3 +299,6 @@ + features/all/codel/0007-fq_codel-should-use-qdisc-backlog-as-threshold.patch + bugfix/all/drm-i915-Disable-FBC-on-SandyBridge.patch + +# AppArmor userland compatibility. This had better be gone in wheezy+1! ++ features/all/AppArmor-compatibility-patch-for-v5-interface.patch From d5d155747a03194c5735be4e2930788b70529aef Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 31 May 2012 12:55:31 +0000 Subject: [PATCH 09/13] Try to fix duplicated modules in hyperv-modules svn path=/dists/sid/linux-2.6/; revision=19049 --- debian/installer/package-list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/installer/package-list b/debian/installer/package-list index 1ce053036..74eb1647c 100644 --- a/debian/installer/package-list +++ b/debian/installer/package-list @@ -480,7 +480,7 @@ Description: LED modules This package contains LED modules. Package: hyperv-modules -Depends: kernel-image +Depends: kernel-image, hid-modules, scsi-core-modules Priority: extra Description: Hyper-V modules This package contains Hyper-V paravirtualised drivers for the kernel. From 303c65230ff59932cf8e480ee89e8abd56c086f5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Jun 2012 03:47:24 +0000 Subject: [PATCH 10/13] Add a bunch of security patches svn path=/dists/sid/linux-2.6/; revision=19050 --- debian/changelog | 4 + ...use-after-free-bug-in-quota-handling.patch | 451 ++++++++++++++++++ ...etlb-fix-resv_map-leak-in-error-path.patch | 95 ++++ .../mm-fix-vma_resv_map-null-pointer.patch | 66 +++ ...ae-pmd-walk-vs-pmd_populate-smp-race.patch | 214 +++++++++ debian/patches/series/base | 5 + 6 files changed, 835 insertions(+) create mode 100644 debian/patches/bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch create mode 100644 debian/patches/bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch create mode 100644 debian/patches/bugfix/all/mm-fix-vma_resv_map-null-pointer.patch create mode 100644 debian/patches/bugfix/x86/mm-pmd_read_atomic-fix-32bit-pae-pmd-walk-vs-pmd_populate-smp-race.patch diff --git a/debian/changelog b/debian/changelog index 95fcff5af..dac770940 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,10 @@ linux-2.6 (3.2.19-1) UNRELEASED; urgency=low * [x86] ata_piix: defer disks to the Hyper-V drivers by default * [x86] drm/i915:: Disable FBC on SandyBridge (Closes: #675022) * AppArmor: compatibility patch for v5 interface (Closes: #661151) + * hugepages: fix use after free bug in "quota" handling (CVE-2012-2133) + * [x86] mm: pmd_read_atomic: fix 32bit PAE pmd walk vs pmd_populate SMP race + condition (CVE-2012-2373) + * hugetlb: fix resv_map leak in error path (CVE-2012-2390) -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/patches/bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch b/debian/patches/bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch new file mode 100644 index 000000000..2105d09cd --- /dev/null +++ b/debian/patches/bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch @@ -0,0 +1,451 @@ +From: David Gibson +Date: Wed, 21 Mar 2012 16:34:12 -0700 +Subject: [PATCH] hugepages: fix use after free bug in "quota" handling + +commit 90481622d75715bfcb68501280a917dbfe516029 upstream. + +hugetlbfs_{get,put}_quota() are badly named. They don't interact with the +general quota handling code, and they don't much resemble its behaviour. +Rather than being about maintaining limits on on-disk block usage by +particular users, they are instead about maintaining limits on in-memory +page usage (including anonymous MAP_PRIVATE copied-on-write pages) +associated with a particular hugetlbfs filesystem instance. + +Worse, they work by having callbacks to the hugetlbfs filesystem code from +the low-level page handling code, in particular from free_huge_page(). +This is a layering violation of itself, but more importantly, if the +kernel does a get_user_pages() on hugepages (which can happen from KVM +amongst others), then the free_huge_page() can be delayed until after the +associated inode has already been freed. If an unmount occurs at the +wrong time, even the hugetlbfs superblock where the "quota" limits are +stored may have been freed. + +Andrew Barry proposed a patch to fix this by having hugepages, instead of +storing a pointer to their address_space and reaching the superblock from +there, had the hugepages store pointers directly to the superblock, +bumping the reference count as appropriate to avoid it being freed. +Andrew Morton rejected that version, however, on the grounds that it made +the existing layering violation worse. + +This is a reworked version of Andrew's patch, which removes the extra, and +some of the existing, layering violation. It works by introducing the +concept of a hugepage "subpool" at the lower hugepage mm layer - that is a +finite logical pool of hugepages to allocate from. hugetlbfs now creates +a subpool for each filesystem instance with a page limit set, and a +pointer to the subpool gets added to each allocated hugepage, instead of +the address_space pointer used now. The subpool has its own lifetime and +is only freed once all pages in it _and_ all other references to it (i.e. +superblocks) are gone. + +subpools are optional - a NULL subpool pointer is taken by the code to +mean that no subpool limits are in effect. + +Previous discussion of this bug found in: "Fix refcounting in hugetlbfs +quota handling.". See: https://lkml.org/lkml/2011/8/11/28 or +http://marc.info/?l=linux-mm&m=126928970510627&w=1 + +v2: Fixed a bug spotted by Hillf Danton, and removed the extra parameter to +alloc_huge_page() - since it already takes the vma, it is not necessary. + +Signed-off-by: Andrew Barry +Signed-off-by: David Gibson +Cc: Hugh Dickins +Cc: Mel Gorman +Cc: Minchan Kim +Cc: Hillf Danton +Cc: Paul Mackerras +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +[bwh: Backported to 3.2: adjust context to apply after commit + c50ac050811d6485616a193eb0f37bfbd191cc89 'hugetlb: fix resv_map leak in + error path' which should be in 3.2.20] +--- +--- a/fs/hugetlbfs/inode.c ++++ b/fs/hugetlbfs/inode.c +@@ -626,9 +626,15 @@ static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) + spin_lock(&sbinfo->stat_lock); + /* If no limits set, just report 0 for max/free/used + * blocks, like simple_statfs() */ +- if (sbinfo->max_blocks >= 0) { +- buf->f_blocks = sbinfo->max_blocks; +- buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; ++ if (sbinfo->spool) { ++ long free_pages; ++ ++ spin_lock(&sbinfo->spool->lock); ++ buf->f_blocks = sbinfo->spool->max_hpages; ++ free_pages = sbinfo->spool->max_hpages ++ - sbinfo->spool->used_hpages; ++ buf->f_bavail = buf->f_bfree = free_pages; ++ spin_unlock(&sbinfo->spool->lock); + buf->f_files = sbinfo->max_inodes; + buf->f_ffree = sbinfo->free_inodes; + } +@@ -644,6 +650,10 @@ static void hugetlbfs_put_super(struct super_block *sb) + + if (sbi) { + sb->s_fs_info = NULL; ++ ++ if (sbi->spool) ++ hugepage_put_subpool(sbi->spool); ++ + kfree(sbi); + } + } +@@ -874,10 +884,14 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) + sb->s_fs_info = sbinfo; + sbinfo->hstate = config.hstate; + spin_lock_init(&sbinfo->stat_lock); +- sbinfo->max_blocks = config.nr_blocks; +- sbinfo->free_blocks = config.nr_blocks; + sbinfo->max_inodes = config.nr_inodes; + sbinfo->free_inodes = config.nr_inodes; ++ sbinfo->spool = NULL; ++ if (config.nr_blocks != -1) { ++ sbinfo->spool = hugepage_new_subpool(config.nr_blocks); ++ if (!sbinfo->spool) ++ goto out_free; ++ } + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = huge_page_size(config.hstate); + sb->s_blocksize_bits = huge_page_shift(config.hstate); +@@ -896,38 +910,12 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) + sb->s_root = root; + return 0; + out_free: ++ if (sbinfo->spool) ++ kfree(sbinfo->spool); + kfree(sbinfo); + return -ENOMEM; + } + +-int hugetlb_get_quota(struct address_space *mapping, long delta) +-{ +- int ret = 0; +- struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); +- +- if (sbinfo->free_blocks > -1) { +- spin_lock(&sbinfo->stat_lock); +- if (sbinfo->free_blocks - delta >= 0) +- sbinfo->free_blocks -= delta; +- else +- ret = -ENOMEM; +- spin_unlock(&sbinfo->stat_lock); +- } +- +- return ret; +-} +- +-void hugetlb_put_quota(struct address_space *mapping, long delta) +-{ +- struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); +- +- if (sbinfo->free_blocks > -1) { +- spin_lock(&sbinfo->stat_lock); +- sbinfo->free_blocks += delta; +- spin_unlock(&sbinfo->stat_lock); +- } +-} +- + static struct dentry *hugetlbfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) + { +diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h +index 7adc492..cf01817 100644 +--- a/include/linux/hugetlb.h ++++ b/include/linux/hugetlb.h +@@ -14,6 +14,15 @@ struct user_struct; + #include + #include + ++struct hugepage_subpool { ++ spinlock_t lock; ++ long count; ++ long max_hpages, used_hpages; ++}; ++ ++struct hugepage_subpool *hugepage_new_subpool(long nr_blocks); ++void hugepage_put_subpool(struct hugepage_subpool *spool); ++ + int PageHuge(struct page *page); + + void reset_vma_resv_huge_pages(struct vm_area_struct *vma); +@@ -129,12 +138,11 @@ enum { + }; + + struct hugetlbfs_sb_info { +- long max_blocks; /* blocks allowed */ +- long free_blocks; /* blocks free */ + long max_inodes; /* inodes allowed */ + long free_inodes; /* inodes free */ + spinlock_t stat_lock; + struct hstate *hstate; ++ struct hugepage_subpool *spool; + }; + + +@@ -146,8 +154,6 @@ extern const struct file_operations hugetlbfs_file_operations; + extern const struct vm_operations_struct hugetlb_vm_ops; + struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct, + struct user_struct **user, int creat_flags); +-int hugetlb_get_quota(struct address_space *mapping, long delta); +-void hugetlb_put_quota(struct address_space *mapping, long delta); + + static inline int is_file_hugepages(struct file *file) + { +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index b1c3148..afa057a 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -53,6 +53,84 @@ static unsigned long __initdata default_hstate_size; + */ + static DEFINE_SPINLOCK(hugetlb_lock); + ++static inline void unlock_or_release_subpool(struct hugepage_subpool *spool) ++{ ++ bool free = (spool->count == 0) && (spool->used_hpages == 0); ++ ++ spin_unlock(&spool->lock); ++ ++ /* If no pages are used, and no other handles to the subpool ++ * remain, free the subpool the subpool remain */ ++ if (free) ++ kfree(spool); ++} ++ ++struct hugepage_subpool *hugepage_new_subpool(long nr_blocks) ++{ ++ struct hugepage_subpool *spool; ++ ++ spool = kmalloc(sizeof(*spool), GFP_KERNEL); ++ if (!spool) ++ return NULL; ++ ++ spin_lock_init(&spool->lock); ++ spool->count = 1; ++ spool->max_hpages = nr_blocks; ++ spool->used_hpages = 0; ++ ++ return spool; ++} ++ ++void hugepage_put_subpool(struct hugepage_subpool *spool) ++{ ++ spin_lock(&spool->lock); ++ BUG_ON(!spool->count); ++ spool->count--; ++ unlock_or_release_subpool(spool); ++} ++ ++static int hugepage_subpool_get_pages(struct hugepage_subpool *spool, ++ long delta) ++{ ++ int ret = 0; ++ ++ if (!spool) ++ return 0; ++ ++ spin_lock(&spool->lock); ++ if ((spool->used_hpages + delta) <= spool->max_hpages) { ++ spool->used_hpages += delta; ++ } else { ++ ret = -ENOMEM; ++ } ++ spin_unlock(&spool->lock); ++ ++ return ret; ++} ++ ++static void hugepage_subpool_put_pages(struct hugepage_subpool *spool, ++ long delta) ++{ ++ if (!spool) ++ return; ++ ++ spin_lock(&spool->lock); ++ spool->used_hpages -= delta; ++ /* If hugetlbfs_put_super couldn't free spool due to ++ * an outstanding quota reference, free it now. */ ++ unlock_or_release_subpool(spool); ++} ++ ++static inline struct hugepage_subpool *subpool_inode(struct inode *inode) ++{ ++ return HUGETLBFS_SB(inode->i_sb)->spool; ++} ++ ++static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma) ++{ ++ return subpool_inode(vma->vm_file->f_dentry->d_inode); ++} ++ + /* + * Region tracking -- allows tracking of reservations and instantiated pages + * across the pages in a mapping. +@@ -540,9 +618,9 @@ static void free_huge_page(struct page *page) + */ + struct hstate *h = page_hstate(page); + int nid = page_to_nid(page); +- struct address_space *mapping; ++ struct hugepage_subpool *spool = ++ (struct hugepage_subpool *)page_private(page); + +- mapping = (struct address_space *) page_private(page); + set_page_private(page, 0); + page->mapping = NULL; + BUG_ON(page_count(page)); +@@ -558,8 +636,7 @@ static void free_huge_page(struct page *page) + enqueue_huge_page(h, page); + } + spin_unlock(&hugetlb_lock); +- if (mapping) +- hugetlb_put_quota(mapping, 1); ++ hugepage_subpool_put_pages(spool, 1); + } + + static void prep_new_huge_page(struct hstate *h, struct page *page, int nid) +@@ -977,11 +1054,12 @@ static void return_unused_surplus_pages(struct hstate *h, + /* + * Determine if the huge page at addr within the vma has an associated + * reservation. Where it does not we will need to logically increase +- * reservation and actually increase quota before an allocation can occur. +- * Where any new reservation would be required the reservation change is +- * prepared, but not committed. Once the page has been quota'd allocated +- * an instantiated the change should be committed via vma_commit_reservation. +- * No action is required on failure. ++ * reservation and actually increase subpool usage before an allocation ++ * can occur. Where any new reservation would be required the ++ * reservation change is prepared, but not committed. Once the page ++ * has been allocated from the subpool and instantiated the change should ++ * be committed via vma_commit_reservation. No action is required on ++ * failure. + */ + static long vma_needs_reservation(struct hstate *h, + struct vm_area_struct *vma, unsigned long addr) +@@ -1030,24 +1108,24 @@ static void vma_commit_reservation(struct hstate *h, + static struct page *alloc_huge_page(struct vm_area_struct *vma, + unsigned long addr, int avoid_reserve) + { ++ struct hugepage_subpool *spool = subpool_vma(vma); + struct hstate *h = hstate_vma(vma); + struct page *page; +- struct address_space *mapping = vma->vm_file->f_mapping; +- struct inode *inode = mapping->host; + long chg; + + /* +- * Processes that did not create the mapping will have no reserves and +- * will not have accounted against quota. Check that the quota can be +- * made before satisfying the allocation +- * MAP_NORESERVE mappings may also need pages and quota allocated +- * if no reserve mapping overlaps. ++ * Processes that did not create the mapping will have no ++ * reserves and will not have accounted against subpool ++ * limit. Check that the subpool limit can be made before ++ * satisfying the allocation MAP_NORESERVE mappings may also ++ * need pages and subpool limit allocated allocated if no reserve ++ * mapping overlaps. + */ + chg = vma_needs_reservation(h, vma, addr); + if (chg < 0) + return ERR_PTR(-VM_FAULT_OOM); + if (chg) +- if (hugetlb_get_quota(inode->i_mapping, chg)) ++ if (hugepage_subpool_get_pages(spool, chg)) + return ERR_PTR(-VM_FAULT_SIGBUS); + + spin_lock(&hugetlb_lock); +@@ -1057,12 +1135,12 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, + if (!page) { + page = alloc_buddy_huge_page(h, NUMA_NO_NODE); + if (!page) { +- hugetlb_put_quota(inode->i_mapping, chg); ++ hugepage_subpool_put_pages(spool, chg); + return ERR_PTR(-VM_FAULT_SIGBUS); + } + } + +- set_page_private(page, (unsigned long) mapping); ++ set_page_private(page, (unsigned long)spool); + + vma_commit_reservation(h, vma, addr); + +@@ -2083,6 +2161,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) + { + struct hstate *h = hstate_vma(vma); + struct resv_map *reservations = vma_resv_map(vma); ++ struct hugepage_subpool *spool = subpool_vma(vma); + unsigned long reserve; + unsigned long start; + unsigned long end; +@@ -2098,7 +2177,7 @@ static void hugetlb_vm_op_close(struct vm_area_struct *vma) + + if (reserve) { + hugetlb_acct_memory(h, -reserve); +- hugetlb_put_quota(vma->vm_file->f_mapping, reserve); ++ hugepage_subpool_put_pages(spool, reserve); + } + } + } +@@ -2331,7 +2410,7 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, + address = address & huge_page_mask(h); + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + + (vma->vm_pgoff >> PAGE_SHIFT); +- mapping = (struct address_space *)page_private(page); ++ mapping = vma->vm_file->f_dentry->d_inode->i_mapping; + + /* + * Take the mapping lock for the duration of the table walk. As +@@ -2884,11 +2963,12 @@ int hugetlb_reserve_pages(struct inode *inode, + { + long ret, chg; + struct hstate *h = hstate_inode(inode); ++ struct hugepage_subpool *spool = subpool_inode(inode); + + /* + * Only apply hugepage reservation if asked. At fault time, an + * attempt will be made for VM_NORESERVE to allocate a page +- * and filesystem quota without using reserves ++ * without using reserves + */ + if (vm_flags & VM_NORESERVE) + return 0; +@@ -2915,19 +2995,19 @@ int hugetlb_reserve_pages(struct inode *inode, + goto out_err; + } + +- /* There must be enough filesystem quota for the mapping */ +- if (hugetlb_get_quota(inode->i_mapping, chg)) { ++ /* There must be enough pages in the subpool for the mapping */ ++ if (hugepage_subpool_get_pages(spool, chg)) { + ret = -ENOSPC; + goto out_err; + } + + /* + * Check enough hugepages are available for the reservation. +- * Hand back the quota if there are not ++ * Hand the pages back to the subpool if there are not + */ + ret = hugetlb_acct_memory(h, chg); + if (ret < 0) { +- hugetlb_put_quota(inode->i_mapping, chg); ++ hugepage_subpool_put_pages(spool, chg); + goto out_err; + } + +@@ -2949,12 +3029,13 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) + { + struct hstate *h = hstate_inode(inode); + long chg = region_truncate(&inode->i_mapping->private_list, offset); ++ struct hugepage_subpool *spool = subpool_inode(inode); + + spin_lock(&inode->i_lock); + inode->i_blocks -= (blocks_per_huge_page(h) * freed); + spin_unlock(&inode->i_lock); + +- hugetlb_put_quota(inode->i_mapping, (chg - freed)); ++ hugepage_subpool_put_pages(spool, (chg - freed)); + hugetlb_acct_memory(h, -(chg - freed)); + } + diff --git a/debian/patches/bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch b/debian/patches/bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch new file mode 100644 index 000000000..2ea5e1c81 --- /dev/null +++ b/debian/patches/bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch @@ -0,0 +1,95 @@ +From: Dave Hansen +Date: Fri, 18 May 2012 11:46:30 -0700 +Subject: hugetlb: fix resv_map leak in error path + +commit c50ac050811d6485616a193eb0f37bfbd191cc89 upstream. + +When called for anonymous (non-shared) mappings, hugetlb_reserve_pages() +does a resv_map_alloc(). It depends on code in hugetlbfs's +vm_ops->close() to release that allocation. + +However, in the mmap() failure path, we do a plain unmap_region() without +the remove_vma() which actually calls vm_ops->close(). + +This is a decent fix. This leak could get reintroduced if new code (say, +after hugetlb_reserve_pages() in hugetlbfs_file_mmap()) decides to return +an error. But, I think it would have to unroll the reservation anyway. + +Christoph's test case: + + http://marc.info/?l=linux-mm&m=133728900729735 + +Signed-off-by: Dave Hansen +[Christoph Lameter: I have rediffed the patch against 2.6.32 and 3.2.0.] +Signed-off-by: Ben Hutchings +--- + mm/hugetlb.c | 28 ++++++++++++++++++++++------ + 1 file changed, 22 insertions(+), 6 deletions(-) + +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -2068,6 +2068,15 @@ + kref_get(&reservations->refs); + } + ++static void resv_map_put(struct vm_area_struct *vma) ++{ ++ struct resv_map *reservations = vma_resv_map(vma); ++ ++ if (!reservations) ++ return; ++ kref_put(&reservations->refs, resv_map_release); ++} ++ + static void hugetlb_vm_op_close(struct vm_area_struct *vma) + { + struct hstate *h = hstate_vma(vma); +@@ -2083,7 +2092,7 @@ + reserve = (end - start) - + region_count(&reservations->regions, start, end); + +- kref_put(&reservations->refs, resv_map_release); ++ resv_map_put(vma); + + if (reserve) { + hugetlb_acct_memory(h, -reserve); +@@ -2884,12 +2893,16 @@ + set_vma_resv_flags(vma, HPAGE_RESV_OWNER); + } + +- if (chg < 0) +- return chg; ++ if (chg < 0) { ++ ret = chg; ++ goto out_err; ++ } + + /* There must be enough filesystem quota for the mapping */ +- if (hugetlb_get_quota(inode->i_mapping, chg)) +- return -ENOSPC; ++ if (hugetlb_get_quota(inode->i_mapping, chg)) { ++ ret = -ENOSPC; ++ goto out_err; ++ } + + /* + * Check enough hugepages are available for the reservation. +@@ -2898,7 +2911,7 @@ + ret = hugetlb_acct_memory(h, chg); + if (ret < 0) { + hugetlb_put_quota(inode->i_mapping, chg); +- return ret; ++ goto out_err; + } + + /* +@@ -2915,6 +2928,9 @@ + if (!vma || vma->vm_flags & VM_MAYSHARE) + region_add(&inode->i_mapping->private_list, from, to); + return 0; ++out_err: ++ resv_map_put(vma); ++ return ret; + } + + void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) diff --git a/debian/patches/bugfix/all/mm-fix-vma_resv_map-null-pointer.patch b/debian/patches/bugfix/all/mm-fix-vma_resv_map-null-pointer.patch new file mode 100644 index 000000000..d6c0c3974 --- /dev/null +++ b/debian/patches/bugfix/all/mm-fix-vma_resv_map-null-pointer.patch @@ -0,0 +1,66 @@ +From: Dave Hansen +Date: Wed, 30 May 2012 07:51:07 -0700 +Subject: mm: fix vma_resv_map() NULL pointer + +commit 4523e1458566a0e8ecfaff90f380dd23acc44d27 upstream. + +hugetlb_reserve_pages() can be used for either normal file-backed +hugetlbfs mappings, or MAP_HUGETLB. In the MAP_HUGETLB, semi-anonymous +mode, there is not a VMA around. The new call to resv_map_put() assumed +that there was, and resulted in a NULL pointer dereference: + + BUG: unable to handle kernel NULL pointer dereference at 0000000000000030 + IP: vma_resv_map+0x9/0x30 + PGD 141453067 PUD 1421e1067 PMD 0 + Oops: 0000 [#1] PREEMPT SMP + ... + Pid: 14006, comm: trinity-child6 Not tainted 3.4.0+ #36 + RIP: vma_resv_map+0x9/0x30 + ... + Process trinity-child6 (pid: 14006, threadinfo ffff8801414e0000, task ffff8801414f26b0) + Call Trace: + resv_map_put+0xe/0x40 + hugetlb_reserve_pages+0xa6/0x1d0 + hugetlb_file_setup+0x102/0x2c0 + newseg+0x115/0x360 + ipcget+0x1ce/0x310 + sys_shmget+0x5a/0x60 + system_call_fastpath+0x16/0x1b + +This was reported by Dave Jones, but was reproducible with the +libhugetlbfs test cases, so shame on me for not running them in the +first place. + +With this, the oops is gone, and the output of libhugetlbfs's +run_tests.py is identical to plain 3.4 again. + +[ Marked for stable, since this was introduced by commit c50ac050811d + ("hugetlb: fix resv_map leak in error path") which was also marked for + stable ] + +Reported-by: Dave Jones +Cc: Mel Gorman +Cc: KOSAKI Motohiro +Cc: Christoph Lameter +Cc: Andrea Arcangeli +Cc: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Ben Hutchings +--- + mm/hugetlb.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 285a81e..e198831 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -3036,7 +3036,8 @@ int hugetlb_reserve_pages(struct inode *inode, + region_add(&inode->i_mapping->private_list, from, to); + return 0; + out_err: +- resv_map_put(vma); ++ if (vma) ++ resv_map_put(vma); + return ret; + } + diff --git a/debian/patches/bugfix/x86/mm-pmd_read_atomic-fix-32bit-pae-pmd-walk-vs-pmd_populate-smp-race.patch b/debian/patches/bugfix/x86/mm-pmd_read_atomic-fix-32bit-pae-pmd-walk-vs-pmd_populate-smp-race.patch new file mode 100644 index 000000000..1b2f44156 --- /dev/null +++ b/debian/patches/bugfix/x86/mm-pmd_read_atomic-fix-32bit-pae-pmd-walk-vs-pmd_populate-smp-race.patch @@ -0,0 +1,214 @@ +From: Andrea Arcangeli +Date: Tue, 29 May 2012 15:06:49 -0700 +Subject: mm: pmd_read_atomic: fix 32bit PAE pmd walk vs pmd_populate SMP race + condition + +commit 26c191788f18129af0eb32a358cdaea0c7479626 upstream. + +When holding the mmap_sem for reading, pmd_offset_map_lock should only +run on a pmd_t that has been read atomically from the pmdp pointer, +otherwise we may read only half of it leading to this crash. + +PID: 11679 TASK: f06e8000 CPU: 3 COMMAND: "do_race_2_panic" + #0 [f06a9dd8] crash_kexec at c049b5ec + #1 [f06a9e2c] oops_end at c083d1c2 + #2 [f06a9e40] no_context at c0433ded + #3 [f06a9e64] bad_area_nosemaphore at c043401a + #4 [f06a9e6c] __do_page_fault at c0434493 + #5 [f06a9eec] do_page_fault at c083eb45 + #6 [f06a9f04] error_code (via page_fault) at c083c5d5 + EAX: 01fb470c EBX: fff35000 ECX: 00000003 EDX: 00000100 EBP: + 00000000 + DS: 007b ESI: 9e201000 ES: 007b EDI: 01fb4700 GS: 00e0 + CS: 0060 EIP: c083bc14 ERR: ffffffff EFLAGS: 00010246 + #7 [f06a9f38] _spin_lock at c083bc14 + #8 [f06a9f44] sys_mincore at c0507b7d + #9 [f06a9fb0] system_call at c083becd + start len + EAX: ffffffda EBX: 9e200000 ECX: 00001000 EDX: 6228537f + DS: 007b ESI: 00000000 ES: 007b EDI: 003d0f00 + SS: 007b ESP: 62285354 EBP: 62285388 GS: 0033 + CS: 0073 EIP: 00291416 ERR: 000000da EFLAGS: 00000286 + +This should be a longstanding bug affecting x86 32bit PAE without THP. +Only archs with 64bit large pmd_t and 32bit unsigned long should be +affected. + +With THP enabled the barrier() in pmd_none_or_trans_huge_or_clear_bad() +would partly hide the bug when the pmd transition from none to stable, +by forcing a re-read of the *pmd in pmd_offset_map_lock, but when THP is +enabled a new set of problem arises by the fact could then transition +freely in any of the none, pmd_trans_huge or pmd_trans_stable states. +So making the barrier in pmd_none_or_trans_huge_or_clear_bad() +unconditional isn't good idea and it would be a flakey solution. + +This should be fully fixed by introducing a pmd_read_atomic that reads +the pmd in order with THP disabled, or by reading the pmd atomically +with cmpxchg8b with THP enabled. + +Luckily this new race condition only triggers in the places that must +already be covered by pmd_none_or_trans_huge_or_clear_bad() so the fix +is localized there but this bug is not related to THP. + +NOTE: this can trigger on x86 32bit systems with PAE enabled with more +than 4G of ram, otherwise the high part of the pmd will never risk to be +truncated because it would be zero at all times, in turn so hiding the +SMP race. + +This bug was discovered and fully debugged by Ulrich, quote: + +---- +[..] +pmd_none_or_trans_huge_or_clear_bad() loads the content of edx and +eax. + + 496 static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t + *pmd) + 497 { + 498 /* depend on compiler for an atomic pmd read */ + 499 pmd_t pmdval = *pmd; + + // edi = pmd pointer +0xc0507a74 : mov 0x8(%esp),%edi +... + // edx = PTE page table high address +0xc0507a84 : mov 0x4(%edi),%edx +... + // eax = PTE page table low address +0xc0507a8e : mov (%edi),%eax + +[..] + +Please note that the PMD is not read atomically. These are two "mov" +instructions where the high order bits of the PMD entry are fetched +first. Hence, the above machine code is prone to the following race. + +- The PMD entry {high|low} is 0x0000000000000000. + The "mov" at 0xc0507a84 loads 0x00000000 into edx. + +- A page fault (on another CPU) sneaks in between the two "mov" + instructions and instantiates the PMD. + +- The PMD entry {high|low} is now 0x00000003fda38067. + The "mov" at 0xc0507a8e loads 0xfda38067 into eax. +---- + +Reported-by: Ulrich Obergfell +Signed-off-by: Andrea Arcangeli +Cc: Mel Gorman +Cc: Hugh Dickins +Cc: Larry Woodman +Cc: Petr Matousek +Cc: Rik van Riel +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Ben Hutchings +--- + arch/x86/include/asm/pgtable-3level.h | 50 +++++++++++++++++++++++++++++++++ + include/asm-generic/pgtable.h | 22 +++++++++++++-- + 2 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/arch/x86/include/asm/pgtable-3level.h b/arch/x86/include/asm/pgtable-3level.h +index effff47..43876f1 100644 +--- a/arch/x86/include/asm/pgtable-3level.h ++++ b/arch/x86/include/asm/pgtable-3level.h +@@ -31,6 +31,56 @@ static inline void native_set_pte(pte_t *ptep, pte_t pte) + ptep->pte_low = pte.pte_low; + } + ++#define pmd_read_atomic pmd_read_atomic ++/* ++ * pte_offset_map_lock on 32bit PAE kernels was reading the pmd_t with ++ * a "*pmdp" dereference done by gcc. Problem is, in certain places ++ * where pte_offset_map_lock is called, concurrent page faults are ++ * allowed, if the mmap_sem is hold for reading. An example is mincore ++ * vs page faults vs MADV_DONTNEED. On the page fault side ++ * pmd_populate rightfully does a set_64bit, but if we're reading the ++ * pmd_t with a "*pmdp" on the mincore side, a SMP race can happen ++ * because gcc will not read the 64bit of the pmd atomically. To fix ++ * this all places running pmd_offset_map_lock() while holding the ++ * mmap_sem in read mode, shall read the pmdp pointer using this ++ * function to know if the pmd is null nor not, and in turn to know if ++ * they can run pmd_offset_map_lock or pmd_trans_huge or other pmd ++ * operations. ++ * ++ * Without THP if the mmap_sem is hold for reading, the ++ * pmd can only transition from null to not null while pmd_read_atomic runs. ++ * So there's no need of literally reading it atomically. ++ * ++ * With THP if the mmap_sem is hold for reading, the pmd can become ++ * THP or null or point to a pte (and in turn become "stable") at any ++ * time under pmd_read_atomic, so it's mandatory to read it atomically ++ * with cmpxchg8b. ++ */ ++#ifndef CONFIG_TRANSPARENT_HUGEPAGE ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ pmdval_t ret; ++ u32 *tmp = (u32 *)pmdp; ++ ++ ret = (pmdval_t) (*tmp); ++ if (ret) { ++ /* ++ * If the low part is null, we must not read the high part ++ * or we can end up with a partial pmd. ++ */ ++ smp_rmb(); ++ ret |= ((pmdval_t)*(tmp + 1)) << 32; ++ } ++ ++ return (pmd_t) { ret }; ++} ++#else /* CONFIG_TRANSPARENT_HUGEPAGE */ ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ return (pmd_t) { atomic64_read((atomic64_t *)pmdp) }; ++} ++#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ ++ + static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) + { + set_64bit((unsigned long long *)(ptep), native_pte_val(pte)); +diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h +index e2768f1..6f2b45a 100644 +--- a/include/asm-generic/pgtable.h ++++ b/include/asm-generic/pgtable.h +@@ -445,6 +445,18 @@ static inline int pmd_write(pmd_t pmd) + #endif /* __HAVE_ARCH_PMD_WRITE */ + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + ++#ifndef pmd_read_atomic ++static inline pmd_t pmd_read_atomic(pmd_t *pmdp) ++{ ++ /* ++ * Depend on compiler for an atomic pmd read. NOTE: this is ++ * only going to work, if the pmdval_t isn't larger than ++ * an unsigned long. ++ */ ++ return *pmdp; ++} ++#endif ++ + /* + * This function is meant to be used by sites walking pagetables with + * the mmap_sem hold in read mode to protect against MADV_DONTNEED and +@@ -458,11 +470,17 @@ static inline int pmd_write(pmd_t pmd) + * undefined so behaving like if the pmd was none is safe (because it + * can return none anyway). The compiler level barrier() is critically + * important to compute the two checks atomically on the same pmdval. ++ * ++ * For 32bit kernels with a 64bit large pmd_t this automatically takes ++ * care of reading the pmd atomically to avoid SMP race conditions ++ * against pmd_populate() when the mmap_sem is hold for reading by the ++ * caller (a special atomic read not done by "gcc" as in the generic ++ * version above, is also needed when THP is disabled because the page ++ * fault can populate the pmd from under us). + */ + static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) + { +- /* depend on compiler for an atomic pmd read */ +- pmd_t pmdval = *pmd; ++ pmd_t pmdval = pmd_read_atomic(pmd); + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. diff --git a/debian/patches/series/base b/debian/patches/series/base index ff71984dd..a2c340fc9 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -302,3 +302,8 @@ # AppArmor userland compatibility. This had better be gone in wheezy+1! + features/all/AppArmor-compatibility-patch-for-v5-interface.patch + ++ bugfix/x86/mm-pmd_read_atomic-fix-32bit-pae-pmd-walk-vs-pmd_populate-smp-race.patch ++ bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch ++ bugfix/all/mm-fix-vma_resv_map-null-pointer.patch ++ bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch From 041284f4010e2bb8ffae3dc0fd6e77a1efa15bc7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Jun 2012 03:47:59 +0000 Subject: [PATCH 11/13] [SCSI] fix scsi_wait_scan (Closes: #647436) svn path=/dists/sid/linux-2.6/; revision=19051 --- debian/changelog | 1 + .../bugfix/all/fix-scsi_wait_scan.patch | 40 +++++++++++++++++++ debian/patches/series/base | 2 + 3 files changed, 43 insertions(+) create mode 100644 debian/patches/bugfix/all/fix-scsi_wait_scan.patch diff --git a/debian/changelog b/debian/changelog index dac770940..05f3b335f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -31,6 +31,7 @@ linux-2.6 (3.2.19-1) UNRELEASED; urgency=low * [x86] mm: pmd_read_atomic: fix 32bit PAE pmd walk vs pmd_populate SMP race condition (CVE-2012-2373) * hugetlb: fix resv_map leak in error path (CVE-2012-2390) + * [SCSI] fix scsi_wait_scan (Closes: #647436) -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 diff --git a/debian/patches/bugfix/all/fix-scsi_wait_scan.patch b/debian/patches/bugfix/all/fix-scsi_wait_scan.patch new file mode 100644 index 000000000..aee0bce6e --- /dev/null +++ b/debian/patches/bugfix/all/fix-scsi_wait_scan.patch @@ -0,0 +1,40 @@ +From: James Bottomley +Date: Wed, 30 May 2012 09:45:39 +0000 +Subject: [SCSI] fix scsi_wait_scan + +commit 1ff2f40305772b159a91c19590ee159d3a504afc upstream. + +Commit c751085943362143f84346d274e0011419c84202 +Author: Rafael J. Wysocki +Date: Sun Apr 12 20:06:56 2009 +0200 + + PM/Hibernate: Wait for SCSI devices scan to complete during resume + +Broke the scsi_wait_scan module in 2.6.30. Apparently debian still uses it so +fix it and backport to stable before removing it in 3.6. + +The breakage is caused because the function template in +include/scsi/scsi_scan.h is defined to be a nop unless SCSI is built in. +That means that in the modular case (which is every distro), the +scsi_wait_scan module does a simple async_synchronize_full() instead of +waiting for scans. + +Signed-off-by: James Bottomley +Signed-off-by: Ben Hutchings +--- + drivers/scsi/scsi_wait_scan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/scsi/scsi_wait_scan.c b/drivers/scsi/scsi_wait_scan.c +index 74708fc..ae78148 100644 +--- a/drivers/scsi/scsi_wait_scan.c ++++ b/drivers/scsi/scsi_wait_scan.c +@@ -12,7 +12,7 @@ + + #include + #include +-#include ++#include "scsi_priv.h" + + static int __init wait_scan_init(void) + { diff --git a/debian/patches/series/base b/debian/patches/series/base index a2c340fc9..1d618cacd 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -307,3 +307,5 @@ + bugfix/all/hugetlb-fix-resv_map-leak-in-error-path.patch + bugfix/all/mm-fix-vma_resv_map-null-pointer.patch + bugfix/all/hugepages-fix-use-after-free-bug-in-quota-handling.patch + ++ bugfix/all/fix-scsi_wait_scan.patch From eb9c0ff36488074902812e60a571c4d62d355fc1 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Jun 2012 12:21:52 +0000 Subject: [PATCH 12/13] Fix hid core dependency for hyperv-modules udeb svn path=/dists/sid/linux-2.6/; revision=19053 --- debian/installer/modules/input-modules | 1 + debian/installer/package-list | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/installer/modules/input-modules b/debian/installer/modules/input-modules index 62fc503cf..bf17a3011 100644 --- a/debian/installer/modules/input-modules +++ b/debian/installer/modules/input-modules @@ -1,3 +1,4 @@ +hid usbhid hid-apple ? hid-belkin ? diff --git a/debian/installer/package-list b/debian/installer/package-list index 74eb1647c..a99061dee 100644 --- a/debian/installer/package-list +++ b/debian/installer/package-list @@ -480,7 +480,7 @@ Description: LED modules This package contains LED modules. Package: hyperv-modules -Depends: kernel-image, hid-modules, scsi-core-modules +Depends: kernel-image, input-modules, scsi-core-modules Priority: extra Description: Hyper-V modules This package contains Hyper-V paravirtualised drivers for the kernel. From 1e9083ce678b087175378249f021f88a9587f821 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Jun 2012 15:11:07 +0000 Subject: [PATCH 13/13] Prepare to release linux-2.6 (3.2.19-1). svn path=/dists/sid/linux-2.6/; revision=19054 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 05f3b335f..e764f3b34 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -linux-2.6 (3.2.19-1) UNRELEASED; urgency=low +linux-2.6 (3.2.19-1) unstable; urgency=low * New upstream stable update: http://www.kernel.org/pub/linux/kernel/v3.x/ChangeLog-3.2.19 @@ -33,7 +33,7 @@ linux-2.6 (3.2.19-1) UNRELEASED; urgency=low * hugetlb: fix resv_map leak in error path (CVE-2012-2390) * [SCSI] fix scsi_wait_scan (Closes: #647436) - -- Ben Hutchings Sun, 27 May 2012 01:12:44 +0100 + -- Ben Hutchings Fri, 01 Jun 2012 13:15:48 +0100 linux-2.6 (3.2.18-1) unstable; urgency=low