Commit 7fab3bfe authored by Ron Mercer's avatar Ron Mercer Committed by David S. Miller

qlge: Fix MAC address bonding issue.

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: default avatarRon Mercer <ron.mercer@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 13cfd5be
...@@ -413,6 +413,41 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, ...@@ -413,6 +413,41 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
return status; 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;
}
/* Get a specific frame routing value from the CAM. /* Get a specific frame routing value from the CAM.
* Used for debug and reg dump. * Used for debug and reg dump.
*/ */
...@@ -3112,14 +3147,15 @@ static int ql_route_initialize(struct ql_adapter *qdev) ...@@ -3112,14 +3147,15 @@ static int ql_route_initialize(struct ql_adapter *qdev)
int ql_cam_route_initialize(struct ql_adapter *qdev) int ql_cam_route_initialize(struct ql_adapter *qdev)
{ {
int status; int status, set;
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); /* If check if the link is up and use to
if (status) * determine if we are setting or clearing
return status; * the MAC address in the CAM.
status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, */
MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); set = ql_read32(qdev, STS);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); set &= qdev->port_link_up;
status = ql_set_mac_addr(qdev, set);
if (status) { if (status) {
QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
return status; return status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment