1 // SPDX-License-Identifier: GPL-2.0 2 /* Marvell CN10K RPM driver 3 * 4 * Copyright (C) 2020 Marvell. 5 * 6 */ 7 8 #include "cgx.h" 9 #include "lmac_common.h" 10 11 static struct mac_ops rpm_mac_ops = { 12 .name = "rpm", 13 .csr_offset = 0x4e00, 14 .lmac_offset = 20, 15 .int_register = RPMX_CMRX_SW_INT, 16 .int_set_reg = RPMX_CMRX_SW_INT_ENA_W1S, 17 .irq_offset = 1, 18 .int_ena_bit = BIT_ULL(0), 19 .lmac_fwi = RPM_LMAC_FWI, 20 .non_contiguous_serdes_lane = true, 21 .rx_stats_cnt = 43, 22 .tx_stats_cnt = 34, 23 .get_nr_lmacs = rpm_get_nr_lmacs, 24 .get_lmac_type = rpm_get_lmac_type, 25 .mac_lmac_intl_lbk = rpm_lmac_internal_loopback, 26 .mac_get_rx_stats = rpm_get_rx_stats, 27 .mac_get_tx_stats = rpm_get_tx_stats, 28 .mac_enadis_rx_pause_fwding = rpm_lmac_enadis_rx_pause_fwding, 29 .mac_get_pause_frm_status = rpm_lmac_get_pause_frm_status, 30 .mac_enadis_pause_frm = rpm_lmac_enadis_pause_frm, 31 .mac_pause_frm_config = rpm_lmac_pause_frm_config, 32 .mac_enadis_ptp_config = rpm_lmac_ptp_config, 33 }; 34 35 struct mac_ops *rpm_get_mac_ops(void) 36 { 37 return &rpm_mac_ops; 38 } 39 40 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val) 41 { 42 cgx_write(rpm, lmac, offset, val); 43 } 44 45 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset) 46 { 47 return cgx_read(rpm, lmac, offset); 48 } 49 50 int rpm_get_nr_lmacs(void *rpmd) 51 { 52 rpm_t *rpm = rpmd; 53 54 return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL); 55 } 56 57 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable) 58 { 59 rpm_t *rpm = rpmd; 60 u64 cfg; 61 62 if (!rpm) 63 return; 64 65 if (enable) { 66 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 67 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 68 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 69 } else { 70 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 71 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 72 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 73 } 74 } 75 76 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id, 77 u8 *tx_pause, u8 *rx_pause) 78 { 79 rpm_t *rpm = rpmd; 80 u64 cfg; 81 82 if (!is_lmac_valid(rpm, lmac_id)) 83 return -ENODEV; 84 85 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 86 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE); 87 88 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 89 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE); 90 return 0; 91 } 92 93 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause, 94 u8 rx_pause) 95 { 96 rpm_t *rpm = rpmd; 97 u64 cfg; 98 99 if (!is_lmac_valid(rpm, lmac_id)) 100 return -ENODEV; 101 102 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 103 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 104 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 105 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 106 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 107 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 108 109 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 110 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 111 cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 112 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 113 114 cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP); 115 if (tx_pause) { 116 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id); 117 } else { 118 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id); 119 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id); 120 } 121 rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg); 122 return 0; 123 } 124 125 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) 126 { 127 rpm_t *rpm = rpmd; 128 u64 cfg; 129 130 if (enable) { 131 /* Enable 802.3 pause frame mode */ 132 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 133 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; 134 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 135 136 /* Enable receive pause frames */ 137 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 138 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 139 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 140 141 /* Enable forward pause to TX block */ 142 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 143 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 144 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 145 146 /* Enable pause frames transmission */ 147 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 148 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 149 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 150 151 /* Set pause time and interval */ 152 cfg = rpm_read(rpm, lmac_id, 153 RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA); 154 cfg &= ~0xFFFFULL; 155 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA, 156 cfg | RPM_DEFAULT_PAUSE_TIME); 157 /* Set pause interval as the hardware default is too short */ 158 cfg = rpm_read(rpm, lmac_id, 159 RPMX_MTI_MAC100X_CL01_QUANTA_THRESH); 160 cfg &= ~0xFFFFULL; 161 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_QUANTA_THRESH, 162 cfg | (RPM_DEFAULT_PAUSE_TIME / 2)); 163 164 } else { 165 /* ALL pause frames received are completely ignored */ 166 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 167 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 168 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 169 170 /* Disable forward pause to TX block */ 171 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 172 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 173 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 174 175 /* Disable pause frames transmission */ 176 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 177 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 178 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 179 } 180 } 181 182 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat) 183 { 184 rpm_t *rpm = rpmd; 185 u64 val_lo, val_hi; 186 187 if (!rpm || lmac_id >= rpm->lmac_count) 188 return -ENODEV; 189 190 mutex_lock(&rpm->lock); 191 192 /* Update idx to point per lmac Rx statistics page */ 193 idx += lmac_id * rpm->mac_ops->rx_stats_cnt; 194 195 /* Read lower 32 bits of counter */ 196 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX + 197 (idx * 8)); 198 199 /* upon read of lower 32 bits, higher 32 bits are written 200 * to RPMX_MTI_STAT_DATA_HI_CDC 201 */ 202 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 203 204 *rx_stat = (val_hi << 32 | val_lo); 205 206 mutex_unlock(&rpm->lock); 207 return 0; 208 } 209 210 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat) 211 { 212 rpm_t *rpm = rpmd; 213 u64 val_lo, val_hi; 214 215 if (!rpm || lmac_id >= rpm->lmac_count) 216 return -ENODEV; 217 218 mutex_lock(&rpm->lock); 219 220 /* Update idx to point per lmac Tx statistics page */ 221 idx += lmac_id * rpm->mac_ops->tx_stats_cnt; 222 223 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX + 224 (idx * 8)); 225 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 226 227 *tx_stat = (val_hi << 32 | val_lo); 228 229 mutex_unlock(&rpm->lock); 230 return 0; 231 } 232 233 u8 rpm_get_lmac_type(void *rpmd, int lmac_id) 234 { 235 rpm_t *rpm = rpmd; 236 u64 req = 0, resp; 237 int err; 238 239 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req); 240 err = cgx_fwi_cmd_generic(req, &resp, rpm, 0); 241 if (!err) 242 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp); 243 return err; 244 } 245 246 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable) 247 { 248 rpm_t *rpm = rpmd; 249 u8 lmac_type; 250 u64 cfg; 251 252 if (!rpm || lmac_id >= rpm->lmac_count) 253 return -ENODEV; 254 lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id); 255 if (lmac_type == LMAC_MODE_100G_R) { 256 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1); 257 258 if (enable) 259 cfg |= RPMX_MTI_PCS_LBK; 260 else 261 cfg &= ~RPMX_MTI_PCS_LBK; 262 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg); 263 } else { 264 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1); 265 if (enable) 266 cfg |= RPMX_MTI_PCS_LBK; 267 else 268 cfg &= ~RPMX_MTI_PCS_LBK; 269 rpm_write(rpm, lmac_id, RPMX_MTI_LPCSX_CONTROL1, cfg); 270 } 271 272 return 0; 273 } 274 275 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable) 276 { 277 rpm_t *rpm = rpmd; 278 u64 cfg; 279 280 if (!is_lmac_valid(rpm, lmac_id)) 281 return; 282 283 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG); 284 if (enable) 285 cfg |= RPMX_RX_TS_PREPEND; 286 else 287 cfg &= ~RPMX_RX_TS_PREPEND; 288 rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg); 289 } 290