* [net-next PATCH 1/4] be2net: remove type argument of be_cmd_mac_addr_query()
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
In-Reply-To: <1348843184-22214-1-git-send-email-sathya.perla@emulex.com>
All invocations of this routine use the same type value.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_cmds.c | 4 ++--
drivers/net/ethernet/emulex/benet/be_cmds.h | 2 +-
drivers/net/ethernet/emulex/benet/be_main.c | 18 ++++++------------
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 701b3e9..6fbfb20 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -717,7 +717,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, u32 pmac_id)
+ bool permanent, u32 if_handle, u32 pmac_id)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_mac_query *req;
@@ -734,7 +734,7 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req), wrb, NULL);
- req->type = type;
+ req->type = MAC_ADDRESS_TYPE_NETWORK;
if (permanent) {
req->permanent = 1;
} else {
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 250f19b..1f5b839 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1687,7 +1687,7 @@ struct be_cmd_req_set_ext_fat_caps {
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_fw_wait_ready(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, u32 pmac_id);
+ 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,
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 84379f4..fa17430 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -241,9 +241,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- status = be_cmd_mac_addr_query(adapter, current_mac,
- MAC_ADDRESS_TYPE_NETWORK, false,
- adapter->if_handle, 0);
+ status = be_cmd_mac_addr_query(adapter, current_mac, false,
+ adapter->if_handle, 0);
if (status)
goto err;
@@ -2693,21 +2692,16 @@ static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
status = be_cmd_get_mac_from_list(adapter, mac,
active_mac, pmac_id, 0);
if (*active_mac) {
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK,
- false, if_handle,
- *pmac_id);
+ status = be_cmd_mac_addr_query(adapter, mac, false,
+ if_handle, *pmac_id);
}
} else if (be_physfn(adapter)) {
/* For BE3, for PF get permanent MAC */
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, true,
- 0, 0);
+ status = be_cmd_mac_addr_query(adapter, mac, true, 0, 0);
*active_mac = false;
} else {
/* For BE3, for VF get soft MAC assigned by PF*/
- status = be_cmd_mac_addr_query(adapter, mac,
- MAC_ADDRESS_TYPE_NETWORK, false,
+ status = be_cmd_mac_addr_query(adapter, mac, false,
if_handle, 0);
*active_mac = true;
}
--
1.7.4
^ permalink raw reply related
* [net-next PATCH 0/4] fixes v2
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
Resending the patch series minus the patch to remove the AMAP macros.
Pls apply.
Sathya Perla (4):
be2net: remove type argument of be_cmd_mac_addr_query()
be2net: fix wrong handling of be_setup() failure in be_probe()
be2net: cleanup code related to be_link_status_query()
be2net: fixup log messages
drivers/net/ethernet/emulex/benet/be.h | 1 -
drivers/net/ethernet/emulex/benet/be_cmds.c | 53 +++++++++++++++------
drivers/net/ethernet/emulex/benet/be_cmds.h | 6 +-
drivers/net/ethernet/emulex/benet/be_ethtool.c | 57 +++++------------------
drivers/net/ethernet/emulex/benet/be_main.c | 60 ++++++++++++++---------
5 files changed, 89 insertions(+), 88 deletions(-)
--
1.7.4
^ permalink raw reply
* [net-next PATCH 2/4] be2net: fix wrong handling of be_setup() failure in be_probe()
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
In-Reply-To: <1348843184-22214-1-git-send-email-sathya.perla@emulex.com>
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_main.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index fa17430..b712091 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -3889,7 +3889,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
status = be_setup(adapter);
if (status)
- goto msix_disable;
+ goto stats_clean;
be_netdev_init(netdev);
status = register_netdev(netdev);
@@ -3910,8 +3910,6 @@ static int __devinit be_probe(struct pci_dev *pdev,
unsetup:
be_clear(adapter);
-msix_disable:
- be_msix_disable(adapter);
stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
--
1.7.4
^ permalink raw reply related
* [net-next PATCH 3/4] be2net: cleanup code related to be_link_status_query()
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
In-Reply-To: <1348843184-22214-1-git-send-email-sathya.perla@emulex.com>
1) link_status_query() is always called to query the link-speed (speed
after applying qos). When there is no qos setting, link-speed is derived from
port-speed. Do all this inside this routine and hide this from the callers.
2) adpater->phy.forced_port_speed is not being set anywhere after being
initialized. Get rid of this variable.
3) Ignore async link_speed notifications till the initial value has been
fetched from FW.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be.h | 1 -
drivers/net/ethernet/emulex/benet/be_cmds.c | 46 ++++++++++++++-----
drivers/net/ethernet/emulex/benet/be_cmds.h | 4 +-
drivers/net/ethernet/emulex/benet/be_ethtool.c | 57 +++++-------------------
drivers/net/ethernet/emulex/benet/be_main.c | 4 +-
5 files changed, 48 insertions(+), 64 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 5b622993..cf4c05b 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -337,7 +337,6 @@ struct phy_info {
u16 auto_speeds_supported;
u16 fixed_speeds_supported;
int link_speed;
- int forced_port_speed;
u32 dac_cable_len;
u32 advertising;
u32 supported;
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 6fbfb20..46a19af 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -165,14 +165,13 @@ static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
}
}
-/* Grp5 QOS Speed evt */
+/* Grp5 QOS Speed evt: qos_link_speed is in units of 10 Mbps */
static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
struct be_async_event_grp5_qos_link_speed *evt)
{
- if (evt->physical_port == adapter->port_num) {
- /* qos_link_speed is in units of 10 Mbps */
- adapter->phy.link_speed = evt->qos_link_speed * 10;
- }
+ if (adapter->phy.link_speed >= 0 &&
+ evt->physical_port == adapter->port_num)
+ adapter->phy.link_speed = le16_to_cpu(evt->qos_link_speed) * 10;
}
/*Grp5 PVID evt*/
@@ -1326,9 +1325,28 @@ err:
return status;
}
-/* Uses synchronous mcc */
-int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
- u16 *link_speed, u8 *link_status, u32 dom)
+static int be_mac_to_link_speed(int mac_speed)
+{
+ switch (mac_speed) {
+ case PHY_LINK_SPEED_ZERO:
+ return 0;
+ case PHY_LINK_SPEED_10MBPS:
+ return 10;
+ case PHY_LINK_SPEED_100MBPS:
+ return 100;
+ case PHY_LINK_SPEED_1GBPS:
+ return 1000;
+ case PHY_LINK_SPEED_10GBPS:
+ return 10000;
+ }
+ return 0;
+}
+
+/* Uses synchronous mcc
+ * Returns link_speed in Mbps
+ */
+int be_cmd_link_status_query(struct be_adapter *adapter, u16 *link_speed,
+ u8 *link_status, u32 dom)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_link_status *req;
@@ -1357,11 +1375,13 @@ int be_cmd_link_status_query(struct be_adapter *adapter, u8 *mac_speed,
status = be_mcc_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_link_status *resp = embedded_payload(wrb);
- if (resp->mac_speed != PHY_LINK_SPEED_ZERO) {
- if (link_speed)
- *link_speed = le16_to_cpu(resp->link_speed);
- if (mac_speed)
- *mac_speed = resp->mac_speed;
+ if (link_speed) {
+ *link_speed = resp->link_speed ?
+ le16_to_cpu(resp->link_speed) * 10 :
+ be_mac_to_link_speed(resp->mac_speed);
+
+ if (!resp->logical_link_status)
+ *link_speed = 0;
}
if (link_status)
*link_status = resp->logical_link_status;
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 1f5b839..0936e21 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1714,8 +1714,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, u8 *link_status, u32 dom);
+extern int be_cmd_link_status_query(struct be_adapter *adapter, 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 c0e7006..8e6fb0b 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -512,28 +512,6 @@ static u32 convert_to_et_setting(u32 if_type, u32 if_speeds)
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 ||
@@ -544,27 +522,16 @@ bool be_pause_supported(struct be_adapter *adapter)
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
- u8 port_speed = 0;
- u16 link_speed = 0;
u8 link_status;
- u32 et_speed = 0;
+ u16 link_speed = 0;
int status;
- 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 * 10;
- else if (link_status)
- et_speed = convert_to_et_speed(port_speed);
- } else {
- et_speed = adapter->phy.forced_port_speed;
- }
-
- ethtool_cmd_speed_set(ecmd, et_speed);
+ if (adapter->phy.link_speed < 0) {
+ status = be_cmd_link_status_query(adapter, &link_speed,
+ &link_status, 0);
+ if (!status)
+ be_link_status_update(adapter, link_status);
+ ethtool_cmd_speed_set(ecmd, link_speed);
status = be_cmd_get_phy_info(adapter);
if (status)
@@ -773,8 +740,8 @@ static void
be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- u8 mac_speed = 0;
- u16 qos_link_speed = 0;
+ int status;
+ u8 link_status = 0;
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
@@ -798,11 +765,11 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
test->flags |= ETH_TEST_FL_FAILED;
}
- if (be_cmd_link_status_query(adapter, &mac_speed,
- &qos_link_speed, NULL, 0) != 0) {
+ status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
+ if (status) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = -1;
- } else if (!mac_speed) {
+ } else if (!link_status) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
}
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index b712091..4855dd6 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -2440,8 +2440,7 @@ static int be_open(struct net_device *netdev)
be_eq_notify(adapter, eqo->q.id, true, false, 0);
}
- status = be_cmd_link_status_query(adapter, NULL, NULL,
- &link_status, 0);
+ status = be_cmd_link_status_query(adapter, NULL, &link_status, 0);
if (!status)
be_link_status_update(adapter, link_status);
@@ -2670,7 +2669,6 @@ static void be_setup_init(struct be_adapter *adapter)
adapter->be3_native = false;
adapter->promiscuous = false;
adapter->eq_next_idx = 0;
- adapter->phy.forced_port_speed = -1;
}
static int be_get_mac_addr(struct be_adapter *adapter, u8 *mac, u32 if_handle,
--
1.7.4
^ permalink raw reply related
* [net-next PATCH 4/4] be2net: fixup log messages
From: Sathya Perla @ 2012-09-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
In-Reply-To: <1348843184-22214-1-git-send-email-sathya.perla@emulex.com>
Added and modified a few log messages mostly in probe path.
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be_cmds.c | 3 ++
drivers/net/ethernet/emulex/benet/be_main.c | 34 ++++++++++++++++++++++----
2 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index 46a19af..af60bb2 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -2425,6 +2425,9 @@ int be_cmd_req_native_mode(struct be_adapter *adapter)
struct be_cmd_resp_set_func_cap *resp = embedded_payload(wrb);
adapter->be3_native = le32_to_cpu(resp->cap_flags) &
CAPABILITY_BE3_NATIVE_ERX_API;
+ if (!adapter->be3_native)
+ dev_warn(&adapter->pdev->dev,
+ "adapter not in advanced mode\n");
}
err:
mutex_unlock(&adapter->mbox_lock);
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 4855dd6..6accb0c 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1896,6 +1896,8 @@ static int be_tx_qs_create(struct be_adapter *adapter)
return status;
}
+ dev_info(&adapter->pdev->dev, "created %d TX queue(s)\n",
+ adapter->num_tx_qs);
return 0;
}
@@ -1946,10 +1948,9 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
return rc;
}
- if (adapter->num_rx_qs != MAX_RX_QS)
- dev_info(&adapter->pdev->dev,
- "Created only %d receive queues\n", adapter->num_rx_qs);
-
+ dev_info(&adapter->pdev->dev,
+ "created %d RSS queue(s) and 1 default RX queue\n",
+ adapter->num_rx_qs - 1);
return 0;
}
@@ -2187,6 +2188,7 @@ static void be_msix_enable(struct be_adapter *adapter)
{
#define BE_MIN_MSIX_VECTORS 1
int i, status, num_vec, num_roce_vec = 0;
+ struct device *dev = &adapter->pdev->dev;
/* If RSS queues are not used, need a vec for default RX Q */
num_vec = min(be_num_rss_want(adapter), num_online_cpus());
@@ -2211,6 +2213,8 @@ static void be_msix_enable(struct be_adapter *adapter)
num_vec) == 0)
goto done;
}
+
+ dev_warn(dev, "MSIx enable failed\n");
return;
done:
if (be_roce_supported(adapter)) {
@@ -2224,6 +2228,7 @@ done:
}
} else
adapter->num_msix_vec = num_vec;
+ dev_info(dev, "enabled %d MSI-x vector(s)\n", adapter->num_msix_vec);
return;
}
@@ -3797,6 +3802,23 @@ static bool be_reset_required(struct be_adapter *adapter)
return be_find_vfs(adapter, ENABLED) > 0 ? false : true;
}
+static char *mc_name(struct be_adapter *adapter)
+{
+ if (adapter->function_mode & FLEX10_MODE)
+ return "FLEX10";
+ else if (adapter->function_mode & VNIC_MODE)
+ return "vNIC";
+ else if (adapter->function_mode & UMC_ENABLED)
+ return "UMC";
+ else
+ return "";
+}
+
+static inline char *func_name(struct be_adapter *adapter)
+{
+ return be_physfn(adapter) ? "PF" : "VF";
+}
+
static int __devinit be_probe(struct pci_dev *pdev,
const struct pci_device_id *pdev_id)
{
@@ -3901,8 +3923,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
be_cmd_query_port_name(adapter, &port_name);
- dev_info(&pdev->dev, "%s: %s port %c\n", netdev->name, nic_name(pdev),
- port_name);
+ dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
+ func_name(adapter), mc_name(adapter), port_name);
return 0;
--
1.7.4
^ permalink raw reply related
* mlx4_en_alloc_frag allocation failures
From: Shawn Bohrer @ 2012-09-28 15:14 UTC (permalink / raw)
To: netdev; +Cc: linux-mm, linux-kernel
We've got a new application that is receiving UDP multicast data using
AF_PACKET and writing out the packets in a custom format to disk. The
packet rates are bursty, but it seems to be roughly 100 Mbps on
average for 1 minute periods. With this application running all day
we get a lot of these messages:
[1298269.103034] kswapd1: page allocation failure: order:2, mode:0x4020
[1298269.103038] Pid: 80, comm: kswapd1 Not tainted 3.4.9-2.rgm.fc16.x86_64 #1
[1298269.103040] Call Trace:
[1298269.103041] <IRQ> [<ffffffff810db746>] warn_alloc_failed+0xf6/0x160
[1298269.103053] [<ffffffff813c767d>] ? skb_copy_bits+0x16d/0x2c0
[1298269.103058] [<ffffffff810e83a9>] ? wakeup_kswapd+0x69/0x160
[1298269.103060] [<ffffffff810df188>] __alloc_pages_nodemask+0x6e8/0x930
[1298269.103064] [<ffffffff81114316>] alloc_pages_current+0xb6/0x120
[1298269.103070] [<ffffffffa00c142b>] mlx4_en_alloc_frag+0x16b/0x1e0 [mlx4_en]
[1298269.103073] [<ffffffffa00c18a0>] mlx4_en_complete_rx_desc+0x120/0x1d0 [mlx4_en]
[1298269.103076] [<ffffffffa00c27d4>] mlx4_en_process_rx_cq+0x584/0x700 [mlx4_en]
[1298269.103079] [<ffffffffa00c29ef>] mlx4_en_poll_rx_cq+0x3f/0x80 [mlx4_en]
[1298269.103083] [<ffffffff813d6569>] net_rx_action+0x119/0x210
[1298269.103086] [<ffffffff8103c690>] __do_softirq+0xb0/0x220
[1298269.103090] [<ffffffff8109911d>] ? handle_irq_event+0x4d/0x70
[1298269.103095] [<ffffffff8148e30c>] call_softirq+0x1c/0x30
[1298269.103100] [<ffffffff81003ef5>] do_softirq+0x55/0x90
[1298269.103101] [<ffffffff8103ca65>] irq_exit+0x75/0x80
[1298269.103103] [<ffffffff8148e853>] do_IRQ+0x63/0xe0
[1298269.103107] [<ffffffff81485667>] common_interrupt+0x67/0x67
[1298269.103108] <EOI> [<ffffffff8148523f>] ? _raw_spin_unlock_irqrestore+0xf/0x20
[1298269.103113] [<ffffffff811184b1>] compaction_alloc+0x361/0x3f0
[1298269.103115] [<ffffffff810e29b7>] ? pagevec_lru_move_fn+0xd7/0xf0
[1298269.103118] [<ffffffff81123d19>] migrate_pages+0xa9/0x470
[1298269.103120] [<ffffffff81118150>] ? perf_trace_mm_compaction_migratepages+0xd0/0xd0
[1298269.103122] [<ffffffff81118abb>] compact_zone+0x4cb/0x910
[1298269.103124] [<ffffffff8111904b>] __compact_pgdat+0x14b/0x190
[1298269.103125] [<ffffffff8111931d>] compact_pgdat+0x2d/0x30
[1298269.103129] [<ffffffff810f32b9>] ? fragmentation_index+0x19/0x70
[1298269.103131] [<ffffffff810eb15f>] balance_pgdat+0x6ef/0x710
[1298269.103133] [<ffffffff810eb2ca>] kswapd+0x14a/0x390
[1298269.103136] [<ffffffff810567c0>] ? add_wait_queue+0x60/0x60
[1298269.103138] [<ffffffff810eb180>] ? balance_pgdat+0x710/0x710
[1298269.103140] [<ffffffff81055e93>] kthread+0x93/0xa0
[1298269.103142] [<ffffffff8148e214>] kernel_thread_helper+0x4/0x10
[1298269.103144] [<ffffffff81055e00>] ? kthread_worker_fn+0x140/0x140
[1298269.103146] [<ffffffff8148e210>] ? gs_change+0xb/0xb
The kernel is based on a Fedora 16 kernel and actually has the 3.4.10
patches applied. I can easily test patches or different kernels.
I'm mostly wondering if there is anything that can be done about these
failures? It appears that these failures have to do with handling
fragmented IP frames, but the majority of the packets this machines
should not be fragmented (there are probably some that are).
>From a memory management point of view the system has 48GB of RAM, and
typically 44GB of that is page cache. The dirty pages seem to hover
around 5-6MB and the filesystem/disks don't seem to have any problems
keeping up with writing out the data.
--
Shawn
--
---------------------------------------------------------------
This email, along with any attachments, is confidential. If you
believe you received this message in error, please contact the
sender immediately and delete all copies of the message.
Thank you.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [net-next PATCH 4/4] be2net: fixup log messages
From: Joe Perches @ 2012-09-28 15:39 UTC (permalink / raw)
To: Sathya Perla; +Cc: netdev
In-Reply-To: <e698cd68-540d-4a7a-bd76-2e9c73ddf19c@CMEXHTCAS2.ad.emulex.com>
On Fri, 2012-09-28 at 20:09 +0530, Sathya Perla wrote:
> Added and modified a few log messages mostly in probe path.
Trivial comment:
> diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
[]
> @@ -3797,6 +3802,23 @@ static bool be_reset_required(struct be_adapter *adapter)
> return be_find_vfs(adapter, ENABLED) > 0 ? false : true;
> }
>
> +static char *mc_name(struct be_adapter *adapter)
> +{
> + if (adapter->function_mode & FLEX10_MODE)
> + return "FLEX10";
> + else if (adapter->function_mode & VNIC_MODE)
> + return "vNIC";
> + else if (adapter->function_mode & UMC_ENABLED)
> + return "UMC";
> + else
> + return "";
> +}
Maybe something other than "" to identify this state
or add a space before or after the actual uses so that
the unprefixed state prints without 2 spaces.
Perhaps if you don't want to identify the non-virtual (?)
state:
static char *mc_name(struct be_adapter *adapter)
{
if (adapter->function_mode & FLEX10_MODE)
return " FLEX10";
else if (adapter->function_mode & VNIC_MODE)
return " vNIC";
else if (adapter->function_mode & UMC_ENABLED)
return " UMC";
else
return "";
}
[]
> @@ -3901,8 +3923,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
>
> be_cmd_query_port_name(adapter, &port_name);
>
> - dev_info(&pdev->dev, "%s: %s port %c\n", netdev->name, nic_name(pdev),
> - port_name);
> + dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
> + func_name(adapter), mc_name(adapter), port_name);
>
> return 0;
and:
dev_info(&pdev->dev, "%s: %s%s port %c\n",
nic_name(pdev), func_name(adapter), mc_name(adapter),
port_name);
^ permalink raw reply
* Re: mlx4_en_alloc_frag allocation failures
From: Eric Dumazet @ 2012-09-28 15:50 UTC (permalink / raw)
To: Shawn Bohrer; +Cc: netdev, linux-mm, linux-kernel
In-Reply-To: <20120928151429.GB2731@BohrerMBP.rgmadvisors.com>
On Fri, 2012-09-28 at 10:14 -0500, Shawn Bohrer wrote:
> We've got a new application that is receiving UDP multicast data using
> AF_PACKET and writing out the packets in a custom format to disk. The
> packet rates are bursty, but it seems to be roughly 100 Mbps on
> average for 1 minute periods. With this application running all day
> we get a lot of these messages:
>
> [1298269.103034] kswapd1: page allocation failure: order:2, mode:0x4020
> [1298269.103038] Pid: 80, comm: kswapd1 Not tainted 3.4.9-2.rgm.fc16.x86_64 #1
> [1298269.103040] Call Trace:
> [1298269.103041] <IRQ> [<ffffffff810db746>] warn_alloc_failed+0xf6/0x160
> [1298269.103053] [<ffffffff813c767d>] ? skb_copy_bits+0x16d/0x2c0
> [1298269.103058] [<ffffffff810e83a9>] ? wakeup_kswapd+0x69/0x160
> [1298269.103060] [<ffffffff810df188>] __alloc_pages_nodemask+0x6e8/0x930
> [1298269.103064] [<ffffffff81114316>] alloc_pages_current+0xb6/0x120
> [1298269.103070] [<ffffffffa00c142b>] mlx4_en_alloc_frag+0x16b/0x1e0 [mlx4_en]
> [1298269.103073] [<ffffffffa00c18a0>] mlx4_en_complete_rx_desc+0x120/0x1d0 [mlx4_en]
> [1298269.103076] [<ffffffffa00c27d4>] mlx4_en_process_rx_cq+0x584/0x700 [mlx4_en]
> [1298269.103079] [<ffffffffa00c29ef>] mlx4_en_poll_rx_cq+0x3f/0x80 [mlx4_en]
> [1298269.103083] [<ffffffff813d6569>] net_rx_action+0x119/0x210
> [1298269.103086] [<ffffffff8103c690>] __do_softirq+0xb0/0x220
> [1298269.103090] [<ffffffff8109911d>] ? handle_irq_event+0x4d/0x70
> [1298269.103095] [<ffffffff8148e30c>] call_softirq+0x1c/0x30
> [1298269.103100] [<ffffffff81003ef5>] do_softirq+0x55/0x90
> [1298269.103101] [<ffffffff8103ca65>] irq_exit+0x75/0x80
> [1298269.103103] [<ffffffff8148e853>] do_IRQ+0x63/0xe0
> [1298269.103107] [<ffffffff81485667>] common_interrupt+0x67/0x67
> [1298269.103108] <EOI> [<ffffffff8148523f>] ? _raw_spin_unlock_irqrestore+0xf/0x20
> [1298269.103113] [<ffffffff811184b1>] compaction_alloc+0x361/0x3f0
> [1298269.103115] [<ffffffff810e29b7>] ? pagevec_lru_move_fn+0xd7/0xf0
> [1298269.103118] [<ffffffff81123d19>] migrate_pages+0xa9/0x470
> [1298269.103120] [<ffffffff81118150>] ? perf_trace_mm_compaction_migratepages+0xd0/0xd0
> [1298269.103122] [<ffffffff81118abb>] compact_zone+0x4cb/0x910
> [1298269.103124] [<ffffffff8111904b>] __compact_pgdat+0x14b/0x190
> [1298269.103125] [<ffffffff8111931d>] compact_pgdat+0x2d/0x30
> [1298269.103129] [<ffffffff810f32b9>] ? fragmentation_index+0x19/0x70
> [1298269.103131] [<ffffffff810eb15f>] balance_pgdat+0x6ef/0x710
> [1298269.103133] [<ffffffff810eb2ca>] kswapd+0x14a/0x390
> [1298269.103136] [<ffffffff810567c0>] ? add_wait_queue+0x60/0x60
> [1298269.103138] [<ffffffff810eb180>] ? balance_pgdat+0x710/0x710
> [1298269.103140] [<ffffffff81055e93>] kthread+0x93/0xa0
> [1298269.103142] [<ffffffff8148e214>] kernel_thread_helper+0x4/0x10
> [1298269.103144] [<ffffffff81055e00>] ? kthread_worker_fn+0x140/0x140
> [1298269.103146] [<ffffffff8148e210>] ? gs_change+0xb/0xb
>
> The kernel is based on a Fedora 16 kernel and actually has the 3.4.10
> patches applied. I can easily test patches or different kernels.
>
> I'm mostly wondering if there is anything that can be done about these
> failures? It appears that these failures have to do with handling
> fragmented IP frames, but the majority of the packets this machines
> should not be fragmented (there are probably some that are).
>
> From a memory management point of view the system has 48GB of RAM, and
> typically 44GB of that is page cache. The dirty pages seem to hover
> around 5-6MB and the filesystem/disks don't seem to have any problems
> keeping up with writing out the data.
What is the value of /proc/sys/vm/min_free_kbytes ?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: mlx4_en_alloc_frag allocation failures
From: Shawn Bohrer @ 2012-09-28 15:52 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, linux-mm, linux-kernel
In-Reply-To: <1348847408.5093.2548.camel@edumazet-glaptop>
On Fri, Sep 28, 2012 at 05:50:08PM +0200, Eric Dumazet wrote:
> On Fri, 2012-09-28 at 10:14 -0500, Shawn Bohrer wrote:
> > We've got a new application that is receiving UDP multicast data using
> > AF_PACKET and writing out the packets in a custom format to disk. The
> > packet rates are bursty, but it seems to be roughly 100 Mbps on
> > average for 1 minute periods. With this application running all day
> > we get a lot of these messages:
> >
> > [1298269.103034] kswapd1: page allocation failure: order:2, mode:0x4020
> > [1298269.103038] Pid: 80, comm: kswapd1 Not tainted 3.4.9-2.rgm.fc16.x86_64 #1
> > [1298269.103040] Call Trace:
> > [1298269.103041] <IRQ> [<ffffffff810db746>] warn_alloc_failed+0xf6/0x160
> > [1298269.103053] [<ffffffff813c767d>] ? skb_copy_bits+0x16d/0x2c0
> > [1298269.103058] [<ffffffff810e83a9>] ? wakeup_kswapd+0x69/0x160
> > [1298269.103060] [<ffffffff810df188>] __alloc_pages_nodemask+0x6e8/0x930
> > [1298269.103064] [<ffffffff81114316>] alloc_pages_current+0xb6/0x120
> > [1298269.103070] [<ffffffffa00c142b>] mlx4_en_alloc_frag+0x16b/0x1e0 [mlx4_en]
> > [1298269.103073] [<ffffffffa00c18a0>] mlx4_en_complete_rx_desc+0x120/0x1d0 [mlx4_en]
> > [1298269.103076] [<ffffffffa00c27d4>] mlx4_en_process_rx_cq+0x584/0x700 [mlx4_en]
> > [1298269.103079] [<ffffffffa00c29ef>] mlx4_en_poll_rx_cq+0x3f/0x80 [mlx4_en]
> > [1298269.103083] [<ffffffff813d6569>] net_rx_action+0x119/0x210
> > [1298269.103086] [<ffffffff8103c690>] __do_softirq+0xb0/0x220
> > [1298269.103090] [<ffffffff8109911d>] ? handle_irq_event+0x4d/0x70
> > [1298269.103095] [<ffffffff8148e30c>] call_softirq+0x1c/0x30
> > [1298269.103100] [<ffffffff81003ef5>] do_softirq+0x55/0x90
> > [1298269.103101] [<ffffffff8103ca65>] irq_exit+0x75/0x80
> > [1298269.103103] [<ffffffff8148e853>] do_IRQ+0x63/0xe0
> > [1298269.103107] [<ffffffff81485667>] common_interrupt+0x67/0x67
> > [1298269.103108] <EOI> [<ffffffff8148523f>] ? _raw_spin_unlock_irqrestore+0xf/0x20
> > [1298269.103113] [<ffffffff811184b1>] compaction_alloc+0x361/0x3f0
> > [1298269.103115] [<ffffffff810e29b7>] ? pagevec_lru_move_fn+0xd7/0xf0
> > [1298269.103118] [<ffffffff81123d19>] migrate_pages+0xa9/0x470
> > [1298269.103120] [<ffffffff81118150>] ? perf_trace_mm_compaction_migratepages+0xd0/0xd0
> > [1298269.103122] [<ffffffff81118abb>] compact_zone+0x4cb/0x910
> > [1298269.103124] [<ffffffff8111904b>] __compact_pgdat+0x14b/0x190
> > [1298269.103125] [<ffffffff8111931d>] compact_pgdat+0x2d/0x30
> > [1298269.103129] [<ffffffff810f32b9>] ? fragmentation_index+0x19/0x70
> > [1298269.103131] [<ffffffff810eb15f>] balance_pgdat+0x6ef/0x710
> > [1298269.103133] [<ffffffff810eb2ca>] kswapd+0x14a/0x390
> > [1298269.103136] [<ffffffff810567c0>] ? add_wait_queue+0x60/0x60
> > [1298269.103138] [<ffffffff810eb180>] ? balance_pgdat+0x710/0x710
> > [1298269.103140] [<ffffffff81055e93>] kthread+0x93/0xa0
> > [1298269.103142] [<ffffffff8148e214>] kernel_thread_helper+0x4/0x10
> > [1298269.103144] [<ffffffff81055e00>] ? kthread_worker_fn+0x140/0x140
> > [1298269.103146] [<ffffffff8148e210>] ? gs_change+0xb/0xb
> >
> > The kernel is based on a Fedora 16 kernel and actually has the 3.4.10
> > patches applied. I can easily test patches or different kernels.
> >
> > I'm mostly wondering if there is anything that can be done about these
> > failures? It appears that these failures have to do with handling
> > fragmented IP frames, but the majority of the packets this machines
> > should not be fragmented (there are probably some that are).
> >
> > From a memory management point of view the system has 48GB of RAM, and
> > typically 44GB of that is page cache. The dirty pages seem to hover
> > around 5-6MB and the filesystem/disks don't seem to have any problems
> > keeping up with writing out the data.
>
> What is the value of /proc/sys/vm/min_free_kbytes ?
$ cat /proc/sys/vm/min_free_kbytes
90112
--
Shawn
--
---------------------------------------------------------------
This email, along with any attachments, is confidential. If you
believe you received this message in error, please contact the
sender immediately and delete all copies of the message.
Thank you.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCHv4 1/4] modem_shm: Add Modem Access Framework
From: Greg KH @ 2012-09-28 16:00 UTC (permalink / raw)
To: Arun Murthy; +Cc: linux-kernel, netdev, linux-doc, alan
In-Reply-To: <1348819504-1303-2-git-send-email-arun.murthy@stericsson.com>
On Fri, Sep 28, 2012 at 01:35:01PM +0530, Arun Murthy wrote:
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/printk.h>
> +#include <linux/modem_shm/modem.h>
> +
> +static struct class *modem_class;
What's wrong with a bus_type instead?
> +static int __modem_is_requested(struct device *dev, void *data)
> +{
> + struct modem_desc *mdesc = (struct modem_desc *)data;
> +
> + if (!mdesc->mclients) {
> + printk(KERN_ERR "modem_access: modem description is NULL\n");
> + return 0;
> + }
> + return atomic_read(&mdesc->mclients->cnt);
> +}
> +
> +int modem_is_requested(struct modem_desc *mdesc)
> +{
> + return class_for_each_device(modem_class, NULL, (void *)mdesc, __modem_is_requested);
> +}
Where is the documentation for your public api functions like this?
> +
> +int modem_release(struct modem_desc *mdesc)
> +{
> + if (!mdesc->release)
> + return -EFAULT;
> +
> + if (modem_is_requested(mdesc)) {
> + atomic_dec(&mdesc->mclients->cnt);
> + if (atomic_read(&mdesc->use_cnt) == 1) {
> + mdesc->release(mdesc);
> + atomic_dec(&mdesc->use_cnt);
> + }
Eeek, why aren't you using the built-in reference counting that the
struct device provided to you, and instead are rolling your own? This
happens in many places, why?
greg k-h
^ permalink raw reply
* Re: Lab: v.1.8 + Linux 2.6.37.6+up #1 + ESXi 5.0 - VM - Slow Network Performance/Failures
From: Stephen Hemminger @ 2012-09-28 16:21 UTC (permalink / raw)
To: Mike Harris; +Cc: netdev
In-Reply-To: <CAJXRGag+VEMYUfhEaVwpVCUpjwC6Rhd0NeOrA15VAEz-5OwAMQ@mail.gmail.com>
On Fri, 28 Sep 2012 04:56:35 +0200
Mike Harris <mharris@onxis.com> wrote:
> Hi,
>
> I hope everyone is well!
>
> Some network throughput/performance oddness with a linux based virtual firewall…
>
> Lab scenario;
>
> [Windows VM #1] --- VLAN X-----(*)Linux Firewall VM ----- VLAN Y
> ---[Windows VM #2]
>
> A tcpdump is kicked off with the following options on the firewall
> this a 100MB file is copied between VM #1 to VM #2 (SMB).
>
> tcpdump -i eth0.x -n -s0 -w file-transfer-1.pcap -c100
>
> Notes:
>
> + Physical blade run ESXi 5.0.
> + Windows VMs run on the same vSwitch and physical blade.
> + VLAN X and Y support up to 1500 bytes MTU.
> + Virtual firewall is configured with the 4095 (any) VLAN (receives
> and transmits tagged frames).
> + Virtual firewall is runs Linux 2.6.37.6+up #1
> + Virtual and physical backbones do support up to 9k frames.
>
> Observations;
>
> 1. The file copy fails…
> 2. The pcap reveals a 12,443 byte uber jumbo frame is present shortly
> after the file transfer starts.
>
> Repeated the same scenario using a test vyatta 6.4 VM and the file
> copy completes normally… no jumbo frames or any other oddness.
> Virtual and physical networking can not originate such a frame
> normally.
>
> Given this, I suspect there's a general framing failure of the network
> driver on the virtual linux firewall, which lead me to the dmesg
> command and this mailing list :)
>
> Has anyone else seen this behavior before on a linux VM before?
>
> Thoughts?
>
> Helpful suggestions :)
Vyatta ran into a problem because the Vmware driver was incorrectly keeping LRO
enabled even when forwarding. Given the age of the kernel that could
be your problem.
The short term workaround used to just force LRO off (change to vmxnet3).
Thankfully, someone later found where the driver was mistakenly renabling LRO
and fixed the real bug.
^ permalink raw reply
* drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:363:64: sparse: incorrect type in argument 3 (different base types)
From: Fengguang Wu @ 2012-09-28 16:36 UTC (permalink / raw)
To: Vipul Pandya; +Cc: kernel-janitors, Jay Hernandez, netdev
[-- Attachment #1: Type: text/plain, Size: 4039 bytes --]
Hi Vipul,
FYI, there are new sparse warnings show up in
commit: 5afc8b84eb7b29e4646d6e8ca7e6d7196031d6f7 cxgb4: Add functions to read memory via PCIE memory window
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:361:33: sparse: incorrect type in assignment (different base types)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:361:33: expected restricted __be32 [usertype] <noident>
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:361:33: got unsigned int
+ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:363:64: sparse: incorrect type in argument 3 (different base types)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:363:64: expected unsigned int [unsigned] [usertype] val
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:363:64: got restricted __be32 [usertype] <noident>
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:694:31: sparse: incorrect type in assignment (different base types)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:694:31: expected unsigned int [unsigned] [usertype] <noident>
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:694:31: got restricted __be32 [usertype] <noident>
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:898:25: sparse: cast to restricted __be32
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:2177:25: sparse: incorrect type in assignment (different base types)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:2177:25: expected restricted __be32 [usertype] <noident>
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:2177:25: got unsigned int
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c: In function 't4_memory_rw.constprop.6':
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c:462:1: warning: the frame size of 2056 bytes is larger than 1024 bytes [-Wframe-larger-than=]
vim +363 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
5afc8b84 (Vipul Pandya 2012-09-26 347)
5afc8b84 (Vipul Pandya 2012-09-26 348) /*
5afc8b84 (Vipul Pandya 2012-09-26 349) * Setup offset into PCIE memory window. Address must be a
5afc8b84 (Vipul Pandya 2012-09-26 350) * MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to
5afc8b84 (Vipul Pandya 2012-09-26 351) * ensure that changes propagate before we attempt to use the new
5afc8b84 (Vipul Pandya 2012-09-26 352) * values.)
5afc8b84 (Vipul Pandya 2012-09-26 353) */
5afc8b84 (Vipul Pandya 2012-09-26 354) t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
5afc8b84 (Vipul Pandya 2012-09-26 355) addr & ~(MEMWIN0_APERTURE - 1));
5afc8b84 (Vipul Pandya 2012-09-26 356) t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
5afc8b84 (Vipul Pandya 2012-09-26 357)
5afc8b84 (Vipul Pandya 2012-09-26 358) /* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
5afc8b84 (Vipul Pandya 2012-09-26 359) for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) {
5afc8b84 (Vipul Pandya 2012-09-26 360) if (dir)
5afc8b84 (Vipul Pandya 2012-09-26 361) *data++ = t4_read_reg(adap, (MEMWIN0_BASE + i));
5afc8b84 (Vipul Pandya 2012-09-26 362) else
5afc8b84 (Vipul Pandya 2012-09-26 @363) t4_write_reg(adap, (MEMWIN0_BASE + i), *data++);
5afc8b84 (Vipul Pandya 2012-09-26 364) }
5afc8b84 (Vipul Pandya 2012-09-26 365)
5afc8b84 (Vipul Pandya 2012-09-26 366) return 0;
5afc8b84 (Vipul Pandya 2012-09-26 367) }
5afc8b84 (Vipul Pandya 2012-09-26 368)
5afc8b84 (Vipul Pandya 2012-09-26 369) /**
5afc8b84 (Vipul Pandya 2012-09-26 370) * t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
5afc8b84 (Vipul Pandya 2012-09-26 371) * @adap: the adapter
---
0-DAY kernel build testing backend Open Source Technology Centre
Fengguang Wu, Yuanhan Liu Intel Corporation
[-- Attachment #2: t4_hw.c --]
[-- Type: text/x-csrc, Size: 94506 bytes --]
/*
* This file is part of the Chelsio T4 Ethernet driver for Linux.
*
* Copyright (c) 2003-2010 Chelsio Communications, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/init.h>
#include <linux/delay.h>
#include "cxgb4.h"
#include "t4_regs.h"
#include "t4fw_api.h"
/**
* t4_wait_op_done_val - wait until an operation is completed
* @adapter: the adapter performing the operation
* @reg: the register to check for completion
* @mask: a single-bit field within @reg that indicates completion
* @polarity: the value of the field when the operation is completed
* @attempts: number of check iterations
* @delay: delay in usecs between iterations
* @valp: where to store the value of the register at completion time
*
* Wait until an operation is completed by checking a bit in a register
* up to @attempts times. If @valp is not NULL the value of the register
* at the time it indicated completion is stored there. Returns 0 if the
* operation completes and -EAGAIN otherwise.
*/
static int t4_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
int polarity, int attempts, int delay, u32 *valp)
{
while (1) {
u32 val = t4_read_reg(adapter, reg);
if (!!(val & mask) == polarity) {
if (valp)
*valp = val;
return 0;
}
if (--attempts == 0)
return -EAGAIN;
if (delay)
udelay(delay);
}
}
static inline int t4_wait_op_done(struct adapter *adapter, int reg, u32 mask,
int polarity, int attempts, int delay)
{
return t4_wait_op_done_val(adapter, reg, mask, polarity, attempts,
delay, NULL);
}
/**
* t4_set_reg_field - set a register field to a value
* @adapter: the adapter to program
* @addr: the register address
* @mask: specifies the portion of the register to modify
* @val: the new value for the register field
*
* Sets a register field specified by the supplied mask to the
* given value.
*/
void t4_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
u32 val)
{
u32 v = t4_read_reg(adapter, addr) & ~mask;
t4_write_reg(adapter, addr, v | val);
(void) t4_read_reg(adapter, addr); /* flush */
}
/**
* t4_read_indirect - read indirectly addressed registers
* @adap: the adapter
* @addr_reg: register holding the indirect address
* @data_reg: register holding the value of the indirect register
* @vals: where the read register values are stored
* @nregs: how many indirect registers to read
* @start_idx: index of first indirect register to read
*
* Reads registers that are accessed indirectly through an address/data
* register pair.
*/
static void t4_read_indirect(struct adapter *adap, unsigned int addr_reg,
unsigned int data_reg, u32 *vals,
unsigned int nregs, unsigned int start_idx)
{
while (nregs--) {
t4_write_reg(adap, addr_reg, start_idx);
*vals++ = t4_read_reg(adap, data_reg);
start_idx++;
}
}
/*
* Get the reply to a mailbox command and store it in @rpl in big-endian order.
*/
static void get_mbox_rpl(struct adapter *adap, __be64 *rpl, int nflit,
u32 mbox_addr)
{
for ( ; nflit; nflit--, mbox_addr += 8)
*rpl++ = cpu_to_be64(t4_read_reg64(adap, mbox_addr));
}
/*
* Handle a FW assertion reported in a mailbox.
*/
static void fw_asrt(struct adapter *adap, u32 mbox_addr)
{
struct fw_debug_cmd asrt;
get_mbox_rpl(adap, (__be64 *)&asrt, sizeof(asrt) / 8, mbox_addr);
dev_alert(adap->pdev_dev,
"FW assertion at %.16s:%u, val0 %#x, val1 %#x\n",
asrt.u.assert.filename_0_7, ntohl(asrt.u.assert.line),
ntohl(asrt.u.assert.x), ntohl(asrt.u.assert.y));
}
static void dump_mbox(struct adapter *adap, int mbox, u32 data_reg)
{
dev_err(adap->pdev_dev,
"mbox %d: %llx %llx %llx %llx %llx %llx %llx %llx\n", mbox,
(unsigned long long)t4_read_reg64(adap, data_reg),
(unsigned long long)t4_read_reg64(adap, data_reg + 8),
(unsigned long long)t4_read_reg64(adap, data_reg + 16),
(unsigned long long)t4_read_reg64(adap, data_reg + 24),
(unsigned long long)t4_read_reg64(adap, data_reg + 32),
(unsigned long long)t4_read_reg64(adap, data_reg + 40),
(unsigned long long)t4_read_reg64(adap, data_reg + 48),
(unsigned long long)t4_read_reg64(adap, data_reg + 56));
}
/**
* t4_wr_mbox_meat - send a command to FW through the given mailbox
* @adap: the adapter
* @mbox: index of the mailbox to use
* @cmd: the command to write
* @size: command length in bytes
* @rpl: where to optionally store the reply
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Sends the given command to FW through the selected mailbox and waits
* for the FW to execute the command. If @rpl is not %NULL it is used to
* store the FW's reply to the command. The command and its optional
* reply are of the same length. FW can take up to %FW_CMD_MAX_TIMEOUT ms
* to respond. @sleep_ok determines whether we may sleep while awaiting
* the response. If sleeping is allowed we use progressive backoff
* otherwise we spin.
*
* The return value is 0 on success or a negative errno on failure. A
* failure can happen either because we are not able to execute the
* command or FW executes it but signals an error. In the latter case
* the return value is the error code indicated by FW (negated).
*/
int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
void *rpl, bool sleep_ok)
{
static const int delay[] = {
1, 1, 3, 5, 10, 10, 20, 50, 100, 200
};
u32 v;
u64 res;
int i, ms, delay_idx;
const __be64 *p = cmd;
u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA);
u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL);
if ((size & 15) || size > MBOX_LEN)
return -EINVAL;
/*
* If the device is off-line, as in EEH, commands will time out.
* Fail them early so we don't waste time waiting.
*/
if (adap->pdev->error_state != pci_channel_io_normal)
return -EIO;
v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
if (v != MBOX_OWNER_DRV)
return v ? -EBUSY : -ETIMEDOUT;
for (i = 0; i < size; i += 8)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++));
t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
t4_read_reg(adap, ctl_reg); /* flush write */
delay_idx = 0;
ms = delay[0];
for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) {
if (sleep_ok) {
ms = delay[delay_idx]; /* last element may repeat */
if (delay_idx < ARRAY_SIZE(delay) - 1)
delay_idx++;
msleep(ms);
} else
mdelay(ms);
v = t4_read_reg(adap, ctl_reg);
if (MBOWNER_GET(v) == MBOX_OWNER_DRV) {
if (!(v & MBMSGVALID)) {
t4_write_reg(adap, ctl_reg, 0);
continue;
}
res = t4_read_reg64(adap, data_reg);
if (FW_CMD_OP_GET(res >> 32) == FW_DEBUG_CMD) {
fw_asrt(adap, data_reg);
res = FW_CMD_RETVAL(EIO);
} else if (rpl)
get_mbox_rpl(adap, rpl, size / 8, data_reg);
if (FW_CMD_RETVAL_GET((int)res))
dump_mbox(adap, mbox, data_reg);
t4_write_reg(adap, ctl_reg, 0);
return -FW_CMD_RETVAL_GET((int)res);
}
}
dump_mbox(adap, mbox, data_reg);
dev_err(adap->pdev_dev, "command %#x in mailbox %d timed out\n",
*(const u8 *)cmd, mbox);
return -ETIMEDOUT;
}
/**
* t4_mc_read - read from MC through backdoor accesses
* @adap: the adapter
* @addr: address of first byte requested
* @data: 64 bytes of data containing the requested address
* @ecc: where to store the corresponding 64-bit ECC word
*
* Read 64 bytes of data from MC starting at a 64-byte-aligned address
* that covers the requested address @addr. If @parity is not %NULL it
* is assigned the 64-bit ECC word for the read data.
*/
int t4_mc_read(struct adapter *adap, u32 addr, __be32 *data, u64 *ecc)
{
int i;
if (t4_read_reg(adap, MC_BIST_CMD) & START_BIST)
return -EBUSY;
t4_write_reg(adap, MC_BIST_CMD_ADDR, addr & ~0x3fU);
t4_write_reg(adap, MC_BIST_CMD_LEN, 64);
t4_write_reg(adap, MC_BIST_DATA_PATTERN, 0xc);
t4_write_reg(adap, MC_BIST_CMD, BIST_OPCODE(1) | START_BIST |
BIST_CMD_GAP(1));
i = t4_wait_op_done(adap, MC_BIST_CMD, START_BIST, 0, 10, 1);
if (i)
return i;
#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
for (i = 15; i >= 0; i--)
*data++ = htonl(t4_read_reg(adap, MC_DATA(i)));
if (ecc)
*ecc = t4_read_reg64(adap, MC_DATA(16));
#undef MC_DATA
return 0;
}
/**
* t4_edc_read - read from EDC through backdoor accesses
* @adap: the adapter
* @idx: which EDC to access
* @addr: address of first byte requested
* @data: 64 bytes of data containing the requested address
* @ecc: where to store the corresponding 64-bit ECC word
*
* Read 64 bytes of data from EDC starting at a 64-byte-aligned address
* that covers the requested address @addr. If @parity is not %NULL it
* is assigned the 64-bit ECC word for the read data.
*/
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
{
int i;
idx *= EDC_STRIDE;
if (t4_read_reg(adap, EDC_BIST_CMD + idx) & START_BIST)
return -EBUSY;
t4_write_reg(adap, EDC_BIST_CMD_ADDR + idx, addr & ~0x3fU);
t4_write_reg(adap, EDC_BIST_CMD_LEN + idx, 64);
t4_write_reg(adap, EDC_BIST_DATA_PATTERN + idx, 0xc);
t4_write_reg(adap, EDC_BIST_CMD + idx,
BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST);
i = t4_wait_op_done(adap, EDC_BIST_CMD + idx, START_BIST, 0, 10, 1);
if (i)
return i;
#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
for (i = 15; i >= 0; i--)
*data++ = htonl(t4_read_reg(adap, EDC_DATA(i)));
if (ecc)
*ecc = t4_read_reg64(adap, EDC_DATA(16));
#undef EDC_DATA
return 0;
}
/*
* t4_mem_win_rw - read/write memory through PCIE memory window
* @adap: the adapter
* @addr: address of first byte requested
* @data: MEMWIN0_APERTURE bytes of data containing the requested address
* @dir: direction of transfer 1 => read, 0 => write
*
* Read/write MEMWIN0_APERTURE bytes of data from MC starting at a
* MEMWIN0_APERTURE-byte-aligned address that covers the requested
* address @addr.
*/
static int t4_mem_win_rw(struct adapter *adap, u32 addr, __be32 *data, int dir)
{
int i;
/*
* Setup offset into PCIE memory window. Address must be a
* MEMWIN0_APERTURE-byte-aligned address. (Read back MA register to
* ensure that changes propagate before we attempt to use the new
* values.)
*/
t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET,
addr & ~(MEMWIN0_APERTURE - 1));
t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
/* Collecting data 4 bytes at a time upto MEMWIN0_APERTURE */
for (i = 0; i < MEMWIN0_APERTURE; i = i+0x4) {
if (dir)
*data++ = t4_read_reg(adap, (MEMWIN0_BASE + i));
else
t4_write_reg(adap, (MEMWIN0_BASE + i), *data++);
}
return 0;
}
/**
* t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
* @adap: the adapter
* @mtype: memory type: MEM_EDC0, MEM_EDC1 or MEM_MC
* @addr: address within indicated memory type
* @len: amount of memory to transfer
* @buf: host memory buffer
* @dir: direction of transfer 1 => read, 0 => write
*
* Reads/writes an [almost] arbitrary memory region in the firmware: the
* firmware memory address, length and host buffer must be aligned on
* 32-bit boudaries. The memory is transferred as a raw byte sequence
* from/to the firmware's memory. If this memory contains data
* structures which contain multi-byte integers, it's the callers
* responsibility to perform appropriate byte order conversions.
*/
static int t4_memory_rw(struct adapter *adap, int mtype, u32 addr, u32 len,
__be32 *buf, int dir)
{
u32 pos, start, end, offset, memoffset;
int ret;
/*
* Argument sanity checks ...
*/
if ((addr & 0x3) || (len & 0x3))
return -EINVAL;
/*
* Offset into the region of memory which is being accessed
* MEM_EDC0 = 0
* MEM_EDC1 = 1
* MEM_MC = 2
*/
memoffset = (mtype * (5 * 1024 * 1024));
/* Determine the PCIE_MEM_ACCESS_OFFSET */
addr = addr + memoffset;
/*
* The underlaying EDC/MC read routines read MEMWIN0_APERTURE bytes
* at a time so we need to round down the start and round up the end.
* We'll start copying out of the first line at (addr - start) a word
* at a time.
*/
start = addr & ~(MEMWIN0_APERTURE-1);
end = (addr + len + MEMWIN0_APERTURE-1) & ~(MEMWIN0_APERTURE-1);
offset = (addr - start)/sizeof(__be32);
for (pos = start; pos < end; pos += MEMWIN0_APERTURE, offset = 0) {
__be32 data[MEMWIN0_APERTURE/sizeof(__be32)];
/*
* If we're writing, copy the data from the caller's memory
* buffer
*/
if (!dir) {
/*
* If we're doing a partial write, then we need to do
* a read-modify-write ...
*/
if (offset || len < MEMWIN0_APERTURE) {
ret = t4_mem_win_rw(adap, pos, data, 1);
if (ret)
return ret;
}
while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
len > 0) {
data[offset++] = *buf++;
len -= sizeof(__be32);
}
}
/*
* Transfer a block of memory and bail if there's an error.
*/
ret = t4_mem_win_rw(adap, pos, data, dir);
if (ret)
return ret;
/*
* If we're reading, copy the data into the caller's memory
* buffer.
*/
if (dir)
while (offset < (MEMWIN0_APERTURE/sizeof(__be32)) &&
len > 0) {
*buf++ = data[offset++];
len -= sizeof(__be32);
}
}
return 0;
}
int t4_memory_write(struct adapter *adap, int mtype, u32 addr, u32 len,
__be32 *buf)
{
return t4_memory_rw(adap, mtype, addr, len, buf, 0);
}
#define EEPROM_STAT_ADDR 0x7bfc
#define VPD_BASE 0
#define VPD_LEN 512
/**
* t4_seeprom_wp - enable/disable EEPROM write protection
* @adapter: the adapter
* @enable: whether to enable or disable write protection
*
* Enables or disables write protection on the serial EEPROM.
*/
int t4_seeprom_wp(struct adapter *adapter, bool enable)
{
unsigned int v = enable ? 0xc : 0;
int ret = pci_write_vpd(adapter->pdev, EEPROM_STAT_ADDR, 4, &v);
return ret < 0 ? ret : 0;
}
/**
* get_vpd_params - read VPD parameters from VPD EEPROM
* @adapter: adapter to read
* @p: where to store the parameters
*
* Reads card parameters stored in VPD EEPROM.
*/
static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
{
int i, ret;
int ec, sn;
u8 vpd[VPD_LEN], csum;
unsigned int vpdr_len, kw_offset, id_len;
ret = pci_read_vpd(adapter->pdev, VPD_BASE, sizeof(vpd), vpd);
if (ret < 0)
return ret;
if (vpd[0] != PCI_VPD_LRDT_ID_STRING) {
dev_err(adapter->pdev_dev, "missing VPD ID string\n");
return -EINVAL;
}
id_len = pci_vpd_lrdt_size(vpd);
if (id_len > ID_LEN)
id_len = ID_LEN;
i = pci_vpd_find_tag(vpd, 0, VPD_LEN, PCI_VPD_LRDT_RO_DATA);
if (i < 0) {
dev_err(adapter->pdev_dev, "missing VPD-R section\n");
return -EINVAL;
}
vpdr_len = pci_vpd_lrdt_size(&vpd[i]);
kw_offset = i + PCI_VPD_LRDT_TAG_SIZE;
if (vpdr_len + kw_offset > VPD_LEN) {
dev_err(adapter->pdev_dev, "bad VPD-R length %u\n", vpdr_len);
return -EINVAL;
}
#define FIND_VPD_KW(var, name) do { \
var = pci_vpd_find_info_keyword(vpd, kw_offset, vpdr_len, name); \
if (var < 0) { \
dev_err(adapter->pdev_dev, "missing VPD keyword " name "\n"); \
return -EINVAL; \
} \
var += PCI_VPD_INFO_FLD_HDR_SIZE; \
} while (0)
FIND_VPD_KW(i, "RV");
for (csum = 0; i >= 0; i--)
csum += vpd[i];
if (csum) {
dev_err(adapter->pdev_dev,
"corrupted VPD EEPROM, actual csum %u\n", csum);
return -EINVAL;
}
FIND_VPD_KW(ec, "EC");
FIND_VPD_KW(sn, "SN");
#undef FIND_VPD_KW
memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
strim(p->id);
memcpy(p->ec, vpd + ec, EC_LEN);
strim(p->ec);
i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
strim(p->sn);
return 0;
}
/* serial flash and firmware constants */
enum {
SF_ATTEMPTS = 10, /* max retries for SF operations */
/* flash command opcodes */
SF_PROG_PAGE = 2, /* program page */
SF_WR_DISABLE = 4, /* disable writes */
SF_RD_STATUS = 5, /* read status register */
SF_WR_ENABLE = 6, /* enable writes */
SF_RD_DATA_FAST = 0xb, /* read flash */
SF_RD_ID = 0x9f, /* read ID */
SF_ERASE_SECTOR = 0xd8, /* erase sector */
FW_MAX_SIZE = 512 * 1024,
};
/**
* sf1_read - read data from the serial flash
* @adapter: the adapter
* @byte_cnt: number of bytes to read
* @cont: whether another operation will be chained
* @lock: whether to lock SF for PL access only
* @valp: where to store the read data
*
* Reads up to 4 bytes of data from the serial flash. The location of
* the read needs to be specified prior to calling this by issuing the
* appropriate commands to the serial flash.
*/
static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
int lock, u32 *valp)
{
int ret;
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
if (t4_read_reg(adapter, SF_OP) & BUSY)
return -EBUSY;
cont = cont ? SF_CONT : 0;
lock = lock ? SF_LOCK : 0;
t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1));
ret = t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
if (!ret)
*valp = t4_read_reg(adapter, SF_DATA);
return ret;
}
/**
* sf1_write - write data to the serial flash
* @adapter: the adapter
* @byte_cnt: number of bytes to write
* @cont: whether another operation will be chained
* @lock: whether to lock SF for PL access only
* @val: value to write
*
* Writes up to 4 bytes of data to the serial flash. The location of
* the write needs to be specified prior to calling this by issuing the
* appropriate commands to the serial flash.
*/
static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
int lock, u32 val)
{
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
if (t4_read_reg(adapter, SF_OP) & BUSY)
return -EBUSY;
cont = cont ? SF_CONT : 0;
lock = lock ? SF_LOCK : 0;
t4_write_reg(adapter, SF_DATA, val);
t4_write_reg(adapter, SF_OP, lock |
cont | BYTECNT(byte_cnt - 1) | OP_WR);
return t4_wait_op_done(adapter, SF_OP, BUSY, 0, SF_ATTEMPTS, 5);
}
/**
* flash_wait_op - wait for a flash operation to complete
* @adapter: the adapter
* @attempts: max number of polls of the status register
* @delay: delay between polls in ms
*
* Wait for a flash operation to complete by polling the status register.
*/
static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
{
int ret;
u32 status;
while (1) {
if ((ret = sf1_write(adapter, 1, 1, 1, SF_RD_STATUS)) != 0 ||
(ret = sf1_read(adapter, 1, 0, 1, &status)) != 0)
return ret;
if (!(status & 1))
return 0;
if (--attempts == 0)
return -EAGAIN;
if (delay)
msleep(delay);
}
}
/**
* t4_read_flash - read words from serial flash
* @adapter: the adapter
* @addr: the start address for the read
* @nwords: how many 32-bit words to read
* @data: where to store the read data
* @byte_oriented: whether to store data as bytes or as words
*
* Read the specified number of 32-bit words from the serial flash.
* If @byte_oriented is set the read data is stored as a byte array
* (i.e., big-endian), otherwise as 32-bit words in the platform's
* natural endianess.
*/
static int t4_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented)
{
int ret;
if (addr + nwords * sizeof(u32) > adapter->params.sf_size || (addr & 3))
return -EINVAL;
addr = swab32(addr) | SF_RD_DATA_FAST;
if ((ret = sf1_write(adapter, 4, 1, 0, addr)) != 0 ||
(ret = sf1_read(adapter, 1, 1, 0, data)) != 0)
return ret;
for ( ; nwords; nwords--, data++) {
ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data);
if (nwords == 1)
t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
if (ret)
return ret;
if (byte_oriented)
*data = htonl(*data);
}
return 0;
}
/**
* t4_write_flash - write up to a page of data to the serial flash
* @adapter: the adapter
* @addr: the start address to write
* @n: length of data to write in bytes
* @data: the data to write
*
* Writes up to a page of data (256 bytes) to the serial flash starting
* at the given address. All the data must be written to the same page.
*/
static int t4_write_flash(struct adapter *adapter, unsigned int addr,
unsigned int n, const u8 *data)
{
int ret;
u32 buf[64];
unsigned int i, c, left, val, offset = addr & 0xff;
if (addr >= adapter->params.sf_size || offset + n > SF_PAGE_SIZE)
return -EINVAL;
val = swab32(addr) | SF_PROG_PAGE;
if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
(ret = sf1_write(adapter, 4, 1, 1, val)) != 0)
goto unlock;
for (left = n; left; left -= c) {
c = min(left, 4U);
for (val = 0, i = 0; i < c; ++i)
val = (val << 8) + *data++;
ret = sf1_write(adapter, c, c != left, 1, val);
if (ret)
goto unlock;
}
ret = flash_wait_op(adapter, 8, 1);
if (ret)
goto unlock;
t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
/* Read the page to verify the write succeeded */
ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
if (ret)
return ret;
if (memcmp(data - n, (u8 *)buf + offset, n)) {
dev_err(adapter->pdev_dev,
"failed to correctly write the flash page at %#x\n",
addr);
return -EIO;
}
return 0;
unlock:
t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
return ret;
}
/**
* get_fw_version - read the firmware version
* @adapter: the adapter
* @vers: where to place the version
*
* Reads the FW version from flash.
*/
static int get_fw_version(struct adapter *adapter, u32 *vers)
{
return t4_read_flash(adapter, adapter->params.sf_fw_start +
offsetof(struct fw_hdr, fw_ver), 1, vers, 0);
}
/**
* get_tp_version - read the TP microcode version
* @adapter: the adapter
* @vers: where to place the version
*
* Reads the TP microcode version from flash.
*/
static int get_tp_version(struct adapter *adapter, u32 *vers)
{
return t4_read_flash(adapter, adapter->params.sf_fw_start +
offsetof(struct fw_hdr, tp_microcode_ver),
1, vers, 0);
}
/**
* t4_check_fw_version - check if the FW is compatible with this driver
* @adapter: the adapter
*
* Checks if an adapter's FW is compatible with the driver. Returns 0
* if there's exact match, a negative error if the version could not be
* read or there's a major version mismatch, and a positive value if the
* expected major version is found but there's a minor version mismatch.
*/
int t4_check_fw_version(struct adapter *adapter)
{
u32 api_vers[2];
int ret, major, minor, micro;
ret = get_fw_version(adapter, &adapter->params.fw_vers);
if (!ret)
ret = get_tp_version(adapter, &adapter->params.tp_vers);
if (!ret)
ret = t4_read_flash(adapter, adapter->params.sf_fw_start +
offsetof(struct fw_hdr, intfver_nic),
2, api_vers, 1);
if (ret)
return ret;
major = FW_HDR_FW_VER_MAJOR_GET(adapter->params.fw_vers);
minor = FW_HDR_FW_VER_MINOR_GET(adapter->params.fw_vers);
micro = FW_HDR_FW_VER_MICRO_GET(adapter->params.fw_vers);
memcpy(adapter->params.api_vers, api_vers,
sizeof(adapter->params.api_vers));
if (major != FW_VERSION_MAJOR) { /* major mismatch - fail */
dev_err(adapter->pdev_dev,
"card FW has major version %u, driver wants %u\n",
major, FW_VERSION_MAJOR);
return -EINVAL;
}
if (minor == FW_VERSION_MINOR && micro == FW_VERSION_MICRO)
return 0; /* perfect match */
/* Minor/micro version mismatch. Report it but often it's OK. */
return 1;
}
/**
* t4_flash_erase_sectors - erase a range of flash sectors
* @adapter: the adapter
* @start: the first sector to erase
* @end: the last sector to erase
*
* Erases the sectors in the given inclusive range.
*/
static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
{
int ret = 0;
while (start <= end) {
if ((ret = sf1_write(adapter, 1, 0, 1, SF_WR_ENABLE)) != 0 ||
(ret = sf1_write(adapter, 4, 0, 1,
SF_ERASE_SECTOR | (start << 8))) != 0 ||
(ret = flash_wait_op(adapter, 14, 500)) != 0) {
dev_err(adapter->pdev_dev,
"erase of flash sector %d failed, error %d\n",
start, ret);
break;
}
start++;
}
t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
return ret;
}
/**
* t4_load_fw - download firmware
* @adap: the adapter
* @fw_data: the firmware image to write
* @size: image size
*
* Write the supplied firmware image to the card's serial flash.
*/
int t4_load_fw(struct adapter *adap, const u8 *fw_data, unsigned int size)
{
u32 csum;
int ret, addr;
unsigned int i;
u8 first_page[SF_PAGE_SIZE];
const u32 *p = (const u32 *)fw_data;
const struct fw_hdr *hdr = (const struct fw_hdr *)fw_data;
unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
unsigned int fw_img_start = adap->params.sf_fw_start;
unsigned int fw_start_sec = fw_img_start / sf_sec_size;
if (!size) {
dev_err(adap->pdev_dev, "FW image has no data\n");
return -EINVAL;
}
if (size & 511) {
dev_err(adap->pdev_dev,
"FW image size not multiple of 512 bytes\n");
return -EINVAL;
}
if (ntohs(hdr->len512) * 512 != size) {
dev_err(adap->pdev_dev,
"FW image size differs from size in FW header\n");
return -EINVAL;
}
if (size > FW_MAX_SIZE) {
dev_err(adap->pdev_dev, "FW image too large, max is %u bytes\n",
FW_MAX_SIZE);
return -EFBIG;
}
for (csum = 0, i = 0; i < size / sizeof(csum); i++)
csum += ntohl(p[i]);
if (csum != 0xffffffff) {
dev_err(adap->pdev_dev,
"corrupted firmware image, checksum %#x\n", csum);
return -EINVAL;
}
i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */
ret = t4_flash_erase_sectors(adap, fw_start_sec, fw_start_sec + i - 1);
if (ret)
goto out;
/*
* We write the correct version at the end so the driver can see a bad
* version if the FW write fails. Start by writing a copy of the
* first page with a bad version.
*/
memcpy(first_page, fw_data, SF_PAGE_SIZE);
((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
ret = t4_write_flash(adap, fw_img_start, SF_PAGE_SIZE, first_page);
if (ret)
goto out;
addr = fw_img_start;
for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
fw_data += SF_PAGE_SIZE;
ret = t4_write_flash(adap, addr, SF_PAGE_SIZE, fw_data);
if (ret)
goto out;
}
ret = t4_write_flash(adap,
fw_img_start + offsetof(struct fw_hdr, fw_ver),
sizeof(hdr->fw_ver), (const u8 *)&hdr->fw_ver);
out:
if (ret)
dev_err(adap->pdev_dev, "firmware download failed, error %d\n",
ret);
return ret;
}
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG)
/**
* t4_link_start - apply link configuration to MAC/PHY
* @phy: the PHY to setup
* @mac: the MAC to setup
* @lc: the requested link configuration
*
* Set up a port's MAC and PHY according to a desired link configuration.
* - If the PHY can auto-negotiate first decide what to advertise, then
* enable/disable auto-negotiation as desired, and reset.
* - If the PHY does not auto-negotiate just reset it.
* - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
* otherwise do it later based on the outcome of auto-negotiation.
*/
int t4_link_start(struct adapter *adap, unsigned int mbox, unsigned int port,
struct link_config *lc)
{
struct fw_port_cmd c;
unsigned int fc = 0, mdi = FW_PORT_MDI(FW_PORT_MDI_AUTO);
lc->link_ok = 0;
if (lc->requested_fc & PAUSE_RX)
fc |= FW_PORT_CAP_FC_RX;
if (lc->requested_fc & PAUSE_TX)
fc |= FW_PORT_CAP_FC_TX;
memset(&c, 0, sizeof(c));
c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
FW_LEN16(c));
if (!(lc->supported & FW_PORT_CAP_ANEG)) {
c.u.l1cfg.rcap = htonl((lc->supported & ADVERT_MASK) | fc);
lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
} else if (lc->autoneg == AUTONEG_DISABLE) {
c.u.l1cfg.rcap = htonl(lc->requested_speed | fc | mdi);
lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
} else
c.u.l1cfg.rcap = htonl(lc->advertising | fc | mdi);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_restart_aneg - restart autonegotiation
* @adap: the adapter
* @mbox: mbox to use for the FW command
* @port: the port id
*
* Restarts autonegotiation for the selected port.
*/
int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
{
struct fw_port_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_PORT_CMD_PORTID(port));
c.action_to_len16 = htonl(FW_PORT_CMD_ACTION(FW_PORT_ACTION_L1_CFG) |
FW_LEN16(c));
c.u.l1cfg.rcap = htonl(FW_PORT_CAP_ANEG);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
typedef void (*int_handler_t)(struct adapter *adap);
struct intr_info {
unsigned int mask; /* bits to check in interrupt status */
const char *msg; /* message to print or NULL */
short stat_idx; /* stat counter to increment or -1 */
unsigned short fatal; /* whether the condition reported is fatal */
int_handler_t int_handler; /* platform-specific int handler */
};
/**
* t4_handle_intr_status - table driven interrupt handler
* @adapter: the adapter that generated the interrupt
* @reg: the interrupt status register to process
* @acts: table of interrupt actions
*
* A table driven interrupt handler that applies a set of masks to an
* interrupt status word and performs the corresponding actions if the
* interrupts described by the mask have occurred. The actions include
* optionally emitting a warning or alert message. The table is terminated
* by an entry specifying mask 0. Returns the number of fatal interrupt
* conditions.
*/
static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
const struct intr_info *acts)
{
int fatal = 0;
unsigned int mask = 0;
unsigned int status = t4_read_reg(adapter, reg);
for ( ; acts->mask; ++acts) {
if (!(status & acts->mask))
continue;
if (acts->fatal) {
fatal++;
dev_alert(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask);
} else if (acts->msg && printk_ratelimit())
dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask);
if (acts->int_handler)
acts->int_handler(adapter);
mask |= acts->mask;
}
status &= mask;
if (status) /* clear processed interrupts */
t4_write_reg(adapter, reg, status);
return fatal;
}
/*
* Interrupt handler for the PCIE module.
*/
static void pcie_intr_handler(struct adapter *adapter)
{
static const struct intr_info sysbus_intr_info[] = {
{ RNPP, "RXNP array parity error", -1, 1 },
{ RPCP, "RXPC array parity error", -1, 1 },
{ RCIP, "RXCIF array parity error", -1, 1 },
{ RCCP, "Rx completions control array parity error", -1, 1 },
{ RFTP, "RXFT array parity error", -1, 1 },
{ 0 }
};
static const struct intr_info pcie_port_intr_info[] = {
{ TPCP, "TXPC array parity error", -1, 1 },
{ TNPP, "TXNP array parity error", -1, 1 },
{ TFTP, "TXFT array parity error", -1, 1 },
{ TCAP, "TXCA array parity error", -1, 1 },
{ TCIP, "TXCIF array parity error", -1, 1 },
{ RCAP, "RXCA array parity error", -1, 1 },
{ OTDD, "outbound request TLP discarded", -1, 1 },
{ RDPE, "Rx data parity error", -1, 1 },
{ TDUE, "Tx uncorrectable data error", -1, 1 },
{ 0 }
};
static const struct intr_info pcie_intr_info[] = {
{ MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
{ MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
{ MSIDATAPERR, "MSI data parity error", -1, 1 },
{ MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
{ MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
{ MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
{ MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
{ PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
{ PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
{ TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
{ CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
{ CREQPERR, "PCI CMD channel request parity error", -1, 1 },
{ CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
{ DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
{ DREQPERR, "PCI DMA channel request parity error", -1, 1 },
{ DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
{ HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
{ HREQPERR, "PCI HMA channel request parity error", -1, 1 },
{ HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
{ CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
{ FIDPERR, "PCI FID parity error", -1, 1 },
{ INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
{ MATAGPERR, "PCI MA tag parity error", -1, 1 },
{ PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
{ RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
{ RXWRPERR, "PCI Rx write parity error", -1, 1 },
{ RPLPERR, "PCI replay buffer parity error", -1, 1 },
{ PCIESINT, "PCI core secondary fault", -1, 1 },
{ PCIEPINT, "PCI core primary fault", -1, 1 },
{ UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 },
{ 0 }
};
int fat;
fat = t4_handle_intr_status(adapter,
PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
sysbus_intr_info) +
t4_handle_intr_status(adapter,
PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
pcie_port_intr_info) +
t4_handle_intr_status(adapter, PCIE_INT_CAUSE, pcie_intr_info);
if (fat)
t4_fatal_err(adapter);
}
/*
* TP interrupt handler.
*/
static void tp_intr_handler(struct adapter *adapter)
{
static const struct intr_info tp_intr_info[] = {
{ 0x3fffffff, "TP parity error", -1, 1 },
{ FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info))
t4_fatal_err(adapter);
}
/*
* SGE interrupt handler.
*/
static void sge_intr_handler(struct adapter *adapter)
{
u64 v;
static const struct intr_info sge_intr_info[] = {
{ ERR_CPL_EXCEED_IQE_SIZE,
"SGE received CPL exceeding IQE size", -1, 1 },
{ ERR_INVALID_CIDX_INC,
"SGE GTS CIDX increment too large", -1, 0 },
{ ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
{ DBFIFO_LP_INT, NULL, -1, 0, t4_db_full },
{ DBFIFO_HP_INT, NULL, -1, 0, t4_db_full },
{ ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped },
{ ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
{ ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
0 },
{ ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
0 },
{ ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
0 },
{ ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
0 },
{ ERR_ING_CTXT_PRIO,
"SGE too many priority ingress contexts", -1, 0 },
{ ERR_EGR_CTXT_PRIO,
"SGE too many priority egress contexts", -1, 0 },
{ INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
{ EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
{ 0 }
};
v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) |
((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
if (v) {
dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n",
(unsigned long long)v);
t4_write_reg(adapter, SGE_INT_CAUSE1, v);
t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32);
}
if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) ||
v != 0)
t4_fatal_err(adapter);
}
/*
* CIM interrupt handler.
*/
static void cim_intr_handler(struct adapter *adapter)
{
static const struct intr_info cim_intr_info[] = {
{ PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
{ OBQPARERR, "CIM OBQ parity error", -1, 1 },
{ IBQPARERR, "CIM IBQ parity error", -1, 1 },
{ MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
{ MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
{ TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
{ TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
{ 0 }
};
static const struct intr_info cim_upintr_info[] = {
{ RSVDSPACEINT, "CIM reserved space access", -1, 1 },
{ ILLTRANSINT, "CIM illegal transaction", -1, 1 },
{ ILLWRINT, "CIM illegal write", -1, 1 },
{ ILLRDINT, "CIM illegal read", -1, 1 },
{ ILLRDBEINT, "CIM illegal read BE", -1, 1 },
{ ILLWRBEINT, "CIM illegal write BE", -1, 1 },
{ SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
{ SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
{ BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
{ SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
{ SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
{ BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
{ SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
{ SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
{ BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
{ BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
{ SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
{ SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
{ BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
{ BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
{ SGLRDPLINT , "CIM single read from PL space", -1, 1 },
{ SGLWRPLINT , "CIM single write to PL space", -1, 1 },
{ BLKRDPLINT , "CIM block read from PL space", -1, 1 },
{ BLKWRPLINT , "CIM block write to PL space", -1, 1 },
{ REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
{ RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
{ TIMEOUTINT , "CIM PIF timeout", -1, 1 },
{ TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
{ 0 }
};
int fat;
fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE,
cim_intr_info) +
t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE,
cim_upintr_info);
if (fat)
t4_fatal_err(adapter);
}
/*
* ULP RX interrupt handler.
*/
static void ulprx_intr_handler(struct adapter *adapter)
{
static const struct intr_info ulprx_intr_info[] = {
{ 0x1800000, "ULPRX context error", -1, 1 },
{ 0x7fffff, "ULPRX parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info))
t4_fatal_err(adapter);
}
/*
* ULP TX interrupt handler.
*/
static void ulptx_intr_handler(struct adapter *adapter)
{
static const struct intr_info ulptx_intr_info[] = {
{ PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
0 },
{ PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
0 },
{ PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1,
0 },
{ PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1,
0 },
{ 0xfffffff, "ULPTX parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info))
t4_fatal_err(adapter);
}
/*
* PM TX interrupt handler.
*/
static void pmtx_intr_handler(struct adapter *adapter)
{
static const struct intr_info pmtx_intr_info[] = {
{ PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
{ PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
{ PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
{ ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
{ PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 },
{ OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 },
{ DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 },
{ ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 },
{ C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1},
{ 0 }
};
if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info))
t4_fatal_err(adapter);
}
/*
* PM RX interrupt handler.
*/
static void pmrx_intr_handler(struct adapter *adapter)
{
static const struct intr_info pmrx_intr_info[] = {
{ ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
{ PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 },
{ OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
{ DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 },
{ IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 },
{ E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1},
{ 0 }
};
if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info))
t4_fatal_err(adapter);
}
/*
* CPL switch interrupt handler.
*/
static void cplsw_intr_handler(struct adapter *adapter)
{
static const struct intr_info cplsw_intr_info[] = {
{ CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
{ CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
{ TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
{ SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 },
{ CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 },
{ ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info))
t4_fatal_err(adapter);
}
/*
* LE interrupt handler.
*/
static void le_intr_handler(struct adapter *adap)
{
static const struct intr_info le_intr_info[] = {
{ LIPMISS, "LE LIP miss", -1, 0 },
{ LIP0, "LE 0 LIP error", -1, 0 },
{ PARITYERR, "LE parity error", -1, 1 },
{ UNKNOWNCMD, "LE unknown command", -1, 1 },
{ REQQPARERR, "LE request queue parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info))
t4_fatal_err(adap);
}
/*
* MPS interrupt handler.
*/
static void mps_intr_handler(struct adapter *adapter)
{
static const struct intr_info mps_rx_intr_info[] = {
{ 0xffffff, "MPS Rx parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_tx_intr_info[] = {
{ TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 },
{ NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
{ TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 },
{ TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 },
{ BUBBLE, "MPS Tx underflow", -1, 1 },
{ SECNTERR, "MPS Tx SOP/EOP error", -1, 1 },
{ FRMERR, "MPS Tx framing error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_trc_intr_info[] = {
{ FILTMEM, "MPS TRC filter parity error", -1, 1 },
{ PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 },
{ MISCPERR, "MPS TRC misc parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_stat_sram_intr_info[] = {
{ 0x1fffff, "MPS statistics SRAM parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_stat_tx_intr_info[] = {
{ 0xfffff, "MPS statistics Tx FIFO parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_stat_rx_intr_info[] = {
{ 0xffffff, "MPS statistics Rx FIFO parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_cls_intr_info[] = {
{ MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
{ MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
{ HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
{ 0 }
};
int fat;
fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE,
mps_rx_intr_info) +
t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE,
mps_tx_intr_info) +
t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE,
mps_trc_intr_info) +
t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM,
mps_stat_sram_intr_info) +
t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO,
mps_stat_tx_intr_info) +
t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO,
mps_stat_rx_intr_info) +
t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE,
mps_cls_intr_info);
t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT |
RXINT | TXINT | STATINT);
t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */
if (fat)
t4_fatal_err(adapter);
}
#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE)
/*
* EDC/MC interrupt handler.
*/
static void mem_intr_handler(struct adapter *adapter, int idx)
{
static const char name[3][5] = { "EDC0", "EDC1", "MC" };
unsigned int addr, cnt_addr, v;
if (idx <= MEM_EDC1) {
addr = EDC_REG(EDC_INT_CAUSE, idx);
cnt_addr = EDC_REG(EDC_ECC_STATUS, idx);
} else {
addr = MC_INT_CAUSE;
cnt_addr = MC_ECC_STATUS;
}
v = t4_read_reg(adapter, addr) & MEM_INT_MASK;
if (v & PERR_INT_CAUSE)
dev_alert(adapter->pdev_dev, "%s FIFO parity error\n",
name[idx]);
if (v & ECC_CE_INT_CAUSE) {
u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr));
t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK);
if (printk_ratelimit())
dev_warn(adapter->pdev_dev,
"%u %s correctable ECC data error%s\n",
cnt, name[idx], cnt > 1 ? "s" : "");
}
if (v & ECC_UE_INT_CAUSE)
dev_alert(adapter->pdev_dev,
"%s uncorrectable ECC data error\n", name[idx]);
t4_write_reg(adapter, addr, v);
if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE))
t4_fatal_err(adapter);
}
/*
* MA interrupt handler.
*/
static void ma_intr_handler(struct adapter *adap)
{
u32 v, status = t4_read_reg(adap, MA_INT_CAUSE);
if (status & MEM_PERR_INT_CAUSE)
dev_alert(adap->pdev_dev,
"MA parity error, parity status %#x\n",
t4_read_reg(adap, MA_PARITY_ERROR_STATUS));
if (status & MEM_WRAP_INT_CAUSE) {
v = t4_read_reg(adap, MA_INT_WRAP_STATUS);
dev_alert(adap->pdev_dev, "MA address wrap-around error by "
"client %u to address %#x\n",
MEM_WRAP_CLIENT_NUM_GET(v),
MEM_WRAP_ADDRESS_GET(v) << 4);
}
t4_write_reg(adap, MA_INT_CAUSE, status);
t4_fatal_err(adap);
}
/*
* SMB interrupt handler.
*/
static void smb_intr_handler(struct adapter *adap)
{
static const struct intr_info smb_intr_info[] = {
{ MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
{ MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
{ SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info))
t4_fatal_err(adap);
}
/*
* NC-SI interrupt handler.
*/
static void ncsi_intr_handler(struct adapter *adap)
{
static const struct intr_info ncsi_intr_info[] = {
{ CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
{ MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
{ TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
{ RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info))
t4_fatal_err(adap);
}
/*
* XGMAC interrupt handler.
*/
static void xgmac_intr_handler(struct adapter *adap, int port)
{
u32 v = t4_read_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE));
v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
if (!v)
return;
if (v & TXFIFO_PRTY_ERR)
dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n",
port);
if (v & RXFIFO_PRTY_ERR)
dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n",
port);
t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v);
t4_fatal_err(adap);
}
/*
* PL interrupt handler.
*/
static void pl_intr_handler(struct adapter *adap)
{
static const struct intr_info pl_intr_info[] = {
{ FATALPERR, "T4 fatal parity error", -1, 1 },
{ PERRVFID, "PL VFID_MAP parity error", -1, 1 },
{ 0 }
};
if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info))
t4_fatal_err(adap);
}
#define PF_INTR_MASK (PFSW)
#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \
CPL_SWITCH | SGE | ULP_TX)
/**
* t4_slow_intr_handler - control path interrupt handler
* @adapter: the adapter
*
* T4 interrupt handler for non-data global interrupt events, e.g., errors.
* The designation 'slow' is because it involves register reads, while
* data interrupts typically don't involve any MMIOs.
*/
int t4_slow_intr_handler(struct adapter *adapter)
{
u32 cause = t4_read_reg(adapter, PL_INT_CAUSE);
if (!(cause & GLBL_INTR_MASK))
return 0;
if (cause & CIM)
cim_intr_handler(adapter);
if (cause & MPS)
mps_intr_handler(adapter);
if (cause & NCSI)
ncsi_intr_handler(adapter);
if (cause & PL)
pl_intr_handler(adapter);
if (cause & SMB)
smb_intr_handler(adapter);
if (cause & XGMAC0)
xgmac_intr_handler(adapter, 0);
if (cause & XGMAC1)
xgmac_intr_handler(adapter, 1);
if (cause & XGMAC_KR0)
xgmac_intr_handler(adapter, 2);
if (cause & XGMAC_KR1)
xgmac_intr_handler(adapter, 3);
if (cause & PCIE)
pcie_intr_handler(adapter);
if (cause & MC)
mem_intr_handler(adapter, MEM_MC);
if (cause & EDC0)
mem_intr_handler(adapter, MEM_EDC0);
if (cause & EDC1)
mem_intr_handler(adapter, MEM_EDC1);
if (cause & LE)
le_intr_handler(adapter);
if (cause & TP)
tp_intr_handler(adapter);
if (cause & MA)
ma_intr_handler(adapter);
if (cause & PM_TX)
pmtx_intr_handler(adapter);
if (cause & PM_RX)
pmrx_intr_handler(adapter);
if (cause & ULP_RX)
ulprx_intr_handler(adapter);
if (cause & CPL_SWITCH)
cplsw_intr_handler(adapter);
if (cause & SGE)
sge_intr_handler(adapter);
if (cause & ULP_TX)
ulptx_intr_handler(adapter);
/* Clear the interrupts just processed for which we are the master. */
t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK);
(void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */
return 1;
}
/**
* t4_intr_enable - enable interrupts
* @adapter: the adapter whose interrupts should be enabled
*
* Enable PF-specific interrupts for the calling function and the top-level
* interrupt concentrator for global interrupts. Interrupts are already
* enabled at each module, here we just enable the roots of the interrupt
* hierarchies.
*
* Note: this function should be called only when the driver manages
* non PF-specific interrupts from the various HW modules. Only one PCI
* function at a time should be doing this.
*/
void t4_intr_enable(struct adapter *adapter)
{
u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI));
t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE |
ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 |
ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 |
ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 |
ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 |
ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO |
ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR |
DBFIFO_HP_INT | DBFIFO_LP_INT |
EGRESS_SIZE_ERR);
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK);
t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf);
}
/**
* t4_intr_disable - disable interrupts
* @adapter: the adapter whose interrupts should be disabled
*
* Disable interrupts. We only disable the top-level interrupt
* concentrators. The caller must be a PCI function managing global
* interrupts.
*/
void t4_intr_disable(struct adapter *adapter)
{
u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI));
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0);
t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0);
}
/**
* hash_mac_addr - return the hash value of a MAC address
* @addr: the 48-bit Ethernet MAC address
*
* Hashes a MAC address according to the hash function used by HW inexact
* (hash) address matching.
*/
static int hash_mac_addr(const u8 *addr)
{
u32 a = ((u32)addr[0] << 16) | ((u32)addr[1] << 8) | addr[2];
u32 b = ((u32)addr[3] << 16) | ((u32)addr[4] << 8) | addr[5];
a ^= b;
a ^= (a >> 12);
a ^= (a >> 6);
return a & 0x3f;
}
/**
* t4_config_rss_range - configure a portion of the RSS mapping table
* @adapter: the adapter
* @mbox: mbox to use for the FW command
* @viid: virtual interface whose RSS subtable is to be written
* @start: start entry in the table to write
* @n: how many table entries to write
* @rspq: values for the response queue lookup table
* @nrspq: number of values in @rspq
*
* Programs the selected part of the VI's RSS mapping table with the
* provided values. If @nrspq < @n the supplied values are used repeatedly
* until the full table range is populated.
*
* The caller must ensure the values in @rspq are in the range allowed for
* @viid.
*/
int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq)
{
int ret;
const u16 *rsp = rspq;
const u16 *rsp_end = rspq + nrspq;
struct fw_rss_ind_tbl_cmd cmd;
memset(&cmd, 0, sizeof(cmd));
cmd.op_to_viid = htonl(FW_CMD_OP(FW_RSS_IND_TBL_CMD) |
FW_CMD_REQUEST | FW_CMD_WRITE |
FW_RSS_IND_TBL_CMD_VIID(viid));
cmd.retval_len16 = htonl(FW_LEN16(cmd));
/* each fw_rss_ind_tbl_cmd takes up to 32 entries */
while (n > 0) {
int nq = min(n, 32);
__be32 *qp = &cmd.iq0_to_iq2;
cmd.niqid = htons(nq);
cmd.startidx = htons(start);
start += nq;
n -= nq;
while (nq > 0) {
unsigned int v;
v = FW_RSS_IND_TBL_CMD_IQ0(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ1(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
v |= FW_RSS_IND_TBL_CMD_IQ2(*rsp);
if (++rsp >= rsp_end)
rsp = rspq;
*qp++ = htonl(v);
nq -= 3;
}
ret = t4_wr_mbox(adapter, mbox, &cmd, sizeof(cmd), NULL);
if (ret)
return ret;
}
return 0;
}
/**
* t4_config_glbl_rss - configure the global RSS mode
* @adapter: the adapter
* @mbox: mbox to use for the FW command
* @mode: global RSS mode
* @flags: mode-specific flags
*
* Sets the global RSS mode.
*/
int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags)
{
struct fw_rss_glb_config_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_write = htonl(FW_CMD_OP(FW_RSS_GLB_CONFIG_CMD) |
FW_CMD_REQUEST | FW_CMD_WRITE);
c.retval_len16 = htonl(FW_LEN16(c));
if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_MANUAL) {
c.u.manual.mode_pkd = htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
} else if (mode == FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL) {
c.u.basicvirtual.mode_pkd =
htonl(FW_RSS_GLB_CONFIG_CMD_MODE(mode));
c.u.basicvirtual.synmapen_to_hashtoeplitz = htonl(flags);
} else
return -EINVAL;
return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
}
/**
* t4_tp_get_tcp_stats - read TP's TCP MIB counters
* @adap: the adapter
* @v4: holds the TCP/IP counter values
* @v6: holds the TCP/IPv6 counter values
*
* Returns the values of TP's TCP/IP and TCP/IPv6 MIB counters.
* Either @v4 or @v6 may be %NULL to skip the corresponding stats.
*/
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6)
{
u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1];
#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST)
#define STAT(x) val[STAT_IDX(x)]
#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
if (v4) {
t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val,
ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST);
v4->tcpOutRsts = STAT(OUT_RST);
v4->tcpInSegs = STAT64(IN_SEG);
v4->tcpOutSegs = STAT64(OUT_SEG);
v4->tcpRetransSegs = STAT64(RXT_SEG);
}
if (v6) {
t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val,
ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST);
v6->tcpOutRsts = STAT(OUT_RST);
v6->tcpInSegs = STAT64(IN_SEG);
v6->tcpOutSegs = STAT64(OUT_SEG);
v6->tcpRetransSegs = STAT64(RXT_SEG);
}
#undef STAT64
#undef STAT
#undef STAT_IDX
}
/**
* t4_read_mtu_tbl - returns the values in the HW path MTU table
* @adap: the adapter
* @mtus: where to store the MTU values
* @mtu_log: where to store the MTU base-2 log (may be %NULL)
*
* Reads the HW path MTU table.
*/
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
{
u32 v;
int i;
for (i = 0; i < NMTUS; ++i) {
t4_write_reg(adap, TP_MTU_TABLE,
MTUINDEX(0xff) | MTUVALUE(i));
v = t4_read_reg(adap, TP_MTU_TABLE);
mtus[i] = MTUVALUE_GET(v);
if (mtu_log)
mtu_log[i] = MTUWIDTH_GET(v);
}
}
/**
* init_cong_ctrl - initialize congestion control parameters
* @a: the alpha values for congestion control
* @b: the beta values for congestion control
*
* Initialize the congestion control parameters.
*/
static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
{
a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
a[9] = 2;
a[10] = 3;
a[11] = 4;
a[12] = 5;
a[13] = 6;
a[14] = 7;
a[15] = 8;
a[16] = 9;
a[17] = 10;
a[18] = 14;
a[19] = 17;
a[20] = 21;
a[21] = 25;
a[22] = 30;
a[23] = 35;
a[24] = 45;
a[25] = 60;
a[26] = 80;
a[27] = 100;
a[28] = 200;
a[29] = 300;
a[30] = 400;
a[31] = 500;
b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
b[9] = b[10] = 1;
b[11] = b[12] = 2;
b[13] = b[14] = b[15] = b[16] = 3;
b[17] = b[18] = b[19] = b[20] = b[21] = 4;
b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
b[28] = b[29] = 6;
b[30] = b[31] = 7;
}
/* The minimum additive increment value for the congestion control table */
#define CC_MIN_INCR 2U
/**
* t4_load_mtus - write the MTU and congestion control HW tables
* @adap: the adapter
* @mtus: the values for the MTU table
* @alpha: the values for the congestion control alpha parameter
* @beta: the values for the congestion control beta parameter
*
* Write the HW MTU table with the supplied MTUs and the high-speed
* congestion control table with the supplied alpha, beta, and MTUs.
* We write the two tables together because the additive increments
* depend on the MTUs.
*/
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta)
{
static const unsigned int avg_pkts[NCCTRL_WIN] = {
2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
28672, 40960, 57344, 81920, 114688, 163840, 229376
};
unsigned int i, w;
for (i = 0; i < NMTUS; ++i) {
unsigned int mtu = mtus[i];
unsigned int log2 = fls(mtu);
if (!(mtu & ((1 << log2) >> 2))) /* round */
log2--;
t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) |
MTUWIDTH(log2) | MTUVALUE(mtu));
for (w = 0; w < NCCTRL_WIN; ++w) {
unsigned int inc;
inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
CC_MIN_INCR);
t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) |
(w << 16) | (beta[w] << 13) | inc);
}
}
}
/**
* get_mps_bg_map - return the buffer groups associated with a port
* @adap: the adapter
* @idx: the port index
*
* Returns a bitmap indicating which MPS buffer groups are associated
* with the given port. Bit i is set if buffer group i is used by the
* port.
*/
static unsigned int get_mps_bg_map(struct adapter *adap, int idx)
{
u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL));
if (n == 0)
return idx == 0 ? 0xf : 0;
if (n == 1)
return idx < 2 ? (3 << (2 * idx)) : 0;
return 1 << idx;
}
/**
* t4_get_port_stats - collect port statistics
* @adap: the adapter
* @idx: the port index
* @p: the stats structure to fill
*
* Collect statistics related to the given port from HW.
*/
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p)
{
u32 bgmap = get_mps_bg_map(adap, idx);
#define GET_STAT(name) \
t4_read_reg64(adap, PORT_REG(idx, MPS_PORT_STAT_##name##_L))
#define GET_STAT_COM(name) t4_read_reg64(adap, MPS_STAT_##name##_L)
p->tx_octets = GET_STAT(TX_PORT_BYTES);
p->tx_frames = GET_STAT(TX_PORT_FRAMES);
p->tx_bcast_frames = GET_STAT(TX_PORT_BCAST);
p->tx_mcast_frames = GET_STAT(TX_PORT_MCAST);
p->tx_ucast_frames = GET_STAT(TX_PORT_UCAST);
p->tx_error_frames = GET_STAT(TX_PORT_ERROR);
p->tx_frames_64 = GET_STAT(TX_PORT_64B);
p->tx_frames_65_127 = GET_STAT(TX_PORT_65B_127B);
p->tx_frames_128_255 = GET_STAT(TX_PORT_128B_255B);
p->tx_frames_256_511 = GET_STAT(TX_PORT_256B_511B);
p->tx_frames_512_1023 = GET_STAT(TX_PORT_512B_1023B);
p->tx_frames_1024_1518 = GET_STAT(TX_PORT_1024B_1518B);
p->tx_frames_1519_max = GET_STAT(TX_PORT_1519B_MAX);
p->tx_drop = GET_STAT(TX_PORT_DROP);
p->tx_pause = GET_STAT(TX_PORT_PAUSE);
p->tx_ppp0 = GET_STAT(TX_PORT_PPP0);
p->tx_ppp1 = GET_STAT(TX_PORT_PPP1);
p->tx_ppp2 = GET_STAT(TX_PORT_PPP2);
p->tx_ppp3 = GET_STAT(TX_PORT_PPP3);
p->tx_ppp4 = GET_STAT(TX_PORT_PPP4);
p->tx_ppp5 = GET_STAT(TX_PORT_PPP5);
p->tx_ppp6 = GET_STAT(TX_PORT_PPP6);
p->tx_ppp7 = GET_STAT(TX_PORT_PPP7);
p->rx_octets = GET_STAT(RX_PORT_BYTES);
p->rx_frames = GET_STAT(RX_PORT_FRAMES);
p->rx_bcast_frames = GET_STAT(RX_PORT_BCAST);
p->rx_mcast_frames = GET_STAT(RX_PORT_MCAST);
p->rx_ucast_frames = GET_STAT(RX_PORT_UCAST);
p->rx_too_long = GET_STAT(RX_PORT_MTU_ERROR);
p->rx_jabber = GET_STAT(RX_PORT_MTU_CRC_ERROR);
p->rx_fcs_err = GET_STAT(RX_PORT_CRC_ERROR);
p->rx_len_err = GET_STAT(RX_PORT_LEN_ERROR);
p->rx_symbol_err = GET_STAT(RX_PORT_SYM_ERROR);
p->rx_runt = GET_STAT(RX_PORT_LESS_64B);
p->rx_frames_64 = GET_STAT(RX_PORT_64B);
p->rx_frames_65_127 = GET_STAT(RX_PORT_65B_127B);
p->rx_frames_128_255 = GET_STAT(RX_PORT_128B_255B);
p->rx_frames_256_511 = GET_STAT(RX_PORT_256B_511B);
p->rx_frames_512_1023 = GET_STAT(RX_PORT_512B_1023B);
p->rx_frames_1024_1518 = GET_STAT(RX_PORT_1024B_1518B);
p->rx_frames_1519_max = GET_STAT(RX_PORT_1519B_MAX);
p->rx_pause = GET_STAT(RX_PORT_PAUSE);
p->rx_ppp0 = GET_STAT(RX_PORT_PPP0);
p->rx_ppp1 = GET_STAT(RX_PORT_PPP1);
p->rx_ppp2 = GET_STAT(RX_PORT_PPP2);
p->rx_ppp3 = GET_STAT(RX_PORT_PPP3);
p->rx_ppp4 = GET_STAT(RX_PORT_PPP4);
p->rx_ppp5 = GET_STAT(RX_PORT_PPP5);
p->rx_ppp6 = GET_STAT(RX_PORT_PPP6);
p->rx_ppp7 = GET_STAT(RX_PORT_PPP7);
p->rx_ovflow0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_DROP_FRAME) : 0;
p->rx_ovflow1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_DROP_FRAME) : 0;
p->rx_ovflow2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_DROP_FRAME) : 0;
p->rx_ovflow3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_DROP_FRAME) : 0;
p->rx_trunc0 = (bgmap & 1) ? GET_STAT_COM(RX_BG_0_MAC_TRUNC_FRAME) : 0;
p->rx_trunc1 = (bgmap & 2) ? GET_STAT_COM(RX_BG_1_MAC_TRUNC_FRAME) : 0;
p->rx_trunc2 = (bgmap & 4) ? GET_STAT_COM(RX_BG_2_MAC_TRUNC_FRAME) : 0;
p->rx_trunc3 = (bgmap & 8) ? GET_STAT_COM(RX_BG_3_MAC_TRUNC_FRAME) : 0;
#undef GET_STAT
#undef GET_STAT_COM
}
/**
* t4_wol_magic_enable - enable/disable magic packet WoL
* @adap: the adapter
* @port: the physical port index
* @addr: MAC address expected in magic packets, %NULL to disable
*
* Enables/disables magic packet wake-on-LAN for the selected port.
*/
void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
const u8 *addr)
{
if (addr) {
t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO),
(addr[2] << 24) | (addr[3] << 16) |
(addr[4] << 8) | addr[5]);
t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI),
(addr[0] << 8) | addr[1]);
}
t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), MAGICEN,
addr ? MAGICEN : 0);
}
/**
* t4_wol_pat_enable - enable/disable pattern-based WoL
* @adap: the adapter
* @port: the physical port index
* @map: bitmap of which HW pattern filters to set
* @mask0: byte mask for bytes 0-63 of a packet
* @mask1: byte mask for bytes 64-127 of a packet
* @crc: Ethernet CRC for selected bytes
* @enable: enable/disable switch
*
* Sets the pattern filters indicated in @map to mask out the bytes
* specified in @mask0/@mask1 in received packets and compare the CRC of
* the resulting packet against @crc. If @enable is %true pattern-based
* WoL is enabled, otherwise disabled.
*/
int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
u64 mask0, u64 mask1, unsigned int crc, bool enable)
{
int i;
if (!enable) {
t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2),
PATEN, 0);
return 0;
}
if (map > 0xff)
return -EINVAL;
#define EPIO_REG(name) PORT_REG(port, XGMAC_PORT_EPIO_##name)
t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
t4_write_reg(adap, EPIO_REG(DATA2), mask1);
t4_write_reg(adap, EPIO_REG(DATA3), mask1 >> 32);
for (i = 0; i < NWOL_PAT; i++, map >>= 1) {
if (!(map & 1))
continue;
/* write byte masks */
t4_write_reg(adap, EPIO_REG(DATA0), mask0);
t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR);
t4_read_reg(adap, EPIO_REG(OP)); /* flush */
if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
return -ETIMEDOUT;
/* write CRC */
t4_write_reg(adap, EPIO_REG(DATA0), crc);
t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR);
t4_read_reg(adap, EPIO_REG(OP)); /* flush */
if (t4_read_reg(adap, EPIO_REG(OP)) & BUSY)
return -ETIMEDOUT;
}
#undef EPIO_REG
t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN);
return 0;
}
#define INIT_CMD(var, cmd, rd_wr) do { \
(var).op_to_write = htonl(FW_CMD_OP(FW_##cmd##_CMD) | \
FW_CMD_REQUEST | FW_CMD_##rd_wr); \
(var).retval_len16 = htonl(FW_LEN16(var)); \
} while (0)
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val)
{
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
F_FW_CMD_WRITE |
V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.addrval.addr = htonl(addr);
c.u.addrval.val = htonl(val);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_mem_win_read_len - read memory through PCIE memory window
* @adap: the adapter
* @addr: address of first byte requested aligned on 32b.
* @data: len bytes to hold the data read
* @len: amount of data to read from window. Must be <=
* MEMWIN0_APERATURE after adjusting for 16B alignment
* requirements of the the memory window.
*
* Read len bytes of data from MC starting at @addr.
*/
int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len)
{
int i;
int off;
/*
* Align on a 16B boundary.
*/
off = addr & 15;
if ((addr & 3) || (len + off) > MEMWIN0_APERTURE)
return -EINVAL;
t4_write_reg(adap, PCIE_MEM_ACCESS_OFFSET, addr & ~15);
t4_read_reg(adap, PCIE_MEM_ACCESS_OFFSET);
for (i = 0; i < len; i += 4)
*data++ = t4_read_reg(adap, (MEMWIN0_BASE + off + i));
return 0;
}
/**
* t4_mdio_rd - read a PHY register through MDIO
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @phy_addr: the PHY address
* @mmd: the PHY MMD to access (0 for clause 22 PHYs)
* @reg: the register to read
* @valp: where to store the value
*
* Issues a FW command through the given mailbox to read a PHY register.
*/
int t4_mdio_rd(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 *valp)
{
int ret;
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
FW_CMD_READ | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
FW_LDST_CMD_MMD(mmd));
c.u.mdio.raddr = htons(reg);
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0)
*valp = ntohs(c.u.mdio.rval);
return ret;
}
/**
* t4_mdio_wr - write a PHY register through MDIO
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @phy_addr: the PHY address
* @mmd: the PHY MMD to access (0 for clause 22 PHYs)
* @reg: the register to write
* @valp: value to write
*
* Issues a FW command through the given mailbox to write a PHY register.
*/
int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
unsigned int mmd, unsigned int reg, u16 val)
{
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_addrspace = htonl(FW_CMD_OP(FW_LDST_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MDIO));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.mdio.paddr_mmd = htons(FW_LDST_CMD_PADDR(phy_addr) |
FW_LDST_CMD_MMD(mmd));
c.u.mdio.raddr = htons(reg);
c.u.mdio.rval = htons(val);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_fw_hello - establish communication with FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @evt_mbox: mailbox to receive async FW events
* @master: specifies the caller's willingness to be the device master
* @state: returns the current device state
*
* Issues a command to establish communication with FW.
*/
int t4_fw_hello(struct adapter *adap, unsigned int mbox, unsigned int evt_mbox,
enum dev_master master, enum dev_state *state)
{
int ret;
struct fw_hello_cmd c;
INIT_CMD(c, HELLO, WRITE);
c.err_to_mbasyncnot = htonl(
FW_HELLO_CMD_MASTERDIS(master == MASTER_CANT) |
FW_HELLO_CMD_MASTERFORCE(master == MASTER_MUST) |
FW_HELLO_CMD_MBMASTER(master == MASTER_MUST ? mbox : 0xff) |
FW_HELLO_CMD_MBASYNCNOT(evt_mbox));
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0 && state) {
u32 v = ntohl(c.err_to_mbasyncnot);
if (v & FW_HELLO_CMD_INIT)
*state = DEV_STATE_INIT;
else if (v & FW_HELLO_CMD_ERR)
*state = DEV_STATE_ERR;
else
*state = DEV_STATE_UNINIT;
}
return ret;
}
/**
* t4_fw_bye - end communication with FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
*
* Issues a command to terminate communication with FW.
*/
int t4_fw_bye(struct adapter *adap, unsigned int mbox)
{
struct fw_bye_cmd c;
INIT_CMD(c, BYE, WRITE);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_init_cmd - ask FW to initialize the device
* @adap: the adapter
* @mbox: mailbox to use for the FW command
*
* Issues a command to FW to partially initialize the device. This
* performs initialization that generally doesn't depend on user input.
*/
int t4_early_init(struct adapter *adap, unsigned int mbox)
{
struct fw_initialize_cmd c;
INIT_CMD(c, INITIALIZE, WRITE);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_fw_reset - issue a reset to FW
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @reset: specifies the type of reset to perform
*
* Issues a reset command of the specified type to FW.
*/
int t4_fw_reset(struct adapter *adap, unsigned int mbox, int reset)
{
struct fw_reset_cmd c;
INIT_CMD(c, RESET, WRITE);
c.val = htonl(reset);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_query_params - query FW or device parameters
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF
* @vf: the VF
* @nparams: the number of parameters
* @params: the parameter names
* @val: the parameter values
*
* Reads the value of FW or device parameters. Up to 7 parameters can be
* queried at once.
*/
int t4_query_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params,
u32 *val)
{
int i, ret;
struct fw_params_cmd c;
__be32 *p = &c.param[0].mnem;
if (nparams > 7)
return -EINVAL;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
FW_CMD_READ | FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
for (i = 0; i < nparams; i++, p += 2)
*p = htonl(*params++);
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0)
for (i = 0, p = &c.param[0].val; i < nparams; i++, p += 2)
*val++ = ntohl(*p);
return ret;
}
/**
* t4_set_params - sets FW or device parameters
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF
* @vf: the VF
* @nparams: the number of parameters
* @params: the parameter names
* @val: the parameter values
*
* Sets the value of FW or device parameters. Up to 7 parameters can be
* specified at once.
*/
int t4_set_params(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int nparams, const u32 *params,
const u32 *val)
{
struct fw_params_cmd c;
__be32 *p = &c.param[0].mnem;
if (nparams > 7)
return -EINVAL;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_PARAMS_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_PARAMS_CMD_PFN(pf) |
FW_PARAMS_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
while (nparams--) {
*p++ = htonl(*params++);
*p++ = htonl(*val++);
}
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_cfg_pfvf - configure PF/VF resource limits
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF being configured
* @vf: the VF being configured
* @txq: the max number of egress queues
* @txq_eth_ctrl: the max number of egress Ethernet or control queues
* @rxqi: the max number of interrupt-capable ingress queues
* @rxq: the max number of interruptless ingress queues
* @tc: the PCI traffic class
* @vi: the max number of virtual interfaces
* @cmask: the channel access rights mask for the PF/VF
* @pmask: the port access rights mask for the PF/VF
* @nexact: the maximum number of exact MPS filters
* @rcaps: read capabilities
* @wxcaps: write/execute capabilities
*
* Configures resource limits and capabilities for a physical or virtual
* function.
*/
int t4_cfg_pfvf(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int txq, unsigned int txq_eth_ctrl,
unsigned int rxqi, unsigned int rxq, unsigned int tc,
unsigned int vi, unsigned int cmask, unsigned int pmask,
unsigned int nexact, unsigned int rcaps, unsigned int wxcaps)
{
struct fw_pfvf_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_PFVF_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_PFVF_CMD_PFN(pf) |
FW_PFVF_CMD_VFN(vf));
c.retval_len16 = htonl(FW_LEN16(c));
c.niqflint_niq = htonl(FW_PFVF_CMD_NIQFLINT(rxqi) |
FW_PFVF_CMD_NIQ(rxq));
c.type_to_neq = htonl(FW_PFVF_CMD_CMASK(cmask) |
FW_PFVF_CMD_PMASK(pmask) |
FW_PFVF_CMD_NEQ(txq));
c.tc_to_nexactf = htonl(FW_PFVF_CMD_TC(tc) | FW_PFVF_CMD_NVI(vi) |
FW_PFVF_CMD_NEXACTF(nexact));
c.r_caps_to_nethctrl = htonl(FW_PFVF_CMD_R_CAPS(rcaps) |
FW_PFVF_CMD_WX_CAPS(wxcaps) |
FW_PFVF_CMD_NETHCTRL(txq_eth_ctrl));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_alloc_vi - allocate a virtual interface
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @port: physical port associated with the VI
* @pf: the PF owning the VI
* @vf: the VF owning the VI
* @nmac: number of MAC addresses needed (1 to 5)
* @mac: the MAC addresses of the VI
* @rss_size: size of RSS table slice associated with this VI
*
* Allocates a virtual interface for the given physical port. If @mac is
* not %NULL it contains the MAC addresses of the VI as assigned by FW.
* @mac should be large enough to hold @nmac Ethernet addresses, they are
* stored consecutively so the space needed is @nmac * 6 bytes.
* Returns a negative error number or the non-negative VI id.
*/
int t4_alloc_vi(struct adapter *adap, unsigned int mbox, unsigned int port,
unsigned int pf, unsigned int vf, unsigned int nmac, u8 *mac,
unsigned int *rss_size)
{
int ret;
struct fw_vi_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_VI_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_CMD_EXEC |
FW_VI_CMD_PFN(pf) | FW_VI_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_VI_CMD_ALLOC | FW_LEN16(c));
c.portid_pkd = FW_VI_CMD_PORTID(port);
c.nmac = nmac - 1;
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret)
return ret;
if (mac) {
memcpy(mac, c.mac, sizeof(c.mac));
switch (nmac) {
case 5:
memcpy(mac + 24, c.nmac3, sizeof(c.nmac3));
case 4:
memcpy(mac + 18, c.nmac2, sizeof(c.nmac2));
case 3:
memcpy(mac + 12, c.nmac1, sizeof(c.nmac1));
case 2:
memcpy(mac + 6, c.nmac0, sizeof(c.nmac0));
}
}
if (rss_size)
*rss_size = FW_VI_CMD_RSSSIZE_GET(ntohs(c.rsssize_pkd));
return FW_VI_CMD_VIID_GET(ntohs(c.type_viid));
}
/**
* t4_set_rxmode - set Rx properties of a virtual interface
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @mtu: the new MTU or -1
* @promisc: 1 to enable promiscuous mode, 0 to disable it, -1 no change
* @all_multi: 1 to enable all-multi mode, 0 to disable it, -1 no change
* @bcast: 1 to enable broadcast Rx, 0 to disable it, -1 no change
* @vlanex: 1 to enable HW VLAN extraction, 0 to disable it, -1 no change
* @sleep_ok: if true we may sleep while awaiting command completion
*
* Sets Rx properties of a virtual interface.
*/
int t4_set_rxmode(struct adapter *adap, unsigned int mbox, unsigned int viid,
int mtu, int promisc, int all_multi, int bcast, int vlanex,
bool sleep_ok)
{
struct fw_vi_rxmode_cmd c;
/* convert to FW values */
if (mtu < 0)
mtu = FW_RXMODE_MTU_NO_CHG;
if (promisc < 0)
promisc = FW_VI_RXMODE_CMD_PROMISCEN_MASK;
if (all_multi < 0)
all_multi = FW_VI_RXMODE_CMD_ALLMULTIEN_MASK;
if (bcast < 0)
bcast = FW_VI_RXMODE_CMD_BROADCASTEN_MASK;
if (vlanex < 0)
vlanex = FW_VI_RXMODE_CMD_VLANEXEN_MASK;
memset(&c, 0, sizeof(c));
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_RXMODE_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_VI_RXMODE_CMD_VIID(viid));
c.retval_len16 = htonl(FW_LEN16(c));
c.mtu_to_vlanexen = htonl(FW_VI_RXMODE_CMD_MTU(mtu) |
FW_VI_RXMODE_CMD_PROMISCEN(promisc) |
FW_VI_RXMODE_CMD_ALLMULTIEN(all_multi) |
FW_VI_RXMODE_CMD_BROADCASTEN(bcast) |
FW_VI_RXMODE_CMD_VLANEXEN(vlanex));
return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}
/**
* t4_alloc_mac_filt - allocates exact-match filters for MAC addresses
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @free: if true any existing filters for this VI id are first removed
* @naddr: the number of MAC addresses to allocate filters for (up to 7)
* @addr: the MAC address(es)
* @idx: where to store the index of each allocated filter
* @hash: pointer to hash address filter bitmap
* @sleep_ok: call is allowed to sleep
*
* Allocates an exact-match filter for each of the supplied addresses and
* sets it to the corresponding address. If @idx is not %NULL it should
* have at least @naddr entries, each of which will be set to the index of
* the filter allocated for the corresponding MAC address. If a filter
* could not be allocated for an address its index is set to 0xffff.
* If @hash is not %NULL addresses that fail to allocate an exact filter
* are hashed and update the hash filter bitmap pointed at by @hash.
*
* Returns a negative error number or the number of filters allocated.
*/
int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
unsigned int viid, bool free, unsigned int naddr,
const u8 **addr, u16 *idx, u64 *hash, bool sleep_ok)
{
int i, ret;
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p;
if (naddr > 7)
return -EINVAL;
memset(&c, 0, sizeof(c));
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | (free ? FW_CMD_EXEC : 0) |
FW_VI_MAC_CMD_VIID(viid));
c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_FREEMACS(free) |
FW_CMD_LEN16((naddr + 2) / 2));
for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
}
ret = t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), &c, sleep_ok);
if (ret)
return ret;
for (i = 0, p = c.u.exact; i < naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx));
if (idx)
idx[i] = index >= NEXACT_MAC ? 0xffff : index;
if (index < NEXACT_MAC)
ret++;
else if (hash)
*hash |= (1ULL << hash_mac_addr(addr[i]));
}
return ret;
}
/**
* t4_change_mac - modifies the exact-match filter for a MAC address
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @idx: index of existing filter for old value of MAC address, or -1
* @addr: the new MAC address value
* @persist: whether a new MAC allocation should be persistent
* @add_smt: if true also add the address to the HW SMT
*
* Modifies an exact-match filter and sets it to the new MAC address.
* Note that in general it is not possible to modify the value of a given
* filter so the generic way to modify an address filter is to free the one
* being used by the old address value and allocate a new filter for the
* new address value. @idx can be -1 if the address is a new addition.
*
* Returns a negative error number or the index of the filter with the new
* MAC value.
*/
int t4_change_mac(struct adapter *adap, unsigned int mbox, unsigned int viid,
int idx, const u8 *addr, bool persist, bool add_smt)
{
int ret, mode;
struct fw_vi_mac_cmd c;
struct fw_vi_mac_exact *p = c.u.exact;
if (idx < 0) /* new allocation */
idx = persist ? FW_VI_MAC_ADD_PERSIST_MAC : FW_VI_MAC_ADD_MAC;
mode = add_smt ? FW_VI_MAC_SMT_AND_MPSTCAM : FW_VI_MAC_MPS_TCAM_ENTRY;
memset(&c, 0, sizeof(c));
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_VI_MAC_CMD_VIID(viid));
c.freemacs_to_len16 = htonl(FW_CMD_LEN16(1));
p->valid_to_idx = htons(FW_VI_MAC_CMD_VALID |
FW_VI_MAC_CMD_SMAC_RESULT(mode) |
FW_VI_MAC_CMD_IDX(idx));
memcpy(p->macaddr, addr, sizeof(p->macaddr));
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret == 0) {
ret = FW_VI_MAC_CMD_IDX_GET(ntohs(p->valid_to_idx));
if (ret >= NEXACT_MAC)
ret = -ENOMEM;
}
return ret;
}
/**
* t4_set_addr_hash - program the MAC inexact-match hash filter
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @ucast: whether the hash filter should also match unicast addresses
* @vec: the value to be written to the hash filter
* @sleep_ok: call is allowed to sleep
*
* Sets the 64-bit inexact-match hash filter for a virtual interface.
*/
int t4_set_addr_hash(struct adapter *adap, unsigned int mbox, unsigned int viid,
bool ucast, u64 vec, bool sleep_ok)
{
struct fw_vi_mac_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_MAC_CMD) | FW_CMD_REQUEST |
FW_CMD_WRITE | FW_VI_ENABLE_CMD_VIID(viid));
c.freemacs_to_len16 = htonl(FW_VI_MAC_CMD_HASHVECEN |
FW_VI_MAC_CMD_HASHUNIEN(ucast) |
FW_CMD_LEN16(1));
c.u.hash.hashvec = cpu_to_be64(vec);
return t4_wr_mbox_meat(adap, mbox, &c, sizeof(c), NULL, sleep_ok);
}
/**
* t4_enable_vi - enable/disable a virtual interface
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @rx_en: 1=enable Rx, 0=disable Rx
* @tx_en: 1=enable Tx, 0=disable Tx
*
* Enables/disables a virtual interface.
*/
int t4_enable_vi(struct adapter *adap, unsigned int mbox, unsigned int viid,
bool rx_en, bool tx_en)
{
struct fw_vi_enable_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_IEN(rx_en) |
FW_VI_ENABLE_CMD_EEN(tx_en) | FW_LEN16(c));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_identify_port - identify a VI's port by blinking its LED
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @viid: the VI id
* @nblinks: how many times to blink LED at 2.5 Hz
*
* Identifies a VI's port by blinking its LED.
*/
int t4_identify_port(struct adapter *adap, unsigned int mbox, unsigned int viid,
unsigned int nblinks)
{
struct fw_vi_enable_cmd c;
c.op_to_viid = htonl(FW_CMD_OP(FW_VI_ENABLE_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_VI_ENABLE_CMD_VIID(viid));
c.ien_to_len16 = htonl(FW_VI_ENABLE_CMD_LED | FW_LEN16(c));
c.blinkdur = htons(nblinks);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_iq_free - free an ingress queue and its FLs
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF owning the queues
* @vf: the VF owning the queues
* @iqtype: the ingress queue type
* @iqid: ingress queue id
* @fl0id: FL0 queue id or 0xffff if no attached FL0
* @fl1id: FL1 queue id or 0xffff if no attached FL1
*
* Frees an ingress queue and its associated FLs, if any.
*/
int t4_iq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int iqtype, unsigned int iqid,
unsigned int fl0id, unsigned int fl1id)
{
struct fw_iq_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_IQ_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_IQ_CMD_PFN(pf) |
FW_IQ_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_IQ_CMD_FREE | FW_LEN16(c));
c.type_to_iqandstindex = htonl(FW_IQ_CMD_TYPE(iqtype));
c.iqid = htons(iqid);
c.fl0id = htons(fl0id);
c.fl1id = htons(fl1id);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_eth_eq_free - free an Ethernet egress queue
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF owning the queue
* @vf: the VF owning the queue
* @eqid: egress queue id
*
* Frees an Ethernet egress queue.
*/
int t4_eth_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid)
{
struct fw_eq_eth_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_ETH_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_EQ_ETH_CMD_PFN(pf) |
FW_EQ_ETH_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_ETH_CMD_FREE | FW_LEN16(c));
c.eqid_pkd = htonl(FW_EQ_ETH_CMD_EQID(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_ctrl_eq_free - free a control egress queue
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF owning the queue
* @vf: the VF owning the queue
* @eqid: egress queue id
*
* Frees a control egress queue.
*/
int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid)
{
struct fw_eq_ctrl_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_CTRL_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_EQ_CTRL_CMD_PFN(pf) |
FW_EQ_CTRL_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_CTRL_CMD_FREE | FW_LEN16(c));
c.cmpliqid_eqid = htonl(FW_EQ_CTRL_CMD_EQID(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_ofld_eq_free - free an offload egress queue
* @adap: the adapter
* @mbox: mailbox to use for the FW command
* @pf: the PF owning the queue
* @vf: the VF owning the queue
* @eqid: egress queue id
*
* Frees a control egress queue.
*/
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid)
{
struct fw_eq_ofld_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_vfn = htonl(FW_CMD_OP(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST |
FW_CMD_EXEC | FW_EQ_OFLD_CMD_PFN(pf) |
FW_EQ_OFLD_CMD_VFN(vf));
c.alloc_to_len16 = htonl(FW_EQ_OFLD_CMD_FREE | FW_LEN16(c));
c.eqid_pkd = htonl(FW_EQ_OFLD_CMD_EQID(eqid));
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/**
* t4_handle_fw_rpl - process a FW reply message
* @adap: the adapter
* @rpl: start of the FW message
*
* Processes a FW message, such as link state change messages.
*/
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
{
u8 opcode = *(const u8 *)rpl;
if (opcode == FW_PORT_CMD) { /* link/module state change message */
int speed = 0, fc = 0;
const struct fw_port_cmd *p = (void *)rpl;
int chan = FW_PORT_CMD_PORTID_GET(ntohl(p->op_to_portid));
int port = adap->chan_map[chan];
struct port_info *pi = adap2pinfo(adap, port);
struct link_config *lc = &pi->link_cfg;
u32 stat = ntohl(p->u.info.lstatus_to_modtype);
int link_ok = (stat & FW_PORT_CMD_LSTATUS) != 0;
u32 mod = FW_PORT_CMD_MODTYPE_GET(stat);
if (stat & FW_PORT_CMD_RXPAUSE)
fc |= PAUSE_RX;
if (stat & FW_PORT_CMD_TXPAUSE)
fc |= PAUSE_TX;
if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
speed = SPEED_100;
else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
speed = SPEED_1000;
else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
speed = SPEED_10000;
if (link_ok != lc->link_ok || speed != lc->speed ||
fc != lc->fc) { /* something changed */
lc->link_ok = link_ok;
lc->speed = speed;
lc->fc = fc;
t4_os_link_changed(adap, port, link_ok);
}
if (mod != pi->mod_type) {
pi->mod_type = mod;
t4_os_portmod_changed(adap, port);
}
}
return 0;
}
static void __devinit get_pci_mode(struct adapter *adapter,
struct pci_params *p)
{
u16 val;
u32 pcie_cap = pci_pcie_cap(adapter->pdev);
if (pcie_cap) {
pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
&val);
p->speed = val & PCI_EXP_LNKSTA_CLS;
p->width = (val & PCI_EXP_LNKSTA_NLW) >> 4;
}
}
/**
* init_link_config - initialize a link's SW state
* @lc: structure holding the link state
* @caps: link capabilities
*
* Initializes the SW state maintained for each link, including the link's
* capabilities and default speed/flow-control/autonegotiation settings.
*/
static void __devinit init_link_config(struct link_config *lc,
unsigned int caps)
{
lc->supported = caps;
lc->requested_speed = 0;
lc->speed = 0;
lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
if (lc->supported & FW_PORT_CAP_ANEG) {
lc->advertising = lc->supported & ADVERT_MASK;
lc->autoneg = AUTONEG_ENABLE;
lc->requested_fc |= PAUSE_AUTONEG;
} else {
lc->advertising = 0;
lc->autoneg = AUTONEG_DISABLE;
}
}
int t4_wait_dev_ready(struct adapter *adap)
{
if (t4_read_reg(adap, PL_WHOAMI) != 0xffffffff)
return 0;
msleep(500);
return t4_read_reg(adap, PL_WHOAMI) != 0xffffffff ? 0 : -EIO;
}
static int __devinit get_flash_params(struct adapter *adap)
{
int ret;
u32 info;
ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
if (!ret)
ret = sf1_read(adap, 3, 0, 1, &info);
t4_write_reg(adap, SF_OP, 0); /* unlock SF */
if (ret)
return ret;
if ((info & 0xff) != 0x20) /* not a Numonix flash */
return -EINVAL;
info >>= 16; /* log2 of size */
if (info >= 0x14 && info < 0x18)
adap->params.sf_nsec = 1 << (info - 16);
else if (info == 0x18)
adap->params.sf_nsec = 64;
else
return -EINVAL;
adap->params.sf_size = 1 << info;
adap->params.sf_fw_start =
t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK;
return 0;
}
/**
* t4_prep_adapter - prepare SW and HW for operation
* @adapter: the adapter
* @reset: if true perform a HW reset
*
* Initialize adapter SW state for the various HW modules, set initial
* values for some adapter tunables, take PHYs out of reset, and
* initialize the MDIO interface.
*/
int __devinit t4_prep_adapter(struct adapter *adapter)
{
int ret;
ret = t4_wait_dev_ready(adapter);
if (ret < 0)
return ret;
get_pci_mode(adapter, &adapter->params.pci);
adapter->params.rev = t4_read_reg(adapter, PL_REV);
ret = get_flash_params(adapter);
if (ret < 0) {
dev_err(adapter->pdev_dev, "error %d identifying flash\n", ret);
return ret;
}
ret = get_vpd_params(adapter, &adapter->params.vpd);
if (ret < 0)
return ret;
init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
/*
* Default port for debugging in case we can't reach FW.
*/
adapter->params.nports = 1;
adapter->params.portvec = 1;
return 0;
}
int __devinit t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
{
u8 addr[6];
int ret, i, j = 0;
struct fw_port_cmd c;
struct fw_rss_vi_config_cmd rvc;
memset(&c, 0, sizeof(c));
memset(&rvc, 0, sizeof(rvc));
for_each_port(adap, i) {
unsigned int rss_size;
struct port_info *p = adap2pinfo(adap, i);
while ((adap->params.portvec & (1 << j)) == 0)
j++;
c.op_to_portid = htonl(FW_CMD_OP(FW_PORT_CMD) |
FW_CMD_REQUEST | FW_CMD_READ |
FW_PORT_CMD_PORTID(j));
c.action_to_len16 = htonl(
FW_PORT_CMD_ACTION(FW_PORT_ACTION_GET_PORT_INFO) |
FW_LEN16(c));
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), &c);
if (ret)
return ret;
ret = t4_alloc_vi(adap, mbox, j, pf, vf, 1, addr, &rss_size);
if (ret < 0)
return ret;
p->viid = ret;
p->tx_chan = j;
p->lport = j;
p->rss_size = rss_size;
memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
memcpy(adap->port[i]->perm_addr, addr, ETH_ALEN);
adap->port[i]->dev_id = j;
ret = ntohl(c.u.info.lstatus_to_modtype);
p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ?
FW_PORT_CMD_MDIOADDR_GET(ret) : -1;
p->port_type = FW_PORT_CMD_PTYPE_GET(ret);
p->mod_type = FW_PORT_MOD_TYPE_NA;
rvc.op_to_viid = htonl(FW_CMD_OP(FW_RSS_VI_CONFIG_CMD) |
FW_CMD_REQUEST | FW_CMD_READ |
FW_RSS_VI_CONFIG_CMD_VIID(p->viid));
rvc.retval_len16 = htonl(FW_LEN16(rvc));
ret = t4_wr_mbox(adap, mbox, &rvc, sizeof(rvc), &rvc);
if (ret)
return ret;
p->rss_mode = ntohl(rvc.u.basicvirtual.defaultq_to_udpen);
init_link_config(&p->link_cfg, ntohs(c.u.info.pcap));
j++;
}
return 0;
}
^ permalink raw reply
* Re: [PATCH] rtlwifi: use %*ph[C] to dump small buffers
From: Larry Finger @ 2012-09-28 16:41 UTC (permalink / raw)
To: David Laight
Cc: Joe Perches, Andy Shevchenko, Chaoming Li, David S. Miller,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <AE90C24D6B3A694183C094C60CF0A2F6026B700D-CgBM+Bx2aUAnGFn1LkZF6NBPR1lH4CV8@public.gmane.org>
On 09/28/2012 04:04 AM, David Laight wrote:
>>> Index: wireless-testing-new/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
>>> ===================================================================
>>> --- wireless-testing-new.orig/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
>>> +++ wireless-testing-new/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
>>> @@ -1964,8 +1965,9 @@ static void rtl92ce_update_hal_rate_mask
>>>
>>> RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
>>> "ratr_bitmap :%x\n", ratr_bitmap);
>>> - *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
>>> - (ratr_index << 28);
>>> + for (i = 0; i < 3; i++)
>>> + rate_mask[i] = ratr_bitmap & (0xff << (i * 4));
>>
>> rate_mask is u8, doesn't this needs (calc) >> (i * 8)
>>
>>> + rate_mask[3] = (ratr_bitmap & 0x0f000000) | (ratr_index << 28);
>>
>> Perhaps you meant:
>>
>> ((ratr_bitmap & 0x0f000000) >> 24) | (ratr_index << 4)
>
> I'd just do:
> rate_mask[0] = ratr_bitmap;
> rate_mask[1] = ratr_bitmap >>= 8;
> rate_mask[2] = ratr_bitmap >>= 8;
> rate_mask[3] = (ratr_bitmap >> 8) & 0xf | ratr_index << 4;
> which is, of course, little endian.
> Which means it is different from the original code on big-endian systems.
> So changing this here ought to require a change when the data is read.
> So this either fixes, or adds, an endianness bug.
Yes, the rate_mask array is little endian after this fragment is run, but the
only use of the byte array is to write it to the device, and LE is what it needs
no matter the platform. This change fixes an endianness bug.
As I tend to get confused when doing these things, I wrote a small test program
and ran it on x86_64 and PPC-32 to confirm the result.
Thanks for teaching me about a = b >>= 8. I was not aware that C could do that.
Larry
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH RFC net-next 0/4] Convert blackfin to phc and remove timecompare
From: Richard Cochran @ 2012-09-28 17:20 UTC (permalink / raw)
To: netdev
Cc: device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
Mike Frysinger, Miroslav Lichvar, Patrick Ohly, Sonic Zhang
This patch series takes care of a legacy issue in the time keeping
core by moving blackfin over to PHC model and removing the dubious
timecompare code.
The blackfin is quite similar to the other MAC based PTP hardware
clocks, and so the implementation is straightforward. However, I don't
have a board to test this on, and I would really appreciate if someone
would test this for me. If anyone wants to lend me a board or make one
available for remote login, please let me know.
The first patch is a bug fix that should be merged in any
case. Pacthes two and three convert the bfin_mac to offer a PHC
device. The last patch removes the timecompare code.
Thanks,
Richard
Richard Cochran (4):
bfin_mac: only advertise hardware time stamped when enabled.
bfin_mac: replace sys time stamps with raw ones instead.
bfin_mac: offer a PTP Hardware Clock.
time: remove the timecompare code.
drivers/net/ethernet/adi/Kconfig | 2 +-
drivers/net/ethernet/adi/bfin_mac.c | 259 ++++++++++++++++++++++++++---------
drivers/net/ethernet/adi/bfin_mac.h | 13 +-
include/linux/timecompare.h | 125 -----------------
kernel/time/Makefile | 2 +-
kernel/time/timecompare.c | 193 --------------------------
6 files changed, 205 insertions(+), 389 deletions(-)
delete mode 100644 include/linux/timecompare.h
delete mode 100644 kernel/time/timecompare.c
--
1.7.2.5
^ permalink raw reply
* [PATCH RFC net-next 1/4] bfin_mac: only advertise hardware time stamped when enabled.
From: Richard Cochran @ 2012-09-28 17:20 UTC (permalink / raw)
To: netdev
Cc: device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
Mike Frysinger, Miroslav Lichvar, Patrick Ohly, Sonic Zhang
In-Reply-To: <cover.1348851539.git.richardcochran@gmail.com>
The hardware time stamping code is a compile time option for the blackfin.
When it is not enabled, the driver should fall back to the standard
ethtool reply to the get_ts_info query.
Compile tested only.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/net/ethernet/adi/bfin_mac.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index f816426..2349abb 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -548,6 +548,7 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
return 0;
}
+#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
@@ -566,6 +567,7 @@ static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
return 0;
}
+#endif
static const struct ethtool_ops bfin_mac_ethtool_ops = {
.get_settings = bfin_mac_ethtool_getsettings,
@@ -574,7 +576,9 @@ static const struct ethtool_ops bfin_mac_ethtool_ops = {
.get_drvinfo = bfin_mac_ethtool_getdrvinfo,
.get_wol = bfin_mac_ethtool_getwol,
.set_wol = bfin_mac_ethtool_setwol,
+#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
.get_ts_info = bfin_mac_ethtool_get_ts_info,
+#endif
};
/**************************************************************************/
--
1.7.2.5
^ permalink raw reply related
* [PATCH RFC net-next 2/4] bfin_mac: replace sys time stamps with raw ones instead.
From: Richard Cochran @ 2012-09-28 17:20 UTC (permalink / raw)
To: netdev
Cc: device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
Mike Frysinger, Miroslav Lichvar, Patrick Ohly, Sonic Zhang
In-Reply-To: <cover.1348851539.git.richardcochran@gmail.com>
This patch replaces the sys time stamps and timecompare code with simple
raw hardware time stamps in nanosecond resolution. The only tricky bit is
to find a PTP Hardware Clock period slower than the input clock period
and a power of two.
Compile tested only.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/net/ethernet/adi/bfin_mac.c | 91 ++++++++++-------------------------
drivers/net/ethernet/adi/bfin_mac.h | 7 +--
2 files changed, 28 insertions(+), 70 deletions(-)
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index 2349abb..393d1b5 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -555,7 +555,7 @@ static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
info->so_timestamping =
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
- SOF_TIMESTAMPING_SYS_HARDWARE;
+ SOF_TIMESTAMPING_RAW_HARDWARE;
info->phc_index = -1;
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
@@ -653,6 +653,20 @@ static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
#define bfin_mac_hwtstamp_is_none(cfg) ((cfg) == HWTSTAMP_FILTER_NONE)
+static u32 bfin_select_phc_clock(u32 input_clk, unsigned int *shift_result)
+{
+ u32 ipn = 1000000000UL / input_clk;
+ u32 ppn = 1;
+ unsigned int shift = 0;
+
+ while (ppn <= ipn) {
+ ppn <<= 1;
+ shift++;
+ }
+ *shift_result = shift;
+ return 1000000000UL / ppn;
+}
+
static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
struct ifreq *ifr, int cmd)
{
@@ -802,19 +816,7 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
bfin_read_EMAC_PTP_TXSNAPLO();
bfin_read_EMAC_PTP_TXSNAPHI();
- /*
- * Set registers so that rollover occurs soon to test this.
- */
- bfin_write_EMAC_PTP_TIMELO(0x00000000);
- bfin_write_EMAC_PTP_TIMEHI(0xFF800000);
-
SSYNC();
-
- lp->compare.last_update = 0;
- timecounter_init(&lp->clock,
- &lp->cycles,
- ktime_to_ns(ktime_get_real()));
- timecompare_update(&lp->compare, 0);
}
lp->stamp_cfg = config;
@@ -822,15 +824,6 @@ static int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
-EFAULT : 0;
}
-static void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompare *cmp)
-{
- ktime_t sys = ktime_get_real();
-
- pr_debug("%s %s hardware:%d,%d transform system:%d,%d system:%d,%d, cmp:%lld, %lld\n",
- __func__, s, hw->tv.sec, hw->tv.nsec, ts->tv.sec, ts->tv.nsec, sys.tv.sec,
- sys.tv.nsec, cmp->offset, cmp->skew);
-}
-
static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
@@ -861,15 +854,9 @@ static void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
regval = bfin_read_EMAC_PTP_TXSNAPLO();
regval |= (u64)bfin_read_EMAC_PTP_TXSNAPHI() << 32;
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
- ns = timecounter_cyc2time(&lp->clock,
- regval);
- timecompare_update(&lp->compare, ns);
+ ns = regval >> lp->shift;
shhwtstamps.hwtstamp = ns_to_ktime(ns);
- shhwtstamps.syststamp =
- timecompare_transform(&lp->compare, ns);
skb_tstamp_tx(skb, &shhwtstamps);
-
- bfin_dump_hwtamp("TX", &shhwtstamps.hwtstamp, &shhwtstamps.syststamp, &lp->compare);
}
}
}
@@ -892,51 +879,25 @@ static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
regval = bfin_read_EMAC_PTP_RXSNAPLO();
regval |= (u64)bfin_read_EMAC_PTP_RXSNAPHI() << 32;
- ns = timecounter_cyc2time(&lp->clock, regval);
- timecompare_update(&lp->compare, ns);
+ ns = regval >> lp->shift;
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
shhwtstamps->hwtstamp = ns_to_ktime(ns);
- shhwtstamps->syststamp = timecompare_transform(&lp->compare, ns);
-
- bfin_dump_hwtamp("RX", &shhwtstamps->hwtstamp, &shhwtstamps->syststamp, &lp->compare);
-}
-
-/*
- * bfin_read_clock - read raw cycle counter (to be used by time counter)
- */
-static cycle_t bfin_read_clock(const struct cyclecounter *tc)
-{
- u64 stamp;
-
- stamp = bfin_read_EMAC_PTP_TIMELO();
- stamp |= (u64)bfin_read_EMAC_PTP_TIMEHI() << 32ULL;
-
- return stamp;
}
-#define PTP_CLK 25000000
-
static void bfin_mac_hwtstamp_init(struct net_device *netdev)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
- u64 append;
+ u64 addend;
+ u32 input_clk, phc_clk;
/* Initialize hardware timer */
- append = PTP_CLK * (1ULL << 32);
- do_div(append, get_sclk());
- bfin_write_EMAC_PTP_ADDEND((u32)append);
-
- memset(&lp->cycles, 0, sizeof(lp->cycles));
- lp->cycles.read = bfin_read_clock;
- lp->cycles.mask = CLOCKSOURCE_MASK(64);
- lp->cycles.mult = 1000000000 / PTP_CLK;
- lp->cycles.shift = 0;
-
- /* Synchronize our NIC clock against system wall clock */
- memset(&lp->compare, 0, sizeof(lp->compare));
- lp->compare.source = &lp->clock;
- lp->compare.target = ktime_get_real;
- lp->compare.num_samples = 10;
+ input_clk = get_sclk();
+ phc_clk = bfin_select_phc_clock(input_clk, &lp->shift);
+ addend = phc_clk * (1ULL << 32);
+ do_div(addend, input_clk);
+ bfin_write_EMAC_PTP_ADDEND((u32)addend);
+
+ lp->addend = addend;
/* Initialize hwstamp config */
lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
index 960905c..57f042c 100644
--- a/drivers/net/ethernet/adi/bfin_mac.h
+++ b/drivers/net/ethernet/adi/bfin_mac.h
@@ -11,8 +11,6 @@
#define _BFIN_MAC_H_
#include <linux/net_tstamp.h>
-#include <linux/clocksource.h>
-#include <linux/timecompare.h>
#include <linux/timer.h>
#include <linux/etherdevice.h>
#include <linux/bfin_mac.h>
@@ -94,9 +92,8 @@ struct bfin_mac_local {
struct mii_bus *mii_bus;
#if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
- struct cyclecounter cycles;
- struct timecounter clock;
- struct timecompare compare;
+ u32 addend;
+ unsigned int shift;
struct hwtstamp_config stamp_cfg;
#endif
};
--
1.7.2.5
^ permalink raw reply related
* [PATCH RFC net-next 3/4] bfin_mac: offer a PTP Hardware Clock.
From: Richard Cochran @ 2012-09-28 17:20 UTC (permalink / raw)
To: netdev
Cc: device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
Mike Frysinger, Miroslav Lichvar, Patrick Ohly, Sonic Zhang
In-Reply-To: <cover.1348851539.git.richardcochran@gmail.com>
The BF518 has a PTP time unit that works in a similar way to other MAC
based clocks, like gianfar, ixp46x, and igb. This patch adds support for
using the blackfin as a PHC. Although the blackfin hardware does offer a
few ancillary features, this patch implements only the basic operations.
Compile tested only.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/net/ethernet/adi/Kconfig | 2 +-
drivers/net/ethernet/adi/bfin_mac.c | 170 ++++++++++++++++++++++++++++++++++-
drivers/net/ethernet/adi/bfin_mac.h | 6 ++
3 files changed, 175 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index 49a30d3..175c38c 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -61,7 +61,7 @@ config BFIN_RX_DESC_NUM
config BFIN_MAC_USE_HWSTAMP
bool "Use IEEE 1588 hwstamp"
- depends on BFIN_MAC && BF518
+ depends on BFIN_MAC && BF518 && PTP_1588_CLOCK && !(BFIN_MAC=y && PTP_1588_CLOCK=m)
default y
---help---
To support the IEEE 1588 Precision Time Protocol (PTP), select y here
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index 393d1b5..88053a4 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -552,11 +552,13 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
static int bfin_mac_ethtool_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
info->so_timestamping =
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
- info->phc_index = -1;
+ info->phc_index = lp->phc_index;
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
@@ -887,7 +889,7 @@ static void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
static void bfin_mac_hwtstamp_init(struct net_device *netdev)
{
struct bfin_mac_local *lp = netdev_priv(netdev);
- u64 addend;
+ u64 addend, ppb;
u32 input_clk, phc_clk;
/* Initialize hardware timer */
@@ -898,18 +900,175 @@ static void bfin_mac_hwtstamp_init(struct net_device *netdev)
bfin_write_EMAC_PTP_ADDEND((u32)addend);
lp->addend = addend;
+ ppb = 1000000000ULL * input_clk;
+ do_div(ppb, phc_clk);
+ lp->max_ppb = ppb - 1000000000ULL - 1ULL;
/* Initialize hwstamp config */
lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
}
+static u64 bfin_ptp_time_read(struct bfin_mac_local *lp)
+{
+ u64 ns;
+ u32 lo, hi;
+
+ lo = bfin_read_EMAC_PTP_TIMELO();
+ hi = bfin_read_EMAC_PTP_TIMEHI();
+
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ ns <<= lp->shift;
+
+ return ns;
+}
+
+static void bfin_ptp_time_write(struct bfin_mac_local *lp, u64 ns)
+{
+ u32 hi, lo;
+
+ ns >>= lp->shift;
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+
+ bfin_write_EMAC_PTP_TIMELO(lo);
+ bfin_write_EMAC_PTP_TIMEHI(hi);
+}
+
+/* PTP Hardware Clock operations */
+
+static int bfin_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ u64 adj;
+ u32 diff, addend;
+ int neg_adj = 0;
+ struct bfin_mac_local *lp =
+ container_of(ptp, struct bfin_mac_local, caps);
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+ addend = lp->addend;
+ adj = addend;
+ adj *= ppb;
+ diff = div_u64(adj, 1000000000ULL);
+
+ addend = neg_adj ? addend - diff : addend + diff;
+
+ bfin_write_EMAC_PTP_ADDEND(addend);
+
+ return 0;
+}
+
+static int bfin_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ s64 now;
+ unsigned long flags;
+ struct bfin_mac_local *lp =
+ container_of(ptp, struct bfin_mac_local, caps);
+
+ spin_lock_irqsave(&lp->phc_lock, flags);
+
+ now = bfin_ptp_time_read(lp);
+ now += delta;
+ bfin_ptp_time_write(lp, now);
+
+ spin_unlock_irqrestore(&lp->phc_lock, flags);
+
+ return 0;
+}
+
+static int bfin_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ u64 ns;
+ u32 remainder;
+ unsigned long flags;
+ struct bfin_mac_local *lp =
+ container_of(ptp, struct bfin_mac_local, caps);
+
+ spin_lock_irqsave(&lp->phc_lock, flags);
+
+ ns = bfin_ptp_time_read(lp);
+
+ spin_unlock_irqrestore(&lp->phc_lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+ ts->tv_nsec = remainder;
+ return 0;
+}
+
+static int bfin_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ u64 ns;
+ unsigned long flags;
+ struct bfin_mac_local *lp =
+ container_of(ptp, struct bfin_mac_local, caps);
+
+ ns = ts->tv_sec * 1000000000ULL;
+ ns += ts->tv_nsec;
+
+ spin_lock_irqsave(&lp->phc_lock, flags);
+
+ bfin_ptp_time_write(lp, ns);
+
+ spin_unlock_irqrestore(&lp->phc_lock, flags);
+
+ return 0;
+}
+
+static int bfin_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info bfin_ptp_caps = {
+ .owner = THIS_MODULE,
+ .name = "BF518 clock",
+ .max_adj = 0,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .pps = 0,
+ .adjfreq = bfin_ptp_adjfreq,
+ .adjtime = bfin_ptp_adjtime,
+ .gettime = bfin_ptp_gettime,
+ .settime = bfin_ptp_settime,
+ .enable = bfin_ptp_enable,
+};
+
+static int bfin_phc_init(struct net_device *netdev, struct device *dev)
+{
+ struct bfin_mac_local *lp = netdev_priv(netdev);
+
+ lp->caps = bfin_ptp_caps;
+ lp->caps.max_adj = lp->max_ppb;
+ lp->clock = ptp_clock_register(&lp->caps, dev);
+ if (IS_ERR(lp->clock))
+ return PTR_ERR(lp->clock);
+
+ lp->phc_index = ptp_clock_index(lp->clock);
+ spin_lock_init(&lp->phc_lock);
+
+ return 0;
+}
+
+static void bfin_phc_release(struct bfin_mac_local *lp)
+{
+ ptp_clock_unregister(lp->clock);
+}
+
#else
# define bfin_mac_hwtstamp_is_none(cfg) 0
# define bfin_mac_hwtstamp_init(dev)
# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
# define bfin_rx_hwtstamp(dev, skb)
# define bfin_tx_hwtstamp(dev, skb)
+# define bfin_phc_init(netdev, dev) 0
+# define bfin_phc_release(lp)
#endif
static inline void _tx_reclaim_skb(void)
@@ -1544,12 +1703,17 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
}
bfin_mac_hwtstamp_init(ndev);
+ if (bfin_phc_init(ndev, &pdev->dev)) {
+ dev_err(&pdev->dev, "Cannot register PHC device!\n");
+ goto out_err_phc;
+ }
/* now, print out the card info, in a short format.. */
netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
return 0;
+out_err_phc:
out_err_reg_ndev:
free_irq(IRQ_MAC_RX, ndev);
out_err_request_irq:
@@ -1568,6 +1732,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct bfin_mac_local *lp = netdev_priv(ndev);
+ bfin_phc_release(lp);
+
platform_set_drvdata(pdev, NULL);
lp->mii_bus->priv = NULL;
diff --git a/drivers/net/ethernet/adi/bfin_mac.h b/drivers/net/ethernet/adi/bfin_mac.h
index 57f042c..7a07ee0 100644
--- a/drivers/net/ethernet/adi/bfin_mac.h
+++ b/drivers/net/ethernet/adi/bfin_mac.h
@@ -11,6 +11,7 @@
#define _BFIN_MAC_H_
#include <linux/net_tstamp.h>
+#include <linux/ptp_clock_kernel.h>
#include <linux/timer.h>
#include <linux/etherdevice.h>
#include <linux/bfin_mac.h>
@@ -94,7 +95,12 @@ struct bfin_mac_local {
#if defined(CONFIG_BFIN_MAC_USE_HWSTAMP)
u32 addend;
unsigned int shift;
+ s32 max_ppb;
struct hwtstamp_config stamp_cfg;
+ struct ptp_clock_info caps;
+ struct ptp_clock *clock;
+ int phc_index;
+ spinlock_t phc_lock; /* protects time lo/hi registers */
#endif
};
--
1.7.2.5
^ permalink raw reply related
* [PATCH RFC net-next 4/4] time: remove the timecompare code.
From: Richard Cochran @ 2012-09-28 17:20 UTC (permalink / raw)
To: netdev
Cc: device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, John Stultz,
Mike Frysinger, Miroslav Lichvar, Patrick Ohly, Sonic Zhang
In-Reply-To: <cover.1348851539.git.richardcochran@gmail.com>
This patch removes the timecompare code from the kernel. The top five
reasons to do this are:
1. There are no more users of this code.
2. The original idea was a bit weak.
3. The original author has disappeared.
4. The code was not general purpose but tuned to a particular hardware,
5. There are better ways to accomplish clock synchronization.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
include/linux/timecompare.h | 125 ----------------------------
kernel/time/Makefile | 2 +-
kernel/time/timecompare.c | 193 -------------------------------------------
3 files changed, 1 insertions(+), 319 deletions(-)
delete mode 100644 include/linux/timecompare.h
delete mode 100644 kernel/time/timecompare.c
diff --git a/include/linux/timecompare.h b/include/linux/timecompare.h
deleted file mode 100644
index 546e223..0000000
--- a/include/linux/timecompare.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Utility code which helps transforming between two different time
- * bases, called "source" and "target" time in this code.
- *
- * Source time has to be provided via the timecounter API while target
- * time is accessed via a function callback whose prototype
- * intentionally matches ktime_get() and ktime_get_real(). These
- * interfaces where chosen like this so that the code serves its
- * initial purpose without additional glue code.
- *
- * This purpose is synchronizing a hardware clock in a NIC with system
- * time, in order to implement the Precision Time Protocol (PTP,
- * IEEE1588) with more accurate hardware assisted time stamping. In
- * that context only synchronization against system time (=
- * ktime_get_real()) is currently needed. But this utility code might
- * become useful in other situations, which is why it was written as
- * general purpose utility code.
- *
- * The source timecounter is assumed to return monotonically
- * increasing time (but this code does its best to compensate if that
- * is not the case) whereas target time may jump.
- *
- * The target time corresponding to a source time is determined by
- * reading target time, reading source time, reading target time
- * again, then assuming that average target time corresponds to source
- * time. In other words, the assumption is that reading the source
- * time is slow and involves equal time for sending the request and
- * receiving the reply, whereas reading target time is assumed to be
- * fast.
- *
- * Copyright (C) 2009 Intel Corporation.
- * Author: Patrick Ohly <patrick.ohly@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#ifndef _LINUX_TIMECOMPARE_H
-#define _LINUX_TIMECOMPARE_H
-
-#include <linux/clocksource.h>
-#include <linux/ktime.h>
-
-/**
- * struct timecompare - stores state and configuration for the two clocks
- *
- * Initialize to zero, then set source/target/num_samples.
- *
- * Transformation between source time and target time is done with:
- * target_time = source_time + offset +
- * (source_time - last_update) * skew /
- * TIMECOMPARE_SKEW_RESOLUTION
- *
- * @source: used to get source time stamps via timecounter_read()
- * @target: function returning target time (for example, ktime_get
- * for monotonic time, or ktime_get_real for wall clock)
- * @num_samples: number of times that source time and target time are to
- * be compared when determining their offset
- * @offset: (target time - source time) at the time of the last update
- * @skew: average (target time - source time) / delta source time *
- * TIMECOMPARE_SKEW_RESOLUTION
- * @last_update: last source time stamp when time offset was measured
- */
-struct timecompare {
- struct timecounter *source;
- ktime_t (*target)(void);
- int num_samples;
-
- s64 offset;
- s64 skew;
- u64 last_update;
-};
-
-/**
- * timecompare_transform - transform source time stamp into target time base
- * @sync: context for time sync
- * @source_tstamp: the result of timecounter_read() or
- * timecounter_cyc2time()
- */
-extern ktime_t timecompare_transform(struct timecompare *sync,
- u64 source_tstamp);
-
-/**
- * timecompare_offset - measure current (target time - source time) offset
- * @sync: context for time sync
- * @offset: average offset during sample period returned here
- * @source_tstamp: average source time during sample period returned here
- *
- * Returns number of samples used. Might be zero (= no result) in the
- * unlikely case that target time was monotonically decreasing for all
- * samples (= broken).
- */
-extern int timecompare_offset(struct timecompare *sync,
- s64 *offset,
- u64 *source_tstamp);
-
-extern void __timecompare_update(struct timecompare *sync,
- u64 source_tstamp);
-
-/**
- * timecompare_update - update offset and skew by measuring current offset
- * @sync: context for time sync
- * @source_tstamp: the result of timecounter_read() or
- * timecounter_cyc2time(), pass zero to force update
- *
- * Updates are only done at most once per second.
- */
-static inline void timecompare_update(struct timecompare *sync,
- u64 source_tstamp)
-{
- if (!source_tstamp ||
- (s64)(source_tstamp - sync->last_update) >= NSEC_PER_SEC)
- __timecompare_update(sync, source_tstamp);
-}
-
-#endif /* _LINUX_TIMECOMPARE_H */
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index e2fd74b..ff7d9d2 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,4 +1,4 @@
-obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
obj-y += timeconv.o posix-clock.o alarmtimer.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
diff --git a/kernel/time/timecompare.c b/kernel/time/timecompare.c
deleted file mode 100644
index a9ae369..0000000
--- a/kernel/time/timecompare.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2009 Intel Corporation.
- * Author: Patrick Ohly <patrick.ohly@intel.com>
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/timecompare.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/math64.h>
-#include <linux/kernel.h>
-
-/*
- * fixed point arithmetic scale factor for skew
- *
- * Usually one would measure skew in ppb (parts per billion, 1e9), but
- * using a factor of 2 simplifies the math.
- */
-#define TIMECOMPARE_SKEW_RESOLUTION (((s64)1)<<30)
-
-ktime_t timecompare_transform(struct timecompare *sync,
- u64 source_tstamp)
-{
- u64 nsec;
-
- nsec = source_tstamp + sync->offset;
- nsec += (s64)(source_tstamp - sync->last_update) * sync->skew /
- TIMECOMPARE_SKEW_RESOLUTION;
-
- return ns_to_ktime(nsec);
-}
-EXPORT_SYMBOL_GPL(timecompare_transform);
-
-int timecompare_offset(struct timecompare *sync,
- s64 *offset,
- u64 *source_tstamp)
-{
- u64 start_source = 0, end_source = 0;
- struct {
- s64 offset;
- s64 duration_target;
- } buffer[10], sample, *samples;
- int counter = 0, i;
- int used;
- int index;
- int num_samples = sync->num_samples;
-
- if (num_samples > ARRAY_SIZE(buffer)) {
- samples = kmalloc(sizeof(*samples) * num_samples, GFP_ATOMIC);
- if (!samples) {
- samples = buffer;
- num_samples = ARRAY_SIZE(buffer);
- }
- } else {
- samples = buffer;
- }
-
- /* run until we have enough valid samples, but do not try forever */
- i = 0;
- counter = 0;
- while (1) {
- u64 ts;
- ktime_t start, end;
-
- start = sync->target();
- ts = timecounter_read(sync->source);
- end = sync->target();
-
- if (!i)
- start_source = ts;
-
- /* ignore negative durations */
- sample.duration_target = ktime_to_ns(ktime_sub(end, start));
- if (sample.duration_target >= 0) {
- /*
- * assume symetric delay to and from source:
- * average target time corresponds to measured
- * source time
- */
- sample.offset =
- (ktime_to_ns(end) + ktime_to_ns(start)) / 2 -
- ts;
-
- /* simple insertion sort based on duration */
- index = counter - 1;
- while (index >= 0) {
- if (samples[index].duration_target <
- sample.duration_target)
- break;
- samples[index + 1] = samples[index];
- index--;
- }
- samples[index + 1] = sample;
- counter++;
- }
-
- i++;
- if (counter >= num_samples || i >= 100000) {
- end_source = ts;
- break;
- }
- }
-
- *source_tstamp = (end_source + start_source) / 2;
-
- /* remove outliers by only using 75% of the samples */
- used = counter * 3 / 4;
- if (!used)
- used = counter;
- if (used) {
- /* calculate average */
- s64 off = 0;
- for (index = 0; index < used; index++)
- off += samples[index].offset;
- *offset = div_s64(off, used);
- }
-
- if (samples && samples != buffer)
- kfree(samples);
-
- return used;
-}
-EXPORT_SYMBOL_GPL(timecompare_offset);
-
-void __timecompare_update(struct timecompare *sync,
- u64 source_tstamp)
-{
- s64 offset;
- u64 average_time;
-
- if (!timecompare_offset(sync, &offset, &average_time))
- return;
-
- if (!sync->last_update) {
- sync->last_update = average_time;
- sync->offset = offset;
- sync->skew = 0;
- } else {
- s64 delta_nsec = average_time - sync->last_update;
-
- /* avoid division by negative or small deltas */
- if (delta_nsec >= 10000) {
- s64 delta_offset_nsec = offset - sync->offset;
- s64 skew; /* delta_offset_nsec *
- TIMECOMPARE_SKEW_RESOLUTION /
- delta_nsec */
- u64 divisor;
-
- /* div_s64() is limited to 32 bit divisor */
- skew = delta_offset_nsec * TIMECOMPARE_SKEW_RESOLUTION;
- divisor = delta_nsec;
- while (unlikely(divisor >= ((s64)1) << 32)) {
- /* divide both by 2; beware, right shift
- of negative value has undefined
- behavior and can only be used for
- the positive divisor */
- skew = div_s64(skew, 2);
- divisor >>= 1;
- }
- skew = div_s64(skew, divisor);
-
- /*
- * Calculate new overall skew as 4/16 the
- * old value and 12/16 the new one. This is
- * a rather arbitrary tradeoff between
- * only using the latest measurement (0/16 and
- * 16/16) and even more weight on past measurements.
- */
-#define TIMECOMPARE_NEW_SKEW_PER_16 12
- sync->skew =
- div_s64((16 - TIMECOMPARE_NEW_SKEW_PER_16) *
- sync->skew +
- TIMECOMPARE_NEW_SKEW_PER_16 * skew,
- 16);
- sync->last_update = average_time;
- sync->offset = offset;
- }
- }
-}
-EXPORT_SYMBOL_GPL(__timecompare_update);
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCH] rtlwifi: use %*ph[C] to dump small buffers
From: Joe Perches @ 2012-09-28 17:24 UTC (permalink / raw)
To: Larry Finger
Cc: David Laight, Andy Shevchenko, Chaoming Li, David S. Miller,
linux-wireless, netdev
In-Reply-To: <5065D32F.9090107@lwfinger.net>
On Fri, 2012-09-28 at 11:41 -0500, Larry Finger wrote:
> On 09/28/2012 04:04 AM, David Laight wrote:
> >>> Index: wireless-testing-new/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
[]
> >>> - *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
> >>> - (ratr_index << 28);
> >>> + for (i = 0; i < 3; i++)
> >>> + rate_mask[i] = ratr_bitmap & (0xff << (i * 4));
[]
> > So this either fixes, or adds, an endianness bug.
>
> Yes, the rate_mask array is little endian after this fragment is run, but the
> only use of the byte array is to write it to the device, and LE is what it needs
> no matter the platform. This change fixes an endianness bug.
>
> As I tend to get confused when doing these things, I wrote a small test program
> and ran it on x86_64 and PPC-32 to confirm the result.
>
> Thanks for teaching me about a = b >>= 8. I was not aware that C could do that.
The other thing that could be done is to use cpu_to_le32()
but David's method I think is superior for this use as there's
no absolute guarantee that rate_mask is aligned on a u32.
I'd add parens to make the precedence explicit.
rate_mask[0] = ratr_bitmap;
rate_mask[1] = (ratr_bitmap >>= 8);
rate_mask[2] = (ratr_bitmap >>= 8);
rate_mask[3] = ((ratr_bitmap >> 8) & 0xf) | (ratr_index << 4);
^ permalink raw reply
* Re: [RFC PATCH net-next] tcp: introduce tcp_tw_interval to specifiy the time of TIME-WAIT
From: Rick Jones @ 2012-09-28 17:30 UTC (permalink / raw)
To: David Miller; +Cc: amwang, nhorman, netdev, kuznet, kaber, edumazet
In-Reply-To: <20120928.024336.598451765169362800.davem@davemloft.net>
On 09/27/2012 11:43 PM, David Miller wrote:
> From: Cong Wang <amwang@redhat.com>
> Date: Fri, 28 Sep 2012 14:33:07 +0800
>
>> I don't think reducing TIME_WAIT is a good idea either, but there must
>> be some reason behind as several UNIX provides a microsecond-scale
>> tuning interface, or maybe in non-recycle mode, their RTO is much less
>> than 2*MSL?
Microsecond? HP-UX uses milliseconds for the units of the tunable,
though that does not necessarily mean it will actually be implemented to
millisecond accuracy
> Yes, there is a reason. It's there for retaining multi-million-dollar
> customers.
>
> There is no other reasons these other systems provide these
> facilities, they are simply there in an attempt to retain a dwindling
> customer base.
>
> Any other belief is extremely naive.
HP-UX's TIME_WAIT interval tunability goes back to HP-UX 11.0, which
first shipped in 1997. It got it by virtue of using a "Mentat-based"
stack which had that functionality. I may not have my history
completely correct, but Solaris 2 also got their networking bits from
Mentat, and I believe shipped before HP-UX 11.
To my recollection, neither were faced with a dwindling customer base at
the time.
rick jones
^ permalink raw reply
* pull request: wireless-next 2012-09-28
From: John W. Linville @ 2012-09-28 17:34 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 22359 bytes --]
commit c487606f835a93a725bac1aefd536be98f22474d
Dave,
Here is another batch of updates intended for 3.7...
Highlights include an hci_connect re-write in Bluetooth, HCI/LLC
layer separation in NFC, removal of the raw pn544 NFC driver, NFC LLCP
raw sockets support, improved IBSS auth frame handling in mac80211,
full-MAC AP mode notification support in mac80211, a lot of attention
paid to brcmfmac, and the usual level of updates to iwlwifi, ath9k,
mwifiex, and rt2x00, and various other updates.
Please let me know if there are problems!
Thanks,
John
P.S. I anticipate having at least one more pull request early in
the upcoming(?) merge window, due to some stragglers posted within
the last week...
---
The following changes since commit d9f72f359e00a45a6cd7cc2d5121b04b9dc927e1:
Revert "be2net: fix vfs enumeration" (2012-09-27 22:19:02 -0400)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next.git for-davem
for you to fetch changes up to c487606f835a93a725bac1aefd536be98f22474d:
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem (2012-09-28 11:11:16 -0400)
----------------------------------------------------------------
Alan Cox (1):
wireless: remove unreachable code
Amitkumar Karwar (3):
mwifiex: fix issue in resumed scan operation
mwifiex: disconnect the device before entering suspend state
mwifiex: block scan request during heavy Tx traffic
Andrei Emeltchenko (7):
Bluetooth: trivial: Shorten variable scope
Bluetooth: trivial: Use preferred method for NULL check
Bluetooth: Remove unneeded zero init
Bluetooth: trivial: Make hci_chan_del return void
Bluetooth: trivial: Remove empty line
Bluetooth: debug: Print refcnt for hci_dev
Bluetooth: AMP: Add Read Data Block Size to amp_init
Antonio Quartulli (2):
mac80211: move ieee80211_send_deauth_disassoc outside mlme code
mac80211: reply to AUTH with DEAUTH if sta allocation fails in IBSS
Arend van Spriel (8):
cfg80211: remove obsolete comment for .sched_scan_stop() callback
brcmfmac: add parameter check in brcmf_c_mkiovar()
brcmfmac: simplify handling e-scan result firmware event
brcmfmac: fix sparse warnings in e-scan related code
brcmfmac: extend brcmf_term_iscan() to abort e-scan
brcmfmac: introduce scheduled scan support
brcmfmac: change struct brcmf_cfg80211_priv comments to kernel-doc
brcmfmac: get rid of void pointer in struct brcmf_cfg80211_priv
Christian Lamparter (2):
p54: connect to 11w protected networks
carl9170: connect to 11w protected networks
Chun-Yeow Yeoh (2):
mac80211: allow re-open the blocked peer link in mesh
ath5k: disable HW crypto in management frame
Cong Wang (1):
NFC: Remove the pn544 raw driver
Dan Carpenter (1):
mwifiex: potential corruption in mwifiex_update_uap_custom_ie()
David Spinadel (2):
iwlwifi: don't reset interupts after disabling
iwlwifi: stop interrupts before stopping device
Eliad Peller (2):
mac80211: use synchronize_net() on key destroying
mac80211: use call_rcu() on sta deletion
Emmanuel Grumbach (2):
iwlwifi: some clean up in transport layer
iwlwifi: don't access the HW when it is not available
Eric Lapuyade (9):
NFC: Changed the HCI cmd execution callback prototype
NFC: Add a public nfc_hci_send_cmd_async method
NFC: Modified hci_transceive to become an asynchronous operation
NFC: Add an LLC Core layer to HCI
NFC: Add a nop (passthrough) llc module to llc core
NFC: Add an shdlc llc module to llc core
NFC: Changed HCI and PN544 HCI driver to use the new HCI LLC Core
NFC: Fix LLC registration definitions for ANSI compliance
NFC: Add HCI module description
Felix Fietkau (1):
mac80211: validate skb->dev in the tx status path
Franky Lin (8):
brcmfmac: absorb brcmf_sendpkt into brcmf_netdev_start_xmit
brcmfmac: remove obsolete sdio bus sleep mechanism
brcmfmac: use atomic variable for interrupt pending flag
brcmfmac: convert SDIO dpc implementation to workqueue
brcmfmac: streamline SDIO dpc
brcmfmac: raise SDIO host lock to higher level
brcmfmac: clear status for in-band interrupt in brcmf_sdbrcm_isr
brcmfmac: streamline SDIO read frame routine
Gertjan van Wingerde (7):
rt2x00: Code clean up in rt2800lib.
rt2x00: rt2800 - Fix default vgc values for RT3572
rt2x00: rt2800lib - code cleanup.
rt2x00: Code style cleanup in rt2800lib.c
rt2x00: Clean up RFCSR1 programming in rt2800_config_channel_rf3xxx.
rt2x00: Deprecate max_sta_intf field of struct rt2x00_ops.
rt2x00: Replace open coded interface checking with interface combinations.
Gustavo Padovan (1):
Bluetooth: Add USB_VENDOR_AND_INTERFACE_INFO() for Broadcom/Foxconn
Hante Meuleman (7):
brcmfmac: fix bug causing errorneous free on exception.
brcmfmac: fix debug printout of event data.
brcmfmac: store usb fw images in local linked list.
brcmfmac: remove unused function.
brcmfmac: fix bug in determining phy bands.
brcmfmac: remove unused usb bmac model code.
brcmfmac: clear control lock on usb error.
Ilan Elias (3):
NFC: Set local general bytes in nci_start_poll
NFC: Parse NCI NFC-DEP activation params
NFC: Implement NCI dep_link_up and dep_link_down
Jaroslav Resler (1):
Bluetooth: Add support for BCM20702A0 [04ca, 2003]
Johan Hedberg (2):
Bluetooth: mgmt: Implement support for passkey notification
Bluetooth: Update management interface revision
Johannes Berg (22):
iwlwifi: remove unused IDI code stubs
Merge remote-tracking branch 'mac80211/master' into mac80211-next
mac80211: don't hang on to sched_scan_ies
mac80211: disconnect if channel switch fails
Merge remote-tracking branch 'wireless-next/master' into mac80211-next
wireless: remove obsolete chan no/center freq conversion functions
mac80211_hwsim: move module_init/exit
mac80211: check power constraint IE size when parsing
mac80211: add key flag for management keys
iwlwifi: fix indentation in iwl_load_given_ucode
iwlwifi: load firmware in chunks
mac80211: remove unneeded CONFIG_PM ifdef
mac80211: handle power constraint/country IE better
mac80211: change locking around ieee80211_recalc_smps
mac80211: make reset debugfs depend on CONFIG_PM
cfg80211: constify name parameter to add_virtual_intf
iwlwifi: use eth_broadcast_addr
iwlwifi: fix async station command crash
mac80211: don't send delBA before disassoc
mac80211: don't send delBA when removing stations
mac80211: don't send delBA on addBA failure
iwlegacy: use eth_broadcast_addr
John W. Linville (11):
Merge branch 'for-john' of git://git.kernel.org/.../jberg/mac80211-next
Merge branch 'for-john' of git://git.kernel.org/.../iwlwifi/iwlwifi-next
Merge branch 'master' of git://git.kernel.org/.../bluetooth/bluetooth-next
Merge tag 'nfc-next-3.7-1' of git://git.kernel.org/.../sameo/nfc-3.0
Merge branch 'for-john' of git://git.kernel.org/.../jberg/mac80211-next
Merge branch 'for-john' of git://git.kernel.org/.../iwlwifi/iwlwifi-next
ath5k: add missing breaks in ath5k_hw_set_spur_mitigation_filter
nfc: add dummy nfc_llc_shdlc_register definition
NFC: Add dummy nfc_llc_shdlc_register definition
Merge tag 'nfc-next-3.7-2' of git://git.kernel.org/.../sameo/nfc-3.0
Merge branch 'master' of git://git.kernel.org/.../linville/wireless-next into for-davem
Michal Kazior (1):
mac80211: refactor set_channel_type
Mikel Astiz (3):
Bluetooth: Add more HCI error codes
Bluetooth: Fix minor coding style in hci_event.c
Bluetooth: mgmt: Add device disconnect reason
Ming Lei (1):
wireless: ath9k-htc: fix possible use after free
Mohammed Shafi Shajakhan (1):
ath9k: update hw_timer_enabled to false when we stop generic timers
Pandiyarajan Pitchaimuthu (1):
cfg80211/nl80211: Notify connection request failure in AP mode
Paul Bolle (1):
ipw2x00: silence GCC warning for unused variable 'dev'
Peter Senna Tschudin (6):
net/mac80211/scan.c: removes unnecessary semicolon
Bluetooth: bluecard_cs.c: removes unnecessary semicolon
Bluetooth: hci_ldisc.c: removes unnecessary semicolon
Bluetooth: hci_ll.c: removes unnecessary semicolon
Bluetooth: hci_vhci.c: removes unnecessary semicolon
Bluetooth: btuart_cs.c: removes unnecessary semicolon
Piotr Haber (1):
brcmsmac: don't start device when RfKill is engaged
Rafał Miłecki (1):
bcma: handle BCM43227
Rajkumar Manoharan (7):
ath9k_hw: move 2g5g switch before nfcal start
ath9k_hw: fix ar9462 selfgen chainmask
ath9k: flush bt profile whenever it is requested
ath9k: move coex param updation within mci work
ath9k: fill led_pin before drv_start
ath9k: fix queuing MCI work twice
ath9k_hw: fix BT sleep state on chip wakeup
Sachin Kamat (1):
Bluetooth: Use module_platform_driver() in btwilink.c file
Samuel Ortiz (4):
NFC: Queue pn533 commands
NFC: Set the IRQF_ONESHOT flag from the pn544_hci IRQ handler request
NFC: Remove unneeded LLC symbols export
MAINTAINERS: Add NFC specific mailing list
Sujith Manoharan (10):
ath9k: Enable SGI correctly
ath9k_hw: Use HW cap ATH9K_HW_CAP_ANT_DIV_COMB
ath9k: Remove redundant variable assignment
ath9k: Remove a couple of unused variables
ath9k_hw: Add antenna diversity group for AR9565
ath9k_hw: Update AR9565 initvals
ath9k_hw: Add a HW callback to set diversity
ath9k: Add a module parameter to enable diversity
ath9k_hw: Enable WLAN RX diversity for AR9565
ath9k: Disable ASPM only for AR9285
Syam Sidhardhan (4):
Bluetooth: debug: Correct the PSM printing
Bluetooth: Use kref for l2cap channel reference counting
NFC: Use module_platform_driver macro for nfcwilink.c
NFC: Remove repeated code for NULL check
Sylvain Roger Rieunier (1):
mac80211: fix IBSS auth TX debug message
Szymon Janc (4):
NFC: Use dynamic initialization for rwlocks
NFC: Fix missing mutex unlock in pn533_send_cmd_frame_async
NFC: Fix sleeping in invalid context when netlink socket is closed
NFC: Fix sleeping in atomic when releasing socket
Tejun Heo (2):
NFC: Use system_nrt_wq instead of custom ones
NFC: Don't use WQ_MEM_RECLAIM for pn533
Thierry Escande (1):
NFC: LLCP raw socket support
Vinicius Costa Gomes (8):
Bluetooth: Remove some functions from being exported
Bluetooth: Rename LE and ACL connection functions
Bluetooth: Refactor LE connection into its own function
Bluetooth: Refactor ACL connection into its own function
Bluetooth: Refactor SCO connection into its own function
Bluetooth: Simplify a the connection type handling
Bluetooth: Add type information to the hci_connect() debug statement
Bluetooth: Fix establishing ESCO links
Vitaly Wool (1):
rfkill: prevent unnecessary event generation
Vladimir Kondratiev (1):
cfg80211: Fix regulatory check for 60GHz band frequencies
Waldemar Rymarkiewicz (6):
NFC: Remove crc generation from shdlc layer
NFC: Correct outgoing frame before requeueing
NFC: xmit from hci ops must return 0 or negative
NFC: Handle RSET in SHDLC_CONNECTING state
NFC: Don't handle consequent RSET frames after UA
NFC: Fix typo negociating -> negotiating
Wei Yongjun (6):
mac80211: use list_move instead of list_del/list_add
Bluetooth: btmrvl: remove pointless conditional before kfree_skb()
NFC: Remove pointless conditional before HCI kfree_skb()
NFC: Fix possible LLCP memory leak
NFC: Move the nfcwilink dereference below the NULL test
NFC: Move the pn544_hci dereference below the NULL test
Documentation/feature-removal-schedule.txt | 12 -
MAINTAINERS | 1 +
drivers/bcma/host_pci.c | 1 +
drivers/bcma/sprom.c | 2 +
drivers/bluetooth/bluecard_cs.c | 2 +-
drivers/bluetooth/btmrvl_sdio.c | 3 +-
drivers/bluetooth/btuart_cs.c | 2 +-
drivers/bluetooth/btusb.c | 3 +-
drivers/bluetooth/btwilink.c | 16 +-
drivers/bluetooth/hci_ldisc.c | 2 +-
drivers/bluetooth/hci_ll.c | 2 +-
drivers/bluetooth/hci_vhci.c | 2 +-
drivers/net/wireless/ath/ath.h | 1 +
drivers/net/wireless/ath/ath5k/base.c | 1 +
drivers/net/wireless/ath/ath5k/mac80211-ops.c | 5 +-
drivers/net/wireless/ath/ath5k/phy.c | 2 +
drivers/net/wireless/ath/ath6kl/cfg80211.c | 4 +-
drivers/net/wireless/ath/ath6kl/cfg80211.h | 2 +-
drivers/net/wireless/ath/ath9k/antenna.c | 117 ++-
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 20 +-
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 7 +-
drivers/net/wireless/ath/ath9k/ar9003_mci.h | 4 +-
drivers/net/wireless/ath/ath9k/ar9003_phy.c | 66 +-
drivers/net/wireless/ath/ath9k/ar9003_phy.h | 24 +
.../net/wireless/ath/ath9k/ar9565_1p0_initvals.h | 100 +-
drivers/net/wireless/ath/ath9k/ath9k.h | 6 +-
drivers/net/wireless/ath/ath9k/gpio.c | 58 +-
drivers/net/wireless/ath/ath9k/hif_usb.c | 5 +-
drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +-
drivers/net/wireless/ath/ath9k/hw-ops.h | 7 +
drivers/net/wireless/ath/ath9k/hw.c | 12 +-
drivers/net/wireless/ath/ath9k/hw.h | 3 +-
drivers/net/wireless/ath/ath9k/init.c | 13 +
drivers/net/wireless/ath/ath9k/main.c | 2 +-
drivers/net/wireless/ath/ath9k/mci.c | 62 +-
drivers/net/wireless/ath/ath9k/pci.c | 5 +-
drivers/net/wireless/ath/ath9k/rc.c | 11 +-
drivers/net/wireless/ath/carl9170/mac.c | 3 +-
drivers/net/wireless/ath/carl9170/main.c | 2 +
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 39 +-
.../net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 25 -
drivers/net/wireless/brcm80211/brcmfmac/dhd.h | 4 -
.../net/wireless/brcm80211/brcmfmac/dhd_common.c | 19 +-
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 2 +
.../net/wireless/brcm80211/brcmfmac/dhd_linux.c | 41 +-
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 1037 ++++++++------------
.../net/wireless/brcm80211/brcmfmac/sdio_host.h | 2 +
drivers/net/wireless/brcm80211/brcmfmac/usb.c | 90 +-
.../net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | 422 ++++++--
.../net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | 202 +++-
.../net/wireless/brcm80211/brcmsmac/mac80211_if.c | 5 +-
drivers/net/wireless/ipw2x00/libipw_wx.c | 2 +-
drivers/net/wireless/iwlegacy/common.c | 4 +-
drivers/net/wireless/iwlwifi/dvm/scan.c | 4 +-
drivers/net/wireless/iwlwifi/dvm/sta.c | 7 +-
drivers/net/wireless/iwlwifi/dvm/ucode.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-drv.c | 26 +-
drivers/net/wireless/iwlwifi/iwl-fw.h | 3 +-
drivers/net/wireless/iwlwifi/pcie/drv.c | 13 -
drivers/net/wireless/iwlwifi/pcie/internal.h | 2 +-
drivers/net/wireless/iwlwifi/pcie/rx.c | 75 +-
drivers/net/wireless/iwlwifi/pcie/trans.c | 84 +-
drivers/net/wireless/mac80211_hwsim.c | 5 +-
drivers/net/wireless/mwifiex/cfg80211.c | 8 +-
drivers/net/wireless/mwifiex/ie.c | 2 +-
drivers/net/wireless/mwifiex/init.c | 1 +
drivers/net/wireless/mwifiex/main.h | 4 +-
drivers/net/wireless/mwifiex/sta_ioctl.c | 13 +
drivers/net/wireless/p54/main.c | 12 +
drivers/net/wireless/rt2x00/rt2400pci.c | 1 -
drivers/net/wireless/rt2x00/rt2500pci.c | 1 -
drivers/net/wireless/rt2x00/rt2500usb.c | 1 -
drivers/net/wireless/rt2x00/rt2800lib.c | 72 +-
drivers/net/wireless/rt2x00/rt2800pci.c | 1 -
drivers/net/wireless/rt2x00/rt2800usb.c | 1 -
drivers/net/wireless/rt2x00/rt2x00.h | 15 +-
drivers/net/wireless/rt2x00/rt2x00dev.c | 33 +
drivers/net/wireless/rt2x00/rt2x00mac.c | 40 -
drivers/net/wireless/rt2x00/rt61pci.c | 1 -
drivers/net/wireless/rt2x00/rt73usb.c | 1 -
drivers/nfc/Kconfig | 14 +-
drivers/nfc/Makefile | 1 -
drivers/nfc/nfcwilink.c | 20 +-
drivers/nfc/pn533.c | 107 +-
drivers/nfc/pn544.c | 893 -----------------
drivers/nfc/pn544_hci.c | 177 ++--
include/linux/ieee80211.h | 80 --
include/linux/nfc.h | 11 +
include/linux/nl80211.h | 24 +
include/net/bluetooth/hci.h | 21 +
include/net/bluetooth/hci_core.h | 26 +-
include/net/bluetooth/l2cap.h | 3 +-
include/net/bluetooth/mgmt.h | 16 +
include/net/cfg80211.h | 25 +-
include/net/mac80211.h | 12 +-
include/net/nfc/hci.h | 21 +-
include/net/nfc/llc.h | 54 +
include/net/nfc/nci.h | 29 +
include/net/nfc/nci_core.h | 5 +
include/net/nfc/nfc.h | 2 +-
include/net/nfc/shdlc.h | 107 --
net/bluetooth/af_bluetooth.c | 10 +-
net/bluetooth/hci_conn.c | 100 +-
net/bluetooth/hci_core.c | 6 +-
net/bluetooth/hci_event.c | 99 +-
net/bluetooth/l2cap_core.c | 17 +-
net/bluetooth/mgmt.c | 28 +-
net/mac80211/agg-tx.c | 2 +-
net/mac80211/cfg.c | 37 +-
net/mac80211/chan.c | 67 +-
net/mac80211/debugfs.c | 4 +
net/mac80211/ibss.c | 35 +-
net/mac80211/ieee80211_i.h | 23 +-
net/mac80211/iface.c | 15 +-
net/mac80211/key.c | 2 +-
net/mac80211/main.c | 10 +-
net/mac80211/mesh_plink.c | 3 +-
net/mac80211/mlme.c | 207 ++--
net/mac80211/offchannel.c | 3 +-
net/mac80211/scan.c | 41 +-
net/mac80211/sta_info.c | 123 +--
net/mac80211/sta_info.h | 2 +
net/mac80211/status.c | 48 +-
net/mac80211/tx.c | 2 +-
net/mac80211/util.c | 51 +-
net/nfc/core.c | 13 +-
net/nfc/hci/Makefile | 4 +-
net/nfc/hci/command.c | 45 +-
net/nfc/hci/core.c | 336 ++++---
net/nfc/hci/hci.h | 15 +-
net/nfc/hci/hcp.c | 6 +-
net/nfc/hci/llc.c | 170 ++++
net/nfc/hci/llc.h | 69 ++
net/nfc/hci/llc_nop.c | 99 ++
net/nfc/hci/{shdlc.c => llc_shdlc.c} | 544 +++++-----
net/nfc/llcp/commands.c | 2 +
net/nfc/llcp/llcp.c | 131 +--
net/nfc/llcp/llcp.h | 6 +-
net/nfc/llcp/sock.c | 93 +-
net/nfc/nci/core.c | 91 +-
net/nfc/nci/ntf.c | 52 +
net/nfc/nci/rsp.c | 14 +
net/nfc/netlink.c | 46 +-
net/rfkill/core.c | 8 +-
net/wireless/mlme.c | 11 +
net/wireless/nl80211.c | 34 +
net/wireless/nl80211.h | 5 +
net/wireless/reg.c | 39 +-
148 files changed, 3919 insertions(+), 3413 deletions(-)
delete mode 100644 drivers/nfc/pn544.c
create mode 100644 include/net/nfc/llc.h
delete mode 100644 include/net/nfc/shdlc.h
create mode 100644 net/nfc/hci/llc.c
create mode 100644 net/nfc/hci/llc.h
create mode 100644 net/nfc/hci/llc_nop.c
rename net/nfc/hci/{shdlc.c => llc_shdlc.c} (54%)
--
John W. Linville Someday the world will need a hero, and you
linville-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org might be all we have. Be ready.
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: You have to fix this
From: David Miller @ 2012-09-28 17:43 UTC (permalink / raw)
To: vipul; +Cc: netdev
In-Reply-To: <5065911A.3000509@chelsio.com>
From: Vipul Pandya <vipul@chelsio.com>
Date: Fri, 28 Sep 2012 17:29:22 +0530
> Please let me know how else would I get above warning message?
Maybe your compiler is too old. Does -Wframe-larger-than= show up in your
build logs with "make V=1"?
^ permalink raw reply
* Re: [PATCH] vlan: Make it possible to add vlan with id 4095
From: David Miller @ 2012-09-28 17:44 UTC (permalink / raw)
To: paulius.zaleckas; +Cc: kaber, netdev
In-Reply-To: <20120928123258.9454.95197.stgit@localhost.localdomain>
From: Paulius Zaleckas <paulius.zaleckas@gmail.com>
Date: Fri, 28 Sep 2012 15:32:58 +0300
> vconfig help tells that vlan_id should be 0-4095, but fails
> with 4095.
>
> There is an off-by-one bug while evaluating vlan_id.
> Fix it by evaluating against count(4096), not mask(0x0fff = 4095).
>
> Signed-off-by: Paulius Zaleckas <paulius.zaleckas@gmail.com>
Awesome, we don't need VXVLAN any more after this fix.
^ permalink raw reply
* Re: [PATCH RFC net-next 4/4] time: remove the timecompare code.
From: John Stultz @ 2012-09-28 17:44 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, device-drivers-devel, uclinux-dist-devel, David Miller,
Jacob Keller, Jeff Kirsher, John Ronciak, Mike Frysinger,
Miroslav Lichvar, Patrick Ohly, Sonic Zhang
In-Reply-To: <e100d86136270dae62ff546e3a6c5ef10631c68c.1348851539.git.richardcochran@gmail.com>
On 09/28/2012 10:20 AM, Richard Cochran wrote:
> This patch removes the timecompare code from the kernel. The top five
> reasons to do this are:
>
> 1. There are no more users of this code.
> 2. The original idea was a bit weak.
> 3. The original author has disappeared.
> 4. The code was not general purpose but tuned to a particular hardware,
> 5. There are better ways to accomplish clock synchronization.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Nice cleanup!
Acked-by: John Stultz <john.stultz@linaro.org>
thanks!
-john
^ permalink raw reply
* [PATCH net-next] mlx4: dont orphan skbs in mlx4_en_xmit()
From: Eric Dumazet @ 2012-09-28 17:53 UTC (permalink / raw)
To: Yevgeny Petrilin; +Cc: David Miller, netdev, Or Gerlitz
In-Reply-To: <1348056777.26523.750.camel@edumazet-glaptop>
From: Eric Dumazet <edumazet@google.com>
After commit e22979d96a55d (mlx4_en: Moving to Interrupts for TX
completions) we no longer need to orphan skbs in mlx4_en_xmit()
since skb wont stay a long time in TX ring before their release.
Orphaning skbs in ndo_start_xmit() should be avoided as much as
possible, since it breaks TCP Small Queue or other flow control
mechanisms (per socket limits)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yevgeny Petrilin <yevgenyp@mellanox.com>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 10bba09..c10e3a6 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -712,10 +712,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
if (bounce)
tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
- /* Run destructor before passing skb to HW */
- if (likely(!skb_shared(skb)))
- skb_orphan(skb);
-
if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) {
*(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
op_own |= htonl((bf_index & 0xffff) << 8);
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox