forked from luck/tmp_suning_uos_patched
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: Ron Mercer <ron.mercer@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
13cfd5be53
commit
7fab3bfe08
|
@ -413,6 +413,41 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
|
|||
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.
|
||||
* Used for debug and reg dump.
|
||||
*/
|
||||
|
@ -3112,14 +3147,15 @@ static int ql_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 (status)
|
||||
return status;
|
||||
status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
|
||||
MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
|
||||
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
|
||||
/* If check if the link is up and use to
|
||||
* determine if we are setting or clearing
|
||||
* the MAC address in the CAM.
|
||||
*/
|
||||
set = ql_read32(qdev, STS);
|
||||
set &= qdev->port_link_up;
|
||||
status = ql_set_mac_addr(qdev, set);
|
||||
if (status) {
|
||||
QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
|
||||
return status;
|
||||
|
|
Loading…
Reference in New Issue
Block a user