/* Update hardware min/max frame size */ static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) { int bgx, lmac, lmac_cnt; u64 lmac_credits; if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) return 1; bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); lmac += bgx * MAX_LMAC_PER_BGX; new_frs += VLAN_ETH_HLEN + ETH_FCS_LEN + 4; /* Update corresponding LMAC credits */ lmac_cnt = bgx_get_lmac_count(nic->node, bgx); lmac_credits = nic_reg_read(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8)); lmac_credits &= ~(0xFFFFFULL << 12); lmac_credits |= (((((48 * 1024) / lmac_cnt) - new_frs) / 16) << 12); nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credits); /* Enforce MTU in HW * This config is supported only from 88xx pass 2.0 onwards. */ if (!pass1_silicon(nic->pdev)) nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG2 + (lmac * 8), new_frs); return 0; }
/* Function to check number of LMACs present and set VF::LMAC mapping. * Mapping will be used while initializing channels. */ static void nic_set_lmac_vf_mapping(struct nicpf *nic) { unsigned bgx_map = bgx_get_map(nic->node); int bgx, next_bgx_lmac = 0; int lmac, lmac_cnt = 0; u64 lmac_credit; nic->num_vf_en = 0; for (bgx = 0; bgx < NIC_MAX_BGX; bgx++) { if (!(bgx_map & (1 << bgx))) continue; lmac_cnt = bgx_get_lmac_count(nic->node, bgx); for (lmac = 0; lmac < lmac_cnt; lmac++) nic->vf_lmac_map[next_bgx_lmac++] = NIC_SET_VF_LMAC_MAP(bgx, lmac); nic->num_vf_en += lmac_cnt; /* Program LMAC credits */ lmac_credit = (1ull << 1); /* channel credit enable */ lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ lmac_credit |= (((((48 * 1024) / lmac_cnt) - NIC_HW_MAX_FRS) / 16) << 12); lmac = bgx * MAX_LMAC_PER_BGX; for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credit); } }
/* Set minimum transmit packet size */ static void nic_set_tx_pkt_pad(struct nicpf *nic, int size) { int lmac, max_lmac; u16 sdevid; u64 lmac_cfg; /* There is a issue in HW where-in while sending GSO sized * pkts as part of TSO, if pkt len falls below this size * NIC will zero PAD packet and also updates IP total length. * Hence set this value to lessthan min pkt size of MAC+IP+TCP * headers, BGX will do the padding to transmit 64 byte pkt. */ if (size > 52) size = 52; pci_read_config_word(nic->pdev, PCI_SUBSYSTEM_ID, &sdevid); /* 81xx's RGX has only one LMAC */ if (sdevid == PCI_SUBSYS_DEVID_81XX_NIC_PF) max_lmac = ((nic->hw->bgx_cnt - 1) * MAX_LMAC_PER_BGX) + 1; else max_lmac = nic->hw->bgx_cnt * MAX_LMAC_PER_BGX; for (lmac = 0; lmac < max_lmac; lmac++) { lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); lmac_cfg &= ~(0xF << 2); lmac_cfg |= ((size / 4) << 2); nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); } }
static void nic_init_hw(struct nicpf *nic) { int i; u64 cqm_cfg; /* Enable NIC HW block */ nic_reg_write(nic, NIC_PF_CFG, 0x3); /* Enable backpressure */ nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); /* Disable TNS mode on both interfaces */ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK); nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK); nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, (1ULL << 63) | BGX0_BLOCK); nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), (1ULL << 63) | BGX1_BLOCK); /* PKIND configuration */ nic->pkind.minlen = 0; nic->pkind.maxlen = NIC_HW_MAX_FRS + ETH_HLEN; nic->pkind.lenerr_en = 1; nic->pkind.rx_hdr = 0; nic->pkind.hdr_sl = 0; for (i = 0; i < NIC_MAX_PKIND; i++) nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), *(u64 *)&nic->pkind); nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); /* Timer config */ nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); /* Enable VLAN ethertype matching and stripping */ nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); /* Check if HW expected value is higher (could be in future chips) */ cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); }
/* Flush all in flight receive packets to memory and * bring down an active RQ */ static int nic_rcv_queue_sw_sync(struct nicpf *nic) { u16 timeout = ~0x00; nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x01); /* Wait till sync cycle is finished */ while (timeout) { if (nic_reg_read(nic, NIC_PF_SW_SYNC_RX_DONE) & 0x1) break; timeout--; } nic_reg_write(nic, NIC_PF_SW_SYNC_RX, 0x00); if (!timeout) { dev_err(&nic->pdev->dev, "Receive queue software sync failed"); return 1; } return 0; }
/* PF -> VF mailbox communication APIs */ static void nic_enable_mbx_intr(struct nicpf *nic) { int vf_cnt = pci_sriov_get_totalvfs(nic->pdev); #define INTR_MASK(vfs) ((vfs < 64) ? (BIT_ULL(vfs) - 1) : (~0ull)) /* Clear it, to avoid spurious interrupts (if any) */ nic_reg_write(nic, NIC_PF_MAILBOX_INT, INTR_MASK(vf_cnt)); /* Enable mailbox interrupt for all VFs */ nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, INTR_MASK(vf_cnt)); /* One mailbox intr enable reg per 64 VFs */ if (vf_cnt > 64) { nic_reg_write(nic, NIC_PF_MAILBOX_INT + sizeof(u64), INTR_MASK(vf_cnt - 64)); nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), INTR_MASK(vf_cnt - 64)); } }
/* Set minimum transmit packet size */ static void nic_set_tx_pkt_pad(struct nicpf *nic, int size) { int lmac; u64 lmac_cfg; /* Max value that can be set is 60 */ if (size > 60) size = 60; for (lmac = 0; lmac < (MAX_BGX_PER_CN88XX * MAX_LMAC_PER_BGX); lmac++) { lmac_cfg = nic_reg_read(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3)); lmac_cfg &= ~(0xF << 2); lmac_cfg |= ((size / 4) << 2); nic_reg_write(nic, NIC_PF_LMAC_0_7_CFG | (lmac << 3), lmac_cfg); } }
/* Update hardware min/max frame size */ static int nic_update_hw_frs(struct nicpf *nic, int new_frs, int vf) { if ((new_frs > NIC_HW_MAX_FRS) || (new_frs < NIC_HW_MIN_FRS)) { dev_err(&nic->pdev->dev, "Invalid MTU setting from VF%d rejected, should be between %d and %d\n", vf, NIC_HW_MIN_FRS, NIC_HW_MAX_FRS); return 1; } new_frs += ETH_HLEN; if (new_frs <= nic->pkind.maxlen) return 0; nic->pkind.maxlen = new_frs; nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG, *(u64 *)&nic->pkind); return 0; }
/* Function to check number of LMACs present and set VF::LMAC mapping. * Mapping will be used while initializing channels. */ static void nic_set_lmac_vf_mapping(struct nicpf *nic) { unsigned bgx_map = bgx_get_map(nic->node); int bgx, next_bgx_lmac = 0; int lmac, lmac_cnt = 0; u64 lmac_credit; nic->num_vf_en = 0; for (bgx = 0; bgx < nic->hw->bgx_cnt; bgx++) { if (!(bgx_map & (1 << bgx))) continue; lmac_cnt = bgx_get_lmac_count(nic->node, bgx); for (lmac = 0; lmac < lmac_cnt; lmac++) nic->vf_lmac_map[next_bgx_lmac++] = NIC_SET_VF_LMAC_MAP(bgx, lmac); nic->num_vf_en += lmac_cnt; /* Program LMAC credits */ lmac_credit = (1ull << 1); /* channel credit enable */ lmac_credit |= (0x1ff << 2); /* Max outstanding pkt count */ /* 48KB BGX Tx buffer size, each unit is of size 16bytes */ lmac_credit |= (((((48 * 1024) / lmac_cnt) - NIC_HW_MAX_FRS) / 16) << 12); lmac = bgx * MAX_LMAC_PER_BGX; for (; lmac < lmac_cnt + (bgx * MAX_LMAC_PER_BGX); lmac++) nic_reg_write(nic, NIC_PF_LMAC_0_7_CREDIT + (lmac * 8), lmac_credit); /* On CN81XX there are only 8 VFs but max possible no of * interfaces are 9. */ if (nic->num_vf_en >= pci_sriov_get_totalvfs(nic->pdev)) { nic->num_vf_en = pci_sriov_get_totalvfs(nic->pdev); break; } } }
/* PF -> VF mailbox communication APIs */ static void nic_enable_mbx_intr(struct nicpf *nic) { /* Enable mailbox interrupt for all 128 VFs */ nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S, ~0ull); nic_reg_write(nic, NIC_PF_MAILBOX_ENA_W1S + sizeof(u64), ~0ull); }
/* Channel parse index configuration */ static void nic_config_cpi(struct nicpf *nic, struct cpi_cfg_msg *cfg) { u32 vnic, bgx, lmac, chan; u32 padd, cpi_count = 0; u64 cpi_base, cpi, rssi_base, rssi; u8 qset, rq_idx = 0; vnic = cfg->vf_id; bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); chan = (lmac * MAX_BGX_CHANS_PER_LMAC) + (bgx * NIC_CHANS_PER_INF); cpi_base = (lmac * NIC_MAX_CPI_PER_LMAC) + (bgx * NIC_CPI_PER_BGX); rssi_base = (lmac * nic->rss_ind_tbl_size) + (bgx * NIC_RSSI_PER_BGX); /* Rx channel configuration */ nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_BP_CFG | (chan << 3), (1ull << 63) | (vnic << 0)); nic_reg_write(nic, NIC_PF_CHAN_0_255_RX_CFG | (chan << 3), ((u64)cfg->cpi_alg << 62) | (cpi_base << 48)); if (cfg->cpi_alg == CPI_ALG_NONE) cpi_count = 1; else if (cfg->cpi_alg == CPI_ALG_VLAN) /* 3 bits of PCP */ cpi_count = 8; else if (cfg->cpi_alg == CPI_ALG_VLAN16) /* 3 bits PCP + DEI */ cpi_count = 16; else if (cfg->cpi_alg == CPI_ALG_DIFF) /* 6bits DSCP */ cpi_count = NIC_MAX_CPI_PER_LMAC; /* RSS Qset, Qidx mapping */ qset = cfg->vf_id; rssi = rssi_base; for (; rssi < (rssi_base + cfg->rq_cnt); rssi++) { nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), (qset << 3) | rq_idx); rq_idx++; } rssi = 0; cpi = cpi_base; for (; cpi < (cpi_base + cpi_count); cpi++) { /* Determine port to channel adder */ if (cfg->cpi_alg != CPI_ALG_DIFF) padd = cpi % cpi_count; else padd = cpi % 8; /* 3 bits CS out of 6bits DSCP */ /* Leave RSS_SIZE as '0' to disable RSS */ if (pass1_silicon(nic)) { nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), (vnic << 24) | (padd << 16) | (rssi_base + rssi)); } else { /* Set MPI_ALG to '0' to disable MCAM parsing */ nic_reg_write(nic, NIC_PF_CPI_0_2047_CFG | (cpi << 3), (padd << 16)); /* MPI index is same as CPI if MPI_ALG is not enabled */ nic_reg_write(nic, NIC_PF_MPI_0_2047_CFG | (cpi << 3), (vnic << 24) | (rssi_base + rssi)); } if ((rssi + 1) >= cfg->rq_cnt) continue; if (cfg->cpi_alg == CPI_ALG_VLAN) rssi++; else if (cfg->cpi_alg == CPI_ALG_VLAN16) rssi = ((cpi - cpi_base) & 0xe) >> 1; else if (cfg->cpi_alg == CPI_ALG_DIFF) rssi = ((cpi - cpi_base) & 0x38) >> 3; }
static void nic_clear_mbx_intr(struct nicpf *nic, int vf, int mbx_reg) { nic_reg_write(nic, NIC_PF_MAILBOX_INT + (mbx_reg << 3), BIT_ULL(vf)); }
static void nic_init_hw(struct nicpf *nic) { int i; u64 cqm_cfg; /* Enable NIC HW block */ nic_reg_write(nic, NIC_PF_CFG, 0x3); /* Enable backpressure */ nic_reg_write(nic, NIC_PF_BP_CFG, (1ULL << 6) | 0x03); /* TNS and TNS bypass modes are present only on 88xx * Also offset of this CSR has changed in 81xx and 83xx. */ if (nic->pdev->subsystem_device == PCI_SUBSYS_DEVID_88XX_NIC_PF) { /* Disable TNS mode on both interfaces */ nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG, (NIC_TNS_BYPASS_MODE << 7) | BGX0_BLOCK | (1ULL << 16)); nic_reg_write(nic, NIC_PF_INTF_0_1_SEND_CFG | (1 << 8), (NIC_TNS_BYPASS_MODE << 7) | BGX1_BLOCK | (1ULL << 16)); } else { /* Configure timestamp generation timeout to 10us */ for (i = 0; i < nic->hw->bgx_cnt; i++) nic_reg_write(nic, NIC_PF_INTFX_SEND_CFG | (i << 3), (1ULL << 16)); } nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG, (1ULL << 63) | BGX0_BLOCK); nic_reg_write(nic, NIC_PF_INTF_0_1_BP_CFG + (1 << 8), (1ULL << 63) | BGX1_BLOCK); /* PKIND configuration */ nic->pkind.minlen = 0; nic->pkind.maxlen = NIC_HW_MAX_FRS + VLAN_ETH_HLEN + ETH_FCS_LEN + 4; nic->pkind.lenerr_en = 1; nic->pkind.rx_hdr = 0; nic->pkind.hdr_sl = 0; for (i = 0; i < NIC_MAX_PKIND; i++) nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (i << 3), *(u64 *)&nic->pkind); nic_set_tx_pkt_pad(nic, NIC_HW_MIN_FRS); /* Timer config */ nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); /* Enable VLAN ethertype matching and stripping */ nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); /* Check if HW expected value is higher (could be in future chips) */ cqm_cfg = nic_reg_read(nic, NIC_PF_CQM_CFG); if (cqm_cfg < NICPF_CQM_MIN_DROP_LEVEL) nic_reg_write(nic, NIC_PF_CQM_CFG, NICPF_CQM_MIN_DROP_LEVEL); }