at v2.6.21 368 lines 9.2 kB view raw
1/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */ 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#if 0 254static int mac_set_ifs(struct cmac *mac, u32 mode) 255{ 256 t1_write_reg_4(mac->adapter, 257 MAC_REG_IFS(mac->instance->index), 258 mode); 259 return 0; 260} 261 262static int mac_enable_isl(struct cmac *mac) 263{ 264 u32 data32 = readl(mac->adapter->regs 265 + MAC_REG_CSR(mac->instance->index)); 266 data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE; 267 t1_write_reg_4(mac->adapter, 268 MAC_REG_CSR(mac->instance->index), 269 data32); 270 return 0; 271} 272#endif 273 274static int mac_set_mtu(struct cmac *mac, int mtu) 275{ 276 if (mtu > 9600) 277 return -EINVAL; 278 writel(mtu + ETH_HLEN + VLAN_HLEN, 279 mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index)); 280 281 return 0; 282} 283 284static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, 285 int flag) 286{ 287 struct mac_statistics st; 288 u32 *p = (u32 *) & st, i; 289 290 writel(0, 291 mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index)); 292 293 for (i = 0; i < sizeof(st) / sizeof(u32); i++) 294 *p++ = readl(mac->adapter->regs 295 + MAC_REG_RMDATA(mac->instance->index)); 296 297 /* XXX convert stats */ 298 return &mac->stats; 299} 300 301static void mac_destroy(struct cmac *mac) 302{ 303 kfree(mac); 304} 305 306static struct cmac_ops chelsio_mac_ops = { 307 .destroy = mac_destroy, 308 .reset = mac_reset, 309 .interrupt_enable = mac_intr_enable, 310 .interrupt_disable = mac_intr_disable, 311 .interrupt_clear = mac_intr_clear, 312 .enable = mac_enable, 313 .disable = mac_disable, 314 .set_mtu = mac_set_mtu, 315 .set_rx_mode = mac_set_rx_mode, 316 .set_speed_duplex_fc = mac_set_speed_duplex_fc, 317 .macaddress_get = mac_get_address, 318 .statistics_update = mac_update_statistics, 319}; 320 321static struct cmac *mac_create(adapter_t *adapter, int index) 322{ 323 struct cmac *mac; 324 u32 data32; 325 326 if (index >= 4) 327 return NULL; 328 329 mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); 330 if (!mac) 331 return NULL; 332 333 mac->ops = &chelsio_mac_ops; 334 mac->instance = (cmac_instance *) (mac + 1); 335 336 mac->instance->index = index; 337 mac->adapter = adapter; 338 339 data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index)); 340 data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC | 341 F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE); 342 data32 |= F_MAC_JUMBO_ENABLE; 343 writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index)); 344 345 /* Initialize the random backoff seed. */ 346 data32 = 0x55aa + (3 * index); 347 writel(data32, 348 adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index)); 349 350 /* Check to see if the mac address needs to be set manually. */ 351 data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index)); 352 if (data32 == 0 || data32 == 0xffffffff) { 353 /* 354 * Add a default MAC address if we can't read one. 355 */ 356 writel(0x43FFFFFF - index, 357 adapter->regs + MAC_REG_IDLO(mac->instance->index)); 358 writel(0x0007, 359 adapter->regs + MAC_REG_IDHI(mac->instance->index)); 360 } 361 362 (void) mac_set_mtu(mac, 1500); 363 return mac; 364} 365 366struct gmac t1_chelsio_mac_ops = { 367 .create = mac_create 368};