📄 rtl8139.c
字号:
t= rl_inw(port, RL_NWAYTR); printf("NWAYTR: 0x%04lx\n", t); t= rl_inw(port, RL_CSCR); printf("CSCR: 0x%04lx\n", t); t= rl_inb(port, RL_CONFIG5); printf("CONFIG5: 0x%02lx\n", t);}#endifstatic int do_hard_int(void){ int i,s; for (i=0; i < RE_PORT_NR; i ++) { /* Run interrupt handler at driver level. */ rl_handler( &re_table[i]); /* Reenable interrupts for this hook. */ if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK) printf("RTL8139: error, couldn't enable interrupts: %d\n", s); }}/*===========================================================================* * rl_handler * *===========================================================================*/static int rl_handler(rep)re_t *rep;{ int i, port, tx_head, tx_tail, link_up; u16_t isr, tsad; u32_t tsd, tcr, ertxth;#if 0 u8_t cr;#endif clock_t t0,t1; int_event_check = FALSE; /* disable check by default */ port= rep->re_base_port; /* Ack interrupt */ isr= rl_inw(port, RL_ISR); rl_outw(port, RL_ISR, isr); if (isr & RL_IMR_FOVW) { isr &= ~RL_IMR_FOVW; /* Should do anything? */ rep->re_stat.ets_fifoOver++; } if (isr & RL_IMR_PUN) { isr &= ~RL_IMR_PUN; /* Either the link status changed or there was a TX fifo * underrun. */ link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB); if (link_up != rep->re_link_up) { rep->re_report_link= TRUE; rep->re_got_int= TRUE; int_event_check = TRUE; } } if (isr & RL_IMR_RXOVW) { isr &= ~RL_IMR_RXOVW; /* Clear the receive buffer */ rep->re_clear_rx= TRUE; rep->re_got_int= TRUE; int_event_check = TRUE; } if (isr & (RL_ISR_RER | RL_ISR_ROK)) { isr &= ~(RL_ISR_RER | RL_ISR_ROK); if (!rep->re_got_int && (rep->re_flags & REF_READING)) { rep->re_got_int= TRUE; int_event_check = TRUE; } }#if 0 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) && (rep->re_flags & REF_SEND_AVAIL) && (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy || rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy)) { printf( "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n", rep->re_tx_head, rep->re_tx_tail, rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); printf( "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", rl_inw(port, RL_TSAD), rl_inl(port, RL_TSD0+0*4), rl_inl(port, RL_TSD0+1*4), rl_inl(port, RL_TSD0+2*4), rl_inl(port, RL_TSD0+3*4)); }#endif if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1) { isr &= ~(RL_ISR_TER | RL_ISR_TOK); tsad= rl_inw(port, RL_TSAD); if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1| RL_TSAD_TABT2|RL_TSAD_TABT3)) {#if 0 /* Do we need a watch dog? */ /* Just reset the whole chip */ rep->re_need_reset= TRUE; rep->re_got_int= TRUE; int_event_check = TRUE;#elif 0 /* Reset transmitter */ rep->re_stat.ets_transAb++; cr= rl_inb(port, RL_CR); cr &= ~RL_CR_TE; rl_outb(port, RL_CR, cr); getuptime(&t0); do { if (!(rl_inb(port, RL_CR) & RL_CR_TE)) break; } while (getuptime(&t1)==OK && (t1-t0) < HZ); if (rl_inb(port, RL_CR) & RL_CR_TE) { panic("rtl8139","cannot disable transmitter", NO_NUM); } rl_outb(port, RL_CR, cr | RL_CR_TE); tcr= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD); printf("rl_handler: reset after abort\n"); if (rep->re_flags & REF_SEND_AVAIL) { printf("rl_handler: REF_SEND_AVAIL\n"); rep->re_send_int= TRUE; rep->re_got_int= TRUE; int_event_check = TRUE; } for (i= 0; i< N_TX_BUF; i++) rep->re_tx[i].ret_busy= FALSE; rep->re_tx_head= 0;#else printf("rl_handler, TABT, tasd = 0x%04x\n", tsad); /* Find the aborted transmit request */ for (i= 0; i< N_TX_BUF; i++) { tsd= rl_inl(port, RL_TSD0+i*4); if (tsd & RL_TSD_TABT) break; } if (i >= N_TX_BUF) { printf( "rl_handler: can't find aborted TX req.\n"); } else { printf("TSD%d = 0x%04lx\n", i, tsd); /* Set head and tail to this buffer */ rep->re_tx_head= rep->re_tx_tail= i; } /* Aborted transmission, just kick the device * and be done with it. */ rep->re_stat.ets_transAb++; tcr= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);#endif } /* Transmit completed */ tx_head= rep->re_tx_head; tx_tail= rep->re_tx_tail; for (i= 0; i< 2*N_TX_BUF; i++) { if (!rep->re_tx[tx_tail].ret_busy) { /* Strange, this buffer is not in-use. * Increment tx_tail until tx_head is * reached (or until we find a buffer that * is in-use. */ if (tx_tail == tx_head) break; if (++tx_tail >= N_TX_BUF) tx_tail= 0; assert(tx_tail < RL_N_TX); rep->re_tx_tail= tx_tail; continue; } tsd= rl_inl(port, RL_TSD0+tx_tail*4); if (!(tsd & RL_TSD_OWN)) { /* Buffer is not yet ready */ break; } /* Should collect statistics */ if (tsd & RL_TSD_CRS) rep->re_stat.ets_carrSense++; if (tsd & RL_TSD_TABT) { printf("rl_handler, TABT, TSD%d = 0x%04lx\n", tx_tail, tsd); assert(0); /* CLRABT is not all that * effective, why not? */ rep->re_stat.ets_transAb++; tcr= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT); } if (tsd & RL_TSD_OWC) rep->re_stat.ets_OWC++; if (tsd & RL_TSD_CDH) rep->re_stat.ets_CDheartbeat++; /* What about collisions? */ if (tsd & RL_TSD_TOK) rep->re_stat.ets_packetT++; else rep->re_stat.ets_sendErr++; if (tsd & RL_TSD_TUN) { rep->re_stat.ets_fifoUnder++; /* Increase ERTXTH */ ertxth= tsd + (1 << RL_TSD_ERTXTH_S); ertxth &= RL_TSD_ERTXTH_M; if (debug && ertxth > rep->re_ertxth) { printf("%s: new ertxth: %ld bytes\n", rep->re_name, (ertxth >> RL_TSD_ERTXTH_S) * 32); rep->re_ertxth= ertxth; } } rep->re_tx[tx_tail].ret_busy= FALSE;#if 0 if (rep->re_flags & REF_SEND_AVAIL) { printf("TSD%d: %08lx\n", tx_tail, tsd); printf( "rl_handler: head %d, tail %d, busy: %d %d %d %d\n", tx_head, tx_tail, rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); }#endif if (++tx_tail >= N_TX_BUF) tx_tail= 0; assert(tx_tail < RL_N_TX); rep->re_tx_tail= tx_tail; if (rep->re_flags & REF_SEND_AVAIL) {#if 0 printf("rl_handler: REF_SEND_AVAIL\n");#endif rep->re_send_int= TRUE; if (!rep->re_got_int) { rep->re_got_int= TRUE; int_event_check = TRUE; } } } assert(i < 2*N_TX_BUF); } if (isr) { printf("rl_handler: unhandled interrupt: isr = 0x%04x\n", isr); } return 1;}/*===========================================================================* * rl_watchdog_f * *===========================================================================*/static void rl_watchdog_f(tp)timer_t *tp;{ int i; re_t *rep; /* Use a synchronous alarm instead of a watchdog timer. */ sys_setalarm(HZ, 0); for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++) { if (rep->re_mode != REM_ENABLED) continue; if (!(rep->re_flags & REF_SEND_AVAIL)) { /* Assume that an idle system is alive */ rep->re_tx_alive= TRUE; continue; } if (rep->re_tx_alive) { rep->re_tx_alive= FALSE; continue; } printf("rl_watchdog_f: resetting port %d\n", i); printf( "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", rl_inw(rep->re_base_port, RL_TSAD), rl_inl(rep->re_base_port, RL_TSD0+0*4), rl_inl(rep->re_base_port, RL_TSD0+1*4), rl_inl(rep->re_base_port, RL_TSD0+2*4), rl_inl(rep->re_base_port, RL_TSD0+3*4)); printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n", rep->re_tx_head, rep->re_tx_tail, rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy); rep->re_need_reset= TRUE; rep->re_got_int= TRUE; check_int_events(); }}#if 0_PROTOTYPE( static void rtl_init, (struct dpeth *dep) );_PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );_PROTOTYPE( static void ee_wen, (dpeth_t *dep) );_PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );_PROTOTYPE( static void ee_wds, (dpeth_t *dep) );static void rtl_init(dep)dpeth_t *dep;{ u8_t reg_a, reg_b, cr, config0, config2, config3; int i; char val[128]; printf("rtl_init called\n"); ne_init(dep); /* ID */ outb_reg0(dep, DP_CR, CR_PS_P0); reg_a = inb_reg0(dep, DP_DUM1); reg_b = inb_reg0(dep, DP_DUM2); printf("rtl_init: '%c', '%c'\n", reg_a, reg_b); outb_reg0(dep, DP_CR, CR_PS_P3); config0 = inb_reg3(dep, 3); config2 = inb_reg3(dep, 5); config3 = inb_reg3(dep, 6); outb_reg0(dep, DP_CR, CR_PS_P0); printf("rtl_init: config 0/2/3 = %x/%x/%x\n", config0, config2, config3); if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val))) { printf("rtl_init: setting full-duplex mode\n"); outb_reg0(dep, DP_CR, CR_PS_P3); cr= inb_reg3(dep, 1); outb_reg3(dep, 1, cr | 0xc0); outb_reg3(dep, 6, config3 | 0x40); config3 = inb_reg3(dep, 6); config2= inb_reg3(dep, 5); outb_reg3(dep, 5, config2 | 0x20); config2= inb_reg3(dep, 5); outb_reg3(dep, 1, cr); outb_reg0(dep, DP_CR, CR_PS_P0); printf("rtl_init: config 2 = %x\n", config2); printf("rtl_init: config 3 = %x\n", config3); } for (i= 0; i<64; i++) printf("%x ", get_ee_word(dep, i)); printf("\n"); if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val))) { ee_wen(dep); set_ee_word(dep, 0x78/2, 0x10ec); set_ee_word(dep, 0x7A/2, 0x8029); set_ee_word(dep, 0x7C/2, 0x10ec); set_ee_word(dep, 0x7E/2, 0x8029); ee_wds(dep); assert(get_ee_word(dep, 0x78/2) == 0x10ec); assert(get_ee_word(dep, 0x7A/2) == 0x8029); assert(get_ee_word(dep, 0x7C/2) == 0x10ec); assert(get_ee_word(dep, 0x7E/2) == 0x8029); } if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val))) { ee_wen(dep); set_ee_word(dep, 0x76/2, 0x8029); ee_wds(dep); assert(get_ee_word(dep, 0x76/2) == 0x8029); }}static u16_t get_ee_word(dep, a)dpeth_t *dep;int a;{ int b, i, cmd; u16_t w; outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ /* Switch to 9346 mode and enable CS */ outb_reg3(dep, 1, 0x80 | 0x8); cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */ for (i= 8; i >= 0; i--) { b= (cmd & (1 << i)); b= (b ? 2 : 0); /* Cmd goes out on the rising edge of the clock */ outb_reg3(dep, 1, 0x80 | 0x8 | b); outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); } outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ w= 0; for (i= 0; i<16; i++) { w <<= 1; /* Data is shifted out on the rising edge. Read at the * falling edge. */ outb_reg3(dep, 1, 0x80 | 0x8 | 0x4); outb_reg3(dep, 1, 0x80 | 0x8 | b); b= inb_reg3(dep, 1); w |= (b & 1); } outb_reg3(dep, 1, 0x80); /* drop CS */ outb_reg3(dep, 1, 0x00); /* back to normal */ outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ return w;}static void ee_wen(dep)dpeth_t *dep;{ int b, i, cmd; u16_t w; outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ /* Switch to 9346 mode and enable CS */ outb_reg3(dep, 1, 0x80 | 0x8); cmd= 0x130; /* 1 0 0 1 1 x x x x */ for (i= 8; i >= 0; i--) { b= (cmd & (1 << i)); b= (b ? 2 : 0); /* Cmd goes out on the rising edge of the clock */ outb_reg3(dep, 1, 0x80 | 0x8 | b); outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); } outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ outb_reg3(dep, 1, 0x80); /* Drop CS */ /* micro_delay(1); */ /* Is this required? */}static void set_ee_word(dep, a, w)dpeth_t *dep;int a;u16_t w;{ int b, i, cmd; clock_t t0, t1; outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ cmd= 0x140 | (a & 0x3f); /* 1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -