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 .mac_rx_tx_enable = rpm_lmac_rx_tx_enable, 34 .mac_tx_enable = rpm_lmac_tx_enable, 35 }; 36 37 struct mac_ops *rpm_get_mac_ops(void) 38 { 39 return &rpm_mac_ops; 40 } 41 42 static void rpm_write(rpm_t *rpm, u64 lmac, u64 offset, u64 val) 43 { 44 cgx_write(rpm, lmac, offset, val); 45 } 46 47 static u64 rpm_read(rpm_t *rpm, u64 lmac, u64 offset) 48 { 49 return cgx_read(rpm, lmac, offset); 50 } 51 52 int rpm_get_nr_lmacs(void *rpmd) 53 { 54 rpm_t *rpm = rpmd; 55 56 return hweight8(rpm_read(rpm, 0, CGXX_CMRX_RX_LMACS) & 0xFULL); 57 } 58 59 int rpm_lmac_tx_enable(void *rpmd, int lmac_id, bool enable) 60 { 61 rpm_t *rpm = rpmd; 62 u64 cfg, last; 63 64 if (!is_lmac_valid(rpm, lmac_id)) 65 return -ENODEV; 66 67 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 68 last = cfg; 69 if (enable) 70 cfg |= RPM_TX_EN; 71 else 72 cfg &= ~(RPM_TX_EN); 73 74 if (cfg != last) 75 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 76 return !!(last & RPM_TX_EN); 77 } 78 79 int rpm_lmac_rx_tx_enable(void *rpmd, int lmac_id, bool enable) 80 { 81 rpm_t *rpm = rpmd; 82 u64 cfg; 83 84 if (!is_lmac_valid(rpm, lmac_id)) 85 return -ENODEV; 86 87 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 88 if (enable) 89 cfg |= RPM_RX_EN | RPM_TX_EN; 90 else 91 cfg &= ~(RPM_RX_EN | RPM_TX_EN); 92 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 93 return 0; 94 } 95 96 void rpm_lmac_enadis_rx_pause_fwding(void *rpmd, int lmac_id, bool enable) 97 { 98 rpm_t *rpm = rpmd; 99 u64 cfg; 100 101 if (!rpm) 102 return; 103 104 if (enable) { 105 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 106 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 107 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 108 } else { 109 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 110 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 111 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 112 } 113 } 114 115 int rpm_lmac_get_pause_frm_status(void *rpmd, int lmac_id, 116 u8 *tx_pause, u8 *rx_pause) 117 { 118 rpm_t *rpm = rpmd; 119 u64 cfg; 120 121 if (!is_lmac_valid(rpm, lmac_id)) 122 return -ENODEV; 123 124 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 125 *rx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE); 126 127 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 128 *tx_pause = !(cfg & RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE); 129 return 0; 130 } 131 132 int rpm_lmac_enadis_pause_frm(void *rpmd, int lmac_id, u8 tx_pause, 133 u8 rx_pause) 134 { 135 rpm_t *rpm = rpmd; 136 u64 cfg; 137 138 if (!is_lmac_valid(rpm, lmac_id)) 139 return -ENODEV; 140 141 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 142 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 143 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 144 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 145 cfg |= rx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 146 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 147 148 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 149 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 150 cfg |= tx_pause ? 0x0 : RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 151 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 152 153 cfg = rpm_read(rpm, 0, RPMX_CMR_RX_OVR_BP); 154 if (tx_pause) { 155 cfg &= ~RPMX_CMR_RX_OVR_BP_EN(lmac_id); 156 } else { 157 cfg |= RPMX_CMR_RX_OVR_BP_EN(lmac_id); 158 cfg &= ~RPMX_CMR_RX_OVR_BP_BP(lmac_id); 159 } 160 rpm_write(rpm, 0, RPMX_CMR_RX_OVR_BP, cfg); 161 return 0; 162 } 163 164 void rpm_lmac_pause_frm_config(void *rpmd, int lmac_id, bool enable) 165 { 166 rpm_t *rpm = rpmd; 167 u64 cfg; 168 169 if (enable) { 170 /* Enable 802.3 pause frame mode */ 171 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 172 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PFC_MODE; 173 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 174 175 /* Enable receive pause frames */ 176 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 177 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 178 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 179 180 /* Enable forward pause to TX block */ 181 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 182 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 183 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 184 185 /* Enable pause frames transmission */ 186 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 187 cfg &= ~RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 188 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 189 190 /* Set pause time and interval */ 191 cfg = rpm_read(rpm, lmac_id, 192 RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA); 193 cfg &= ~0xFFFFULL; 194 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_PAUSE_QUANTA, 195 cfg | RPM_DEFAULT_PAUSE_TIME); 196 /* Set pause interval as the hardware default is too short */ 197 cfg = rpm_read(rpm, lmac_id, 198 RPMX_MTI_MAC100X_CL01_QUANTA_THRESH); 199 cfg &= ~0xFFFFULL; 200 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_CL01_QUANTA_THRESH, 201 cfg | (RPM_DEFAULT_PAUSE_TIME / 2)); 202 203 } else { 204 /* ALL pause frames received are completely ignored */ 205 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 206 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_RX_P_DISABLE; 207 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 208 209 /* Disable forward pause to TX block */ 210 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 211 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_PAUSE_IGNORE; 212 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 213 214 /* Disable pause frames transmission */ 215 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG); 216 cfg |= RPMX_MTI_MAC100X_COMMAND_CONFIG_TX_P_DISABLE; 217 rpm_write(rpm, lmac_id, RPMX_MTI_MAC100X_COMMAND_CONFIG, cfg); 218 } 219 } 220 221 int rpm_get_rx_stats(void *rpmd, int lmac_id, int idx, u64 *rx_stat) 222 { 223 rpm_t *rpm = rpmd; 224 u64 val_lo, val_hi; 225 226 if (!rpm || lmac_id >= rpm->lmac_count) 227 return -ENODEV; 228 229 mutex_lock(&rpm->lock); 230 231 /* Update idx to point per lmac Rx statistics page */ 232 idx += lmac_id * rpm->mac_ops->rx_stats_cnt; 233 234 /* Read lower 32 bits of counter */ 235 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_RX_STAT_PAGES_COUNTERX + 236 (idx * 8)); 237 238 /* upon read of lower 32 bits, higher 32 bits are written 239 * to RPMX_MTI_STAT_DATA_HI_CDC 240 */ 241 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 242 243 *rx_stat = (val_hi << 32 | val_lo); 244 245 mutex_unlock(&rpm->lock); 246 return 0; 247 } 248 249 int rpm_get_tx_stats(void *rpmd, int lmac_id, int idx, u64 *tx_stat) 250 { 251 rpm_t *rpm = rpmd; 252 u64 val_lo, val_hi; 253 254 if (!rpm || lmac_id >= rpm->lmac_count) 255 return -ENODEV; 256 257 mutex_lock(&rpm->lock); 258 259 /* Update idx to point per lmac Tx statistics page */ 260 idx += lmac_id * rpm->mac_ops->tx_stats_cnt; 261 262 val_lo = rpm_read(rpm, 0, RPMX_MTI_STAT_TX_STAT_PAGES_COUNTERX + 263 (idx * 8)); 264 val_hi = rpm_read(rpm, 0, RPMX_MTI_STAT_DATA_HI_CDC); 265 266 *tx_stat = (val_hi << 32 | val_lo); 267 268 mutex_unlock(&rpm->lock); 269 return 0; 270 } 271 272 u8 rpm_get_lmac_type(void *rpmd, int lmac_id) 273 { 274 rpm_t *rpm = rpmd; 275 u64 req = 0, resp; 276 int err; 277 278 req = FIELD_SET(CMDREG_ID, CGX_CMD_GET_LINK_STS, req); 279 err = cgx_fwi_cmd_generic(req, &resp, rpm, 0); 280 if (!err) 281 return FIELD_GET(RESP_LINKSTAT_LMAC_TYPE, resp); 282 return err; 283 } 284 285 int rpm_lmac_internal_loopback(void *rpmd, int lmac_id, bool enable) 286 { 287 rpm_t *rpm = rpmd; 288 u8 lmac_type; 289 u64 cfg; 290 291 if (!rpm || lmac_id >= rpm->lmac_count) 292 return -ENODEV; 293 lmac_type = rpm->mac_ops->get_lmac_type(rpm, lmac_id); 294 295 if (lmac_type == LMAC_MODE_QSGMII || lmac_type == LMAC_MODE_SGMII) { 296 dev_err(&rpm->pdev->dev, "loopback not supported for LPC mode\n"); 297 return 0; 298 } 299 300 cfg = rpm_read(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1); 301 302 if (enable) 303 cfg |= RPMX_MTI_PCS_LBK; 304 else 305 cfg &= ~RPMX_MTI_PCS_LBK; 306 rpm_write(rpm, lmac_id, RPMX_MTI_PCS100X_CONTROL1, cfg); 307 308 return 0; 309 } 310 311 void rpm_lmac_ptp_config(void *rpmd, int lmac_id, bool enable) 312 { 313 rpm_t *rpm = rpmd; 314 u64 cfg; 315 316 if (!is_lmac_valid(rpm, lmac_id)) 317 return; 318 319 cfg = rpm_read(rpm, lmac_id, RPMX_CMRX_CFG); 320 if (enable) 321 cfg |= RPMX_RX_TS_PREPEND; 322 else 323 cfg &= ~RPMX_RX_TS_PREPEND; 324 rpm_write(rpm, lmac_id, RPMX_CMRX_CFG, cfg); 325 } 326