From: Michal Schmidt <mschmidt@redhat.com> Date: Fri, 3 Sep 2010 00:19:20 -0400 Subject: [net] vxge: fix multicast issues Message-id: <20100903001919.16045.85973.stgit@localhost6.localdomain6> Patchwork-id: 28056 O-Subject: [RHEL5.6 BZ608598 PATCH 15/15] vxge: Fix multicast issues Bugzilla: 608598 RH-Acked-by: David S. Miller <davem@redhat.com> RH-Acked-by: Bob Picco <bpicco@redhat.com> RH-Acked-by: Neil Horman <nhorman@redhat.com> Fix error in multicast flag check, add calls to restore the status of multicast and promiscuous mode settings after change_mtu, and style cleanups to shorten the function calls by using a temporary variable. Signed-off-by: Jon Mason <jon.mason@exar.com> Signed-off-by: Sreenivasa Honnur <sreenivasa.honnur@exar.com> Signed-off-by: Ramkrishna Vepa <ramkrishna.vepa@exar.com> Signed-off-by: David S. Miller <davem@davemloft.net> (cherry picked from commit 7adf7d1b0d50075e252aa82505fb473af38c3f20) Conflicts: drivers/net/vxge/vxge-main.c diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b5d4325..58d18e3 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -1116,7 +1116,8 @@ static void vxge_set_multicast(struct net_device *dev) struct dev_mc_list *mclist; struct vxgedev *vdev; int i, mcast_cnt = 0; - struct __vxge_hw_device *hldev; + struct __vxge_hw_device *hldev; + struct vxge_vpath *vpath; enum vxge_hw_status status = VXGE_HW_OK; struct macInfo mac_info; int vpath_idx = 0; @@ -1136,46 +1137,48 @@ static void vxge_set_multicast(struct net_device *dev) if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) { for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_open); - status = vxge_hw_vpath_mcast_enable( - vdev->vpaths[i].handle); + vpath = &vdev->vpaths[i]; + vxge_assert(vpath->is_open); + status = vxge_hw_vpath_mcast_enable(vpath->handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, "failed to enable " + "multicast, status %d", status); vdev->all_multi_flg = 1; } - } else if ((dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) { + } else if (!(dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) { for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_open); - status = vxge_hw_vpath_mcast_disable( - vdev->vpaths[i].handle); - vdev->all_multi_flg = 1; + vpath = &vdev->vpaths[i]; + vxge_assert(vpath->is_open); + status = vxge_hw_vpath_mcast_disable(vpath->handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, "failed to disable " + "multicast, status %d", status); + vdev->all_multi_flg = 0; } } - if (status != VXGE_HW_OK) - vxge_debug_init(VXGE_ERR, - "failed to %s multicast, status %d", - dev->flags & IFF_ALLMULTI ? - "enable" : "disable", status); if (!vdev->config.addr_learn_en) { - if (dev->flags & IFF_PROMISC) { - for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_open); + for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; + vxge_assert(vpath->is_open); + + if (dev->flags & IFF_PROMISC) status = vxge_hw_vpath_promisc_enable( - vdev->vpaths[i].handle); - } - } else { - for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_open); + vpath->handle); + else status = vxge_hw_vpath_promisc_disable( - vdev->vpaths[i].handle); - } + vpath->handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, "failed to %s promisc" + ", status %d", dev->flags&IFF_PROMISC ? + "enable" : "disable", status); } } memset(&mac_info, 0, sizeof(struct macInfo)); /* Update individual M_CAST address list */ if ((!vdev->all_multi_flg) && dev->mc_count) { - mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; list_head = &vdev->vpaths[0].mac_addr_list; if ((dev->mc_count + @@ -1185,14 +1188,7 @@ static void vxge_set_multicast(struct net_device *dev) /* Delete previous MC's */ for (i = 0; i < mcast_cnt; i++) { - if (!list_empty(list_head)) - mac_entry = (struct vxge_mac_addrs *) - list_first_entry(list_head, - struct vxge_mac_addrs, - item); - list_for_each_safe(entry, next, list_head) { - mac_entry = (struct vxge_mac_addrs *) entry; /* Copy the mac address to delete */ mac_address = (u8 *)&mac_entry->macaddr; @@ -1237,9 +1233,7 @@ _set_all_mcast: mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; /* Delete previous MC's */ for (i = 0; i < mcast_cnt; i++) { - list_for_each_safe(entry, next, list_head) { - mac_entry = (struct vxge_mac_addrs *) entry; /* Copy the mac address to delete */ mac_address = (u8 *)&mac_entry->macaddr; @@ -1259,9 +1253,10 @@ _set_all_mcast: /* Enable all multicast */ for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_open); - status = vxge_hw_vpath_mcast_enable( - vdev->vpaths[i].handle); + vpath = &vdev->vpaths[i]; + vxge_assert(vpath->is_open); + + status = vxge_hw_vpath_mcast_enable(vpath->handle); if (status != VXGE_HW_OK) { vxge_debug_init(VXGE_ERR, "%s:%d Enabling all multicasts failed", @@ -1422,6 +1417,7 @@ void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id) static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) { enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; int ret = 0; /* check if device is down already */ @@ -1432,12 +1428,10 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) return 0; - if (vdev->vpaths[vp_id].handle) { - if (vxge_hw_vpath_reset(vdev->vpaths[vp_id].handle) - == VXGE_HW_OK) { + if (vpath->handle) { + if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) { if (is_vxge_card_up(vdev) && - vxge_hw_vpath_recover_from_reset( - vdev->vpaths[vp_id].handle) + vxge_hw_vpath_recover_from_reset(vpath->handle) != VXGE_HW_OK) { vxge_debug_init(VXGE_ERR, "vxge_hw_vpath_recover_from_reset" @@ -1453,11 +1447,20 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) } else return VXGE_HW_FAIL; - vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]); - vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]); + vxge_restore_vpath_mac_addr(vpath); + vxge_restore_vpath_vid_table(vpath); /* Enable all broadcast */ - vxge_hw_vpath_bcast_enable(vdev->vpaths[vp_id].handle); + vxge_hw_vpath_bcast_enable(vpath->handle); + + /* Enable all multicast */ + if (vdev->all_multi_flg) { + status = vxge_hw_vpath_mcast_enable(vpath->handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, + "%s:%d Enabling multicast failed", + __func__, __LINE__); + } /* Enable the interrupts */ vxge_vpath_intr_enable(vdev, vp_id); @@ -1465,17 +1468,17 @@ static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) smp_wmb(); /* Enable the flow of traffic through the vpath */ - vxge_hw_vpath_enable(vdev->vpaths[vp_id].handle); + vxge_hw_vpath_enable(vpath->handle); smp_wmb(); - vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[vp_id].handle); - vdev->vpaths[vp_id].ring.last_status = VXGE_HW_OK; + vxge_hw_vpath_rx_doorbell_init(vpath->handle); + vpath->ring.last_status = VXGE_HW_OK; /* Vpath reset done */ clear_bit(vp_id, &vdev->vp_reset); /* Start the vpath queue */ - vxge_wake_tx_queue(&vdev->vpaths[vp_id].fifo, NULL); + vxge_wake_tx_queue(&vpath->fifo, NULL); return ret; } @@ -1509,9 +1512,9 @@ static int do_vxge_reset(struct vxgedev *vdev, int event) vxge_debug_init(VXGE_ERR, "%s: execution mode is debug, returning..", vdev->ndev->name); - clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); - vxge_stop_all_tx_queue(vdev); - return 0; + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + vxge_stop_all_tx_queue(vdev); + return 0; } } @@ -1658,8 +1661,7 @@ out: */ int vxge_reset(struct vxgedev *vdev) { - do_vxge_reset(vdev, VXGE_LL_FULL_RESET); - return 0; + return do_vxge_reset(vdev, VXGE_LL_FULL_RESET); } /** @@ -2057,17 +2059,17 @@ enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath) /* reset vpaths */ enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) { - int i; enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath; + int i; - for (i = 0; i < vdev->no_of_vpath; i++) - if (vdev->vpaths[i].handle) { - if (vxge_hw_vpath_reset(vdev->vpaths[i].handle) - == VXGE_HW_OK) { + for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; + if (vpath->handle) { + if (vxge_hw_vpath_reset(vpath->handle) == VXGE_HW_OK) { if (is_vxge_card_up(vdev) && vxge_hw_vpath_recover_from_reset( - vdev->vpaths[i].handle) - != VXGE_HW_OK) { + vpath->handle) != VXGE_HW_OK) { vxge_debug_init(VXGE_ERR, "vxge_hw_vpath_recover_" "from_reset failed for vpath: " @@ -2081,83 +2083,87 @@ enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) return status; } } + } + return status; } /* close vpaths */ void vxge_close_vpaths(struct vxgedev *vdev, int index) { + struct vxge_vpath *vpath; int i; + for (i = index; i < vdev->no_of_vpath; i++) { - if (vdev->vpaths[i].handle && vdev->vpaths[i].is_open) { - vxge_hw_vpath_close(vdev->vpaths[i].handle); + vpath = &vdev->vpaths[i]; + + if (vpath->handle && vpath->is_open) { + vxge_hw_vpath_close(vpath->handle); vdev->stats.vpaths_open--; } - vdev->vpaths[i].is_open = 0; - vdev->vpaths[i].handle = NULL; + vpath->is_open = 0; + vpath->handle = NULL; } } /* open vpaths */ int vxge_open_vpaths(struct vxgedev *vdev) { + struct vxge_hw_vpath_attr attr; enum vxge_hw_status status; - int i; + struct vxge_vpath *vpath; u32 vp_id = 0; - struct vxge_hw_vpath_attr attr; + int i; for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_assert(vdev->vpaths[i].is_configured); - attr.vp_id = vdev->vpaths[i].device_id; + vpath = &vdev->vpaths[i]; + + vxge_assert(vpath->is_configured); + attr.vp_id = vpath->device_id; attr.fifo_attr.callback = vxge_xmit_compl; attr.fifo_attr.txdl_term = vxge_tx_term; attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv); - attr.fifo_attr.userdata = (void *)&vdev->vpaths[i].fifo; + attr.fifo_attr.userdata = &vpath->fifo; attr.ring_attr.callback = vxge_rx_1b_compl; attr.ring_attr.rxd_init = vxge_rx_initial_replenish; attr.ring_attr.rxd_term = vxge_rx_term; attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv); - attr.ring_attr.userdata = (void *)&vdev->vpaths[i].ring; + attr.ring_attr.userdata = &vpath->ring; - vdev->vpaths[i].ring.ndev = vdev->ndev; - vdev->vpaths[i].ring.pdev = vdev->pdev; - status = vxge_hw_vpath_open(vdev->devh, &attr, - &(vdev->vpaths[i].handle)); + vpath->ring.ndev = vdev->ndev; + vpath->ring.pdev = vdev->pdev; + status = vxge_hw_vpath_open(vdev->devh, &attr, &vpath->handle); if (status == VXGE_HW_OK) { - vdev->vpaths[i].fifo.handle = + vpath->fifo.handle = (struct __vxge_hw_fifo *)attr.fifo_attr.userdata; - vdev->vpaths[i].ring.handle = + vpath->ring.handle = (struct __vxge_hw_ring *)attr.ring_attr.userdata; - vdev->vpaths[i].fifo.tx_steering_type = + vpath->fifo.tx_steering_type = vdev->config.tx_steering_type; - vdev->vpaths[i].fifo.ndev = vdev->ndev; - vdev->vpaths[i].fifo.pdev = vdev->pdev; - vdev->vpaths[i].fifo.indicate_max_pkts = + vpath->fifo.ndev = vdev->ndev; + vpath->fifo.pdev = vdev->pdev; + vpath->fifo.indicate_max_pkts = vdev->config.fifo_indicate_max_pkts; - vdev->vpaths[i].ring.rx_vector_no = 0; - vdev->vpaths[i].ring.rx_csum = vdev->rx_csum; - vdev->vpaths[i].is_open = 1; - vdev->vp_handles[i] = vdev->vpaths[i].handle; - vdev->vpaths[i].ring.gro_enable = - vdev->config.gro_enable; - vdev->vpaths[i].ring.vlan_tag_strip = - vdev->vlan_tag_strip; + vpath->ring.rx_vector_no = 0; + vpath->ring.rx_csum = vdev->rx_csum; + vpath->is_open = 1; + vdev->vp_handles[i] = vpath->handle; + vpath->ring.gro_enable = vdev->config.gro_enable; + vpath->ring.vlan_tag_strip = vdev->vlan_tag_strip; vdev->stats.vpaths_open++; } else { vdev->stats.vpath_open_fail++; vxge_debug_init(VXGE_ERR, "%s: vpath: %d failed to open " "with status: %d", - vdev->ndev->name, vdev->vpaths[i].device_id, + vdev->ndev->name, vpath->device_id, status); vxge_close_vpaths(vdev, 0); return -EPERM; } - vp_id = - ((struct __vxge_hw_vpath_handle *)vdev->vpaths[i].handle)-> - vpath->vp_id; + vp_id = vpath->handle->vpath->vp_id; vdev->vpaths_deployed |= vxge_mBIT(vp_id); } return VXGE_HW_OK; @@ -2331,7 +2337,6 @@ start: vdev->vxge_entries[j].in_use = 0; ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt); - if (ret > 0) { vxge_debug_init(VXGE_ERR, "%s: MSI-X enable failed for %d vectors, ret: %d", @@ -2377,17 +2382,16 @@ static int vxge_enable_msix(struct vxgedev *vdev) ret = vxge_alloc_msix(vdev); if (!ret) { for (i = 0; i < vdev->no_of_vpath; i++) { + struct vxge_vpath *vpath = &vdev->vpaths[i]; - /* If fifo or ring are not enabled - the MSIX vector for that should be set to 0 - Hence initializeing this array to all 0s. - */ - vdev->vpaths[i].ring.rx_vector_no = - (vdev->vpaths[i].device_id * - VXGE_HW_VPATH_MSIX_ACTIVE) + 1; + /* If fifo or ring are not enabled, the MSIX vector for + * it should be set to 0. + */ + vpath->ring.rx_vector_no = (vpath->device_id * + VXGE_HW_VPATH_MSIX_ACTIVE) + 1; - vxge_hw_vpath_msix_set(vdev->vpaths[i].handle, - tim_msix_id, VXGE_ALARM_MSIX_ID); + vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id, + VXGE_ALARM_MSIX_ID); } } @@ -2602,9 +2606,10 @@ static void vxge_poll_vp_reset(unsigned long data) static void vxge_poll_vp_lockup(unsigned long data) { struct vxgedev *vdev = (struct vxgedev *)data; - int i; - struct vxge_ring *ring; enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath; + struct vxge_ring *ring; + int i; for (i = 0; i < vdev->no_of_vpath; i++) { ring = &vdev->vpaths[i].ring; @@ -2618,13 +2623,13 @@ static void vxge_poll_vp_lockup(unsigned long data) /* schedule vpath reset */ if (!test_and_set_bit(i, &vdev->vp_reset)) { + vpath = &vdev->vpaths[i]; /* disable interrupts for this vpath */ vxge_vpath_intr_disable(vdev, i); /* stop the queue for this vpath */ - vxge_stop_tx_queue(&vdev->vpaths[i]. - fifo); + vxge_stop_tx_queue(&vpath->fifo); continue; } } @@ -2669,6 +2674,7 @@ vxge_open(struct net_device *dev) enum vxge_hw_status status; struct vxgedev *vdev; struct __vxge_hw_device *hldev; + struct vxge_vpath *vpath; int ret = 0; int i; u64 val64, function_mode; @@ -2717,24 +2723,26 @@ vxge_open(struct net_device *dev) set_bit(__LINK_STATE_START, &napi_nd->state); vdev->napi.dev = napi_nd; netif_poll_enable(napi_nd); - for (i = 0; i < vdev->no_of_vpath; i++) - vdev->vpaths[i].ring.napi_p = &vdev->napi; + for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; + vpath->ring.napi_p = &vdev->napi; + } } else { for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; napi_nd = alloc_netdev(0, "", ether_setup); if (!napi_nd) { ret = -ENOMEM; goto out3; } - napi_nd->priv = &vdev->vpaths[i].ring; + napi_nd->priv = &vpath->ring; napi_nd->weight = vdev->config.napi_weight; napi_nd->poll = rhel_vxge_poll_msix; set_bit(__LINK_STATE_START, &napi_nd->state); - vdev->vpaths[i].ring.napi.dev = napi_nd; + vpath->ring.napi.dev = napi_nd; netif_poll_enable(napi_nd); - vdev->vpaths[i].ring.napi_p = - &vdev->vpaths[i].ring.napi; + vpath->ring.napi_p = &vpath->ring.napi; } } @@ -2751,9 +2759,10 @@ vxge_open(struct net_device *dev) } for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; + /* set initial mtu before enabling the device */ - status = vxge_hw_vpath_mtu_set(vdev->vpaths[i].handle, - vdev->mtu); + status = vxge_hw_vpath_mtu_set(vpath->handle, vdev->mtu); if (status != VXGE_HW_OK) { vxge_debug_init(VXGE_ERR, "%s: fatal: can not set new MTU", dev->name); @@ -2767,10 +2776,21 @@ vxge_open(struct net_device *dev) "%s: MTU is %d", vdev->ndev->name, vdev->mtu); VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev); - /* Reprogram the DA table with populated mac addresses */ - for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_restore_vpath_mac_addr(&vdev->vpaths[i]); - vxge_restore_vpath_vid_table(&vdev->vpaths[i]); + /* Restore the DA, VID table and also multicast and promiscuous mode + * states + */ + if (vdev->all_multi_flg) { + for (i = 0; i < vdev->no_of_vpath; i++) { + vpath = &vdev->vpaths[i]; + vxge_restore_vpath_mac_addr(vpath); + vxge_restore_vpath_vid_table(vpath); + + status = vxge_hw_vpath_mcast_enable(vpath->handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, + "%s:%d Enabling multicast failed", + __func__, __LINE__); + } } /* Enable vpath to sniff all unicast/multicast traffic that not @@ -2799,14 +2819,14 @@ vxge_open(struct net_device *dev) /* Enabling Bcast and mcast for all vpath */ for (i = 0; i < vdev->no_of_vpath; i++) { - status = vxge_hw_vpath_bcast_enable(vdev->vpaths[i].handle); + vpath = &vdev->vpaths[i]; + status = vxge_hw_vpath_bcast_enable(vpath->handle); if (status != VXGE_HW_OK) vxge_debug_init(VXGE_ERR, "%s : Can not enable bcast for vpath " "id %d", dev->name, i); if (vdev->config.addr_learn_en) { - status = - vxge_hw_vpath_mcast_enable(vdev->vpaths[i].handle); + status = vxge_hw_vpath_mcast_enable(vpath->handle); if (status != VXGE_HW_OK) vxge_debug_init(VXGE_ERR, "%s : Can not enable mcast for vpath " @@ -2841,9 +2861,11 @@ vxge_open(struct net_device *dev) smp_wmb(); for (i = 0; i < vdev->no_of_vpath; i++) { - vxge_hw_vpath_enable(vdev->vpaths[i].handle); + vpath = &vdev->vpaths[i]; + + vxge_hw_vpath_enable(vpath->handle); smp_wmb(); - vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle); + vxge_hw_vpath_rx_doorbell_init(vpath->handle); } vxge_start_all_tx_queue(vdev);