static inline void nicvf_mbox_send_msg_to_pf_raw(struct nicvf *nic, struct nic_mbx *mbx) { uint64_t *mbx_data; uint64_t mbx_addr; int i; mbx_addr = NIC_VF_PF_MAILBOX_0_1; mbx_data = (uint64_t *)mbx; for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { nicvf_reg_write(nic, mbx_addr, *mbx_data); mbx_data++; mbx_addr += sizeof(uint64_t); } nicvf_mbox_log("msg sent %s (VF%d)", nicvf_mbox_msg_str(mbx->msg.msg), nic->vf_id); }
static int nicvf_set_rss_hash_opts(struct nicvf *nic, struct ethtool_rxnfc *info) { struct nicvf_rss_info *rss = &nic->rss_info; u64 rss_cfg = nicvf_reg_read(nic, NIC_VNIC_RSS_CFG); if (!rss->enable) netdev_err(nic->netdev, "RSS is disabled, hash cannot be set\n"); netdev_info(nic->netdev, "Set RSS flow type = %d, data = %lld\n", info->flow_type, info->data); if (!(info->data & RXH_IP_SRC) || !(info->data & RXH_IP_DST)) return -EINVAL; switch (info->flow_type) { case TCP_V4_FLOW: case TCP_V6_FLOW: switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: rss_cfg &= ~(1ULL << RSS_HASH_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): rss_cfg |= (1ULL << RSS_HASH_TCP); break; default: return -EINVAL; } break; case UDP_V4_FLOW: case UDP_V6_FLOW: switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: rss_cfg &= ~(1ULL << RSS_HASH_UDP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): rss_cfg |= (1ULL << RSS_HASH_UDP); break; default: return -EINVAL; } break; case SCTP_V4_FLOW: case SCTP_V6_FLOW: switch (info->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: rss_cfg &= ~(1ULL << RSS_HASH_L4ETC); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): rss_cfg |= (1ULL << RSS_HASH_L4ETC); break; default: return -EINVAL; } break; case IPV4_FLOW: case IPV6_FLOW: rss_cfg = RSS_HASH_IP; break; default: return -EINVAL; } nicvf_reg_write(nic, NIC_VNIC_RSS_CFG, rss_cfg); return 0; }
int nicvf_handle_mbx_intr(struct nicvf *nic) { struct nic_mbx mbx; uint64_t *mbx_data = (uint64_t *)&mbx; uint64_t mbx_addr = NIC_VF_PF_MAILBOX_0_1; size_t i; for (i = 0; i < NIC_PF_VF_MAILBOX_SIZE; i++) { *mbx_data = nicvf_reg_read(nic, mbx_addr); mbx_data++; mbx_addr += sizeof(uint64_t); } /* Overwrite the message so we won't receive it again */ nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1, 0x0); nicvf_mbox_log("msg received id=0x%hhx %s (VF%d)", mbx.msg.msg, nicvf_mbox_msg_str(mbx.msg.msg), nic->vf_id); switch (mbx.msg.msg) { case NIC_MBOX_MSG_READY: nic->vf_id = mbx.nic_cfg.vf_id & 0x7F; nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F; nic->node = mbx.nic_cfg.node_id; nic->sqs_mode = mbx.nic_cfg.sqs_mode; nic->loopback_supported = mbx.nic_cfg.loopback_supported; ether_addr_copy((struct ether_addr *)mbx.nic_cfg.mac_addr, (struct ether_addr *)nic->mac_addr); nic->pf_acked = true; break; case NIC_MBOX_MSG_ACK: nic->pf_acked = true; break; case NIC_MBOX_MSG_NACK: nic->pf_nacked = true; break; case NIC_MBOX_MSG_RSS_SIZE: nic->rss_info.rss_size = mbx.rss_size.ind_tbl_size; nic->pf_acked = true; break; case NIC_MBOX_MSG_BGX_LINK_CHANGE: nic->link_up = mbx.link_status.link_up; nic->duplex = mbx.link_status.duplex; nic->speed = mbx.link_status.speed; nic->pf_acked = true; break; case NIC_MBOX_MSG_ALLOC_SQS: assert_primary(nic); if (mbx.sqs_alloc.qs_count != nic->sqs_count) { nicvf_log_error("Received %" PRIu8 "/%" PRIu8 " secondary qsets", mbx.sqs_alloc.qs_count, nic->sqs_count); abort(); } for (i = 0; i < mbx.sqs_alloc.qs_count; i++) { if (mbx.sqs_alloc.svf[i] != nic->snicvf[i]->vf_id) { nicvf_log_error("Received secondary qset[%zu] " "ID %" PRIu8 " expected %" PRIu8, i, mbx.sqs_alloc.svf[i], nic->snicvf[i]->vf_id); abort(); } } nic->pf_acked = true; break; default: nicvf_log_error("Invalid message from PF, msg_id=0x%hhx %s", mbx.msg.msg, nicvf_mbox_msg_str(mbx.msg.msg)); break; } nicvf_smp_wmb(); return mbx.msg.msg; }
static void nicvf_if_init_locked(struct nicvf *nic) { struct queue_set *qs = nic->qs; struct ifnet *ifp; int qidx; int err; caddr_t if_addr; NICVF_CORE_LOCK_ASSERT(nic); ifp = nic->ifp; if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0) nicvf_stop_locked(nic); err = nicvf_enable_misc_interrupt(nic); if (err != 0) { if_printf(ifp, "Could not reenable Mbox interrupt\n"); return; } /* Get the latest MAC address */ if_addr = if_getlladdr(ifp); /* Update MAC address if changed */ if (memcmp(nic->hwaddr, if_addr, ETHER_ADDR_LEN) != 0) { memcpy(nic->hwaddr, if_addr, ETHER_ADDR_LEN); nicvf_hw_set_mac_addr(nic, if_addr); } /* Initialize the queues */ err = nicvf_init_resources(nic); if (err != 0) goto error; /* Make sure queue initialization is written */ wmb(); nicvf_reg_write(nic, NIC_VF_INT, ~0UL); /* Enable Qset err interrupt */ nicvf_enable_intr(nic, NICVF_INTR_QS_ERR, 0); /* Enable completion queue interrupt */ for (qidx = 0; qidx < qs->cq_cnt; qidx++) nicvf_enable_intr(nic, NICVF_INTR_CQ, qidx); /* Enable RBDR threshold interrupt */ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) nicvf_enable_intr(nic, NICVF_INTR_RBDR, qidx); nic->drv_stats.txq_stop = 0; nic->drv_stats.txq_wake = 0; /* Activate network interface */ if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE); /* Schedule callout to update stats */ callout_reset(&nic->stats_callout, hz, nicvf_tick_stats, nic); return; error: /* Something went very wrong. Disable this ifnet for good */ if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); }