1/* $Date: 2007/08/03 18:52:46 $ $RCSfile: mac.c,v $ $Revision: 1.1.1.1 $ */ 2#include "gmac.h" 3#include "regs.h" 4#include "fpga_defs.h" 5 6#define MAC_CSR_INTERFACE_GMII 0x0 7#define MAC_CSR_INTERFACE_TBI 0x1 8#define MAC_CSR_INTERFACE_MII 0x2 9#define MAC_CSR_INTERFACE_RMII 0x3 10 11/* Chelsio's MAC statistics. */ 12struct mac_statistics { 13 14 /* Transmit */ 15 u32 TxFramesTransmittedOK; 16 u32 TxReserved1; 17 u32 TxReserved2; 18 u32 TxOctetsTransmittedOK; 19 u32 TxFramesWithDeferredXmissions; 20 u32 TxLateCollisions; 21 u32 TxFramesAbortedDueToXSCollisions; 22 u32 TxFramesLostDueToIntMACXmitError; 23 u32 TxReserved3; 24 u32 TxMulticastFrameXmittedOK; 25 u32 TxBroadcastFramesXmittedOK; 26 u32 TxFramesWithExcessiveDeferral; 27 u32 TxPAUSEMACCtrlFramesTransmitted; 28 29 /* Receive */ 30 u32 RxFramesReceivedOK; 31 u32 RxFrameCheckSequenceErrors; 32 u32 RxAlignmentErrors; 33 u32 RxOctetsReceivedOK; 34 u32 RxFramesLostDueToIntMACRcvError; 35 u32 RxMulticastFramesReceivedOK; 36 u32 RxBroadcastFramesReceivedOK; 37 u32 RxInRangeLengthErrors; 38 u32 RxTxOutOfRangeLengthField; 39 u32 RxFrameTooLongErrors; 40 u32 RxPAUSEMACCtrlFramesReceived; 41}; 42 43static int static_aPorts[] = { 44 FPGA_GMAC_INTERRUPT_PORT0, 45 FPGA_GMAC_INTERRUPT_PORT1, 46 FPGA_GMAC_INTERRUPT_PORT2, 47 FPGA_GMAC_INTERRUPT_PORT3 48}; 49 50struct _cmac_instance { 51 u32 index; 52}; 53 54static int mac_intr_enable(struct cmac *mac) 55{ 56 u32 mac_intr; 57 58 if (t1_is_asic(mac->adapter)) { 59 /* ASIC */ 60 61 /* We don't use the on chip MAC for ASIC products. */ 62 } else { 63 /* FPGA */ 64 65 /* Set parent gmac interrupt. */ 66 mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); 67 mac_intr |= FPGA_PCIX_INTERRUPT_GMAC; 68 writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); 69 70 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 71 mac_intr |= static_aPorts[mac->instance->index]; 72 writel(mac_intr, 73 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 74 } 75 76 return 0; 77} 78 79static int mac_intr_disable(struct cmac *mac) 80{ 81 u32 mac_intr; 82 83 if (t1_is_asic(mac->adapter)) { 84 /* ASIC */ 85 86 /* We don't use the on chip MAC for ASIC products. */ 87 } else { 88 /* FPGA */ 89 90 /* Set parent gmac interrupt. */ 91 mac_intr = readl(mac->adapter->regs + A_PL_ENABLE); 92 mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC; 93 writel(mac_intr, mac->adapter->regs + A_PL_ENABLE); 94 95 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 96 mac_intr &= ~(static_aPorts[mac->instance->index]); 97 writel(mac_intr, 98 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE); 99 } 100 101 return 0; 102} 103 104static int mac_intr_clear(struct cmac *mac) 105{ 106 u32 mac_intr; 107 108 if (t1_is_asic(mac->adapter)) { 109 /* ASIC */ 110 111 /* We don't use the on chip MAC for ASIC products. */ 112 } else { 113 /* FPGA */ 114 115 /* Set parent gmac interrupt. */ 116 writel(FPGA_PCIX_INTERRUPT_GMAC, 117 mac->adapter->regs + A_PL_CAUSE); 118 mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); 119 mac_intr |= (static_aPorts[mac->instance->index]); 120 writel(mac_intr, 121 mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE); 122 } 123 124 return 0; 125} 126 127static int mac_get_address(struct cmac *mac, u8 addr[6]) 128{ 129 u32 data32_lo, data32_hi; 130 131 data32_lo = readl(mac->adapter->regs 132 + MAC_REG_IDLO(mac->instance->index)); 133 data32_hi = readl(mac->adapter->regs 134 + MAC_REG_IDHI(mac->instance->index)); 135 136 addr[0] = (u8) ((data32_hi >> 8) & 0xFF); 137 addr[1] = (u8) ((data32_hi) & 0xFF); 138 addr[2] = (u8) ((data32_lo >> 24) & 0xFF); 139 addr[3] = (u8) ((data32_lo >> 16) & 0xFF); 140 addr[4] = (u8) ((data32_lo >> 8) & 0xFF); 141 addr[5] = (u8) ((data32_lo) & 0xFF); 142 return 0; 143} 144 145static int mac_reset(struct cmac *mac) 146{ 147 u32 data32; 148 int mac_in_reset, time_out = 100; 149 int idx = mac->instance->index; 150 151 data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); 152 writel(data32 | F_MAC_RESET, 153 mac->adapter->regs + MAC_REG_CSR(idx)); 154 155 do { 156 data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx)); 157 158 mac_in_reset = data32 & F_MAC_RESET; 159 if (mac_in_reset) 160 udelay(1); 161 } while (mac_in_reset && --time_out); 162 163 if (mac_in_reset) { 164 CH_ERR("%s: MAC %d reset timed out\n", 165 mac->adapter->name, idx); 166 return 2; 167 } 168 169 return 0; 170} 171 172static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) 173{ 174 u32 val; 175 176 val = readl(mac->adapter->regs 177 + MAC_REG_CSR(mac->instance->index)); 178 val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE); 179 val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0); 180 val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0); 181 writel(val, 182 mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); 183 184 return 0; 185} 186 187static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, 188 int fc) 189{ 190 u32 data32; 191 192 data32 = readl(mac->adapter->regs 193 + MAC_REG_CSR(mac->instance->index)); 194 data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) | 195 V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE | 196 F_MAC_RX_PAUSE_ENABLE); 197 198 switch (speed) { 199 case SPEED_10: 200 case SPEED_100: 201 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII); 202 data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1); 203 break; 204 case SPEED_1000: 205 data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII); 206 data32 |= V_MAC_SPEED(2); 207 break; 208 } 209 210 if (duplex >= 0) 211 data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF); 212 213 if (fc >= 0) { 214 data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0); 215 data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0); 216 } 217 218 writel(data32, 219 mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); 220 return 0; 221} 222 223static int mac_enable(struct cmac *mac, int which) 224{ 225 u32 val; 226 227 val = readl(mac->adapter->regs 228 + MAC_REG_CSR(mac->instance->index)); 229 if (which & MAC_DIRECTION_RX) 230 val |= F_MAC_RX_ENABLE; 231 if (which & MAC_DIRECTION_TX) 232 val |= F_MAC_TX_ENABLE; 233 writel(val, 234 mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); 235 return 0; 236} 237 238static int mac_disable(struct cmac *mac, int which) 239{ 240 u32 val; 241 242 val = readl(mac->adapter->regs 243 + MAC_REG_CSR(mac->instance->index)); 244 if (which & MAC_DIRECTION_RX) 245 val &= ~F_MAC_RX_ENABLE; 246 if (which & MAC_DIRECTION_TX) 247 val &= ~F_MAC_TX_ENABLE; 248 writel(val, 249 mac->adapter->regs + MAC_REG_CSR(mac->instance->index)); 250 return 0; 251} 252 253 254static int mac_set_mtu(struct cmac *mac, int mtu) 255{ 256 if (mtu > 9600) 257 return -EINVAL; 258 writel(mtu + ETH_HLEN + VLAN_HLEN, 259 mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index)); 260 261 return 0; 262} 263 264static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 265 int flag) 266{ 267 struct mac_statistics st; 268 u32 *p = (u32 *) & st, i; 269 270 writel(0, 271 mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index)); 272 273 for (i = 0; i < sizeof(st) / sizeof(u32); i++) 274 *p++ = readl(mac->adapter->regs 275 + MAC_REG_RMDATA(mac->instance->index)); 276 277 return &mac->stats; 278} 279 280static void mac_destroy(struct cmac *mac) 281{ 282 kfree(mac); 283} 284 285static struct cmac_ops chelsio_mac_ops = { 286 .destroy = mac_destroy, 287 .reset = mac_reset, 288 .interrupt_enable = mac_intr_enable, 289 .interrupt_disable = mac_intr_disable, 290 .interrupt_clear = mac_intr_clear, 291 .enable = mac_enable, 292 .disable = mac_disable, 293 .set_mtu = mac_set_mtu, 294 .set_rx_mode = mac_set_rx_mode, 295 .set_speed_duplex_fc = mac_set_speed_duplex_fc, 296 .macaddress_get = mac_get_address, 297 .statistics_update = mac_update_statistics, 298}; 299 300static struct cmac *mac_create(adapter_t *adapter, int index) 301{ 302 struct cmac *mac; 303 u32 data32; 304 305 if (index >= 4) 306 return NULL; 307 308 mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); 309 if (!mac) 310 return NULL; 311 312 mac->ops = &chelsio_mac_ops; 313 mac->instance = (cmac_instance *) (mac + 1); 314 315 mac->instance->index = index; 316 mac->adapter = adapter; 317 318 data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index)); 319 data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC | 320 F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE); 321 data32 |= F_MAC_JUMBO_ENABLE; 322 writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index)); 323 324 /* Initialize the random backoff seed. */ 325 data32 = 0x55aa + (3 * index); 326 writel(data32, 327 adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index)); 328 329 /* Check to see if the mac address needs to be set manually. */ 330 data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index)); 331 if (data32 == 0 || data32 == 0xffffffff) { 332 /* 333 * Add a default MAC address if we can't read one. 334 */ 335 writel(0x43FFFFFF - index, 336 adapter->regs + MAC_REG_IDLO(mac->instance->index)); 337 writel(0x0007, 338 adapter->regs + MAC_REG_IDHI(mac->instance->index)); 339 } 340 341 (void) mac_set_mtu(mac, 1500); 342 return mac; 343} 344 345const struct gmac t1_chelsio_mac_ops = { 346 .create = mac_create 347}; 348