int set_vid_knc(mic_ctx_t *mic_ctx, unsigned int vidcode) { uint32_t status = 0; sbox_svid_control svidctrl_regval = {0}; uint32_t svid_idle = 0; uint32_t svid_error = 0; int i = 0; uint32_t wait_cnt = 0; sbox_core_volt_t core_volt_regval = {0}; int retry = 0; if (mic_ctx->bi_stepping >= KNC_B0_STEP) { for (retry = 0; retry < SET_VID_RETRY_COUNT; retry++) { status = 0; for (i = 0; i < KNC_SETVID_ATTEMPTS; i++) { svidctrl_regval.value = pm_reg_read(mic_ctx,SBOX_SVID_CONTROL); svid_idle = svidctrl_regval.bits.svid_idle; if (svid_idle) { set_vid(mic_ctx, svidctrl_regval, vidcode); svidctrl_regval.value = pm_reg_read(mic_ctx,SBOX_SVID_CONTROL); svid_idle = svidctrl_regval.bits.svid_idle; svid_error = svidctrl_regval.bits.svid_error; if (!svid_idle) { printk(KERN_ERR "%s SVID command failed - Idle not set\n", __func__); msleep(10); continue; } if (svid_error) { if (SBOX_SVIDCTRL_ACK1ACK0(svidctrl_regval.value) == 0x2) { printk(KERN_ERR "%s SVID command failed - rx parity error\n", __func__); } else { printk(KERN_ERR "%s SVID command failed - tx parity error\n", __func__); } status = -EINVAL; goto exit; } else { PM_DEBUG("SVID Command Successful - VID set to %d\n",vidcode); break; } } } if (i == KNC_SETVID_ATTEMPTS) { printk(KERN_ERR "%s Timed out waiting for SVID idle\n", __func__); status = -EINVAL; goto exit; } /* Verify that the voltage is set */ for(wait_cnt = 0; wait_cnt <= 100; wait_cnt++) { core_volt_regval.value = pm_reg_read(mic_ctx, SBOX_COREVOLT); if(vidcode == core_volt_regval.bits.vid) { return status; } msleep(10); PM_DEBUG("Retry: %d Voltage not set yet. vidcode = 0x%x Current vid = 0x%x\n", retry, vidcode, core_volt_regval.bits.vid); } PM_PRINT("Retry: %d Failed to set vid for node %d. vid code = 0x%x Current vid = 0x%x.\n", retry, mic_get_scifnode_id(mic_ctx), vidcode, core_volt_regval.bits.vid); status = -ENODEV; } } else { set_vid(mic_ctx, svidctrl_regval, vidcode); /* SBOX_COREVOLT does not reflect the correct vid * value on A0. Just wait here for sometime to * allow for the vid to be set. */ msleep(20); } exit: return status; }
void nl_bridge::update_vlans(rtnl_link *old_link, rtnl_link *new_link) { assert(sw); assert(bridge); // already checked rtnl_link_bridge_vlan *old_br_vlan, *new_br_vlan; rtnl_link *_link; if (old_link == nullptr) { // link added old_br_vlan = &empty_br_vlan; new_br_vlan = rtnl_link_bridge_get_port_vlan(new_link); _link = nl->get_link(rtnl_link_get_ifindex(new_link), AF_UNSPEC); } else if (new_link == nullptr) { // link deleted old_br_vlan = rtnl_link_bridge_get_port_vlan(old_link); new_br_vlan = &empty_br_vlan; _link = nl->get_link(rtnl_link_get_ifindex(old_link), AF_UNSPEC); } else { // link updated old_br_vlan = rtnl_link_bridge_get_port_vlan(old_link); new_br_vlan = rtnl_link_bridge_get_port_vlan(new_link); _link = nl->get_link(rtnl_link_get_ifindex(new_link), AF_UNSPEC); } if (old_br_vlan == nullptr) { old_br_vlan = &empty_br_vlan; } if (new_br_vlan == nullptr) { new_br_vlan = &empty_br_vlan; } if (_link == nullptr) { // XXX FIXME in case a vxlan has been deleted the vxlan_domain and // vxlan_dom_bitmap need an update, maybe this can be handled already from // the link_deleted of the vxlan itself? LOG(WARNING) << __FUNCTION__ << ": could not get parent link of bridge interface. This " "case needs further checks if everything got already " "deleted."; return; } // check for vid changes if (br_vlan_equal(old_br_vlan, new_br_vlan)) { VLOG(2) << __FUNCTION__ << ": vlans did not change"; return; } link_type lt = get_link_type(_link); uint32_t pport_no = 0; uint32_t tunnel_id = -1; std::deque<rtnl_link *> bridge_ports; if (lt == LT_VXLAN) { assert(nl); nl->get_bridge_ports(rtnl_link_get_master(_link), &bridge_ports); if (vxlan->get_tunnel_id(_link, nullptr, &tunnel_id) != 0) { LOG(ERROR) << __FUNCTION__ << ": failed to get vni of link " << OBJ_CAST(_link); } } else { pport_no = nl->get_port_id(rtnl_link_get_ifindex(_link)); if (pport_no == 0) { LOG(ERROR) << __FUNCTION__ << ": invalid pport_no=0 of link: " << OBJ_CAST(_link); return; } } for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) { int base_bit; uint32_t a = old_br_vlan->vlan_bitmap[k]; uint32_t b = new_br_vlan->vlan_bitmap[k]; uint32_t vlan_diff = a ^ b; #if 0 // untagged change not yet implemented uint32_t c = old_br_vlan->untagged_bitmap[k]; uint32_t d = new_br_vlan->untagged_bitmap[k]; uint32_t untagged_diff = c ^ d; #endif // 0 base_bit = k * 32; int i = -1; int done = 0; while (!done) { int j = find_next_bit(i, vlan_diff); if (j > 0) { // vlan added or removed int vid = j - 1 + base_bit; bool egress_untagged = false; // check if egress is untagged if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) { egress_untagged = true; #if 0 // untagged change not yet implemented // clear untagged_diff bit untagged_diff &= ~((uint32_t)1 << (j - 1)); #endif // 0 } if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) { // vlan added if (lt == LT_VXLAN) { // update vxlan domain if (!is_vid_set(vid, vxlan_dom_bitmap)) { VLOG(1) << __FUNCTION__ << ": new vxlan domain vid=" << vid << ", tunnel_id=" << tunnel_id; vxlan_domain.emplace(vid, tunnel_id); set_vid(vid, vxlan_dom_bitmap); } else { // XXX TODO check the map } // update all bridge ports to be access ports update_access_ports(_link, new_link ? new_link : old_link, vid, tunnel_id, bridge_ports, true); } else { assert(pport_no); if (is_vid_set(vid, vxlan_dom_bitmap)) { // configure as access port std::string port_name = std::string(rtnl_link_get_name(_link)); auto vxd_it = vxlan_domain.find(vid); if (vxd_it != vxlan_domain.end()) { vxlan->create_access_port((new_link) ? new_link : old_link, vxd_it->second, port_name, pport_no, vid, egress_untagged, nullptr); } else { LOG(FATAL) << __FUNCTION__ << ": should not happen, something is broken"; } } else { // normal vlan port VLOG(3) << __FUNCTION__ << ": add vid=" << vid << " on pport_no=" << pport_no << " link: " << OBJ_CAST(_link); sw->egress_bridge_port_vlan_add(pport_no, vid, egress_untagged); sw->ingress_port_vlan_add(pport_no, vid, new_br_vlan->pvid == vid); } } } else { // vlan removed if (lt == LT_VXLAN) { unset_vid(vid, vxlan_dom_bitmap); vxlan_domain.erase(vid); // update all bridge ports to be normal bridge ports update_access_ports(_link, new_link ? new_link : old_link, vid, tunnel_id, bridge_ports, false); } else { VLOG(3) << __FUNCTION__ << ": remove vid=" << vid << " on pport_no=" << pport_no << " link: " << OBJ_CAST(_link); sw->ingress_port_vlan_remove(pport_no, vid, old_br_vlan->pvid == vid); // delete all FM pointing to this group first sw->l2_addr_remove_all_in_vlan(pport_no, vid); std::unique_ptr<rtnl_neigh, decltype(&rtnl_neigh_put)> filter( rtnl_neigh_alloc(), rtnl_neigh_put); rtnl_neigh_set_ifindex(filter.get(), rtnl_link_get_ifindex(bridge)); rtnl_neigh_set_master(filter.get(), rtnl_link_get_master(bridge)); rtnl_neigh_set_family(filter.get(), AF_BRIDGE); rtnl_neigh_set_vlan(filter.get(), vid); rtnl_neigh_set_flags(filter.get(), NTF_MASTER | NTF_EXT_LEARNED); rtnl_neigh_set_state(filter.get(), NUD_REACHABLE); nl_cache_foreach_filter(l2_cache.get(), OBJ_CAST(filter.get()), [](struct nl_object *o, void *arg) { VLOG(3) << "l2_cache remove object " << o; nl_cache_remove(o); }, nullptr); sw->egress_bridge_port_vlan_remove(pport_no, vid); } } i = j; } else { done = 1; } } #if 0 // not yet implemented the update done = 0; i = -1; while (!done) { // vlan is existing, but swapping egress tagged/untagged int j = find_next_bit(i, untagged_diff); if (j > 0) { // egress untagged changed int vid = j - 1 + base_bit; bool egress_untagged = false; // check if egress is untagged if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) { egress_untagged = true; } // XXX implement update fm_driver.update_port_vid_egress(devname, vid, egress_untagged); i = j; } else { done = 1; } } #endif } }