[9] | 1 | /*
|
---|
| 2 | * fxp.c
|
---|
| 3 | *
|
---|
| 4 | * This file contains an ethernet device driver for Intel 82557, 82558,
|
---|
| 5 | * 82559, 82550, and 82562 fast ethernet controllers.
|
---|
| 6 | *
|
---|
| 7 | * The valid messages and their parameters are:
|
---|
| 8 | *
|
---|
| 9 | * m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
|
---|
| 10 | * |------------+----------+---------+----------+---------+---------|
|
---|
| 11 | * | HARDINT | | | | | |
|
---|
| 12 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 13 | * | DL_WRITE | port nr | proc nr | count | mode | address |
|
---|
| 14 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 15 | * | DL_WRITEV | port nr | proc nr | count | mode | address |
|
---|
| 16 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 17 | * | DL_READ | port nr | proc nr | count | | address |
|
---|
| 18 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 19 | * | DL_READV | port nr | proc nr | count | | address |
|
---|
| 20 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 21 | * | DL_INIT | port nr | proc nr | mode | | address |
|
---|
| 22 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 23 | * | DL_GETSTAT | port nr | proc nr | | | address |
|
---|
| 24 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 25 | * | DL_STOP | port_nr | | | | |
|
---|
| 26 | * |------------|----------|---------|----------|---------|---------|
|
---|
| 27 | *
|
---|
| 28 | * The messages sent are:
|
---|
| 29 | *
|
---|
| 30 | * m-type DL_PORT DL_PROC DL_COUNT DL_STAT DL_CLCK
|
---|
| 31 | * |-------------+----------+---------+----------+---------+---------|
|
---|
| 32 | * |DL_TASK_REPLY| port nr | proc nr | rd-count | err|stat| clock |
|
---|
| 33 | * |-------------+----------+---------+----------+---------+---------|
|
---|
| 34 | *
|
---|
| 35 | * m_type m3_i1 m3_i2 m3_ca1
|
---|
| 36 | * |-------------+---------+-----------+---------------|
|
---|
| 37 | * |DL_INIT_REPLY| port nr | last port | ethernet addr |
|
---|
| 38 | * |-------------+---------+-----------+---------------|
|
---|
| 39 | *
|
---|
| 40 | * Created: Nov 2004 by Philip Homburg <philip@f-mnx.phicoh.com>
|
---|
| 41 | */
|
---|
| 42 |
|
---|
| 43 | #include "../drivers.h"
|
---|
| 44 |
|
---|
| 45 | #include <stdlib.h>
|
---|
| 46 | #include <net/hton.h>
|
---|
| 47 | #include <net/gen/ether.h>
|
---|
| 48 | #include <net/gen/eth_io.h>
|
---|
| 49 | #include <ibm/pci.h>
|
---|
| 50 |
|
---|
| 51 | #include <timers.h>
|
---|
| 52 |
|
---|
| 53 | #define tmra_ut timer_t
|
---|
| 54 | #define tmra_inittimer(tp) tmr_inittimer(tp)
|
---|
| 55 | #define Proc_number(p) proc_number(p)
|
---|
| 56 | #define debug 0
|
---|
| 57 | #define RAND_UPDATE /**/
|
---|
| 58 | #define printW() ((void)0)
|
---|
| 59 | #define vm_1phys2bus(p) (p)
|
---|
| 60 |
|
---|
| 61 | #include "assert.h"
|
---|
| 62 | #include "fxp.h"
|
---|
| 63 | #include "mii.h"
|
---|
| 64 |
|
---|
| 65 | /* Number of receive buffers */
|
---|
| 66 | #define N_RX_BUF 40
|
---|
| 67 |
|
---|
| 68 | /* Number of transmit buffers */
|
---|
| 69 | #define N_TX_BUF 4
|
---|
| 70 |
|
---|
| 71 | /* I/O vectors are handled IOVEC_NR entries at a time. */
|
---|
| 72 | #define IOVEC_NR 16
|
---|
| 73 |
|
---|
| 74 | /* Configuration */
|
---|
| 75 | #define FXP_ENVVAR "FXPETH"
|
---|
| 76 |
|
---|
| 77 | struct pcitab
|
---|
| 78 | {
|
---|
| 79 | u16_t vid;
|
---|
| 80 | u16_t did;
|
---|
| 81 | int checkclass;
|
---|
| 82 | };
|
---|
| 83 |
|
---|
| 84 | PRIVATE struct pcitab pcitab_fxp[]=
|
---|
| 85 | {
|
---|
| 86 | { 0x8086, 0x1229, 0 }, /* Intel 82557, etc. */
|
---|
| 87 | { 0x8086, 0x2449, 0 }, /* Intel 82801BA/BAM/CA/CAM */
|
---|
| 88 |
|
---|
| 89 | { 0x0000, 0x0000, 0 }
|
---|
| 90 | };
|
---|
| 91 |
|
---|
| 92 | #define FXP_PORT_NR 1 /* Minix */
|
---|
| 93 |
|
---|
| 94 | typedef int irq_hook_t;
|
---|
| 95 |
|
---|
| 96 | /* Translate a pointer to a field in a structure to a pointer to the structure
|
---|
| 97 | * itself. So it translates '&struct_ptr->field' back to 'struct_ptr'.
|
---|
| 98 | */
|
---|
| 99 | #define structof(type, field, ptr) \
|
---|
| 100 | ((type *) (((char *) (ptr)) - offsetof(type, field)))
|
---|
| 101 |
|
---|
| 102 | #define MICROS_TO_TICKS(m) (((m)*HZ/1000000)+1)
|
---|
| 103 |
|
---|
| 104 | static timer_t *fxp_timers= NULL;
|
---|
| 105 | static clock_t fxp_next_timeout= 0;
|
---|
| 106 |
|
---|
| 107 | static void micro_delay(unsigned long usecs);
|
---|
| 108 |
|
---|
| 109 | /* ignore interrupt for the moment */
|
---|
| 110 | #define interrupt(x) 0
|
---|
| 111 |
|
---|
| 112 | char buffer[70*1024];
|
---|
| 113 |
|
---|
| 114 | typedef struct fxp
|
---|
| 115 | {
|
---|
| 116 | port_t fxp_base_port;
|
---|
| 117 | int fxp_mode;
|
---|
| 118 | int fxp_got_int;
|
---|
| 119 | int fxp_send_int;
|
---|
| 120 | int fxp_flags;
|
---|
| 121 | int fxp_client;
|
---|
| 122 | int fxp_features; /* Needed? */
|
---|
| 123 | int fxp_irq;
|
---|
| 124 | int fxp_type; /* What kind of hardware */
|
---|
| 125 | int fxp_ee_addrlen; /* #EEPROM address bits */
|
---|
| 126 | int fxp_tx_alive;
|
---|
| 127 | int fxp_need_reset;
|
---|
| 128 |
|
---|
| 129 | /* Rx */
|
---|
| 130 | vir_bytes fxp_read_s;
|
---|
| 131 | int fxp_rx_nbuf;
|
---|
| 132 | int fxp_rx_bufsize;
|
---|
| 133 | struct rfd *fxp_rx_buf;
|
---|
| 134 | phys_bytes fxp_rx_busaddr;
|
---|
| 135 | int fxp_rx_head;
|
---|
| 136 | int fxp_rx_need_restart;
|
---|
| 137 | int fxp_need_conf; /* Re-configure after draining send
|
---|
| 138 | * queue
|
---|
| 139 | */
|
---|
| 140 |
|
---|
| 141 | /* Tx */
|
---|
| 142 | int fxp_tx_nbuf;
|
---|
| 143 | int fxp_tx_bufsize;
|
---|
| 144 | struct tx *fxp_tx_buf;
|
---|
| 145 | phys_bytes fxp_tx_busaddr;
|
---|
| 146 | int fxp_tx_idle;
|
---|
| 147 | int fxp_tx_head;
|
---|
| 148 | int fxp_tx_tail;
|
---|
| 149 | int fxp_tx_threshold;
|
---|
| 150 |
|
---|
| 151 | /* Link status */
|
---|
| 152 | int fxp_report_link;
|
---|
| 153 | int fxp_link_up;
|
---|
| 154 | int fxp_mii_busy;
|
---|
| 155 | u16_t fxp_mii_scr;
|
---|
| 156 |
|
---|
| 157 | /* PCI related */
|
---|
| 158 | int fxp_seen; /* TRUE iff device available */
|
---|
| 159 | u8_t fxp_pcibus;
|
---|
| 160 | u8_t fxp_pcidev;
|
---|
| 161 | u8_t fxp_pcifunc;
|
---|
| 162 |
|
---|
| 163 | /* 'large' items */
|
---|
| 164 | irq_hook_t fxp_hook;
|
---|
| 165 | ether_addr_t fxp_address;
|
---|
| 166 | message fxp_rx_mess;
|
---|
| 167 | message fxp_tx_mess;
|
---|
| 168 | struct sc fxp_stat;
|
---|
| 169 | u8_t fxp_conf_bytes[CC_BYTES_NR];
|
---|
| 170 | char fxp_name[sizeof("fxp#n")];
|
---|
| 171 | iovec_t fxp_iovec[IOVEC_NR];
|
---|
| 172 | }
|
---|
| 173 | fxp_t;
|
---|
| 174 |
|
---|
| 175 | /* fxp_mode */
|
---|
| 176 | #define FM_DISABLED 0x0
|
---|
| 177 | #define FM_ENABLED 0x1
|
---|
| 178 |
|
---|
| 179 | /* fxp_flags */
|
---|
| 180 | #define FF_EMPTY 0x000
|
---|
| 181 | #define FF_PACK_SENT 0x001
|
---|
| 182 | #define FF_PACK_RECV 0x002
|
---|
| 183 | #define FF_SEND_AVAIL 0x004
|
---|
| 184 | #define FF_READING 0x010
|
---|
| 185 | #define FF_PROMISC 0x040
|
---|
| 186 | #define FF_MULTI 0x080
|
---|
| 187 | #define FF_BROAD 0x100
|
---|
| 188 | #define FF_ENABLED 0x200
|
---|
| 189 |
|
---|
| 190 | /* fxp_features */
|
---|
| 191 | #define FFE_NONE 0x0
|
---|
| 192 |
|
---|
| 193 | /* fxp_type */
|
---|
| 194 | #define FT_UNKNOWN 0x0
|
---|
| 195 | #define FT_82557 0x1
|
---|
| 196 | #define FT_82558A 0x2
|
---|
| 197 | #define FT_82559 0x4
|
---|
| 198 |
|
---|
| 199 | static fxp_t fxp_table[FXP_PORT_NR];
|
---|
| 200 |
|
---|
| 201 | static int fxp_tasknr= ANY;
|
---|
| 202 | static u16_t eth_ign_proto;
|
---|
| 203 | static tmra_ut fxp_watchdog;
|
---|
| 204 | static char *progname;
|
---|
| 205 |
|
---|
| 206 | extern int errno;
|
---|
| 207 |
|
---|
| 208 | #define fxp_inb(port, offset) (do_inb((port) + (offset)))
|
---|
| 209 | #define fxp_inw(port, offset) (do_inw((port) + (offset)))
|
---|
| 210 | #define fxp_inl(port, offset) (do_inl((port) + (offset)))
|
---|
| 211 | #define fxp_outb(port, offset, value) (do_outb((port) + (offset), (value)))
|
---|
| 212 | #define fxp_outw(port, offset, value) (do_outw((port) + (offset), (value)))
|
---|
| 213 | #define fxp_outl(port, offset, value) (do_outl((port) + (offset), (value)))
|
---|
| 214 |
|
---|
| 215 | _PROTOTYPE( static void fxp_init, (message *mp) );
|
---|
| 216 | _PROTOTYPE( static void fxp_pci_conf, (void) );
|
---|
| 217 | _PROTOTYPE( static int fxp_probe, (fxp_t *fp) );
|
---|
| 218 | _PROTOTYPE( static void fxp_conf_hw, (fxp_t *fp) );
|
---|
| 219 | _PROTOTYPE( static void fxp_init_hw, (fxp_t *fp) );
|
---|
| 220 | _PROTOTYPE( static void fxp_init_buf, (fxp_t *fp) );
|
---|
| 221 | _PROTOTYPE( static void fxp_reset_hw, (fxp_t *fp) );
|
---|
| 222 | _PROTOTYPE( static void fxp_confaddr, (fxp_t *fp) );
|
---|
| 223 | _PROTOTYPE( static void fxp_rec_mode, (fxp_t *fp) );
|
---|
| 224 | _PROTOTYPE( static void fxp_writev, (message *mp, int from_int,
|
---|
| 225 | int vectored) );
|
---|
| 226 | _PROTOTYPE( static void fxp_readv, (message *mp, int from_int,
|
---|
| 227 | int vectored) );
|
---|
| 228 | _PROTOTYPE( static void fxp_do_conf, (fxp_t *fp) );
|
---|
| 229 | _PROTOTYPE( static void fxp_cu_ptr_cmd, (fxp_t *fp, int cmd,
|
---|
| 230 | phys_bytes bus_addr, int check_idle) );
|
---|
| 231 | _PROTOTYPE( static void fxp_ru_ptr_cmd, (fxp_t *fp, int cmd,
|
---|
| 232 | phys_bytes bus_addr, int check_idle) );
|
---|
| 233 | _PROTOTYPE( static void fxp_restart_ru, (fxp_t *fp) );
|
---|
| 234 | _PROTOTYPE( static void fxp_getstat, (message *mp) );
|
---|
| 235 | _PROTOTYPE( static void fxp_getname, (message *mp) );
|
---|
| 236 | _PROTOTYPE( static int fxp_handler, (fxp_t *fp) );
|
---|
| 237 | _PROTOTYPE( static void fxp_check_ints, (fxp_t *fp) );
|
---|
| 238 | _PROTOTYPE( static void fxp_watchdog_f, (timer_t *tp) );
|
---|
| 239 | _PROTOTYPE( static int fxp_link_changed, (fxp_t *fp) );
|
---|
| 240 | _PROTOTYPE( static void fxp_report_link, (fxp_t *fp) );
|
---|
| 241 | _PROTOTYPE( static void fxp_stop, (void));
|
---|
| 242 | _PROTOTYPE( static void reply, (fxp_t *fp, int err, int may_block) );
|
---|
| 243 | _PROTOTYPE( static void mess_reply, (message *req, message *reply) );
|
---|
| 244 | _PROTOTYPE( static void put_userdata, (int user_proc,
|
---|
| 245 | vir_bytes user_addr, vir_bytes count, void *loc_addr) );
|
---|
| 246 | _PROTOTYPE( static u16_t eeprom_read, (fxp_t *fp, int reg) );
|
---|
| 247 | _PROTOTYPE( static void eeprom_addrsize, (fxp_t *fp) );
|
---|
| 248 | _PROTOTYPE( static u16_t mii_read, (fxp_t *fp, int reg) );
|
---|
| 249 | _PROTOTYPE( static void fxp_set_timer,(timer_t *tp, clock_t delta,
|
---|
| 250 | tmr_func_t watchdog) );
|
---|
| 251 | _PROTOTYPE( static void fxp_expire_timers,(void) );
|
---|
| 252 | _PROTOTYPE( static u8_t do_inb, (port_t port) );
|
---|
| 253 | _PROTOTYPE( static u32_t do_inl, (port_t port) );
|
---|
| 254 | _PROTOTYPE( static void do_outb, (port_t port, u8_t v) );
|
---|
| 255 | _PROTOTYPE( static void do_outl, (port_t port, u32_t v) );
|
---|
| 256 |
|
---|
| 257 | /*===========================================================================*
|
---|
| 258 | * main *
|
---|
| 259 | *===========================================================================*/
|
---|
| 260 | int main(int argc, char *argv[])
|
---|
| 261 | {
|
---|
| 262 | message m;
|
---|
| 263 | int i, r, tasknr;
|
---|
| 264 | fxp_t *fp;
|
---|
| 265 | long v;
|
---|
| 266 |
|
---|
| 267 | if ((fxp_tasknr= getprocnr())<0)
|
---|
| 268 | panic("FXP", "couldn't get proc nr", errno);
|
---|
| 269 |
|
---|
| 270 | if (argc < 1)
|
---|
| 271 | panic("FXP", "A head which at this time has no name", NO_NUM);
|
---|
| 272 | (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
|
---|
| 273 |
|
---|
| 274 | v= 0;
|
---|
| 275 | #if 0
|
---|
| 276 | (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
|
---|
| 277 | #endif
|
---|
| 278 | eth_ign_proto= htons((u16_t) v);
|
---|
| 279 |
|
---|
| 280 | #if 0 /* What about memory allocation? */
|
---|
| 281 | /* Claim buffer memory now under Minix, before MM takes it all. */
|
---|
| 282 | for (fp= &fxp_table[0]; fp < fxp_table+FXP_PORT_NR; fp++)
|
---|
| 283 | fxp_init_buf(fp);
|
---|
| 284 | #endif
|
---|
| 285 |
|
---|
| 286 | /* Try to notify inet that we are present (again) */
|
---|
| 287 | r = _pm_findproc("inet", &tasknr);
|
---|
| 288 | if (r == OK)
|
---|
| 289 | notify(tasknr);
|
---|
| 290 |
|
---|
| 291 | while (TRUE)
|
---|
| 292 | {
|
---|
| 293 | if ((r= receive(ANY, &m)) != OK)
|
---|
| 294 | panic("FXP","receive failed", r);
|
---|
| 295 |
|
---|
| 296 | switch (m.m_type)
|
---|
| 297 | {
|
---|
| 298 | case DEV_PING: notify(m.m_source); continue;
|
---|
| 299 | case DL_WRITEV: fxp_writev(&m, FALSE, TRUE); break;
|
---|
| 300 | case DL_WRITE: fxp_writev(&m, FALSE, FALSE); break;
|
---|
| 301 | #if 0
|
---|
| 302 | case DL_READ: fxp_vread(&m, FALSE); break;
|
---|
| 303 | #endif
|
---|
| 304 | case DL_READV: fxp_readv(&m, FALSE, TRUE); break;
|
---|
| 305 | case DL_INIT: fxp_init(&m); break;
|
---|
| 306 | case DL_GETSTAT: fxp_getstat(&m); break;
|
---|
| 307 | case DL_GETNAME: fxp_getname(&m); break;
|
---|
| 308 | case HARD_INT:
|
---|
| 309 | for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
|
---|
| 310 | {
|
---|
| 311 | if (fp->fxp_mode != FM_ENABLED)
|
---|
| 312 | continue;
|
---|
| 313 | fxp_handler(fp);
|
---|
| 314 |
|
---|
| 315 | r= sys_irqenable(&fp->fxp_hook);
|
---|
| 316 | if (r != OK)
|
---|
| 317 | panic("FXP","unable enable interrupts", r);
|
---|
| 318 |
|
---|
| 319 | if (!fp->fxp_got_int)
|
---|
| 320 | continue;
|
---|
| 321 | fp->fxp_got_int= 0;
|
---|
| 322 | assert(fp->fxp_flags & FF_ENABLED);
|
---|
| 323 | fxp_check_ints(fp);
|
---|
| 324 | }
|
---|
| 325 | break;
|
---|
| 326 | case SYS_SIG: {
|
---|
| 327 | sigset_t sigset = m.NOTIFY_ARG;
|
---|
| 328 | if (sigismember(&sigset, SIGKSTOP)) fxp_stop();
|
---|
| 329 | break;
|
---|
| 330 | }
|
---|
| 331 | case PROC_EVENT: break;
|
---|
| 332 | case SYN_ALARM: fxp_expire_timers(); break;
|
---|
| 333 | default:
|
---|
| 334 | panic("FXP"," illegal message", m.m_type);
|
---|
| 335 | }
|
---|
| 336 | }
|
---|
| 337 | }
|
---|
| 338 |
|
---|
| 339 | /*===========================================================================*
|
---|
| 340 | * fxp_init *
|
---|
| 341 | *===========================================================================*/
|
---|
| 342 | static void fxp_init(mp)
|
---|
| 343 | message *mp;
|
---|
| 344 | {
|
---|
| 345 | static int first_time= 1;
|
---|
| 346 |
|
---|
| 347 | int port;
|
---|
| 348 | fxp_t *fp;
|
---|
| 349 | message reply_mess;
|
---|
| 350 |
|
---|
| 351 | if (first_time)
|
---|
| 352 | {
|
---|
| 353 | first_time= 0;
|
---|
| 354 | fxp_pci_conf(); /* Configure PCI devices. */
|
---|
| 355 |
|
---|
| 356 | tmra_inittimer(&fxp_watchdog);
|
---|
| 357 | tmr_arg(&fxp_watchdog)->ta_int= 0;
|
---|
| 358 | fxp_set_timer(&fxp_watchdog, HZ, fxp_watchdog_f);
|
---|
| 359 | }
|
---|
| 360 |
|
---|
| 361 | port = mp->DL_PORT;
|
---|
| 362 | if (port < 0 || port >= FXP_PORT_NR)
|
---|
| 363 | {
|
---|
| 364 | reply_mess.m_type= DL_INIT_REPLY;
|
---|
| 365 | reply_mess.m3_i1= ENXIO;
|
---|
| 366 | mess_reply(mp, &reply_mess);
|
---|
| 367 | return;
|
---|
| 368 | }
|
---|
| 369 | fp= &fxp_table[port];
|
---|
| 370 | if (fp->fxp_mode == FM_DISABLED)
|
---|
| 371 | {
|
---|
| 372 | /* This is the default, try to (re)locate the device. */
|
---|
| 373 | fxp_conf_hw(fp);
|
---|
| 374 | if (fp->fxp_mode == FM_DISABLED)
|
---|
| 375 | {
|
---|
| 376 | /* Probe failed, or the device is configured off. */
|
---|
| 377 | reply_mess.m_type= DL_INIT_REPLY;
|
---|
| 378 | reply_mess.m3_i1= ENXIO;
|
---|
| 379 | mess_reply(mp, &reply_mess);
|
---|
| 380 | return;
|
---|
| 381 | }
|
---|
| 382 | if (fp->fxp_mode == FM_ENABLED)
|
---|
| 383 | fxp_init_hw(fp);
|
---|
| 384 | fxp_report_link(fp);
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | assert(fp->fxp_mode == FM_ENABLED);
|
---|
| 388 | assert(fp->fxp_flags & FF_ENABLED);
|
---|
| 389 |
|
---|
| 390 | fp->fxp_flags &= ~(FF_PROMISC | FF_MULTI | FF_BROAD);
|
---|
| 391 |
|
---|
| 392 | if (mp->DL_MODE & DL_PROMISC_REQ)
|
---|
| 393 | fp->fxp_flags |= FF_PROMISC;
|
---|
| 394 | if (mp->DL_MODE & DL_MULTI_REQ)
|
---|
| 395 | fp->fxp_flags |= FF_MULTI;
|
---|
| 396 | if (mp->DL_MODE & DL_BROAD_REQ)
|
---|
| 397 | fp->fxp_flags |= FF_BROAD;
|
---|
| 398 |
|
---|
| 399 | fp->fxp_client = mp->m_source;
|
---|
| 400 | fxp_rec_mode(fp);
|
---|
| 401 |
|
---|
| 402 | reply_mess.m_type = DL_INIT_REPLY;
|
---|
| 403 | reply_mess.m3_i1 = mp->DL_PORT;
|
---|
| 404 | reply_mess.m3_i2 = FXP_PORT_NR;
|
---|
| 405 | *(ether_addr_t *) reply_mess.m3_ca1 = fp->fxp_address;
|
---|
| 406 |
|
---|
| 407 | mess_reply(mp, &reply_mess);
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | /*===========================================================================*
|
---|
| 411 | * fxp_pci_conf *
|
---|
| 412 | *===========================================================================*/
|
---|
| 413 | static void fxp_pci_conf()
|
---|
| 414 | {
|
---|
| 415 | static char envvar[] = FXP_ENVVAR "#";
|
---|
| 416 | static char envfmt[] = "*:d.d.d";
|
---|
| 417 |
|
---|
| 418 | int i, h;
|
---|
| 419 | fxp_t *fp;
|
---|
| 420 | long v;
|
---|
| 421 |
|
---|
| 422 | for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++)
|
---|
| 423 | {
|
---|
| 424 | strcpy(fp->fxp_name, "fxp#0");
|
---|
| 425 | fp->fxp_name[4] += i;
|
---|
| 426 | fp->fxp_seen= FALSE;
|
---|
| 427 | fp->fxp_features= FFE_NONE;
|
---|
| 428 | envvar[sizeof(FXP_ENVVAR)-1]= '0'+i;
|
---|
| 429 | #if 0
|
---|
| 430 | if (getenv(envvar) != NULL)
|
---|
| 431 | {
|
---|
| 432 | if (strcmp(getenv(envvar), "off") == 0)
|
---|
| 433 | {
|
---|
| 434 | fp->fxp_pcibus= 255;
|
---|
| 435 | continue;
|
---|
| 436 | }
|
---|
| 437 | if (!env_prefix(envvar, "pci"))
|
---|
| 438 | env_panic(envvar);
|
---|
| 439 | }
|
---|
| 440 | #endif
|
---|
| 441 |
|
---|
| 442 | v= 0;
|
---|
| 443 | #if 0
|
---|
| 444 | (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
|
---|
| 445 | #endif
|
---|
| 446 | fp->fxp_pcibus= v;
|
---|
| 447 | v= 0;
|
---|
| 448 | #if 0
|
---|
| 449 | (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
|
---|
| 450 | #endif
|
---|
| 451 | fp->fxp_pcidev= v;
|
---|
| 452 | v= 0;
|
---|
| 453 | #if 0
|
---|
| 454 | (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
|
---|
| 455 | #endif
|
---|
| 456 | fp->fxp_pcifunc= v;
|
---|
| 457 | }
|
---|
| 458 |
|
---|
| 459 | pci_init();
|
---|
| 460 |
|
---|
| 461 | for (h= 1; h >= 0; h--) {
|
---|
| 462 | for (i= 0, fp= fxp_table; i<FXP_PORT_NR; i++, fp++)
|
---|
| 463 | {
|
---|
| 464 | if (fp->fxp_pcibus == 255)
|
---|
| 465 | continue;
|
---|
| 466 | if (((fp->fxp_pcibus | fp->fxp_pcidev |
|
---|
| 467 | fp->fxp_pcifunc) != 0) != h)
|
---|
| 468 | {
|
---|
| 469 | continue;
|
---|
| 470 | }
|
---|
| 471 | if (fxp_probe(fp))
|
---|
| 472 | fp->fxp_seen= TRUE;
|
---|
| 473 | }
|
---|
| 474 | }
|
---|
| 475 | }
|
---|
| 476 |
|
---|
| 477 | /*===========================================================================*
|
---|
| 478 | * fxp_probe *
|
---|
| 479 | *===========================================================================*/
|
---|
| 480 | static int fxp_probe(fp)
|
---|
| 481 | fxp_t *fp;
|
---|
| 482 | {
|
---|
| 483 | int i, r, devind, just_one;
|
---|
| 484 | u16_t vid, did;
|
---|
| 485 | u32_t bar;
|
---|
| 486 | u8_t ilr, rev;
|
---|
| 487 | char *dname, *str;
|
---|
| 488 |
|
---|
| 489 | if ((fp->fxp_pcibus | fp->fxp_pcidev | fp->fxp_pcifunc) != 0)
|
---|
| 490 | {
|
---|
| 491 | /* Look for specific PCI device */
|
---|
| 492 | r= pci_find_dev(fp->fxp_pcibus, fp->fxp_pcidev,
|
---|
| 493 | fp->fxp_pcifunc, &devind);
|
---|
| 494 | if (r == 0)
|
---|
| 495 | {
|
---|
| 496 | printf("%s: no PCI device found at %d.%d.%d\n",
|
---|
| 497 | fp->fxp_name, fp->fxp_pcibus,
|
---|
| 498 | fp->fxp_pcidev, fp->fxp_pcifunc);
|
---|
| 499 | return FALSE;
|
---|
| 500 | }
|
---|
| 501 | pci_ids(devind, &vid, &did);
|
---|
| 502 | just_one= TRUE;
|
---|
| 503 | }
|
---|
| 504 | else
|
---|
| 505 | {
|
---|
| 506 | r= pci_first_dev(&devind, &vid, &did);
|
---|
| 507 | if (r == 0)
|
---|
| 508 | return FALSE;
|
---|
| 509 | just_one= FALSE;
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | for(;;)
|
---|
| 513 | {
|
---|
| 514 | for (i= 0; pcitab_fxp[i].vid != 0; i++)
|
---|
| 515 | {
|
---|
| 516 | if (pcitab_fxp[i].vid != vid)
|
---|
| 517 | continue;
|
---|
| 518 | if (pcitab_fxp[i].did != did)
|
---|
| 519 | continue;
|
---|
| 520 | if (pcitab_fxp[i].checkclass)
|
---|
| 521 | {
|
---|
| 522 | panic("FXP","fxp_probe: class check not implemented",
|
---|
| 523 | NO_NUM);
|
---|
| 524 | }
|
---|
| 525 | break;
|
---|
| 526 | }
|
---|
| 527 | if (pcitab_fxp[i].vid != 0)
|
---|
| 528 | break;
|
---|
| 529 |
|
---|
| 530 | if (just_one)
|
---|
| 531 | {
|
---|
| 532 | printf(
|
---|
| 533 | "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
|
---|
| 534 | fp->fxp_name, vid, did,
|
---|
| 535 | fp->fxp_pcibus,
|
---|
| 536 | fp->fxp_pcidev, fp->fxp_pcifunc);
|
---|
| 537 | return FALSE;
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | r= pci_next_dev(&devind, &vid, &did);
|
---|
| 541 | if (!r)
|
---|
| 542 | return FALSE;
|
---|
| 543 | }
|
---|
| 544 |
|
---|
| 545 | dname= pci_dev_name(vid, did);
|
---|
| 546 | #if VERBOSE
|
---|
| 547 | if (!dname)
|
---|
| 548 | dname= "unknown device";
|
---|
| 549 | printf("%s: %s (%04x/%04x) at %s\n",
|
---|
| 550 | fp->fxp_name, dname, vid, did, pci_slot_name(devind));
|
---|
| 551 | #endif
|
---|
| 552 | pci_reserve(devind);
|
---|
| 553 |
|
---|
| 554 | bar= pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
|
---|
| 555 | if (bar < 0x400)
|
---|
| 556 | {
|
---|
| 557 | panic("FXP","fxp_probe: base address is not properly configured",
|
---|
| 558 | NO_NUM);
|
---|
| 559 | }
|
---|
| 560 | fp->fxp_base_port= bar;
|
---|
| 561 |
|
---|
| 562 | ilr= pci_attr_r8(devind, PCI_ILR);
|
---|
| 563 | fp->fxp_irq= ilr;
|
---|
| 564 | if (debug)
|
---|
| 565 | {
|
---|
| 566 | printf("%s: using I/O address 0x%lx, IRQ %d\n",
|
---|
| 567 | fp->fxp_name, (unsigned long)bar, ilr);
|
---|
| 568 | }
|
---|
| 569 |
|
---|
| 570 | rev= pci_attr_r8(devind, PCI_REV);
|
---|
| 571 | str= NULL;
|
---|
| 572 | fp->fxp_type= FT_UNKNOWN;
|
---|
| 573 | switch(rev)
|
---|
| 574 | {
|
---|
| 575 | case FXP_REV_82557A: str= "82557A"; /* 0x01 */
|
---|
| 576 | fp->fxp_type= FT_82557;
|
---|
| 577 | break;
|
---|
| 578 | case FXP_REV_82557B: str= "82557B"; break; /* 0x02 */
|
---|
| 579 | case FXP_REV_82557C: str= "82557C"; break; /* 0x03 */
|
---|
| 580 | case FXP_REV_82558A: str= "82558A"; /* 0x04 */
|
---|
| 581 | fp->fxp_type= FT_82558A;
|
---|
| 582 | break;
|
---|
| 583 | case FXP_REV_82558B: str= "82558B"; break; /* 0x05 */
|
---|
| 584 | case FXP_REV_82559A: str= "82559A"; break; /* 0x06 */
|
---|
| 585 | case FXP_REV_82559B: str= "82559B"; break; /* 0x07 */
|
---|
| 586 | case FXP_REV_82559C: str= "82559C"; /* 0x08 */
|
---|
| 587 | fp->fxp_type= FT_82559;
|
---|
| 588 | break;
|
---|
| 589 | case FXP_REV_82559ERA: str= "82559ER-A"; /* 0x09 */
|
---|
| 590 | fp->fxp_type= FT_82559;
|
---|
| 591 | break;
|
---|
| 592 | case FXP_REV_82550_1: str= "82550(1)"; /* 0x0C */
|
---|
| 593 | fp->fxp_type= FT_82559;
|
---|
| 594 | break;
|
---|
| 595 | case FXP_REV_82550_2: str= "82550(2)"; /* 0x0D */
|
---|
| 596 | fp->fxp_type= FT_82559;
|
---|
| 597 | break;
|
---|
| 598 | case FXP_REV_82550_3: str= "82550(3)"; /* 0x0E */
|
---|
| 599 | fp->fxp_type= FT_82559;
|
---|
| 600 | break;
|
---|
| 601 | case FXP_REV_82551_1: str= "82551(1)"; /* 0x0F */
|
---|
| 602 | fp->fxp_type= FT_82559;
|
---|
| 603 | break;
|
---|
| 604 | case FXP_REV_82551_2: str= "82551(2)"; /* 0x10 */
|
---|
| 605 | fp->fxp_type= FT_82559;
|
---|
| 606 | break;
|
---|
| 607 | }
|
---|
| 608 |
|
---|
| 609 | #if VERBOSE
|
---|
| 610 | if (str)
|
---|
| 611 | printf("%s: device revision: %s\n", fp->fxp_name, str);
|
---|
| 612 | else
|
---|
| 613 | printf("%s: unknown revision: 0x%x\n", fp->fxp_name, rev);
|
---|
| 614 | #endif
|
---|
| 615 |
|
---|
| 616 | if (fp->fxp_type == FT_UNKNOWN)
|
---|
| 617 | {
|
---|
| 618 | printf("fxp_probe: device is not supported by this driver\n");
|
---|
| 619 | return FALSE;
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | return TRUE;
|
---|
| 623 | }
|
---|
| 624 |
|
---|
| 625 | /*===========================================================================*
|
---|
| 626 | * fxp_conf_hw *
|
---|
| 627 | *===========================================================================*/
|
---|
| 628 | static void fxp_conf_hw(fp)
|
---|
| 629 | fxp_t *fp;
|
---|
| 630 | {
|
---|
| 631 | int i;
|
---|
| 632 | int mwi, ext_stat1, ext_stat2, lim_fifo, i82503, fc;
|
---|
| 633 |
|
---|
| 634 | fp->fxp_mode= FM_DISABLED; /* Superfluous */
|
---|
| 635 |
|
---|
| 636 | if (!fp->fxp_seen)
|
---|
| 637 | return;
|
---|
| 638 |
|
---|
| 639 | /* PCI device is present */
|
---|
| 640 | fp->fxp_mode= FM_ENABLED;
|
---|
| 641 |
|
---|
| 642 | fp->fxp_flags= FF_EMPTY;
|
---|
| 643 | fp->fxp_got_int= 0;
|
---|
| 644 | fp->fxp_send_int= 0;
|
---|
| 645 | fp->fxp_ee_addrlen= 0; /* Unknown */
|
---|
| 646 | fp->fxp_need_reset= 0;
|
---|
| 647 | fp->fxp_report_link= 0;
|
---|
| 648 | fp->fxp_link_up= -1; /* Unknown */
|
---|
| 649 | fp->fxp_mii_busy= 0;
|
---|
| 650 | fp->fxp_read_s= 0;
|
---|
| 651 | fp->fxp_rx_need_restart= 0;
|
---|
| 652 | fp->fxp_need_conf= 0;
|
---|
| 653 | fp->fxp_tx_head= 0;
|
---|
| 654 | fp->fxp_tx_tail= 0;
|
---|
| 655 | fp->fxp_tx_alive= 0;
|
---|
| 656 | fp->fxp_tx_threshold= TXTT_MIN;
|
---|
| 657 |
|
---|
| 658 | /* Try to come up with a sensible configuration for the current
|
---|
| 659 | * device. Unfortunately every device is different, defaults are
|
---|
| 660 | * not always zero, and some fields are re-used with a completely
|
---|
| 661 | * different interpretation. We start out with a sensible default
|
---|
| 662 | * for all devices and then add device specific changes.
|
---|
| 663 | */
|
---|
| 664 | fp->fxp_conf_bytes[0]= CC_BYTES_NR;
|
---|
| 665 | fp->fxp_conf_bytes[1]= CTL_DEFAULT | CRL_DEFAULT;
|
---|
| 666 | fp->fxp_conf_bytes[2]= CAI_DEFAULT;
|
---|
| 667 | fp->fxp_conf_bytes[3]= 0;
|
---|
| 668 | fp->fxp_conf_bytes[4]= 0;
|
---|
| 669 | fp->fxp_conf_bytes[5]= 0;
|
---|
| 670 | fp->fxp_conf_bytes[6]= CCB6_ESC | CCB6_ETCB | CCB6_RES;
|
---|
| 671 | fp->fxp_conf_bytes[7]= CUR_1;
|
---|
| 672 | fp->fxp_conf_bytes[8]= CCB8_503_MII;
|
---|
| 673 | fp->fxp_conf_bytes[9]= 0;
|
---|
| 674 | fp->fxp_conf_bytes[10]= CLB_NORMAL | CPAL_DEFAULT | CCB10_NSAI |
|
---|
| 675 | CCB10_RES1;
|
---|
| 676 | fp->fxp_conf_bytes[11]= 0;
|
---|
| 677 | fp->fxp_conf_bytes[12]= CIS_DEFAULT;
|
---|
| 678 | fp->fxp_conf_bytes[13]= CCB13_DEFAULT;
|
---|
| 679 | fp->fxp_conf_bytes[14]= CCB14_DEFAULT;
|
---|
| 680 | fp->fxp_conf_bytes[15]= CCB15_RES1 | CCB15_RES2;
|
---|
| 681 | fp->fxp_conf_bytes[16]= CCB16_DEFAULT;
|
---|
| 682 | fp->fxp_conf_bytes[17]= CCB17_DEFAULT;
|
---|
| 683 | fp->fxp_conf_bytes[18]= CCB18_RES1 | CCB18_PFCT | CCB18_PE;
|
---|
| 684 | fp->fxp_conf_bytes[19]= CCB19_FDPE;
|
---|
| 685 | fp->fxp_conf_bytes[20]= CCB20_PFCL | CCB20_RES1;
|
---|
| 686 | fp->fxp_conf_bytes[21]= CCB21_RES21;
|
---|
| 687 |
|
---|
| 688 | #if VERBOSE
|
---|
| 689 | for (i= 0; i<CC_BYTES_NR; i++)
|
---|
| 690 | printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
|
---|
| 691 | printf("\n");
|
---|
| 692 | #endif
|
---|
| 693 |
|
---|
| 694 | mwi= 0; /* Do we want "Memory Write and Invalidate"? */
|
---|
| 695 | ext_stat1= 0; /* Do we want extended statistical counters? */
|
---|
| 696 | ext_stat2= 0; /* Do we want even more statistical counters? */
|
---|
| 697 | lim_fifo= 0; /* Limit number of frame in TX FIFO */
|
---|
| 698 | i82503= 0; /* Older 10 Mbps interface on the 82557 */
|
---|
| 699 | fc= 0; /* Flow control */
|
---|
| 700 |
|
---|
| 701 | switch(fp->fxp_type)
|
---|
| 702 | {
|
---|
| 703 | case FT_82557:
|
---|
| 704 | if (i82503)
|
---|
| 705 | {
|
---|
| 706 | fp->fxp_conf_bytes[8] &= ~CCB8_503_MII;
|
---|
| 707 | fp->fxp_conf_bytes[15] |= CCB15_CRSCDT;
|
---|
| 708 | }
|
---|
| 709 | break;
|
---|
| 710 | case FT_82558A:
|
---|
| 711 | case FT_82559:
|
---|
| 712 | if (mwi)
|
---|
| 713 | fp->fxp_conf_bytes[3] |= CCB3_MWIE;
|
---|
| 714 | if (ext_stat1)
|
---|
| 715 | fp->fxp_conf_bytes[6] &= ~CCB6_ESC;
|
---|
| 716 | if (ext_stat2)
|
---|
| 717 | fp->fxp_conf_bytes[6] &= ~CCB6_TCOSC;
|
---|
| 718 | if (lim_fifo)
|
---|
| 719 | fp->fxp_conf_bytes[7] |= CCB7_2FFIFO;
|
---|
| 720 | if (fc)
|
---|
| 721 | {
|
---|
| 722 | /* From FreeBSD driver */
|
---|
| 723 | fp->fxp_conf_bytes[16]= 0x1f;
|
---|
| 724 | fp->fxp_conf_bytes[17]= 0x01;
|
---|
| 725 |
|
---|
| 726 | fp->fxp_conf_bytes[19] |= CCB19_FDRSTAFC |
|
---|
| 727 | CCB19_FDRSTOFC;
|
---|
| 728 | }
|
---|
| 729 |
|
---|
| 730 | fp->fxp_conf_bytes[18] |= CCB18_LROK;
|
---|
| 731 | break;
|
---|
| 732 | default:
|
---|
| 733 | panic("FXP","fxp_conf_hw: bad device type", fp->fxp_type);
|
---|
| 734 | }
|
---|
| 735 |
|
---|
| 736 | #if VERBOSE
|
---|
| 737 | for (i= 0; i<CC_BYTES_NR; i++)
|
---|
| 738 | printf("%d: %0x, ", i, fp->fxp_conf_bytes[i]);
|
---|
| 739 | printf("\n");
|
---|
| 740 | #endif
|
---|
| 741 | }
|
---|
| 742 |
|
---|
| 743 | /*===========================================================================*
|
---|
| 744 | * fxp_init_hw *
|
---|
| 745 | *===========================================================================*/
|
---|
| 746 | static void fxp_init_hw(fp)
|
---|
| 747 | fxp_t *fp;
|
---|
| 748 | {
|
---|
| 749 | int i, r, isr;
|
---|
| 750 | port_t port;
|
---|
| 751 | u32_t bus_addr;
|
---|
| 752 |
|
---|
| 753 | port= fp->fxp_base_port;
|
---|
| 754 |
|
---|
| 755 | fxp_init_buf(fp);
|
---|
| 756 |
|
---|
| 757 | fp->fxp_flags = FF_EMPTY;
|
---|
| 758 | fp->fxp_flags |= FF_ENABLED;
|
---|
| 759 |
|
---|
| 760 | /* Set the interrupt handler and policy. Do not automatically
|
---|
| 761 | * reenable interrupts. Return the IRQ line number on interrupts.
|
---|
| 762 | */
|
---|
| 763 | fp->fxp_hook = fp->fxp_irq;
|
---|
| 764 | r= sys_irqsetpolicy(fp->fxp_irq, 0, &fp->fxp_hook);
|
---|
| 765 | if (r != OK)
|
---|
| 766 | panic("FXP","sys_irqsetpolicy failed", r);
|
---|
| 767 |
|
---|
| 768 | fxp_reset_hw(fp);
|
---|
| 769 |
|
---|
| 770 | r= sys_irqenable(&fp->fxp_hook);
|
---|
| 771 | if (r != OK)
|
---|
| 772 | panic("FXP","sys_irqenable failed", r);
|
---|
| 773 |
|
---|
| 774 | /* Reset PHY? */
|
---|
| 775 |
|
---|
| 776 | fxp_do_conf(fp);
|
---|
| 777 |
|
---|
| 778 | /* Set pointer to statistical counters */
|
---|
| 779 | r= sys_umap(SELF, D, (vir_bytes)&fp->fxp_stat, sizeof(fp->fxp_stat),
|
---|
| 780 | &bus_addr);
|
---|
| 781 | if (r != OK)
|
---|
| 782 | panic("FXP","sys_umap failed", r);
|
---|
| 783 | fxp_cu_ptr_cmd(fp, SC_CU_LOAD_DCA, bus_addr, TRUE /* check idle */);
|
---|
| 784 |
|
---|
| 785 | /* Ack previous interrupts */
|
---|
| 786 | isr= fxp_inb(port, SCB_INT_STAT);
|
---|
| 787 | fxp_outb(port, SCB_INT_STAT, isr);
|
---|
| 788 |
|
---|
| 789 | /* Enable interrupts */
|
---|
| 790 | fxp_outb(port, SCB_INT_MASK, 0);
|
---|
| 791 |
|
---|
| 792 | fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
|
---|
| 793 | TRUE /* check idle */);
|
---|
| 794 |
|
---|
| 795 | fxp_confaddr(fp);
|
---|
| 796 | if (debug)
|
---|
| 797 | {
|
---|
| 798 | printf("%s: Ethernet address ", fp->fxp_name);
|
---|
| 799 | for (i= 0; i < 6; i++)
|
---|
| 800 | {
|
---|
| 801 | printf("%x%c", fp->fxp_address.ea_addr[i],
|
---|
| 802 | i < 5 ? ':' : '\n');
|
---|
| 803 | }
|
---|
| 804 | }
|
---|
| 805 | }
|
---|
| 806 |
|
---|
| 807 | /*===========================================================================*
|
---|
| 808 | * fxp_init_buf *
|
---|
| 809 | *===========================================================================*/
|
---|
| 810 | static void fxp_init_buf(fp)
|
---|
| 811 | fxp_t *fp;
|
---|
| 812 | {
|
---|
| 813 | size_t rx_totbufsize, tx_totbufsize, tot_bufsize;
|
---|
| 814 | phys_bytes buf;
|
---|
| 815 | int i, r;
|
---|
| 816 | struct rfd *rfdp;
|
---|
| 817 | struct tx *txp;
|
---|
| 818 |
|
---|
| 819 | fp->fxp_rx_nbuf= N_RX_BUF;
|
---|
| 820 | rx_totbufsize= fp->fxp_rx_nbuf * sizeof(struct rfd);
|
---|
| 821 | fp->fxp_rx_bufsize= rx_totbufsize;
|
---|
| 822 |
|
---|
| 823 | fp->fxp_tx_nbuf= N_TX_BUF;
|
---|
| 824 | tx_totbufsize= fp->fxp_tx_nbuf * sizeof(struct tx);
|
---|
| 825 | fp->fxp_tx_bufsize= tx_totbufsize;
|
---|
| 826 |
|
---|
| 827 | tot_bufsize= tx_totbufsize + rx_totbufsize;
|
---|
| 828 |
|
---|
| 829 | /* What about memory allocation? */
|
---|
| 830 | {
|
---|
| 831 | static int first_time= 1;
|
---|
| 832 |
|
---|
| 833 | assert(first_time);
|
---|
| 834 | first_time= 0;
|
---|
| 835 |
|
---|
| 836 | #define BUFALIGN 4096
|
---|
| 837 | assert(tot_bufsize <= sizeof(buffer)-BUFALIGN);
|
---|
| 838 | buf= (phys_bytes)buffer;
|
---|
| 839 | buf += BUFALIGN - (buf % BUFALIGN);
|
---|
| 840 | }
|
---|
| 841 |
|
---|
| 842 | fp->fxp_rx_buf= (struct rfd *)buf;
|
---|
| 843 | r= sys_umap(SELF, D, (vir_bytes)buf, rx_totbufsize,
|
---|
| 844 | &fp->fxp_rx_busaddr);
|
---|
| 845 | if (r != OK)
|
---|
| 846 | panic("FXP","sys_umap failed", r);
|
---|
| 847 | for (i= 0, rfdp= fp->fxp_rx_buf; i<fp->fxp_rx_nbuf; i++, rfdp++)
|
---|
| 848 | {
|
---|
| 849 | rfdp->rfd_status= 0;
|
---|
| 850 | rfdp->rfd_command= 0;
|
---|
| 851 | if (i != fp->fxp_rx_nbuf-1)
|
---|
| 852 | {
|
---|
| 853 | r= sys_umap(SELF, D, (vir_bytes)&rfdp[1],
|
---|
| 854 | sizeof(rfdp[1]), &rfdp->rfd_linkaddr);
|
---|
| 855 | if (r != OK)
|
---|
| 856 | panic("FXP","sys_umap failed", r);
|
---|
| 857 | }
|
---|
| 858 | else
|
---|
| 859 | {
|
---|
| 860 | rfdp->rfd_linkaddr= fp->fxp_rx_busaddr;
|
---|
| 861 | rfdp->rfd_command |= RFDC_EL;
|
---|
| 862 | }
|
---|
| 863 | rfdp->rfd_reserved= 0;
|
---|
| 864 | rfdp->rfd_res= 0;
|
---|
| 865 | rfdp->rfd_size= sizeof(rfdp->rfd_buf);
|
---|
| 866 |
|
---|
| 867 | }
|
---|
| 868 | fp->fxp_rx_head= 0;
|
---|
| 869 |
|
---|
| 870 | fp->fxp_tx_buf= (struct tx *)(buf+rx_totbufsize);
|
---|
| 871 | r= sys_umap(SELF, D, (vir_bytes)fp->fxp_tx_buf,
|
---|
| 872 | (phys_bytes)tx_totbufsize, &fp->fxp_tx_busaddr);
|
---|
| 873 | if (r != OK)
|
---|
| 874 | panic("FXP","sys_umap failed", r);
|
---|
| 875 |
|
---|
| 876 | for (i= 0, txp= fp->fxp_tx_buf; i<fp->fxp_tx_nbuf; i++, txp++)
|
---|
| 877 | {
|
---|
| 878 | txp->tx_status= 0;
|
---|
| 879 | txp->tx_command= TXC_EL | CBL_NOP; /* Just in case */
|
---|
| 880 | if (i != fp->fxp_tx_nbuf-1)
|
---|
| 881 | {
|
---|
| 882 | r= sys_umap(SELF, D, (vir_bytes)&txp[1],
|
---|
| 883 | (phys_bytes)sizeof(txp[1]),
|
---|
| 884 | &txp->tx_linkaddr);
|
---|
| 885 | if (r != OK)
|
---|
| 886 | panic("FXP","sys_umap failed", r);
|
---|
| 887 | }
|
---|
| 888 | else
|
---|
| 889 | {
|
---|
| 890 | txp->tx_linkaddr= fp->fxp_tx_busaddr;
|
---|
| 891 | }
|
---|
| 892 | txp->tx_tbda= TX_TBDA_NIL;
|
---|
| 893 | txp->tx_size= 0;
|
---|
| 894 | txp->tx_tthresh= fp->fxp_tx_threshold;
|
---|
| 895 | txp->tx_ntbd= 0;
|
---|
| 896 | }
|
---|
| 897 | fp->fxp_tx_idle= 1;
|
---|
| 898 | }
|
---|
| 899 |
|
---|
| 900 | /*===========================================================================*
|
---|
| 901 | * fxp_reset_hw *
|
---|
| 902 | *===========================================================================*/
|
---|
| 903 | static void fxp_reset_hw(fp)
|
---|
| 904 | fxp_t *fp;
|
---|
| 905 | {
|
---|
| 906 | /* Inline the function in init? */
|
---|
| 907 | port_t port;
|
---|
| 908 |
|
---|
| 909 | port= fp->fxp_base_port;
|
---|
| 910 |
|
---|
| 911 | /* Reset device */
|
---|
| 912 | fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
|
---|
| 913 | tickdelay(MICROS_TO_TICKS(CSR_PORT_RESET_DELAY));
|
---|
| 914 |
|
---|
| 915 | /* Disable interrupts */
|
---|
| 916 | fxp_outb(port, SCB_INT_MASK, SIM_M);
|
---|
| 917 |
|
---|
| 918 | /* Set CU base to zero */
|
---|
| 919 | fxp_cu_ptr_cmd(fp, SC_CU_LOAD_BASE, 0, TRUE /* check idle */);
|
---|
| 920 |
|
---|
| 921 | /* Set RU base to zero */
|
---|
| 922 | fxp_ru_ptr_cmd(fp, SC_RU_LOAD_BASE, 0, TRUE /* check idle */);
|
---|
| 923 | }
|
---|
| 924 |
|
---|
| 925 | /*===========================================================================*
|
---|
| 926 | * fxp_confaddr *
|
---|
| 927 | *===========================================================================*/
|
---|
| 928 | static void fxp_confaddr(fp)
|
---|
| 929 | fxp_t *fp;
|
---|
| 930 | {
|
---|
| 931 | static char eakey[]= FXP_ENVVAR "#_EA";
|
---|
| 932 | static char eafmt[]= "x:x:x:x:x:x";
|
---|
| 933 | clock_t t0,t1;
|
---|
| 934 | int i, r;
|
---|
| 935 | port_t port;
|
---|
| 936 | u32_t bus_addr;
|
---|
| 937 | long v;
|
---|
| 938 | struct ias ias;
|
---|
| 939 |
|
---|
| 940 | port= fp->fxp_base_port;
|
---|
| 941 |
|
---|
| 942 | /* User defined ethernet address? */
|
---|
| 943 | eakey[sizeof(FXP_ENVVAR)-1]= '0' + (fp-fxp_table);
|
---|
| 944 |
|
---|
| 945 | #if 0
|
---|
| 946 | for (i= 0; i < 6; i++)
|
---|
| 947 | {
|
---|
| 948 | if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
|
---|
| 949 | break;
|
---|
| 950 | fp->fxp_address.ea_addr[i]= v;
|
---|
| 951 | }
|
---|
| 952 | #else
|
---|
| 953 | i= 0;
|
---|
| 954 | #endif
|
---|
| 955 |
|
---|
| 956 | #if 0
|
---|
| 957 | if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
|
---|
| 958 | #endif
|
---|
| 959 |
|
---|
| 960 | if (i == 0)
|
---|
| 961 | {
|
---|
| 962 | /* Get ethernet address from EEPROM */
|
---|
| 963 | for (i= 0; i<3; i++)
|
---|
| 964 | {
|
---|
| 965 | v= eeprom_read(fp, i);
|
---|
| 966 | fp->fxp_address.ea_addr[i*2]= (v & 0xff);
|
---|
| 967 | fp->fxp_address.ea_addr[i*2+1]= ((v >> 8) & 0xff);
|
---|
| 968 | }
|
---|
| 969 | }
|
---|
| 970 |
|
---|
| 971 | /* Tell NIC about ethernet address */
|
---|
| 972 | ias.ias_status= 0;
|
---|
| 973 | ias.ias_command= CBL_C_EL | CBL_AIS;
|
---|
| 974 | ias.ias_linkaddr= 0;
|
---|
| 975 | memcpy(ias.ias_ethaddr, fp->fxp_address.ea_addr,
|
---|
| 976 | sizeof(ias.ias_ethaddr));
|
---|
| 977 | r= sys_umap(SELF, D, (vir_bytes)&ias, (phys_bytes)sizeof(ias),
|
---|
| 978 | &bus_addr);
|
---|
| 979 | if (r != OK)
|
---|
| 980 | panic("FXP","sys_umap failed", r);
|
---|
| 981 |
|
---|
| 982 | fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
|
---|
| 983 |
|
---|
| 984 | getuptime(&t0);
|
---|
| 985 | do {
|
---|
| 986 | /* Wait for CU command to complete */
|
---|
| 987 | if (ias.ias_status & CBL_F_C)
|
---|
| 988 | break;
|
---|
| 989 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000));
|
---|
| 990 |
|
---|
| 991 | if (!(ias.ias_status & CBL_F_C))
|
---|
| 992 | panic("FXP","fxp_confaddr: CU command failed to complete", NO_NUM);
|
---|
| 993 | if (!(ias.ias_status & CBL_F_OK))
|
---|
| 994 | panic("FXP","fxp_confaddr: CU command failed", NO_NUM);
|
---|
| 995 |
|
---|
| 996 | #if VERBOSE
|
---|
| 997 | printf("%s: hardware ethernet address: ", fp->fxp_name);
|
---|
| 998 | for (i= 0; i<6; i++)
|
---|
| 999 | {
|
---|
| 1000 | printf("%02x%s", fp->fxp_address.ea_addr[i],
|
---|
| 1001 | i < 5 ? ":" : "");
|
---|
| 1002 | }
|
---|
| 1003 | printf("\n");
|
---|
| 1004 | #endif
|
---|
| 1005 | }
|
---|
| 1006 |
|
---|
| 1007 | /*===========================================================================*
|
---|
| 1008 | * fxp_rec_mode *
|
---|
| 1009 | *===========================================================================*/
|
---|
| 1010 | static void fxp_rec_mode(fp)
|
---|
| 1011 | fxp_t *fp;
|
---|
| 1012 | {
|
---|
| 1013 | fp->fxp_conf_bytes[0]= CC_BYTES_NR; /* Just to be sure */
|
---|
| 1014 | fp->fxp_conf_bytes[15] &= ~(CCB15_BD|CCB15_PM);
|
---|
| 1015 | fp->fxp_conf_bytes[21] &= ~CCB21_MA;
|
---|
| 1016 |
|
---|
| 1017 | if (fp->fxp_flags & FF_PROMISC)
|
---|
| 1018 | fp->fxp_conf_bytes[15] |= CCB15_PM;
|
---|
| 1019 | if (fp->fxp_flags & FF_MULTI)
|
---|
| 1020 | fp->fxp_conf_bytes[21] |= CCB21_MA;
|
---|
| 1021 |
|
---|
| 1022 | if (!(fp->fxp_flags & (FF_BROAD|FF_MULTI|FF_PROMISC)))
|
---|
| 1023 | fp->fxp_conf_bytes[15] |= CCB15_BD;
|
---|
| 1024 |
|
---|
| 1025 | /* Queue request if not idle */
|
---|
| 1026 | if (fp->fxp_tx_idle)
|
---|
| 1027 | {
|
---|
| 1028 | fxp_do_conf(fp);
|
---|
| 1029 | }
|
---|
| 1030 | else
|
---|
| 1031 | {
|
---|
| 1032 | printf("fxp_rec_mode: setting fxp_need_conf\n");
|
---|
| 1033 | fp->fxp_need_conf= TRUE;
|
---|
| 1034 | }
|
---|
| 1035 | }
|
---|
| 1036 |
|
---|
| 1037 | /*===========================================================================*
|
---|
| 1038 | * fxp_writev *
|
---|
| 1039 | *===========================================================================*/
|
---|
| 1040 | static void fxp_writev(mp, from_int, vectored)
|
---|
| 1041 | message *mp;
|
---|
| 1042 | int from_int;
|
---|
| 1043 | int vectored;
|
---|
| 1044 | {
|
---|
| 1045 | vir_bytes iov_src;
|
---|
| 1046 | int i, j, n, o, r, s, dl_port, count, size, prev_head;
|
---|
| 1047 | int fxp_client, fxp_tx_nbuf, fxp_tx_head;
|
---|
| 1048 | u16_t tx_command;
|
---|
| 1049 | fxp_t *fp;
|
---|
| 1050 | iovec_t *iovp;
|
---|
| 1051 | struct tx *txp, *prev_txp;
|
---|
| 1052 |
|
---|
| 1053 | dl_port = mp->DL_PORT;
|
---|
| 1054 | count = mp->DL_COUNT;
|
---|
| 1055 | if (dl_port < 0 || dl_port >= FXP_PORT_NR)
|
---|
| 1056 | panic("FXP","fxp_writev: illegal port", dl_port);
|
---|
| 1057 | fp= &fxp_table[dl_port];
|
---|
| 1058 | fxp_client= mp->DL_PROC;
|
---|
| 1059 | fp->fxp_client= fxp_client;
|
---|
| 1060 |
|
---|
| 1061 | assert(fp->fxp_mode == FM_ENABLED);
|
---|
| 1062 | assert(fp->fxp_flags & FF_ENABLED);
|
---|
| 1063 |
|
---|
| 1064 | if (from_int)
|
---|
| 1065 | {
|
---|
| 1066 | assert(fp->fxp_flags & FF_SEND_AVAIL);
|
---|
| 1067 | fp->fxp_flags &= ~FF_SEND_AVAIL;
|
---|
| 1068 | fp->fxp_tx_alive= TRUE;
|
---|
| 1069 | }
|
---|
| 1070 |
|
---|
| 1071 | if (fp->fxp_tx_idle)
|
---|
| 1072 | {
|
---|
| 1073 | txp= fp->fxp_tx_buf;
|
---|
| 1074 | fxp_tx_head= 0; /* lint */
|
---|
| 1075 | prev_txp= NULL; /* lint */
|
---|
| 1076 | }
|
---|
| 1077 | else
|
---|
| 1078 | {
|
---|
| 1079 | fxp_tx_nbuf= fp->fxp_tx_nbuf;
|
---|
| 1080 | prev_head= fp->fxp_tx_head;
|
---|
| 1081 | fxp_tx_head= prev_head+1;
|
---|
| 1082 | if (fxp_tx_head == fxp_tx_nbuf)
|
---|
| 1083 | fxp_tx_head= 0;
|
---|
| 1084 | assert(fxp_tx_head < fxp_tx_nbuf);
|
---|
| 1085 |
|
---|
| 1086 | if (fxp_tx_head == fp->fxp_tx_tail)
|
---|
| 1087 | {
|
---|
| 1088 | /* Send queue is full */
|
---|
| 1089 | assert(!(fp->fxp_flags & FF_SEND_AVAIL));
|
---|
| 1090 | fp->fxp_flags |= FF_SEND_AVAIL;
|
---|
| 1091 | goto suspend;
|
---|
| 1092 | }
|
---|
| 1093 |
|
---|
| 1094 | prev_txp= &fp->fxp_tx_buf[prev_head];
|
---|
| 1095 | txp= &fp->fxp_tx_buf[fxp_tx_head];
|
---|
| 1096 | }
|
---|
| 1097 |
|
---|
| 1098 | assert(!(fp->fxp_flags & FF_SEND_AVAIL));
|
---|
| 1099 | assert(!(fp->fxp_flags & FF_PACK_SENT));
|
---|
| 1100 |
|
---|
| 1101 | if (vectored)
|
---|
| 1102 | {
|
---|
| 1103 |
|
---|
| 1104 | iov_src = (vir_bytes)mp->DL_ADDR;
|
---|
| 1105 |
|
---|
| 1106 | size= 0;
|
---|
| 1107 | o= 0;
|
---|
| 1108 | for (i= 0; i<count; i += IOVEC_NR,
|
---|
| 1109 | iov_src += IOVEC_NR * sizeof(fp->fxp_iovec[0]))
|
---|
| 1110 | {
|
---|
| 1111 | n= IOVEC_NR;
|
---|
| 1112 | if (i+n > count)
|
---|
| 1113 | n= count-i;
|
---|
| 1114 | r= sys_vircopy(fxp_client, D, iov_src,
|
---|
| 1115 | SELF, D, (vir_bytes)fp->fxp_iovec,
|
---|
| 1116 | n * sizeof(fp->fxp_iovec[0]));
|
---|
| 1117 | if (r != OK)
|
---|
| 1118 | panic("FXP","fxp_writev: sys_vircopy failed", r);
|
---|
| 1119 |
|
---|
| 1120 | for (j= 0, iovp= fp->fxp_iovec; j<n; j++, iovp++)
|
---|
| 1121 | {
|
---|
| 1122 | s= iovp->iov_size;
|
---|
| 1123 | if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
|
---|
| 1124 | {
|
---|
| 1125 | panic("FXP","fxp_writev: invalid packet size",
|
---|
| 1126 | NO_NUM);
|
---|
| 1127 | }
|
---|
| 1128 |
|
---|
| 1129 | r= sys_vircopy(fxp_client, D, iovp->iov_addr,
|
---|
| 1130 | SELF, D, (vir_bytes)(txp->tx_buf+o),
|
---|
| 1131 | s);
|
---|
| 1132 | if (r != OK)
|
---|
| 1133 | {
|
---|
| 1134 | panic("FXP","fxp_writev: sys_vircopy failed",
|
---|
| 1135 | r);
|
---|
| 1136 | }
|
---|
| 1137 | size += s;
|
---|
| 1138 | o += s;
|
---|
| 1139 | }
|
---|
| 1140 | }
|
---|
| 1141 | if (size < ETH_MIN_PACK_SIZE)
|
---|
| 1142 | panic("FXP","fxp_writev: invalid packet size", size);
|
---|
| 1143 | }
|
---|
| 1144 | else
|
---|
| 1145 | {
|
---|
| 1146 | size= mp->DL_COUNT;
|
---|
| 1147 | if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
|
---|
| 1148 | panic("FXP","fxp_writev: invalid packet size", size);
|
---|
| 1149 |
|
---|
| 1150 | r= sys_vircopy(fxp_client, D, (vir_bytes)mp->DL_ADDR,
|
---|
| 1151 | SELF, D, (vir_bytes)txp->tx_buf, size);
|
---|
| 1152 | if (r != OK)
|
---|
| 1153 | panic("FXP","fxp_writev: sys_vircopy failed", r);
|
---|
| 1154 | }
|
---|
| 1155 |
|
---|
| 1156 | txp->tx_status= 0;
|
---|
| 1157 | txp->tx_command= TXC_EL | CBL_XMIT;
|
---|
| 1158 | txp->tx_tbda= TX_TBDA_NIL;
|
---|
| 1159 | txp->tx_size= TXSZ_EOF | size;
|
---|
| 1160 | txp->tx_tthresh= fp->fxp_tx_threshold;
|
---|
| 1161 | txp->tx_ntbd= 0;
|
---|
| 1162 | if (fp->fxp_tx_idle)
|
---|
| 1163 | {
|
---|
| 1164 | fp->fxp_tx_idle= 0;
|
---|
| 1165 | fp->fxp_tx_head= fp->fxp_tx_tail= 0;
|
---|
| 1166 |
|
---|
| 1167 | fxp_cu_ptr_cmd(fp, SC_CU_START, fp->fxp_tx_busaddr,
|
---|
| 1168 | TRUE /* check idle */);
|
---|
| 1169 | }
|
---|
| 1170 | else
|
---|
| 1171 | {
|
---|
| 1172 | /* Link new request in transmit list */
|
---|
| 1173 | tx_command= prev_txp->tx_command;
|
---|
| 1174 | assert(tx_command == (TXC_EL | CBL_XMIT));
|
---|
| 1175 | prev_txp->tx_command= CBL_XMIT;
|
---|
| 1176 | fp->fxp_tx_head= fxp_tx_head;
|
---|
| 1177 | }
|
---|
| 1178 |
|
---|
| 1179 | fp->fxp_flags |= FF_PACK_SENT;
|
---|
| 1180 |
|
---|
| 1181 | /* If the interrupt handler called, don't send a reply. The reply
|
---|
| 1182 | * will be sent after all interrupts are handled.
|
---|
| 1183 | */
|
---|
| 1184 | if (from_int)
|
---|
| 1185 | return;
|
---|
| 1186 | reply(fp, OK, FALSE);
|
---|
| 1187 | return;
|
---|
| 1188 |
|
---|
| 1189 | suspend:
|
---|
| 1190 | if (from_int)
|
---|
| 1191 | panic("FXP","fxp: should not be sending\n", NO_NUM);
|
---|
| 1192 |
|
---|
| 1193 | fp->fxp_tx_mess= *mp;
|
---|
| 1194 | reply(fp, OK, FALSE);
|
---|
| 1195 | }
|
---|
| 1196 |
|
---|
| 1197 | /*===========================================================================*
|
---|
| 1198 | * fxp_readv *
|
---|
| 1199 | *===========================================================================*/
|
---|
| 1200 | static void fxp_readv(mp, from_int, vectored)
|
---|
| 1201 | message *mp;
|
---|
| 1202 | int from_int;
|
---|
| 1203 | int vectored;
|
---|
| 1204 | {
|
---|
| 1205 | int i, j, n, o, r, s, dl_port, fxp_client, count, size,
|
---|
| 1206 | fxp_rx_head, fxp_rx_nbuf;
|
---|
| 1207 | port_t port;
|
---|
| 1208 | unsigned packlen;
|
---|
| 1209 | vir_bytes iov_src;
|
---|
| 1210 | u16_t rfd_status;
|
---|
| 1211 | u16_t rfd_res;
|
---|
| 1212 | u8_t scb_status;
|
---|
| 1213 | fxp_t *fp;
|
---|
| 1214 | iovec_t *iovp;
|
---|
| 1215 | struct rfd *rfdp, *prev_rfdp;
|
---|
| 1216 |
|
---|
| 1217 | dl_port = mp->DL_PORT;
|
---|
| 1218 | count = mp->DL_COUNT;
|
---|
| 1219 | if (dl_port < 0 || dl_port >= FXP_PORT_NR)
|
---|
| 1220 | panic("FXP","fxp_readv: illegal port", dl_port);
|
---|
| 1221 | fp= &fxp_table[dl_port];
|
---|
| 1222 | fxp_client= mp->DL_PROC;
|
---|
| 1223 | fp->fxp_client= fxp_client;
|
---|
| 1224 |
|
---|
| 1225 | assert(fp->fxp_mode == FM_ENABLED);
|
---|
| 1226 | assert(fp->fxp_flags & FF_ENABLED);
|
---|
| 1227 |
|
---|
| 1228 | port= fp->fxp_base_port;
|
---|
| 1229 |
|
---|
| 1230 | fxp_rx_head= fp->fxp_rx_head;
|
---|
| 1231 | rfdp= &fp->fxp_rx_buf[fxp_rx_head];
|
---|
| 1232 |
|
---|
| 1233 | rfd_status= rfdp->rfd_status;
|
---|
| 1234 | if (!(rfd_status & RFDS_C))
|
---|
| 1235 | {
|
---|
| 1236 | /* Receive buffer is empty, suspend */
|
---|
| 1237 | goto suspend;
|
---|
| 1238 | }
|
---|
| 1239 |
|
---|
| 1240 | if (!rfd_status & RFDS_OK)
|
---|
| 1241 | {
|
---|
| 1242 | /* Not OK? What happened? */
|
---|
| 1243 | assert(0);
|
---|
| 1244 | }
|
---|
| 1245 | else
|
---|
| 1246 | {
|
---|
| 1247 | assert(!(rfd_status & (RFDS_CRCERR | RFDS_ALIGNERR |
|
---|
| 1248 | RFDS_OUTOFBUF | RFDS_DMAOVR | RFDS_TOOSHORT |
|
---|
| 1249 | RFDS_RXERR)));
|
---|
| 1250 | }
|
---|
| 1251 | rfd_res= rfdp->rfd_res;
|
---|
| 1252 | assert(rfd_res & RFDR_EOF);
|
---|
| 1253 | assert(rfd_res & RFDR_F);
|
---|
| 1254 |
|
---|
| 1255 | packlen= rfd_res & RFDSZ_SIZE;
|
---|
| 1256 |
|
---|
| 1257 | if (vectored)
|
---|
| 1258 | {
|
---|
| 1259 | iov_src = (vir_bytes)mp->DL_ADDR;
|
---|
| 1260 |
|
---|
| 1261 | size= 0;
|
---|
| 1262 | o= 0;
|
---|
| 1263 | for (i= 0; i<count; i += IOVEC_NR,
|
---|
| 1264 | iov_src += IOVEC_NR * sizeof(fp->fxp_iovec[0]))
|
---|
| 1265 | {
|
---|
| 1266 | n= IOVEC_NR;
|
---|
| 1267 | if (i+n > count)
|
---|
| 1268 | n= count-i;
|
---|
| 1269 | r= sys_vircopy(fxp_client, D, iov_src,
|
---|
| 1270 | SELF, D, (vir_bytes)fp->fxp_iovec,
|
---|
| 1271 | n * sizeof(fp->fxp_iovec[0]));
|
---|
| 1272 | if (r != OK)
|
---|
| 1273 | panic("FXP","fxp_readv: sys_vircopy failed", r);
|
---|
| 1274 |
|
---|
| 1275 | for (j= 0, iovp= fp->fxp_iovec; j<n; j++, iovp++)
|
---|
| 1276 | {
|
---|
| 1277 | s= iovp->iov_size;
|
---|
| 1278 | if (size + s > packlen)
|
---|
| 1279 | {
|
---|
| 1280 | assert(packlen > size);
|
---|
| 1281 | s= packlen-size;
|
---|
| 1282 | }
|
---|
| 1283 |
|
---|
| 1284 | r= sys_vircopy(SELF, D,
|
---|
| 1285 | (vir_bytes)(rfdp->rfd_buf+o),
|
---|
| 1286 | fxp_client, D, iovp->iov_addr, s);
|
---|
| 1287 | if (r != OK)
|
---|
| 1288 | {
|
---|
| 1289 | panic("FXP","fxp_readv: sys_vircopy failed",
|
---|
| 1290 | r);
|
---|
| 1291 | }
|
---|
| 1292 |
|
---|
| 1293 | size += s;
|
---|
| 1294 | if (size == packlen)
|
---|
| 1295 | break;
|
---|
| 1296 | o += s;
|
---|
| 1297 | }
|
---|
| 1298 | if (size == packlen)
|
---|
| 1299 | break;
|
---|
| 1300 | }
|
---|
| 1301 | if (size < packlen)
|
---|
| 1302 | {
|
---|
| 1303 | assert(0);
|
---|
| 1304 | }
|
---|
| 1305 | }
|
---|
| 1306 | else
|
---|
| 1307 | {
|
---|
| 1308 | assert(0);
|
---|
| 1309 | }
|
---|
| 1310 |
|
---|
| 1311 | fp->fxp_read_s= packlen;
|
---|
| 1312 | fp->fxp_flags= (fp->fxp_flags & ~FF_READING) | FF_PACK_RECV;
|
---|
| 1313 |
|
---|
| 1314 | /* Re-init the current buffer */
|
---|
| 1315 | rfdp->rfd_status= 0;
|
---|
| 1316 | rfdp->rfd_command= RFDC_EL;
|
---|
| 1317 | rfdp->rfd_reserved= 0;
|
---|
| 1318 | rfdp->rfd_res= 0;
|
---|
| 1319 | rfdp->rfd_size= sizeof(rfdp->rfd_buf);
|
---|
| 1320 |
|
---|
| 1321 | fxp_rx_nbuf= fp->fxp_rx_nbuf;
|
---|
| 1322 | if (fxp_rx_head == 0)
|
---|
| 1323 | {
|
---|
| 1324 | prev_rfdp= &fp->fxp_rx_buf[fxp_rx_nbuf-1];
|
---|
| 1325 | }
|
---|
| 1326 | else
|
---|
| 1327 | prev_rfdp= &rfdp[-1];
|
---|
| 1328 |
|
---|
| 1329 | assert(prev_rfdp->rfd_command & RFDC_EL);
|
---|
| 1330 | prev_rfdp->rfd_command &= ~RFDC_EL;
|
---|
| 1331 |
|
---|
| 1332 | fxp_rx_head++;
|
---|
| 1333 | if (fxp_rx_head == fxp_rx_nbuf)
|
---|
| 1334 | fxp_rx_head= 0;
|
---|
| 1335 | assert(fxp_rx_head < fxp_rx_nbuf);
|
---|
| 1336 | fp->fxp_rx_head= fxp_rx_head;
|
---|
| 1337 |
|
---|
| 1338 | if (!from_int)
|
---|
| 1339 | reply(fp, OK, FALSE);
|
---|
| 1340 |
|
---|
| 1341 | return;
|
---|
| 1342 |
|
---|
| 1343 | suspend:
|
---|
| 1344 | if (fp->fxp_rx_need_restart)
|
---|
| 1345 | {
|
---|
| 1346 | fp->fxp_rx_need_restart= 0;
|
---|
| 1347 |
|
---|
| 1348 | /* Check the status of the RU */
|
---|
| 1349 | scb_status= fxp_inb(port, SCB_STATUS);
|
---|
| 1350 | if ((scb_status & SS_RUS_MASK) != SS_RU_NORES)
|
---|
| 1351 | {
|
---|
| 1352 | /* Race condition? */
|
---|
| 1353 | printf("fxp_readv: restart race: 0x%x\n",
|
---|
| 1354 | scb_status);
|
---|
| 1355 | assert((scb_status & SS_RUS_MASK) == SS_RU_READY);
|
---|
| 1356 | }
|
---|
| 1357 | else
|
---|
| 1358 | {
|
---|
| 1359 | fxp_restart_ru(fp);
|
---|
| 1360 | }
|
---|
| 1361 | }
|
---|
| 1362 | if (from_int)
|
---|
| 1363 | {
|
---|
| 1364 | assert(fp->fxp_flags & FF_READING);
|
---|
| 1365 |
|
---|
| 1366 | /* No need to store any state */
|
---|
| 1367 | return;
|
---|
| 1368 | }
|
---|
| 1369 |
|
---|
| 1370 | fp->fxp_rx_mess= *mp;
|
---|
| 1371 | assert(!(fp->fxp_flags & FF_READING));
|
---|
| 1372 | fp->fxp_flags |= FF_READING;
|
---|
| 1373 |
|
---|
| 1374 | reply(fp, OK, FALSE);
|
---|
| 1375 | }
|
---|
| 1376 |
|
---|
| 1377 | /*===========================================================================*
|
---|
| 1378 | * fxp_do_conf *
|
---|
| 1379 | *===========================================================================*/
|
---|
| 1380 | static void fxp_do_conf(fp)
|
---|
| 1381 | fxp_t *fp;
|
---|
| 1382 | {
|
---|
| 1383 | int r;
|
---|
| 1384 | u32_t bus_addr;
|
---|
| 1385 | struct cbl_conf cc;
|
---|
| 1386 | clock_t t0,t1;
|
---|
| 1387 |
|
---|
| 1388 | /* Configure device */
|
---|
| 1389 | cc.cc_status= 0;
|
---|
| 1390 | cc.cc_command= CBL_C_EL | CBL_CONF;
|
---|
| 1391 | cc.cc_linkaddr= 0;
|
---|
| 1392 | memcpy(cc.cc_bytes, fp->fxp_conf_bytes, sizeof(cc.cc_bytes));
|
---|
| 1393 |
|
---|
| 1394 | r= sys_umap(SELF, D, (vir_bytes)&cc, (phys_bytes)sizeof(cc),
|
---|
| 1395 | &bus_addr);
|
---|
| 1396 | if (r != OK)
|
---|
| 1397 | panic("FXP","sys_umap failed", r);
|
---|
| 1398 |
|
---|
| 1399 | fxp_cu_ptr_cmd(fp, SC_CU_START, bus_addr, TRUE /* check idle */);
|
---|
| 1400 |
|
---|
| 1401 | getuptime(&t0);
|
---|
| 1402 | do {
|
---|
| 1403 | /* Wait for CU command to complete */
|
---|
| 1404 | if (cc.cc_status & CBL_F_C)
|
---|
| 1405 | break;
|
---|
| 1406 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000));
|
---|
| 1407 |
|
---|
| 1408 | if (!(cc.cc_status & CBL_F_C))
|
---|
| 1409 | panic("FXP","fxp_do_conf: CU command failed to complete", NO_NUM);
|
---|
| 1410 | if (!(cc.cc_status & CBL_F_OK))
|
---|
| 1411 | panic("FXP","fxp_do_conf: CU command failed", NO_NUM);
|
---|
| 1412 |
|
---|
| 1413 | }
|
---|
| 1414 |
|
---|
| 1415 | /*===========================================================================*
|
---|
| 1416 | * fxp_cu_ptr_cmd *
|
---|
| 1417 | *===========================================================================*/
|
---|
| 1418 | static void fxp_cu_ptr_cmd(fp, cmd, bus_addr, check_idle)
|
---|
| 1419 | fxp_t *fp;
|
---|
| 1420 | int cmd;
|
---|
| 1421 | phys_bytes bus_addr;
|
---|
| 1422 | int check_idle;
|
---|
| 1423 | {
|
---|
| 1424 | clock_t t0,t1;
|
---|
| 1425 | port_t port;
|
---|
| 1426 | u8_t scb_cmd;
|
---|
| 1427 |
|
---|
| 1428 | port= fp->fxp_base_port;
|
---|
| 1429 |
|
---|
| 1430 | if (check_idle)
|
---|
| 1431 | {
|
---|
| 1432 | /* Consistency check. Make sure that CU is idle */
|
---|
| 1433 | if ((fxp_inb(port, SCB_STATUS) & SS_CUS_MASK) != SS_CU_IDLE)
|
---|
| 1434 | panic("FXP","fxp_cu_ptr_cmd: CU is not idle", NO_NUM);
|
---|
| 1435 | }
|
---|
| 1436 |
|
---|
| 1437 | fxp_outl(port, SCB_POINTER, bus_addr);
|
---|
| 1438 | fxp_outb(port, SCB_CMD, cmd);
|
---|
| 1439 |
|
---|
| 1440 | /* What is a reasonable time-out? There is nothing in the
|
---|
| 1441 | * documentation. 1 ms should be enough.
|
---|
| 1442 | */
|
---|
| 1443 | getuptime(&t0);
|
---|
| 1444 | do {
|
---|
| 1445 | /* Wait for CU command to be accepted */
|
---|
| 1446 | scb_cmd= fxp_inb(port, SCB_CMD);
|
---|
| 1447 | if ((scb_cmd & SC_CUC_MASK) == SC_CU_NOP)
|
---|
| 1448 | break;
|
---|
| 1449 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000));
|
---|
| 1450 |
|
---|
| 1451 | if ((scb_cmd & SC_CUC_MASK) != SC_CU_NOP)
|
---|
| 1452 | panic("FXP","fxp_cu_ptr_cmd: CU does not accept command", NO_NUM);
|
---|
| 1453 | }
|
---|
| 1454 |
|
---|
| 1455 | /*===========================================================================*
|
---|
| 1456 | * fxp_ru_ptr_cmd *
|
---|
| 1457 | *===========================================================================*/
|
---|
| 1458 | static void fxp_ru_ptr_cmd(fp, cmd, bus_addr, check_idle)
|
---|
| 1459 | fxp_t *fp;
|
---|
| 1460 | int cmd;
|
---|
| 1461 | phys_bytes bus_addr;
|
---|
| 1462 | int check_idle;
|
---|
| 1463 | {
|
---|
| 1464 | clock_t t0,t1;
|
---|
| 1465 | port_t port;
|
---|
| 1466 | u8_t scb_cmd;
|
---|
| 1467 |
|
---|
| 1468 | port= fp->fxp_base_port;
|
---|
| 1469 |
|
---|
| 1470 | if (check_idle)
|
---|
| 1471 | {
|
---|
| 1472 | /* Consistency check, make sure that RU is idle */
|
---|
| 1473 | if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_IDLE)
|
---|
| 1474 | panic("FXP","fxp_ru_ptr_cmd: RU is not idle", NO_NUM);
|
---|
| 1475 | }
|
---|
| 1476 |
|
---|
| 1477 | fxp_outl(port, SCB_POINTER, bus_addr);
|
---|
| 1478 | fxp_outb(port, SCB_CMD, cmd);
|
---|
| 1479 |
|
---|
| 1480 | getuptime(&t0);
|
---|
| 1481 | do {
|
---|
| 1482 | /* Wait for RU command to be accepted */
|
---|
| 1483 | scb_cmd= fxp_inb(port, SCB_CMD);
|
---|
| 1484 | if ((scb_cmd & SC_RUC_MASK) == SC_RU_NOP)
|
---|
| 1485 | break;
|
---|
| 1486 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000));
|
---|
| 1487 |
|
---|
| 1488 | if ((scb_cmd & SC_RUC_MASK) != SC_RU_NOP)
|
---|
| 1489 | panic("FXP","fxp_ru_ptr_cmd: RU does not accept command", NO_NUM);
|
---|
| 1490 | }
|
---|
| 1491 |
|
---|
| 1492 | /*===========================================================================*
|
---|
| 1493 | * fxp_restart_ru *
|
---|
| 1494 | *===========================================================================*/
|
---|
| 1495 | static void fxp_restart_ru(fp)
|
---|
| 1496 | fxp_t *fp;
|
---|
| 1497 | {
|
---|
| 1498 | int i, fxp_rx_nbuf;
|
---|
| 1499 | port_t port;
|
---|
| 1500 | struct rfd *rfdp;
|
---|
| 1501 |
|
---|
| 1502 | port= fp->fxp_base_port;
|
---|
| 1503 |
|
---|
| 1504 | fxp_rx_nbuf= fp->fxp_rx_nbuf;
|
---|
| 1505 | for (i= 0, rfdp= fp->fxp_rx_buf; i<fxp_rx_nbuf; i++, rfdp++)
|
---|
| 1506 | {
|
---|
| 1507 | rfdp->rfd_status= 0;
|
---|
| 1508 | rfdp->rfd_command= 0;
|
---|
| 1509 | if (i == fp->fxp_rx_nbuf-1)
|
---|
| 1510 | rfdp->rfd_command= RFDC_EL;
|
---|
| 1511 | rfdp->rfd_reserved= 0;
|
---|
| 1512 | rfdp->rfd_res= 0;
|
---|
| 1513 | rfdp->rfd_size= sizeof(rfdp->rfd_buf);
|
---|
| 1514 | }
|
---|
| 1515 | fp->fxp_rx_head= 0;
|
---|
| 1516 |
|
---|
| 1517 | /* Make sure that RU is in the 'No resources' state */
|
---|
| 1518 | if ((fxp_inb(port, SCB_STATUS) & SS_RUS_MASK) != SS_RU_NORES)
|
---|
| 1519 | panic("FXP","fxp_restart_ru: RU is in an unexpected state", NO_NUM);
|
---|
| 1520 |
|
---|
| 1521 | fxp_ru_ptr_cmd(fp, SC_RU_START, fp->fxp_rx_busaddr,
|
---|
| 1522 | FALSE /* do not check idle */);
|
---|
| 1523 | }
|
---|
| 1524 |
|
---|
| 1525 | /*===========================================================================*
|
---|
| 1526 | * fxp_getstat *
|
---|
| 1527 | *===========================================================================*/
|
---|
| 1528 | static void fxp_getstat(mp)
|
---|
| 1529 | message *mp;
|
---|
| 1530 | {
|
---|
| 1531 | clock_t t0,t1;
|
---|
| 1532 | int dl_port;
|
---|
| 1533 | port_t port;
|
---|
| 1534 | fxp_t *fp;
|
---|
| 1535 | u32_t *p;
|
---|
| 1536 | eth_stat_t stats;
|
---|
| 1537 |
|
---|
| 1538 | dl_port = mp->DL_PORT;
|
---|
| 1539 | if (dl_port < 0 || dl_port >= FXP_PORT_NR)
|
---|
| 1540 | panic("FXP","fxp_getstat: illegal port", dl_port);
|
---|
| 1541 | fp= &fxp_table[dl_port];
|
---|
| 1542 | fp->fxp_client= mp->DL_PROC;
|
---|
| 1543 |
|
---|
| 1544 | assert(fp->fxp_mode == FM_ENABLED);
|
---|
| 1545 | assert(fp->fxp_flags & FF_ENABLED);
|
---|
| 1546 |
|
---|
| 1547 | port= fp->fxp_base_port;
|
---|
| 1548 |
|
---|
| 1549 | p= &fp->fxp_stat.sc_tx_fcp;
|
---|
| 1550 | *p= 0;
|
---|
| 1551 |
|
---|
| 1552 | /* The dump commmand doesn't take a pointer. Setting a pointer
|
---|
| 1553 | * doesn't hard though.
|
---|
| 1554 | */
|
---|
| 1555 | fxp_cu_ptr_cmd(fp, SC_CU_DUMP_SC, 0, FALSE /* do not check idle */);
|
---|
| 1556 |
|
---|
| 1557 | getuptime(&t0);
|
---|
| 1558 | do {
|
---|
| 1559 | /* Wait for CU command to complete */
|
---|
| 1560 | if (*p != 0)
|
---|
| 1561 | break;
|
---|
| 1562 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(1000));
|
---|
| 1563 |
|
---|
| 1564 | if (*p == 0)
|
---|
| 1565 | panic("FXP","fxp_getstat: CU command failed to complete", NO_NUM);
|
---|
| 1566 | if (*p != SCM_DSC)
|
---|
| 1567 | panic("FXP","fxp_getstat: bad magic", NO_NUM);
|
---|
| 1568 |
|
---|
| 1569 | stats.ets_recvErr=
|
---|
| 1570 | fp->fxp_stat.sc_rx_crc +
|
---|
| 1571 | fp->fxp_stat.sc_rx_align +
|
---|
| 1572 | fp->fxp_stat.sc_rx_resource +
|
---|
| 1573 | fp->fxp_stat.sc_rx_overrun +
|
---|
| 1574 | fp->fxp_stat.sc_rx_cd +
|
---|
| 1575 | fp->fxp_stat.sc_rx_short;
|
---|
| 1576 | stats.ets_sendErr=
|
---|
| 1577 | fp->fxp_stat.sc_tx_maxcol +
|
---|
| 1578 | fp->fxp_stat.sc_tx_latecol +
|
---|
| 1579 | fp->fxp_stat.sc_tx_crs;
|
---|
| 1580 | stats.ets_OVW= fp->fxp_stat.sc_rx_overrun;
|
---|
| 1581 | stats.ets_CRCerr= fp->fxp_stat.sc_rx_crc;
|
---|
| 1582 | stats.ets_frameAll= fp->fxp_stat.sc_rx_align;
|
---|
| 1583 | stats.ets_missedP= fp->fxp_stat.sc_rx_resource;
|
---|
| 1584 | stats.ets_packetR= fp->fxp_stat.sc_rx_good;
|
---|
| 1585 | stats.ets_packetT= fp->fxp_stat.sc_tx_good;
|
---|
| 1586 | stats.ets_transDef= fp->fxp_stat.sc_tx_defered;
|
---|
| 1587 | stats.ets_collision= fp->fxp_stat.sc_tx_totcol;
|
---|
| 1588 | stats.ets_transAb= fp->fxp_stat.sc_tx_maxcol;
|
---|
| 1589 | stats.ets_carrSense= fp->fxp_stat.sc_tx_crs;
|
---|
| 1590 | stats.ets_fifoUnder= fp->fxp_stat.sc_tx_underrun;
|
---|
| 1591 | stats.ets_fifoOver= fp->fxp_stat.sc_rx_overrun;
|
---|
| 1592 | stats.ets_CDheartbeat= 0;
|
---|
| 1593 | stats.ets_OWC= fp->fxp_stat.sc_tx_latecol;
|
---|
| 1594 |
|
---|
| 1595 | put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
|
---|
| 1596 | (vir_bytes) sizeof(stats), &stats);
|
---|
| 1597 | reply(fp, OK, FALSE);
|
---|
| 1598 | }
|
---|
| 1599 |
|
---|
| 1600 |
|
---|
| 1601 | /*===========================================================================*
|
---|
| 1602 | * fxp_getname *
|
---|
| 1603 | *===========================================================================*/
|
---|
| 1604 | static void fxp_getname(mp)
|
---|
| 1605 | message *mp;
|
---|
| 1606 | {
|
---|
| 1607 | int r;
|
---|
| 1608 |
|
---|
| 1609 | strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
|
---|
| 1610 | mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
|
---|
| 1611 | mp->m_type= DL_NAME_REPLY;
|
---|
| 1612 | r= send(mp->m_source, mp);
|
---|
| 1613 | if (r != OK)
|
---|
| 1614 | panic("FXP", "fxp_getname: send failed", r);
|
---|
| 1615 | }
|
---|
| 1616 |
|
---|
| 1617 | /*===========================================================================*
|
---|
| 1618 | * fxp_handler *
|
---|
| 1619 | *===========================================================================*/
|
---|
| 1620 | static int fxp_handler(fp)
|
---|
| 1621 | fxp_t *fp;
|
---|
| 1622 | {
|
---|
| 1623 | int port;
|
---|
| 1624 | u16_t isr;
|
---|
| 1625 |
|
---|
| 1626 | RAND_UPDATE
|
---|
| 1627 |
|
---|
| 1628 | port= fp->fxp_base_port;
|
---|
| 1629 |
|
---|
| 1630 | /* Ack interrupt */
|
---|
| 1631 | isr= fxp_inb(port, SCB_INT_STAT);
|
---|
| 1632 | fxp_outb(port, SCB_INT_STAT, isr);
|
---|
| 1633 |
|
---|
| 1634 | if (isr & SIS_FR)
|
---|
| 1635 | {
|
---|
| 1636 | isr &= ~SIS_FR;
|
---|
| 1637 |
|
---|
| 1638 | if (!fp->fxp_got_int && (fp->fxp_flags & FF_READING))
|
---|
| 1639 | {
|
---|
| 1640 | fp->fxp_got_int= TRUE;
|
---|
| 1641 | interrupt(fxp_tasknr);
|
---|
| 1642 | }
|
---|
| 1643 | }
|
---|
| 1644 | if (isr & SIS_CNA)
|
---|
| 1645 | {
|
---|
| 1646 | isr &= ~SIS_CNA;
|
---|
| 1647 | if (!fp->fxp_tx_idle)
|
---|
| 1648 | {
|
---|
| 1649 | fp->fxp_send_int= TRUE;
|
---|
| 1650 | if (!fp->fxp_got_int)
|
---|
| 1651 | {
|
---|
| 1652 | fp->fxp_got_int= TRUE;
|
---|
| 1653 | interrupt(fxp_tasknr);
|
---|
| 1654 | }
|
---|
| 1655 | }
|
---|
| 1656 | }
|
---|
| 1657 | if (isr & SIS_RNR)
|
---|
| 1658 | {
|
---|
| 1659 | isr &= ~SIS_RNR;
|
---|
| 1660 |
|
---|
| 1661 | /* Assume that receive buffer is full of packets. fxp_readv
|
---|
| 1662 | * will restart the RU.
|
---|
| 1663 | */
|
---|
| 1664 | fp->fxp_rx_need_restart= 1;
|
---|
| 1665 | }
|
---|
| 1666 | if (isr)
|
---|
| 1667 | {
|
---|
| 1668 | printf("fxp_handler: unhandled interrupt: isr = 0x%02x\n",
|
---|
| 1669 | isr);
|
---|
| 1670 | }
|
---|
| 1671 |
|
---|
| 1672 | return 1;
|
---|
| 1673 | }
|
---|
| 1674 |
|
---|
| 1675 | /*===========================================================================*
|
---|
| 1676 | * fxp_check_ints *
|
---|
| 1677 | *===========================================================================*/
|
---|
| 1678 | static void fxp_check_ints(fp)
|
---|
| 1679 | fxp_t *fp;
|
---|
| 1680 | {
|
---|
| 1681 | int n, fxp_flags, prev_tail;
|
---|
| 1682 | int fxp_tx_tail, fxp_tx_nbuf, fxp_tx_threshold;
|
---|
| 1683 | port_t port;
|
---|
| 1684 | u32_t busaddr;
|
---|
| 1685 | u16_t tx_status;
|
---|
| 1686 | u8_t scb_status;
|
---|
| 1687 | struct tx *txp;
|
---|
| 1688 |
|
---|
| 1689 | fxp_flags= fp->fxp_flags;
|
---|
| 1690 |
|
---|
| 1691 | if (fxp_flags & FF_READING)
|
---|
| 1692 | {
|
---|
| 1693 | if (!(fp->fxp_rx_buf[fp->fxp_rx_head].rfd_status & RFDS_C))
|
---|
| 1694 | ; /* Nothing */
|
---|
| 1695 | else if (fp->fxp_rx_mess.m_type == DL_READV)
|
---|
| 1696 | {
|
---|
| 1697 | fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
|
---|
| 1698 | TRUE /* vectored */);
|
---|
| 1699 | }
|
---|
| 1700 | else
|
---|
| 1701 | {
|
---|
| 1702 | assert(fp->fxp_rx_mess.m_type == DL_READ);
|
---|
| 1703 | fxp_readv(&fp->fxp_rx_mess, TRUE /* from int */,
|
---|
| 1704 | FALSE /* !vectored */);
|
---|
| 1705 | }
|
---|
| 1706 | }
|
---|
| 1707 | if (fp->fxp_tx_idle)
|
---|
| 1708 | ; /* Nothing to do */
|
---|
| 1709 | else if (fp->fxp_send_int)
|
---|
| 1710 | {
|
---|
| 1711 | fp->fxp_send_int= FALSE;
|
---|
| 1712 | fxp_tx_tail= fp->fxp_tx_tail;
|
---|
| 1713 | fxp_tx_nbuf= fp->fxp_tx_nbuf;
|
---|
| 1714 | n= 0;
|
---|
| 1715 | for (;;)
|
---|
| 1716 | {
|
---|
| 1717 | txp= &fp->fxp_tx_buf[fxp_tx_tail];
|
---|
| 1718 | tx_status= txp->tx_status;
|
---|
| 1719 | if (!(tx_status & TXS_C))
|
---|
| 1720 | break;
|
---|
| 1721 |
|
---|
| 1722 | n++;
|
---|
| 1723 |
|
---|
| 1724 | assert(tx_status & TXS_OK);
|
---|
| 1725 | if (tx_status & TXS_U)
|
---|
| 1726 | {
|
---|
| 1727 | fxp_tx_threshold= fp->fxp_tx_threshold;
|
---|
| 1728 | if (fxp_tx_threshold < TXTT_MAX)
|
---|
| 1729 | {
|
---|
| 1730 | fxp_tx_threshold++;
|
---|
| 1731 | fp->fxp_tx_threshold= fxp_tx_threshold;
|
---|
| 1732 | }
|
---|
| 1733 | printf(
|
---|
| 1734 | "fxp_check_ints: fxp_tx_threshold = 0x%x\n",
|
---|
| 1735 | fxp_tx_threshold);
|
---|
| 1736 | }
|
---|
| 1737 |
|
---|
| 1738 | if (txp->tx_command & TXC_EL)
|
---|
| 1739 | {
|
---|
| 1740 | fp->fxp_tx_idle= 1;
|
---|
| 1741 | break;
|
---|
| 1742 | }
|
---|
| 1743 |
|
---|
| 1744 | fxp_tx_tail++;
|
---|
| 1745 | if (fxp_tx_tail == fxp_tx_nbuf)
|
---|
| 1746 | fxp_tx_tail= 0;
|
---|
| 1747 | assert(fxp_tx_tail < fxp_tx_nbuf);
|
---|
| 1748 | }
|
---|
| 1749 |
|
---|
| 1750 | if (fp->fxp_need_conf)
|
---|
| 1751 | {
|
---|
| 1752 | /* Check the status of the CU */
|
---|
| 1753 | port= fp->fxp_base_port;
|
---|
| 1754 | scb_status= fxp_inb(port, SCB_STATUS);
|
---|
| 1755 | if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
|
---|
| 1756 | {
|
---|
| 1757 | /* Nothing to do */
|
---|
| 1758 | printf("scb_status = 0x%x\n", scb_status);
|
---|
| 1759 | }
|
---|
| 1760 | else
|
---|
| 1761 | {
|
---|
| 1762 | printf("fxp_check_ints: fxp_need_conf\n");
|
---|
| 1763 | fp->fxp_need_conf= FALSE;
|
---|
| 1764 | fxp_do_conf(fp);
|
---|
| 1765 | }
|
---|
| 1766 | }
|
---|
| 1767 |
|
---|
| 1768 | if (n)
|
---|
| 1769 | {
|
---|
| 1770 | if (!fp->fxp_tx_idle)
|
---|
| 1771 | {
|
---|
| 1772 | fp->fxp_tx_tail= fxp_tx_tail;
|
---|
| 1773 |
|
---|
| 1774 | /* Check the status of the CU */
|
---|
| 1775 | port= fp->fxp_base_port;
|
---|
| 1776 | scb_status= fxp_inb(port, SCB_STATUS);
|
---|
| 1777 | if ((scb_status & SS_CUS_MASK) != SS_CU_IDLE)
|
---|
| 1778 | {
|
---|
| 1779 | /* Nothing to do */
|
---|
| 1780 | printf("scb_status = 0x%x\n",
|
---|
| 1781 | scb_status);
|
---|
| 1782 |
|
---|
| 1783 | }
|
---|
| 1784 | else
|
---|
| 1785 | {
|
---|
| 1786 | if (fxp_tx_tail == 0)
|
---|
| 1787 | prev_tail= fxp_tx_nbuf-1;
|
---|
| 1788 | else
|
---|
| 1789 | prev_tail= fxp_tx_tail-1;
|
---|
| 1790 | busaddr= fp->fxp_tx_buf[prev_tail].
|
---|
| 1791 | tx_linkaddr;
|
---|
| 1792 |
|
---|
| 1793 | fxp_cu_ptr_cmd(fp, SC_CU_START,
|
---|
| 1794 | busaddr, 1 /* check idle */);
|
---|
| 1795 | }
|
---|
| 1796 | }
|
---|
| 1797 |
|
---|
| 1798 | if (fp->fxp_flags & FF_SEND_AVAIL)
|
---|
| 1799 | {
|
---|
| 1800 | if (fp->fxp_tx_mess.m_type == DL_WRITEV)
|
---|
| 1801 | {
|
---|
| 1802 | fxp_writev(&fp->fxp_tx_mess,
|
---|
| 1803 | TRUE /* from int */,
|
---|
| 1804 | TRUE /* vectored */);
|
---|
| 1805 | }
|
---|
| 1806 | else
|
---|
| 1807 | {
|
---|
| 1808 | assert(fp->fxp_tx_mess.m_type ==
|
---|
| 1809 | DL_WRITE);
|
---|
| 1810 | fxp_writev(&fp->fxp_tx_mess,
|
---|
| 1811 | TRUE /* from int */,
|
---|
| 1812 | FALSE /* !vectored */);
|
---|
| 1813 | }
|
---|
| 1814 | }
|
---|
| 1815 | }
|
---|
| 1816 |
|
---|
| 1817 | }
|
---|
| 1818 | if (fp->fxp_report_link)
|
---|
| 1819 | fxp_report_link(fp);
|
---|
| 1820 |
|
---|
| 1821 | if (fp->fxp_flags & (FF_PACK_SENT | FF_PACK_RECV))
|
---|
| 1822 | reply(fp, OK, TRUE);
|
---|
| 1823 | }
|
---|
| 1824 |
|
---|
| 1825 | /*===========================================================================*
|
---|
| 1826 | * fxp_watchdog_f *
|
---|
| 1827 | *===========================================================================*/
|
---|
| 1828 | static void fxp_watchdog_f(tp)
|
---|
| 1829 | timer_t *tp;
|
---|
| 1830 | {
|
---|
| 1831 | int i;
|
---|
| 1832 | fxp_t *fp;
|
---|
| 1833 |
|
---|
| 1834 | tmr_arg(&fxp_watchdog)->ta_int= 0;
|
---|
| 1835 | fxp_set_timer(&fxp_watchdog, HZ, fxp_watchdog_f);
|
---|
| 1836 |
|
---|
| 1837 | for (i= 0, fp = &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
|
---|
| 1838 | {
|
---|
| 1839 | if (fp->fxp_mode != FM_ENABLED)
|
---|
| 1840 | continue;
|
---|
| 1841 |
|
---|
| 1842 | /* Handle race condition, MII interface mgith be busy */
|
---|
| 1843 | if(!fp->fxp_mii_busy)
|
---|
| 1844 | {
|
---|
| 1845 | /* Check the link status. */
|
---|
| 1846 | if (fxp_link_changed(fp))
|
---|
| 1847 | {
|
---|
| 1848 | #if VERBOSE
|
---|
| 1849 | printf("fxp_watchdog_f: link changed\n");
|
---|
| 1850 | #endif
|
---|
| 1851 | fp->fxp_report_link= TRUE;
|
---|
| 1852 | fp->fxp_got_int= TRUE;
|
---|
| 1853 | interrupt(fxp_tasknr);
|
---|
| 1854 | }
|
---|
| 1855 | }
|
---|
| 1856 |
|
---|
| 1857 | if (!(fp->fxp_flags & FF_SEND_AVAIL))
|
---|
| 1858 | {
|
---|
| 1859 | /* Assume that an idle system is alive */
|
---|
| 1860 | fp->fxp_tx_alive= TRUE;
|
---|
| 1861 | continue;
|
---|
| 1862 | }
|
---|
| 1863 | if (fp->fxp_tx_alive)
|
---|
| 1864 | {
|
---|
| 1865 | fp->fxp_tx_alive= FALSE;
|
---|
| 1866 | continue;
|
---|
| 1867 | }
|
---|
| 1868 |
|
---|
| 1869 | fp->fxp_need_reset= TRUE;
|
---|
| 1870 | fp->fxp_got_int= TRUE;
|
---|
| 1871 | interrupt(fxp_tasknr);
|
---|
| 1872 | }
|
---|
| 1873 | }
|
---|
| 1874 |
|
---|
| 1875 | /*===========================================================================*
|
---|
| 1876 | * fxp_link_changed *
|
---|
| 1877 | *===========================================================================*/
|
---|
| 1878 | static int fxp_link_changed(fp)
|
---|
| 1879 | fxp_t *fp;
|
---|
| 1880 | {
|
---|
| 1881 | u16_t scr;
|
---|
| 1882 |
|
---|
| 1883 | scr= mii_read(fp, MII_SCR);
|
---|
| 1884 | scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
|
---|
| 1885 |
|
---|
| 1886 | return (fp->fxp_mii_scr != scr);
|
---|
| 1887 | }
|
---|
| 1888 |
|
---|
| 1889 | /*===========================================================================*
|
---|
| 1890 | * fxp_report_link *
|
---|
| 1891 | *===========================================================================*/
|
---|
| 1892 | static void fxp_report_link(fp)
|
---|
| 1893 | fxp_t *fp;
|
---|
| 1894 | {
|
---|
| 1895 | port_t port;
|
---|
| 1896 | u16_t mii_ctrl, mii_status, mii_id1, mii_id2,
|
---|
| 1897 | mii_ana, mii_anlpa, mii_ane, mii_extstat,
|
---|
| 1898 | mii_ms_ctrl, mii_ms_status, scr;
|
---|
| 1899 | u32_t oui;
|
---|
| 1900 | int model, rev;
|
---|
| 1901 | int f, link_up, ms_regs;
|
---|
| 1902 |
|
---|
| 1903 | /* Assume an 82555 (compatible) PHY. The should be changed for
|
---|
| 1904 | * 82557 NICs with different PHYs
|
---|
| 1905 | */
|
---|
| 1906 | ms_regs= 0; /* No master/slave registers. */
|
---|
| 1907 |
|
---|
| 1908 | fp->fxp_report_link= FALSE;
|
---|
| 1909 | port= fp->fxp_base_port;
|
---|
| 1910 |
|
---|
| 1911 | scr= mii_read(fp, MII_SCR);
|
---|
| 1912 | scr &= ~(MII_SCR_RES|MII_SCR_RES_1);
|
---|
| 1913 | fp->fxp_mii_scr= scr;
|
---|
| 1914 |
|
---|
| 1915 | mii_ctrl= mii_read(fp, MII_CTRL);
|
---|
| 1916 | mii_read(fp, MII_STATUS); /* Read the status register twice, why? */
|
---|
| 1917 | mii_status= mii_read(fp, MII_STATUS);
|
---|
| 1918 | mii_id1= mii_read(fp, MII_PHYID_H);
|
---|
| 1919 | mii_id2= mii_read(fp, MII_PHYID_L);
|
---|
| 1920 | mii_ana= mii_read(fp, MII_ANA);
|
---|
| 1921 | mii_anlpa= mii_read(fp, MII_ANLPA);
|
---|
| 1922 | mii_ane= mii_read(fp, MII_ANE);
|
---|
| 1923 | if (mii_status & MII_STATUS_EXT_STAT)
|
---|
| 1924 | mii_extstat= mii_read(fp, MII_EXT_STATUS);
|
---|
| 1925 | else
|
---|
| 1926 | mii_extstat= 0;
|
---|
| 1927 | if (ms_regs)
|
---|
| 1928 | {
|
---|
| 1929 | mii_ms_ctrl= mii_read(fp, MII_MS_CTRL);
|
---|
| 1930 | mii_ms_status= mii_read(fp, MII_MS_STATUS);
|
---|
| 1931 | }
|
---|
| 1932 | else
|
---|
| 1933 | {
|
---|
| 1934 | mii_ms_ctrl= 0;
|
---|
| 1935 | mii_ms_status= 0;
|
---|
| 1936 | }
|
---|
| 1937 |
|
---|
| 1938 | /* How do we know about the link status? */
|
---|
| 1939 | link_up= !!(mii_status & MII_STATUS_LS);
|
---|
| 1940 |
|
---|
| 1941 | fp->fxp_link_up= link_up;
|
---|
| 1942 | if (!link_up)
|
---|
| 1943 | {
|
---|
| 1944 | #if VERBOSE
|
---|
| 1945 | printf("%s: link down\n", fp->fxp_name);
|
---|
| 1946 | #endif
|
---|
| 1947 | return;
|
---|
| 1948 | }
|
---|
| 1949 |
|
---|
| 1950 | oui= (mii_id1 << MII_PH_OUI_H_C_SHIFT) |
|
---|
| 1951 | ((mii_id2 & MII_PL_OUI_L_MASK) >> MII_PL_OUI_L_SHIFT);
|
---|
| 1952 | model= ((mii_id2 & MII_PL_MODEL_MASK) >> MII_PL_MODEL_SHIFT);
|
---|
| 1953 | rev= (mii_id2 & MII_PL_REV_MASK);
|
---|
| 1954 |
|
---|
| 1955 | #if VERBOSE
|
---|
| 1956 | printf("OUI 0x%06lx, Model 0x%02x, Revision 0x%x\n", oui, model, rev);
|
---|
| 1957 | #endif
|
---|
| 1958 |
|
---|
| 1959 | if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
|
---|
| 1960 | {
|
---|
| 1961 | printf("%s: PHY: ", fp->fxp_name);
|
---|
| 1962 | f= 1;
|
---|
| 1963 | if (mii_ctrl & MII_CTRL_LB)
|
---|
| 1964 | {
|
---|
| 1965 | printf("loopback mode");
|
---|
| 1966 | f= 0;
|
---|
| 1967 | }
|
---|
| 1968 | if (mii_ctrl & MII_CTRL_PD)
|
---|
| 1969 | {
|
---|
| 1970 | if (!f) printf(", ");
|
---|
| 1971 | f= 0;
|
---|
| 1972 | printf("powered down");
|
---|
| 1973 | }
|
---|
| 1974 | if (mii_ctrl & MII_CTRL_ISO)
|
---|
| 1975 | {
|
---|
| 1976 | if (!f) printf(", ");
|
---|
| 1977 | f= 0;
|
---|
| 1978 | printf("isolated");
|
---|
| 1979 | }
|
---|
| 1980 | printf("\n");
|
---|
| 1981 | return;
|
---|
| 1982 | }
|
---|
| 1983 | if (!(mii_ctrl & MII_CTRL_ANE))
|
---|
| 1984 | {
|
---|
| 1985 | printf("%s: manual config: ", fp->fxp_name);
|
---|
| 1986 | switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
|
---|
| 1987 | {
|
---|
| 1988 | case MII_CTRL_SP_10: printf("10 Mbps"); break;
|
---|
| 1989 | case MII_CTRL_SP_100: printf("100 Mbps"); break;
|
---|
| 1990 | case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
|
---|
| 1991 | case MII_CTRL_SP_RES: printf("reserved speed"); break;
|
---|
| 1992 | }
|
---|
| 1993 | if (mii_ctrl & MII_CTRL_DM)
|
---|
| 1994 | printf(", full duplex");
|
---|
| 1995 | else
|
---|
| 1996 | printf(", half duplex");
|
---|
| 1997 | printf("\n");
|
---|
| 1998 | return;
|
---|
| 1999 | }
|
---|
| 2000 |
|
---|
| 2001 | if (!debug) goto resspeed;
|
---|
| 2002 |
|
---|
| 2003 | printf("%s: ", fp->fxp_name);
|
---|
| 2004 | mii_print_stat_speed(mii_status, mii_extstat);
|
---|
| 2005 | printf("\n");
|
---|
| 2006 |
|
---|
| 2007 | if (!(mii_status & MII_STATUS_ANC))
|
---|
| 2008 | printf("%s: auto-negotiation not complete\n", fp->fxp_name);
|
---|
| 2009 | if (mii_status & MII_STATUS_RF)
|
---|
| 2010 | printf("%s: remote fault detected\n", fp->fxp_name);
|
---|
| 2011 | if (!(mii_status & MII_STATUS_ANA))
|
---|
| 2012 | {
|
---|
| 2013 | printf("%s: local PHY has no auto-negotiation ability\n",
|
---|
| 2014 | fp->fxp_name);
|
---|
| 2015 | }
|
---|
| 2016 | if (!(mii_status & MII_STATUS_LS))
|
---|
| 2017 | printf("%s: link down\n", fp->fxp_name);
|
---|
| 2018 | if (mii_status & MII_STATUS_JD)
|
---|
| 2019 | printf("%s: jabber condition detected\n", fp->fxp_name);
|
---|
| 2020 | if (!(mii_status & MII_STATUS_EC))
|
---|
| 2021 | {
|
---|
| 2022 | printf("%s: no extended register set\n", fp->fxp_name);
|
---|
| 2023 | goto resspeed;
|
---|
| 2024 | }
|
---|
| 2025 | if (!(mii_status & MII_STATUS_ANC))
|
---|
| 2026 | goto resspeed;
|
---|
| 2027 |
|
---|
| 2028 | printf("%s: local cap.: ", fp->fxp_name);
|
---|
| 2029 | if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
|
---|
| 2030 | {
|
---|
| 2031 | printf("1000 Mbps: T-");
|
---|
| 2032 | switch(mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
|
---|
| 2033 | {
|
---|
| 2034 | case MII_MSC_1000T_FD: printf("FD"); break;
|
---|
| 2035 | case MII_MSC_1000T_HD: printf("HD"); break;
|
---|
| 2036 | default: printf("FD/HD"); break;
|
---|
| 2037 | }
|
---|
| 2038 | if (mii_ana)
|
---|
| 2039 | printf(", ");
|
---|
| 2040 | }
|
---|
| 2041 | mii_print_techab(mii_ana);
|
---|
| 2042 | printf("\n");
|
---|
| 2043 |
|
---|
| 2044 | if (mii_ane & MII_ANE_PDF)
|
---|
| 2045 | printf("%s: parallel detection fault\n", fp->fxp_name);
|
---|
| 2046 | if (!(mii_ane & MII_ANE_LPANA))
|
---|
| 2047 | {
|
---|
| 2048 | printf("%s: link-partner does not support auto-negotiation\n",
|
---|
| 2049 | fp->fxp_name);
|
---|
| 2050 | goto resspeed;
|
---|
| 2051 | }
|
---|
| 2052 |
|
---|
| 2053 | printf("%s: remote cap.: ", fp->fxp_name);
|
---|
| 2054 | if (mii_ms_ctrl & (MII_MSC_1000T_FD | MII_MSC_1000T_HD))
|
---|
| 2055 | if (mii_ms_status & (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
|
---|
| 2056 | {
|
---|
| 2057 | printf("1000 Mbps: T-");
|
---|
| 2058 | switch(mii_ms_status &
|
---|
| 2059 | (MII_MSS_LP1000T_FD | MII_MSS_LP1000T_HD))
|
---|
| 2060 | {
|
---|
| 2061 | case MII_MSS_LP1000T_FD: printf("FD"); break;
|
---|
| 2062 | case MII_MSS_LP1000T_HD: printf("HD"); break;
|
---|
| 2063 | default: printf("FD/HD"); break;
|
---|
| 2064 | }
|
---|
| 2065 | if (mii_anlpa)
|
---|
| 2066 | printf(", ");
|
---|
| 2067 | }
|
---|
| 2068 | mii_print_techab(mii_anlpa);
|
---|
| 2069 | printf("\n");
|
---|
| 2070 |
|
---|
| 2071 | if (ms_regs)
|
---|
| 2072 | {
|
---|
| 2073 | printf("%s: ", fp->fxp_name);
|
---|
| 2074 | if (mii_ms_ctrl & MII_MSC_MS_MANUAL)
|
---|
| 2075 | {
|
---|
| 2076 | printf("manual %s",
|
---|
| 2077 | (mii_ms_ctrl & MII_MSC_MS_VAL) ?
|
---|
| 2078 | "MASTER" : "SLAVE");
|
---|
| 2079 | }
|
---|
| 2080 | else
|
---|
| 2081 | {
|
---|
| 2082 | printf("%s device",
|
---|
| 2083 | (mii_ms_ctrl & MII_MSC_MULTIPORT) ?
|
---|
| 2084 | "multiport" : "single-port");
|
---|
| 2085 | }
|
---|
| 2086 | if (mii_ms_ctrl & MII_MSC_RES)
|
---|
| 2087 | printf(" reserved<0x%x>", mii_ms_ctrl & MII_MSC_RES);
|
---|
| 2088 | printf(": ");
|
---|
| 2089 | if (mii_ms_status & MII_MSS_FAULT)
|
---|
| 2090 | printf("M/S config fault");
|
---|
| 2091 | else if (mii_ms_status & MII_MSS_MASTER)
|
---|
| 2092 | printf("MASTER");
|
---|
| 2093 | else
|
---|
| 2094 | printf("SLAVE");
|
---|
| 2095 | printf("\n");
|
---|
| 2096 | }
|
---|
| 2097 |
|
---|
| 2098 | if (mii_ms_status & (MII_MSS_LP1000T_FD|MII_MSS_LP1000T_HD))
|
---|
| 2099 | {
|
---|
| 2100 | if (!(mii_ms_status & MII_MSS_LOCREC))
|
---|
| 2101 | {
|
---|
| 2102 | printf("%s: local receiver not OK\n",
|
---|
| 2103 | fp->fxp_name);
|
---|
| 2104 | }
|
---|
| 2105 | if (!(mii_ms_status & MII_MSS_REMREC))
|
---|
| 2106 | {
|
---|
| 2107 | printf("%s: remote receiver not OK\n",
|
---|
| 2108 | fp->fxp_name);
|
---|
| 2109 | }
|
---|
| 2110 | }
|
---|
| 2111 | if (mii_ms_status & (MII_MSS_RES|MII_MSS_IDLE_ERR))
|
---|
| 2112 | {
|
---|
| 2113 | printf("%s", fp->fxp_name);
|
---|
| 2114 | if (mii_ms_status & MII_MSS_RES)
|
---|
| 2115 | printf(" reserved<0x%x>", mii_ms_status & MII_MSS_RES);
|
---|
| 2116 | if (mii_ms_status & MII_MSS_IDLE_ERR)
|
---|
| 2117 | {
|
---|
| 2118 | printf(" idle error %d",
|
---|
| 2119 | mii_ms_status & MII_MSS_IDLE_ERR);
|
---|
| 2120 | }
|
---|
| 2121 | printf("\n");
|
---|
| 2122 | }
|
---|
| 2123 |
|
---|
| 2124 | resspeed:
|
---|
| 2125 | #if VERBOSE
|
---|
| 2126 | printf("%s: link up, %d Mbps, %s duplex\n",
|
---|
| 2127 | fp->fxp_name, (scr & MII_SCR_100) ? 100 : 10,
|
---|
| 2128 | (scr & MII_SCR_FD) ? "full" : "half");
|
---|
| 2129 | #endif
|
---|
| 2130 | ;
|
---|
| 2131 | }
|
---|
| 2132 |
|
---|
| 2133 | /*===========================================================================*
|
---|
| 2134 | * fxp_stop *
|
---|
| 2135 | *===========================================================================*/
|
---|
| 2136 | static void fxp_stop()
|
---|
| 2137 | {
|
---|
| 2138 | int i;
|
---|
| 2139 | port_t port;
|
---|
| 2140 | fxp_t *fp;
|
---|
| 2141 |
|
---|
| 2142 | for (i= 0, fp= &fxp_table[0]; i<FXP_PORT_NR; i++, fp++)
|
---|
| 2143 | {
|
---|
| 2144 | if (fp->fxp_mode != FM_ENABLED)
|
---|
| 2145 | continue;
|
---|
| 2146 | if (!(fp->fxp_flags & FF_ENABLED))
|
---|
| 2147 | continue;
|
---|
| 2148 | port= fp->fxp_base_port;
|
---|
| 2149 |
|
---|
| 2150 | /* Reset device */
|
---|
| 2151 | if (debug)
|
---|
| 2152 | printf("%s: resetting device\n", fp->fxp_name);
|
---|
| 2153 | fxp_outl(port, CSR_PORT, CP_CMD_SOFT_RESET);
|
---|
| 2154 | }
|
---|
| 2155 | sys_exit(0);
|
---|
| 2156 | }
|
---|
| 2157 |
|
---|
| 2158 | /*===========================================================================*
|
---|
| 2159 | * reply *
|
---|
| 2160 | *===========================================================================*/
|
---|
| 2161 | static void reply(fp, err, may_block)
|
---|
| 2162 | fxp_t *fp;
|
---|
| 2163 | int err;
|
---|
| 2164 | int may_block;
|
---|
| 2165 | {
|
---|
| 2166 | message reply;
|
---|
| 2167 | int status;
|
---|
| 2168 | int r;
|
---|
| 2169 |
|
---|
| 2170 | status = 0;
|
---|
| 2171 | if (fp->fxp_flags & FF_PACK_SENT)
|
---|
| 2172 | status |= DL_PACK_SEND;
|
---|
| 2173 | if (fp->fxp_flags & FF_PACK_RECV)
|
---|
| 2174 | status |= DL_PACK_RECV;
|
---|
| 2175 |
|
---|
| 2176 | reply.m_type = DL_TASK_REPLY;
|
---|
| 2177 | reply.DL_PORT = fp - fxp_table;
|
---|
| 2178 | reply.DL_PROC = fp->fxp_client;
|
---|
| 2179 | reply.DL_STAT = status | ((u32_t) err << 16);
|
---|
| 2180 | reply.DL_COUNT = fp->fxp_read_s;
|
---|
| 2181 | #if 0
|
---|
| 2182 | reply.DL_CLCK = get_uptime();
|
---|
| 2183 | #else
|
---|
| 2184 | reply.DL_CLCK = 0;
|
---|
| 2185 | #endif
|
---|
| 2186 |
|
---|
| 2187 | r= send(fp->fxp_client, &reply);
|
---|
| 2188 |
|
---|
| 2189 | if (r == ELOCKED && may_block)
|
---|
| 2190 | {
|
---|
| 2191 | #if 0
|
---|
| 2192 | printW(); printf("send locked\n");
|
---|
| 2193 | #endif
|
---|
| 2194 | return;
|
---|
| 2195 | }
|
---|
| 2196 |
|
---|
| 2197 | if (r < 0)
|
---|
| 2198 | panic("FXP","fxp: send failed:", r);
|
---|
| 2199 |
|
---|
| 2200 | fp->fxp_read_s = 0;
|
---|
| 2201 | fp->fxp_flags &= ~(FF_PACK_SENT | FF_PACK_RECV);
|
---|
| 2202 | }
|
---|
| 2203 |
|
---|
| 2204 | /*===========================================================================*
|
---|
| 2205 | * mess_reply *
|
---|
| 2206 | *===========================================================================*/
|
---|
| 2207 | static void mess_reply(req, reply_mess)
|
---|
| 2208 | message *req;
|
---|
| 2209 | message *reply_mess;
|
---|
| 2210 | {
|
---|
| 2211 | if (send(req->m_source, reply_mess) != OK)
|
---|
| 2212 | panic("FXP","fxp: unable to mess_reply", NO_NUM);
|
---|
| 2213 | }
|
---|
| 2214 |
|
---|
| 2215 | /*===========================================================================*
|
---|
| 2216 | * put_userdata *
|
---|
| 2217 | *===========================================================================*/
|
---|
| 2218 | static void put_userdata(user_proc, user_addr, count, loc_addr)
|
---|
| 2219 | int user_proc;
|
---|
| 2220 | vir_bytes user_addr;
|
---|
| 2221 | vir_bytes count;
|
---|
| 2222 | void *loc_addr;
|
---|
| 2223 | {
|
---|
| 2224 | int r;
|
---|
| 2225 |
|
---|
| 2226 | r= sys_vircopy(SELF, D, (vir_bytes)loc_addr,
|
---|
| 2227 | user_proc, D, user_addr, count);
|
---|
| 2228 | if (r != OK)
|
---|
| 2229 | panic("FXP","put_userdata: sys_vircopy failed", r);
|
---|
| 2230 | }
|
---|
| 2231 |
|
---|
| 2232 | /*===========================================================================*
|
---|
| 2233 | * eeprom_read *
|
---|
| 2234 | *===========================================================================*/
|
---|
| 2235 | PRIVATE u16_t eeprom_read(fp, reg)
|
---|
| 2236 | fxp_t *fp;
|
---|
| 2237 | int reg;
|
---|
| 2238 | {
|
---|
| 2239 | port_t port;
|
---|
| 2240 | u16_t v;
|
---|
| 2241 | int b, i, alen;
|
---|
| 2242 |
|
---|
| 2243 | alen= fp->fxp_ee_addrlen;
|
---|
| 2244 | if (!alen)
|
---|
| 2245 | {
|
---|
| 2246 | eeprom_addrsize(fp);
|
---|
| 2247 | alen= fp->fxp_ee_addrlen;
|
---|
| 2248 | assert(alen == 6 || alen == 8);
|
---|
| 2249 | }
|
---|
| 2250 |
|
---|
| 2251 | port= fp->fxp_base_port;
|
---|
| 2252 |
|
---|
| 2253 | fxp_outb(port, CSR_EEPROM, CE_EECS); /* Enable EEPROM */
|
---|
| 2254 | v= EEPROM_READ_PREFIX;
|
---|
| 2255 | for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
|
---|
| 2256 | {
|
---|
| 2257 | b= ((v & (1 << i)) ? CE_EEDI : 0);
|
---|
| 2258 | fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */
|
---|
| 2259 | fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
|
---|
| 2260 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2261 | fxp_outb(port, CSR_EEPROM, CE_EECS | b);
|
---|
| 2262 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2263 | }
|
---|
| 2264 |
|
---|
| 2265 | v= reg;
|
---|
| 2266 | for (i= alen-1; i >= 0; i--)
|
---|
| 2267 | {
|
---|
| 2268 | b= ((v & (1 << i)) ? CE_EEDI : 0);
|
---|
| 2269 | fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */
|
---|
| 2270 | fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
|
---|
| 2271 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2272 | fxp_outb(port, CSR_EEPROM, CE_EECS | b);
|
---|
| 2273 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2274 | }
|
---|
| 2275 |
|
---|
| 2276 | v= 0;
|
---|
| 2277 | for (i= 0; i<16; i++)
|
---|
| 2278 | {
|
---|
| 2279 | fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
|
---|
| 2280 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2281 | b= !!(fxp_inb(port, CSR_EEPROM) & CE_EEDO);
|
---|
| 2282 | v= (v << 1) | b;
|
---|
| 2283 | fxp_outb(port, CSR_EEPROM, CE_EECS );
|
---|
| 2284 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2285 | }
|
---|
| 2286 | fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */
|
---|
| 2287 | micro_delay(EECS_DELAY);
|
---|
| 2288 |
|
---|
| 2289 | return v;
|
---|
| 2290 | }
|
---|
| 2291 |
|
---|
| 2292 | /*===========================================================================*
|
---|
| 2293 | * eeprom_addrsize *
|
---|
| 2294 | *===========================================================================*/
|
---|
| 2295 | PRIVATE void eeprom_addrsize(fp)
|
---|
| 2296 | fxp_t *fp;
|
---|
| 2297 | {
|
---|
| 2298 | port_t port;
|
---|
| 2299 | u16_t v;
|
---|
| 2300 | int b, i;
|
---|
| 2301 |
|
---|
| 2302 | port= fp->fxp_base_port;
|
---|
| 2303 |
|
---|
| 2304 | /* Try to find out the size of the EEPROM */
|
---|
| 2305 | fxp_outb(port, CSR_EEPROM, CE_EECS); /* Enable EEPROM */
|
---|
| 2306 | v= EEPROM_READ_PREFIX;
|
---|
| 2307 | for (i= EEPROM_PREFIX_LEN-1; i >= 0; i--)
|
---|
| 2308 | {
|
---|
| 2309 | b= ((v & (1 << i)) ? CE_EEDI : 0);
|
---|
| 2310 | fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */
|
---|
| 2311 | fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
|
---|
| 2312 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2313 | fxp_outb(port, CSR_EEPROM, CE_EECS | b);
|
---|
| 2314 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2315 | }
|
---|
| 2316 |
|
---|
| 2317 | for (i= 0; i<32; i++)
|
---|
| 2318 | {
|
---|
| 2319 | b= 0;
|
---|
| 2320 | fxp_outb(port, CSR_EEPROM, CE_EECS | b); /* bit */
|
---|
| 2321 | fxp_outb(port, CSR_EEPROM, CE_EECS | b | CE_EESK); /* Clock */
|
---|
| 2322 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2323 | fxp_outb(port, CSR_EEPROM, CE_EECS | b);
|
---|
| 2324 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2325 | v= fxp_inb(port, CSR_EEPROM);
|
---|
| 2326 | if (!(v & CE_EEDO))
|
---|
| 2327 | break;
|
---|
| 2328 | }
|
---|
| 2329 | if (i >= 32)
|
---|
| 2330 | panic("FXP","eeprom_addrsize: failed", NO_NUM);
|
---|
| 2331 | fp->fxp_ee_addrlen= i+1;
|
---|
| 2332 |
|
---|
| 2333 | /* Discard 16 data bits */
|
---|
| 2334 | for (i= 0; i<16; i++)
|
---|
| 2335 | {
|
---|
| 2336 | fxp_outb(port, CSR_EEPROM, CE_EECS | CE_EESK); /* Clock */
|
---|
| 2337 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2338 | fxp_outb(port, CSR_EEPROM, CE_EECS );
|
---|
| 2339 | micro_delay(EESK_PERIOD/2+1);
|
---|
| 2340 | }
|
---|
| 2341 | fxp_outb(port, CSR_EEPROM, 0); /* Disable EEPROM */
|
---|
| 2342 | micro_delay(EECS_DELAY);
|
---|
| 2343 |
|
---|
| 2344 | #if VERBOSE
|
---|
| 2345 | printf("%s EEPROM address length: %d\n",
|
---|
| 2346 | fp->fxp_name, fp->fxp_ee_addrlen);
|
---|
| 2347 | #endif
|
---|
| 2348 | }
|
---|
| 2349 |
|
---|
| 2350 | /*===========================================================================*
|
---|
| 2351 | * mii_read *
|
---|
| 2352 | *===========================================================================*/
|
---|
| 2353 | PRIVATE u16_t mii_read(fp, reg)
|
---|
| 2354 | fxp_t *fp;
|
---|
| 2355 | int reg;
|
---|
| 2356 | {
|
---|
| 2357 | clock_t t0,t1;
|
---|
| 2358 | port_t port;
|
---|
| 2359 | u32_t v;
|
---|
| 2360 |
|
---|
| 2361 | port= fp->fxp_base_port;
|
---|
| 2362 |
|
---|
| 2363 | assert(!fp->fxp_mii_busy);
|
---|
| 2364 | fp->fxp_mii_busy++;
|
---|
| 2365 |
|
---|
| 2366 | if (!(fxp_inl(port, CSR_MDI_CTL) & CM_READY))
|
---|
| 2367 | panic("FXP","mii_read: MDI not ready", NO_NUM);
|
---|
| 2368 | fxp_outl(port, CSR_MDI_CTL, CM_READ | (1 << CM_PHYADDR_SHIFT) |
|
---|
| 2369 | (reg << CM_REG_SHIFT));
|
---|
| 2370 |
|
---|
| 2371 | getuptime(&t0);
|
---|
| 2372 | do {
|
---|
| 2373 | v= fxp_inl(port, CSR_MDI_CTL);
|
---|
| 2374 | if (v & CM_READY)
|
---|
| 2375 | break;
|
---|
| 2376 | } while (getuptime(&t1)==OK && (t1-t0) < MICROS_TO_TICKS(100000));
|
---|
| 2377 |
|
---|
| 2378 | if (!(v & CM_READY))
|
---|
| 2379 | panic("FXP","mii_read: MDI not ready after command", NO_NUM);
|
---|
| 2380 |
|
---|
| 2381 | fp->fxp_mii_busy--;
|
---|
| 2382 | assert(!fp->fxp_mii_busy);
|
---|
| 2383 |
|
---|
| 2384 | return v & CM_DATA_MASK;
|
---|
| 2385 | }
|
---|
| 2386 |
|
---|
| 2387 | /*===========================================================================*
|
---|
| 2388 | * fxp_set_timer *
|
---|
| 2389 | *===========================================================================*/
|
---|
| 2390 | PRIVATE void fxp_set_timer(tp, delta, watchdog)
|
---|
| 2391 | timer_t *tp; /* timer to be set */
|
---|
| 2392 | clock_t delta; /* in how many ticks */
|
---|
| 2393 | tmr_func_t watchdog; /* watchdog function to be called */
|
---|
| 2394 | {
|
---|
| 2395 | clock_t now; /* current time */
|
---|
| 2396 | int r;
|
---|
| 2397 |
|
---|
| 2398 | /* Get the current time. */
|
---|
| 2399 | r= getuptime(&now);
|
---|
| 2400 | if (r != OK)
|
---|
| 2401 | panic("FXP","unable to get uptime from clock", r);
|
---|
| 2402 |
|
---|
| 2403 | /* Add the timer to the local timer queue. */
|
---|
| 2404 | tmrs_settimer(&fxp_timers, tp, now + delta, watchdog, NULL);
|
---|
| 2405 |
|
---|
| 2406 | /* Possibly reschedule an alarm call. This happens when a new timer
|
---|
| 2407 | * is added in front.
|
---|
| 2408 | */
|
---|
| 2409 | if (fxp_next_timeout == 0 ||
|
---|
| 2410 | fxp_timers->tmr_exp_time < fxp_next_timeout)
|
---|
| 2411 | {
|
---|
| 2412 | fxp_next_timeout= fxp_timers->tmr_exp_time;
|
---|
| 2413 | #if VERBOSE
|
---|
| 2414 | printf("fxp_set_timer: calling sys_setalarm for %d (now+%d)\n",
|
---|
| 2415 | fxp_next_timeout, fxp_next_timeout-now);
|
---|
| 2416 | #endif
|
---|
| 2417 | r= sys_setalarm(fxp_next_timeout, 1);
|
---|
| 2418 | if (r != OK)
|
---|
| 2419 | panic("FXP","unable to set synchronous alarm", r);
|
---|
| 2420 | }
|
---|
| 2421 | }
|
---|
| 2422 |
|
---|
| 2423 | /*===========================================================================*
|
---|
| 2424 | * fxp_expire_tmrs *
|
---|
| 2425 | *===========================================================================*/
|
---|
| 2426 | PRIVATE void fxp_expire_timers()
|
---|
| 2427 | {
|
---|
| 2428 | /* A synchronous alarm message was received. Check if there are any expired
|
---|
| 2429 | * timers. Possibly reschedule the next alarm.
|
---|
| 2430 | */
|
---|
| 2431 | clock_t now; /* current time */
|
---|
| 2432 | timer_t *tp;
|
---|
| 2433 | int r;
|
---|
| 2434 |
|
---|
| 2435 | /* Get the current time to compare the timers against. */
|
---|
| 2436 | r= getuptime(&now);
|
---|
| 2437 | if (r != OK)
|
---|
| 2438 | panic("FXP","Unable to get uptime from clock.", r);
|
---|
| 2439 |
|
---|
| 2440 | /* Scan the timers queue for expired timers. Dispatch the watchdog function
|
---|
| 2441 | * for each expired timers. Possibly a new alarm call must be scheduled.
|
---|
| 2442 | */
|
---|
| 2443 | tmrs_exptimers(&fxp_timers, now, NULL);
|
---|
| 2444 | if (fxp_timers == NULL)
|
---|
| 2445 | fxp_next_timeout= TMR_NEVER;
|
---|
| 2446 | else
|
---|
| 2447 | { /* set new alarm */
|
---|
| 2448 | fxp_next_timeout = fxp_timers->tmr_exp_time;
|
---|
| 2449 | r= sys_setalarm(fxp_next_timeout, 1);
|
---|
| 2450 | if (r != OK)
|
---|
| 2451 | panic("FXP","Unable to set synchronous alarm.", r);
|
---|
| 2452 | }
|
---|
| 2453 | }
|
---|
| 2454 |
|
---|
| 2455 | static void micro_delay(unsigned long usecs)
|
---|
| 2456 | {
|
---|
| 2457 | tickdelay(MICROS_TO_TICKS(usecs));
|
---|
| 2458 | }
|
---|
| 2459 |
|
---|
| 2460 | static u8_t do_inb(port_t port)
|
---|
| 2461 | {
|
---|
| 2462 | int r;
|
---|
| 2463 | u32_t value;
|
---|
| 2464 |
|
---|
| 2465 | r= sys_inb(port, &value);
|
---|
| 2466 | if (r != OK)
|
---|
| 2467 | panic("FXP","sys_inb failed", r);
|
---|
| 2468 | return value;
|
---|
| 2469 | }
|
---|
| 2470 |
|
---|
| 2471 | static u32_t do_inl(port_t port)
|
---|
| 2472 | {
|
---|
| 2473 | int r;
|
---|
| 2474 | u32_t value;
|
---|
| 2475 |
|
---|
| 2476 | r= sys_inl(port, &value);
|
---|
| 2477 | if (r != OK)
|
---|
| 2478 | panic("FXP","sys_inl failed", r);
|
---|
| 2479 | return value;
|
---|
| 2480 | }
|
---|
| 2481 |
|
---|
| 2482 | static void do_outb(port_t port, u8_t value)
|
---|
| 2483 | {
|
---|
| 2484 | int r;
|
---|
| 2485 |
|
---|
| 2486 | r= sys_outb(port, value);
|
---|
| 2487 | if (r != OK)
|
---|
| 2488 | panic("FXP","sys_outb failed", r);
|
---|
| 2489 | }
|
---|
| 2490 |
|
---|
| 2491 | static void do_outl(port_t port, u32_t value)
|
---|
| 2492 | {
|
---|
| 2493 | int r;
|
---|
| 2494 |
|
---|
| 2495 | r= sys_outl(port, value);
|
---|
| 2496 | if (r != OK)
|
---|
| 2497 | panic("FXP","sys_outl failed", r);
|
---|
| 2498 | }
|
---|
| 2499 |
|
---|
| 2500 | /*
|
---|
| 2501 | * $PchId: fxp.c,v 1.4 2005/01/31 22:10:37 philip Exp $
|
---|
| 2502 | */
|
---|
| 2503 |
|
---|