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