[net-2.6 PATCH 1/8] qlge: Expand coverage of hw lock for config register.

Previous thread: Upgrade Your Email Account by Upgrade Team on Thursday, July 2, 2009 - 11:29 am. (1 message)

Next thread: [PATCH] IPv6: preferred lifetime of address not getting updated by Brian Haley on Thursday, July 2, 2009 - 1:10 pm. (2 messages)
To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

The hardware semaphore covers the configuration register as well as the
ICB registers. The ICB high and low regs contain the address of the
initialization control block and the config register is used to signal
the hardware that a block is ready to be downloaded. Currently we were
only protecting the ICB regs. This changes expands to cover the config
register as well.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 90d1f76..7f37267 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -214,6 +214,10 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
return -ENOMEM;
}

+ status = ql_sem_spinlock(qdev, SEM_ICB_MASK);
+ if (status)
+ return status;
+
status = ql_wait_cfg(qdev, bit);
if (status) {
QPRINTK(qdev, IFUP, ERR,
@@ -221,12 +225,8 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
goto exit;
}

- status = ql_sem_spinlock(qdev, SEM_ICB_MASK);
- if (status)
- goto exit;
ql_write32(qdev, ICB_L, (u32) map);
ql_write32(qdev, ICB_H, (u32) (map >> 32));
- ql_sem_unlock(qdev, SEM_ICB_MASK); /* does flush too */

mask = CFG_Q_MASK | (bit << 16);
value = bit | (q_id << CFG_Q_SHIFT);
@@ -237,6 +237,7 @@ int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
*/
status = ql_wait_cfg(qdev, bit);
exit:
+ ql_sem_unlock(qdev, SEM_ICB_MASK); /* does flush too */
pci_unmap_single(qdev->pdev, map, size, direction);
return status;
}
--
1.6.0.2

--

To: <ron.mercer@...>
Cc: <netdev@...>
Date: Friday, July 3, 2009 - 10:13 pm

All 8 patches applied, thanks.
--

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

The caller will free acquired resouces if a failure occurs.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index c226257..1b75f6e 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3374,11 +3374,6 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev)
return -ENOMEM;
}
status = ql_request_irq(qdev);
- if (status)
- goto err_irq;
- return status;
-err_irq:
- ql_free_mem_resources(qdev);
return status;
}

--
1.6.0.2

--

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

We were turning on the carrier without verifying the link was up.
This adds link up to the link initialize check before turning carrier
on.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 1da831e..c226257 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3343,7 +3343,11 @@ static int ql_adapter_up(struct ql_adapter *qdev)
}
set_bit(QL_ADAPTER_UP, &qdev->flags);
ql_alloc_rx_buffers(qdev);
- if ((ql_read32(qdev, STS) & qdev->port_init))
+ /* If the port is initialized and the
+ * link is up the turn on the carrier.
+ */
+ if ((ql_read32(qdev, STS) & qdev->port_init) &&
+ (ql_read32(qdev, STS) & qdev->port_link_up))
netif_carrier_on(qdev->ndev);
ql_enable_interrupts(qdev);
ql_enable_all_completion_interrupts(qdev);
--
1.6.0.2

--

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

This addes functionality to set/clear the MAC address in the hardware
when the link goes up/down.
The MAC address register is persistent across function resets. In
bonding the same address can bounce from one port to the other. This
can cause packets to be delivered to the wrong port.
This patch clears the MAC address in the hardware when the link is down
and sets it when the link comes up.
It was found that pulling/pushing the cable from one port to another
causes the same MAC address to be in both ports.
The next patch in this series will use this functionality as well.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 50 ++++++++++++++++++++++++++++++++++++------
1 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 74ed84a..46dea2b 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -413,6 +413,41 @@ exit:
return status;
}

+/* Set or clear MAC address in hardware. We sometimes
+ * have to clear it to prevent wrong frame routing
+ * especially in a bonding environment.
+ */
+static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
+{
+ int status;
+ char zero_mac_addr[ETH_ALEN];
+ char *addr;
+
+ if (set) {
+ addr = &qdev->ndev->dev_addr[0];
+ QPRINTK(qdev, IFUP, DEBUG,
+ "Set Mac addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr[0], addr[1], addr[2], addr[3],
+ addr[4], addr[5]);
+ } else {
+ memset(zero_mac_addr, 0, ETH_ALEN);
+ addr = &zero_mac_addr[0];
+ QPRINTK(qdev, IFUP, DEBUG,
+ "Clearing MAC address on %s\n",
+ qdev->ndev->name);
+ }
+ status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+ if (status)
+ return status;
+ status = ql_set_mac_addr_reg(qdev, (u8 *) addr,
+ MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
+ ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+ if (status)
+ QPRINTK(qdev, IFUP, ERR, "Failed to init mac "
+ "address.\n");
+ return status;
...

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

We need to set/clear the mac address register when the link goes up/down
respectively. Without this both ports of a 2-port device can end up
with the same mac address in a bonding scenario.
The new ql_link_on() and ql_link_off() will also be used in handling
certain firmware events.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 2 ++
drivers/net/qlge/qlge_main.c | 26 +++++++++++++++++++++-----
drivers/net/qlge/qlge_mpi.c | 6 +++---
3 files changed, 26 insertions(+), 8 deletions(-)

diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 156e02e..6ed5317 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1607,6 +1607,8 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_mb_about_fw(struct ql_adapter *qdev);
+void ql_link_on(struct ql_adapter *qdev);
+void ql_link_off(struct ql_adapter *qdev);

#if 1
#define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 46dea2b..35ba95a 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -448,6 +448,22 @@ static int ql_set_mac_addr(struct ql_adapter *qdev, int set)
return status;
}

+void ql_link_on(struct ql_adapter *qdev)
+{
+ QPRINTK(qdev, LINK, ERR, "%s: Link is up.\n",
+ qdev->ndev->name);
+ netif_carrier_on(qdev->ndev);
+ ql_set_mac_addr(qdev, 1);
+}
+
+void ql_link_off(struct ql_adapter *qdev)
+{
+ QPRINTK(qdev, LINK, ERR, "%s: Link is down.\n",
+ qdev->ndev->name);
+ netif_carrier_off(qdev->ndev);
+ ql_set_mac_addr(qdev, 0);
+}
+
/* Get a specific frame routing value from the CAM.
* Used for debug and reg dump.
*/
@@ -1696,13 +1712,13 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
/* Fire up a handler to reset the MPI processor. */
void ql_queue_fw_error(struct ql_adapter *qd...

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 1b75f6e..74ed84a 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -1629,7 +1629,7 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
tx_ring = &qdev->tx_ring[mac_rsp->txq_idx];
tx_ring_desc = &tx_ring->q[mac_rsp->tid];
ql_unmap_send(qdev, tx_ring_desc, tx_ring_desc->map_cnt);
- qdev->stats.tx_bytes += tx_ring_desc->map_cnt;
+ qdev->stats.tx_bytes += (tx_ring_desc->skb)->len;
qdev->stats.tx_packets++;
dev_kfree_skb(tx_ring_desc->skb);
tx_ring_desc->skb = NULL;
--
1.6.0.2

--

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

Some usage was only sizing a pointer rather than the data type.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_ethtool.c | 4 ++--
drivers/net/qlge/qlge_main.c | 14 +++++++-------
2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 37c99fe..eb6a9ee 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -59,7 +59,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
cqicb->pkt_delay =
cpu_to_le16(qdev->tx_max_coalesced_frames);
cqicb->flags = FLAGS_LI;
- status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+ status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
CFG_LCQ, rx_ring->cq_id);
if (status) {
QPRINTK(qdev, IFUP, ERR,
@@ -82,7 +82,7 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
cqicb->pkt_delay =
cpu_to_le16(qdev->rx_max_coalesced_frames);
cqicb->flags = FLAGS_LI;
- status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
+ status = ql_write_cfg(qdev, cqicb, sizeof(*cqicb),
CFG_LCQ, rx_ring->cq_id);
if (status) {
QPRINTK(qdev, IFUP, ERR,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 35ba95a..5768af1 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -2156,7 +2156,7 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
}
tx_ring_desc = &tx_ring->q[tx_ring->prod_idx];
mac_iocb_ptr = tx_ring_desc->queue_entry;
- memset((void *)mac_iocb_ptr, 0, sizeof(mac_iocb_ptr));
+ memset((void *)mac_iocb_ptr, 0, sizeof(*mac_iocb_ptr));

mac_iocb_ptr->opcode = OPCODE_OB_MAC_IOCB;
mac_iocb_ptr->tid = tx_ring_desc->index;
@@ -2795,7 +2795,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)

ql_init_tx_ring(qdev, tx_ring);

- err = ql_write_cfg(qdev, wqicb, sizeof(wqi...

To: <davem@...>
Cc: <netdev@...>, <ron.mercer@...>
Date: Thursday, July 2, 2009 - 12:06 pm

Not clearing the routing bits can cause frames to erroneously get routed to
management processor.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 41 ++++++++++++++++++++++++++++++++---------
1 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 7f37267..1da831e 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3040,25 +3040,40 @@ static int ql_start_rss(struct ql_adapter *qdev)
return status;
}

-/* Initialize the frame-to-queue routing. */
-static int ql_route_initialize(struct ql_adapter *qdev)
+static int ql_clear_routing_entries(struct ql_adapter *qdev)
{
- int status = 0;
- int i;
+ int i, status = 0;

status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
if (status)
return status;
-
/* Clear all the entries in the routing table. */
for (i = 0; i < 16; i++) {
status = ql_set_routing_reg(qdev, i, 0, 0);
if (status) {
QPRINTK(qdev, IFUP, ERR,
- "Failed to init routing register for CAM packets.\n");
- goto exit;
+ "Failed to init routing register for CAM "
+ "packets.\n");
+ break;
}
}
+ ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+ return status;
+}
+
+/* Initialize the frame-to-queue routing. */
+static int ql_route_initialize(struct ql_adapter *qdev)
+{
+ int status = 0;
+
+ status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+ if (status)
+ return status;
+
+ /* Clear all the entries in the routing table. */
+ status = ql_clear_routing_entries(qdev);
+ if (status)
+ goto exit;

status = ql_set_routing_reg(qdev, RT_IDX_ALL_ERR_SLOT, RT_IDX_ERR, 1);
if (status) {
@@ -3211,9 +3226,17 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
{
u32 value;
int status = 0;
- unsigned long end_jiffies = jiffies +
- max((unsigned long)1, usecs_to_jiffies(30));
+ unsigned long end_jiffies;

+ /* Clear all the entries in the routing table. */
+ status =...

Previous thread: Upgrade Your Email Account by Upgrade Team on Thursday, July 2, 2009 - 11:29 am. (1 message)

Next thread: [PATCH] IPv6: preferred lifetime of address not getting updated by Brian Haley on Thursday, July 2, 2009 - 1:10 pm. (2 messages)