Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. |
| 3 | * |
| 4 | * See: |
| 5 | * Intel Microcommunications 1991 |
| 6 | * p1-1 to p1-37 |
| 7 | * Intel order No. 231658 |
| 8 | * ISBN 1-55512-119-5 |
| 9 | * |
| 10 | * Unfortunately, the above chapter mentions neither |
| 11 | * the System Configuration Pointer (SCP) nor the |
| 12 | * Intermediate System Configuration Pointer (ISCP), |
| 13 | * so we probably need to look elsewhere for the |
| 14 | * whole story -- some recommend the "Intel LAN |
| 15 | * Components manual" but I have neither a copy |
| 16 | * nor a full reference. But "elsewhere" may be |
| 17 | * in the same publication... |
| 18 | * The description of a later device, the |
| 19 | * "82596CA High-Performance 32-Bit Local Area Network |
| 20 | * Coprocessor", (ibid. p1-38 to p1-109) does mention |
| 21 | * the SCP and ISCP and also has an i82586 compatibility |
| 22 | * mode. Even more useful is "AP-235 An 82586 Data Link |
| 23 | * Driver" (ibid. p1-337 to p1-417). |
| 24 | */ |
| 25 | |
| 26 | #define I82586_MEMZ (64 * 1024) |
| 27 | |
| 28 | #define I82586_SCP_ADDR (I82586_MEMZ - sizeof(scp_t)) |
| 29 | |
| 30 | #define ADDR_LEN 6 |
| 31 | #define I82586NULL 0xFFFF |
| 32 | |
| 33 | #define toff(t,p,f) (unsigned short)((void *)(&((t *)((void *)0 + (p)))->f) - (void *)0) |
| 34 | |
| 35 | /* |
| 36 | * System Configuration Pointer (SCP). |
| 37 | */ |
| 38 | typedef struct scp_t scp_t; |
| 39 | struct scp_t |
| 40 | { |
| 41 | unsigned short scp_sysbus; /* 82586 bus width: */ |
| 42 | #define SCP_SY_16BBUS (0x0 << 0) /* 16 bits */ |
| 43 | #define SCP_SY_8BBUS (0x1 << 0) /* 8 bits. */ |
| 44 | unsigned short scp_junk[2]; /* Unused */ |
| 45 | unsigned short scp_iscpl; /* lower 16 bits of ISCP_ADDR */ |
| 46 | unsigned short scp_iscph; /* upper 16 bits of ISCP_ADDR */ |
| 47 | }; |
| 48 | |
| 49 | /* |
| 50 | * Intermediate System Configuration Pointer (ISCP). |
| 51 | */ |
| 52 | typedef struct iscp_t iscp_t; |
| 53 | struct iscp_t |
| 54 | { |
| 55 | unsigned short iscp_busy; /* set by CPU before first CA, */ |
| 56 | /* cleared by 82586 after read. */ |
| 57 | unsigned short iscp_offset; /* offset of SCB */ |
| 58 | unsigned short iscp_basel; /* base of SCB */ |
| 59 | unsigned short iscp_baseh; /* " */ |
| 60 | }; |
| 61 | |
| 62 | /* |
| 63 | * System Control Block (SCB). |
| 64 | * The 82586 writes its status to scb_status and then |
| 65 | * raises an interrupt to alert the CPU. |
| 66 | * The CPU writes a command to scb_command and |
| 67 | * then issues a Channel Attention (CA) to alert the 82586. |
| 68 | */ |
| 69 | typedef struct scb_t scb_t; |
| 70 | struct scb_t |
| 71 | { |
| 72 | unsigned short scb_status; /* Status of 82586 */ |
| 73 | #define SCB_ST_INT (0xF << 12) /* Some of: */ |
| 74 | #define SCB_ST_CX (0x1 << 15) /* Cmd completed */ |
| 75 | #define SCB_ST_FR (0x1 << 14) /* Frame received */ |
| 76 | #define SCB_ST_CNA (0x1 << 13) /* Cmd unit not active */ |
| 77 | #define SCB_ST_RNR (0x1 << 12) /* Rcv unit not ready */ |
| 78 | #define SCB_ST_JUNK0 (0x1 << 11) /* 0 */ |
| 79 | #define SCB_ST_CUS (0x7 << 8) /* Cmd unit status */ |
| 80 | #define SCB_ST_CUS_IDLE (0 << 8) /* Idle */ |
| 81 | #define SCB_ST_CUS_SUSP (1 << 8) /* Suspended */ |
| 82 | #define SCB_ST_CUS_ACTV (2 << 8) /* Active */ |
| 83 | #define SCB_ST_JUNK1 (0x1 << 7) /* 0 */ |
| 84 | #define SCB_ST_RUS (0x7 << 4) /* Rcv unit status */ |
| 85 | #define SCB_ST_RUS_IDLE (0 << 4) /* Idle */ |
| 86 | #define SCB_ST_RUS_SUSP (1 << 4) /* Suspended */ |
| 87 | #define SCB_ST_RUS_NRES (2 << 4) /* No resources */ |
| 88 | #define SCB_ST_RUS_RDY (4 << 4) /* Ready */ |
| 89 | unsigned short scb_command; /* Next command */ |
| 90 | #define SCB_CMD_ACK_CX (0x1 << 15) /* Ack cmd completion */ |
| 91 | #define SCB_CMD_ACK_FR (0x1 << 14) /* Ack frame received */ |
| 92 | #define SCB_CMD_ACK_CNA (0x1 << 13) /* Ack CU not active */ |
| 93 | #define SCB_CMD_ACK_RNR (0x1 << 12) /* Ack RU not ready */ |
| 94 | #define SCB_CMD_JUNKX (0x1 << 11) /* Unused */ |
| 95 | #define SCB_CMD_CUC (0x7 << 8) /* Command Unit command */ |
| 96 | #define SCB_CMD_CUC_NOP (0 << 8) /* Nop */ |
| 97 | #define SCB_CMD_CUC_GO (1 << 8) /* Start cbl_offset */ |
| 98 | #define SCB_CMD_CUC_RES (2 << 8) /* Resume execution */ |
| 99 | #define SCB_CMD_CUC_SUS (3 << 8) /* Suspend " */ |
| 100 | #define SCB_CMD_CUC_ABT (4 << 8) /* Abort " */ |
| 101 | #define SCB_CMD_RESET (0x1 << 7) /* Reset chip (hardware) */ |
| 102 | #define SCB_CMD_RUC (0x7 << 4) /* Receive Unit command */ |
| 103 | #define SCB_CMD_RUC_NOP (0 << 4) /* Nop */ |
| 104 | #define SCB_CMD_RUC_GO (1 << 4) /* Start rfa_offset */ |
| 105 | #define SCB_CMD_RUC_RES (2 << 4) /* Resume reception */ |
| 106 | #define SCB_CMD_RUC_SUS (3 << 4) /* Suspend " */ |
| 107 | #define SCB_CMD_RUC_ABT (4 << 4) /* Abort " */ |
| 108 | unsigned short scb_cbl_offset; /* Offset of first command unit */ |
| 109 | /* Action Command */ |
| 110 | unsigned short scb_rfa_offset; /* Offset of first Receive */ |
| 111 | /* Frame Descriptor in the */ |
| 112 | /* Receive Frame Area */ |
| 113 | unsigned short scb_crcerrs; /* Properly aligned frames */ |
| 114 | /* received with a CRC error */ |
| 115 | unsigned short scb_alnerrs; /* Misaligned frames received */ |
| 116 | /* with a CRC error */ |
| 117 | unsigned short scb_rscerrs; /* Frames lost due to no space */ |
| 118 | unsigned short scb_ovrnerrs; /* Frames lost due to slow bus */ |
| 119 | }; |
| 120 | |
| 121 | #define scboff(p,f) toff(scb_t, p, f) |
| 122 | |
| 123 | /* |
| 124 | * The eight Action Commands. |
| 125 | */ |
| 126 | typedef enum acmd_e acmd_e; |
| 127 | enum acmd_e |
| 128 | { |
| 129 | acmd_nop = 0, /* Do nothing */ |
| 130 | acmd_ia_setup = 1, /* Load an (ethernet) address into the */ |
| 131 | /* 82586 */ |
| 132 | acmd_configure = 2, /* Update the 82586 operating parameters */ |
| 133 | acmd_mc_setup = 3, /* Load a list of (ethernet) multicast */ |
| 134 | /* addresses into the 82586 */ |
| 135 | acmd_transmit = 4, /* Transmit a frame */ |
| 136 | acmd_tdr = 5, /* Perform a Time Domain Reflectometer */ |
| 137 | /* test on the serial link */ |
| 138 | acmd_dump = 6, /* Copy 82586 registers to memory */ |
| 139 | acmd_diagnose = 7, /* Run an internal self test */ |
| 140 | }; |
| 141 | |
| 142 | /* |
| 143 | * Generic Action Command header. |
| 144 | */ |
| 145 | typedef struct ach_t ach_t; |
| 146 | struct ach_t |
| 147 | { |
| 148 | unsigned short ac_status; /* Command status: */ |
| 149 | #define AC_SFLD_C (0x1 << 15) /* Command completed */ |
| 150 | #define AC_SFLD_B (0x1 << 14) /* Busy executing */ |
| 151 | #define AC_SFLD_OK (0x1 << 13) /* Completed error free */ |
| 152 | #define AC_SFLD_A (0x1 << 12) /* Command aborted */ |
| 153 | #define AC_SFLD_FAIL (0x1 << 11) /* Selftest failed */ |
| 154 | #define AC_SFLD_S10 (0x1 << 10) /* No carrier sense */ |
| 155 | /* during transmission */ |
| 156 | #define AC_SFLD_S9 (0x1 << 9) /* Tx unsuccessful: */ |
| 157 | /* (stopped) lost CTS */ |
| 158 | #define AC_SFLD_S8 (0x1 << 8) /* Tx unsuccessful: */ |
| 159 | /* (stopped) slow DMA */ |
| 160 | #define AC_SFLD_S7 (0x1 << 7) /* Tx deferred: */ |
| 161 | /* other link traffic */ |
| 162 | #define AC_SFLD_S6 (0x1 << 6) /* Heart Beat: collision */ |
| 163 | /* detect after last tx */ |
| 164 | #define AC_SFLD_S5 (0x1 << 5) /* Tx stopped: */ |
| 165 | /* excessive collisions */ |
| 166 | #define AC_SFLD_MAXCOL (0xF << 0) /* Collision count */ |
| 167 | unsigned short ac_command; /* Command specifier: */ |
| 168 | #define AC_CFLD_EL (0x1 << 15) /* End of command list */ |
| 169 | #define AC_CFLD_S (0x1 << 14) /* Suspend on completion */ |
| 170 | #define AC_CFLD_I (0x1 << 13) /* Interrupt on completion */ |
| 171 | #define AC_CFLD_CMD (0x7 << 0) /* acmd_e */ |
| 172 | unsigned short ac_link; /* Next Action Command */ |
| 173 | }; |
| 174 | |
| 175 | #define acoff(p,f) toff(ach_t, p, f) |
| 176 | |
| 177 | /* |
| 178 | * The Nop Action Command. |
| 179 | */ |
| 180 | typedef struct ac_nop_t ac_nop_t; |
| 181 | struct ac_nop_t |
| 182 | { |
| 183 | ach_t nop_h; |
| 184 | }; |
| 185 | |
| 186 | /* |
| 187 | * The IA-Setup Action Command. |
| 188 | */ |
| 189 | typedef struct ac_ias_t ac_ias_t; |
| 190 | struct ac_ias_t |
| 191 | { |
| 192 | ach_t ias_h; |
| 193 | unsigned char ias_addr[ADDR_LEN]; /* The (ethernet) address */ |
| 194 | }; |
| 195 | |
| 196 | /* |
| 197 | * The Configure Action Command. |
| 198 | */ |
| 199 | typedef struct ac_cfg_t ac_cfg_t; |
| 200 | struct ac_cfg_t |
| 201 | { |
| 202 | ach_t cfg_h; |
| 203 | unsigned char cfg_byte_cnt; /* Size foll data: 4-12 */ |
| 204 | #define AC_CFG_BYTE_CNT(v) (((v) & 0xF) << 0) |
| 205 | unsigned char cfg_fifolim; /* FIFO threshold */ |
| 206 | #define AC_CFG_FIFOLIM(v) (((v) & 0xF) << 0) |
| 207 | unsigned char cfg_byte8; |
| 208 | #define AC_CFG_SAV_BF(v) (((v) & 0x1) << 7) /* Save rxd bad frames */ |
| 209 | #define AC_CFG_SRDY(v) (((v) & 0x1) << 6) /* SRDY/ARDY pin means */ |
| 210 | /* external sync. */ |
| 211 | unsigned char cfg_byte9; |
| 212 | #define AC_CFG_ELPBCK(v) (((v) & 0x1) << 7) /* External loopback */ |
| 213 | #define AC_CFG_ILPBCK(v) (((v) & 0x1) << 6) /* Internal loopback */ |
| 214 | #define AC_CFG_PRELEN(v) (((v) & 0x3) << 4) /* Preamble length */ |
| 215 | #define AC_CFG_PLEN_2 0 /* 2 bytes */ |
| 216 | #define AC_CFG_PLEN_4 1 /* 4 bytes */ |
| 217 | #define AC_CFG_PLEN_8 2 /* 8 bytes */ |
| 218 | #define AC_CFG_PLEN_16 3 /* 16 bytes */ |
| 219 | #define AC_CFG_ALOC(v) (((v) & 0x1) << 3) /* Addr/len data is */ |
| 220 | /* explicit in buffers */ |
| 221 | #define AC_CFG_ADDRLEN(v) (((v) & 0x7) << 0) /* Bytes per address */ |
| 222 | unsigned char cfg_byte10; |
| 223 | #define AC_CFG_BOFMET(v) (((v) & 0x1) << 7) /* Use alternate expo. */ |
| 224 | /* backoff method */ |
| 225 | #define AC_CFG_ACR(v) (((v) & 0x7) << 4) /* Accelerated cont. res. */ |
| 226 | #define AC_CFG_LINPRIO(v) (((v) & 0x7) << 0) /* Linear priority */ |
| 227 | unsigned char cfg_ifs; /* Interframe spacing */ |
| 228 | unsigned char cfg_slotl; /* Slot time (low byte) */ |
| 229 | unsigned char cfg_byte13; |
| 230 | #define AC_CFG_RETRYNUM(v) (((v) & 0xF) << 4) /* Max. collision retry */ |
| 231 | #define AC_CFG_SLTTMHI(v) (((v) & 0x7) << 0) /* Slot time (high bits) */ |
| 232 | unsigned char cfg_byte14; |
| 233 | #define AC_CFG_FLGPAD(v) (((v) & 0x1) << 7) /* Pad with HDLC flags */ |
| 234 | #define AC_CFG_BTSTF(v) (((v) & 0x1) << 6) /* Do HDLC bitstuffing */ |
| 235 | #define AC_CFG_CRC16(v) (((v) & 0x1) << 5) /* 16 bit CCITT CRC */ |
| 236 | #define AC_CFG_NCRC(v) (((v) & 0x1) << 4) /* Insert no CRC */ |
| 237 | #define AC_CFG_TNCRS(v) (((v) & 0x1) << 3) /* Tx even if no carrier */ |
| 238 | #define AC_CFG_MANCH(v) (((v) & 0x1) << 2) /* Manchester coding */ |
| 239 | #define AC_CFG_BCDIS(v) (((v) & 0x1) << 1) /* Disable broadcast */ |
| 240 | #define AC_CFG_PRM(v) (((v) & 0x1) << 0) /* Promiscuous mode */ |
| 241 | unsigned char cfg_byte15; |
| 242 | #define AC_CFG_ICDS(v) (((v) & 0x1) << 7) /* Internal collision */ |
| 243 | /* detect source */ |
| 244 | #define AC_CFG_CDTF(v) (((v) & 0x7) << 4) /* Collision detect */ |
| 245 | /* filter in bit times */ |
| 246 | #define AC_CFG_ICSS(v) (((v) & 0x1) << 3) /* Internal carrier */ |
| 247 | /* sense source */ |
| 248 | #define AC_CFG_CSTF(v) (((v) & 0x7) << 0) /* Carrier sense */ |
| 249 | /* filter in bit times */ |
| 250 | unsigned short cfg_min_frm_len; |
| 251 | #define AC_CFG_MNFRM(v) (((v) & 0xFF) << 0) /* Min. bytes/frame (<= 255) */ |
| 252 | }; |
| 253 | |
| 254 | /* |
| 255 | * The MC-Setup Action Command. |
| 256 | */ |
| 257 | typedef struct ac_mcs_t ac_mcs_t; |
| 258 | struct ac_mcs_t |
| 259 | { |
| 260 | ach_t mcs_h; |
| 261 | unsigned short mcs_cnt; /* No. of bytes of MC addresses */ |
| 262 | #if 0 |
| 263 | unsigned char mcs_data[ADDR_LEN]; /* The first MC address .. */ |
| 264 | ... |
| 265 | #endif |
| 266 | }; |
| 267 | |
| 268 | #define I82586_MAX_MULTICAST_ADDRESSES 128 /* Hardware hashed filter */ |
| 269 | |
| 270 | /* |
| 271 | * The Transmit Action Command. |
| 272 | */ |
| 273 | typedef struct ac_tx_t ac_tx_t; |
| 274 | struct ac_tx_t |
| 275 | { |
| 276 | ach_t tx_h; |
| 277 | unsigned short tx_tbd_offset; /* Address of list of buffers. */ |
| 278 | #if 0 |
| 279 | Linux packets are passed down with the destination MAC address |
| 280 | and length/type field already prepended to the data, |
| 281 | so we do not need to insert it. Consistent with this |
| 282 | we must also set the AC_CFG_ALOC(..) flag during the |
| 283 | ac_cfg_t action command. |
| 284 | unsigned char tx_addr[ADDR_LEN]; /* The frame dest. address */ |
| 285 | unsigned short tx_length; /* The frame length */ |
| 286 | #endif /* 0 */ |
| 287 | }; |
| 288 | |
| 289 | /* |
| 290 | * The Time Domain Reflectometer Action Command. |
| 291 | */ |
| 292 | typedef struct ac_tdr_t ac_tdr_t; |
| 293 | struct ac_tdr_t |
| 294 | { |
| 295 | ach_t tdr_h; |
| 296 | unsigned short tdr_result; /* Result. */ |
| 297 | #define AC_TDR_LNK_OK (0x1 << 15) /* No link problem */ |
| 298 | #define AC_TDR_XCVR_PRB (0x1 << 14) /* Txcvr cable problem */ |
| 299 | #define AC_TDR_ET_OPN (0x1 << 13) /* Open on the link */ |
| 300 | #define AC_TDR_ET_SRT (0x1 << 12) /* Short on the link */ |
| 301 | #define AC_TDR_TIME (0x7FF << 0) /* Distance to problem */ |
| 302 | /* site in transmit */ |
| 303 | /* clock cycles */ |
| 304 | }; |
| 305 | |
| 306 | /* |
| 307 | * The Dump Action Command. |
| 308 | */ |
| 309 | typedef struct ac_dmp_t ac_dmp_t; |
| 310 | struct ac_dmp_t |
| 311 | { |
| 312 | ach_t dmp_h; |
| 313 | unsigned short dmp_offset; /* Result. */ |
| 314 | }; |
| 315 | |
| 316 | /* |
| 317 | * Size of the result of the dump command. |
| 318 | */ |
| 319 | #define DUMPBYTES 170 |
| 320 | |
| 321 | /* |
| 322 | * The Diagnose Action Command. |
| 323 | */ |
| 324 | typedef struct ac_dgn_t ac_dgn_t; |
| 325 | struct ac_dgn_t |
| 326 | { |
| 327 | ach_t dgn_h; |
| 328 | }; |
| 329 | |
| 330 | /* |
| 331 | * Transmit Buffer Descriptor (TBD). |
| 332 | */ |
| 333 | typedef struct tbd_t tbd_t; |
| 334 | struct tbd_t |
| 335 | { |
| 336 | unsigned short tbd_status; /* Written by the CPU */ |
| 337 | #define TBD_STATUS_EOF (0x1 << 15) /* This TBD is the */ |
| 338 | /* last for this frame */ |
| 339 | #define TBD_STATUS_ACNT (0x3FFF << 0) /* Actual count of data */ |
| 340 | /* bytes in this buffer */ |
| 341 | unsigned short tbd_next_bd_offset; /* Next in list */ |
| 342 | unsigned short tbd_bufl; /* Buffer address (low) */ |
| 343 | unsigned short tbd_bufh; /* " " (high) */ |
| 344 | }; |
| 345 | |
| 346 | /* |
| 347 | * Receive Buffer Descriptor (RBD). |
| 348 | */ |
| 349 | typedef struct rbd_t rbd_t; |
| 350 | struct rbd_t |
| 351 | { |
| 352 | unsigned short rbd_status; /* Written by the 82586 */ |
| 353 | #define RBD_STATUS_EOF (0x1 << 15) /* This RBD is the */ |
| 354 | /* last for this frame */ |
| 355 | #define RBD_STATUS_F (0x1 << 14) /* ACNT field is valid */ |
| 356 | #define RBD_STATUS_ACNT (0x3FFF << 0) /* Actual no. of data */ |
| 357 | /* bytes in this buffer */ |
| 358 | unsigned short rbd_next_rbd_offset; /* Next rbd in list */ |
| 359 | unsigned short rbd_bufl; /* Data pointer (low) */ |
| 360 | unsigned short rbd_bufh; /* " " (high) */ |
| 361 | unsigned short rbd_el_size; /* EL+Data buf. size */ |
| 362 | #define RBD_EL (0x1 << 15) /* This BD is the */ |
| 363 | /* last in the list */ |
| 364 | #define RBD_SIZE (0x3FFF << 0) /* No. of bytes the */ |
| 365 | /* buffer can hold */ |
| 366 | }; |
| 367 | |
| 368 | #define rbdoff(p,f) toff(rbd_t, p, f) |
| 369 | |
| 370 | /* |
| 371 | * Frame Descriptor (FD). |
| 372 | */ |
| 373 | typedef struct fd_t fd_t; |
| 374 | struct fd_t |
| 375 | { |
| 376 | unsigned short fd_status; /* Written by the 82586 */ |
| 377 | #define FD_STATUS_C (0x1 << 15) /* Completed storing frame */ |
| 378 | #define FD_STATUS_B (0x1 << 14) /* FD was consumed by RU */ |
| 379 | #define FD_STATUS_OK (0x1 << 13) /* Frame rxd successfully */ |
| 380 | #define FD_STATUS_S11 (0x1 << 11) /* CRC error */ |
| 381 | #define FD_STATUS_S10 (0x1 << 10) /* Alignment error */ |
| 382 | #define FD_STATUS_S9 (0x1 << 9) /* Ran out of resources */ |
| 383 | #define FD_STATUS_S8 (0x1 << 8) /* Rx DMA overrun */ |
| 384 | #define FD_STATUS_S7 (0x1 << 7) /* Frame too short */ |
| 385 | #define FD_STATUS_S6 (0x1 << 6) /* No EOF flag */ |
| 386 | unsigned short fd_command; /* Command */ |
| 387 | #define FD_COMMAND_EL (0x1 << 15) /* Last FD in list */ |
| 388 | #define FD_COMMAND_S (0x1 << 14) /* Suspend RU after rx */ |
| 389 | unsigned short fd_link_offset; /* Next FD */ |
| 390 | unsigned short fd_rbd_offset; /* First RBD (data) */ |
| 391 | /* Prepared by CPU, */ |
| 392 | /* updated by 82586 */ |
| 393 | #if 0 |
| 394 | I think the rest is unused since we |
| 395 | have set AC_CFG_ALOC(..). However, just |
| 396 | in case, we leave the space. |
| 397 | #endif /* 0 */ |
| 398 | unsigned char fd_dest[ADDR_LEN]; /* Destination address */ |
| 399 | /* Written by 82586 */ |
| 400 | unsigned char fd_src[ADDR_LEN]; /* Source address */ |
| 401 | /* Written by 82586 */ |
| 402 | unsigned short fd_length; /* Frame length or type */ |
| 403 | /* Written by 82586 */ |
| 404 | }; |
| 405 | |
| 406 | #define fdoff(p,f) toff(fd_t, p, f) |
| 407 | |
| 408 | /* |
| 409 | * This software may only be used and distributed |
| 410 | * according to the terms of the GNU General Public License. |
| 411 | * |
| 412 | * For more details, see wavelan.c. |
| 413 | */ |