📄 rtl8139.c
字号:
*(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address; mess_reply(mp, &reply_mess);}/*===========================================================================* * rl_pci_conf * *===========================================================================*/static void rl_pci_conf(){ int i, h; re_t *rep; static char envvar[] = RL_ENVVAR "#"; static char envfmt[] = "*:d.d.d"; static char val[128]; long v; for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++) { strcpy(rep->re_name, "rtl8139#0"); rep->re_name[8] += i; rep->re_seen= FALSE; envvar[sizeof(RL_ENVVAR)-1]= '0'+i; if (0 == env_get_param(envvar, val, sizeof(val)) && ! env_prefix(envvar, "pci")) { env_panic(envvar); } v= 0; (void) env_parse(envvar, envfmt, 1, &v, 0, 255); rep->re_pcibus= v; v= 0; (void) env_parse(envvar, envfmt, 2, &v, 0, 255); rep->re_pcidev= v; v= 0; (void) env_parse(envvar, envfmt, 3, &v, 0, 255); rep->re_pcifunc= v; } pci_init(); for (h= 1; h >= 0; h--) { for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++) { if (((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0) != h) { continue; } if (rl_probe(rep)) rep->re_seen= TRUE; } }}/*===========================================================================* * rl_probe * *===========================================================================*/static int rl_probe(rep)re_t *rep;{ int i, r, devind, just_one; u16_t vid, did; u32_t bar; u8_t ilr; char *dname; if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0) { /* Look for specific PCI device */ r= pci_find_dev(rep->re_pcibus, rep->re_pcidev, rep->re_pcifunc, &devind); if (r == 0) { printf("%s: no PCI found at %d.%d.%d\n", rep->re_name, rep->re_pcibus, rep->re_pcidev, rep->re_pcifunc); return 0; } pci_ids(devind, &vid, &did); just_one= TRUE; } else { r= pci_first_dev(&devind, &vid, &did); if (r == 0) return 0; just_one= FALSE; } for(;;) { for (i= 0; pcitab[i].vid != 0; i++) { if (pcitab[i].vid != vid) continue; if (pcitab[i].did != did) continue; if (pcitab[i].checkclass) { panic("rtl_probe", "class check not implemented", NO_NUM); } break; } if (pcitab[i].vid != 0) break; if (just_one) { printf( "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n", rep->re_name, vid, did, rep->re_pcibus, rep->re_pcidev, rep->re_pcifunc); return 0; } r= pci_next_dev(&devind, &vid, &did); if (!r) return 0; }#if VERBOSE /* stay silent at startup, can always get status later */ dname= pci_dev_name(vid, did); if (!dname) dname= "unknown device"; printf("%s: ", rep->re_name); printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));#endif pci_reserve(devind); /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */ bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; if ((bar & 0x3ff) >= 0x100-32 || bar < 0x400) panic("rtl_probe", "base address is not properly configured", NO_NUM); rep->re_base_port= bar; ilr= pci_attr_r8(devind, PCI_ILR); rep->re_irq= ilr; if (debug) { printf("%s: using I/O address 0x%lx, IRQ %d\n", rep->re_name, (unsigned long)bar, ilr); } return TRUE;}/*===========================================================================* * rl_conf_hw * *===========================================================================*/static void rl_conf_hw(rep)re_t *rep;{ static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ }; rep->re_mode= REM_DISABLED; /* Superfluous */ if (rep->re_seen) { /* PCI device is present */ rep->re_mode= REM_ENABLED; } if (rep->re_mode != REM_ENABLED) return; rep->re_flags= REF_EMPTY; rep->re_link_up= -1; /* Unknown */ rep->re_got_int= 0; rep->re_send_int= 0; rep->re_report_link= 0; rep->re_clear_rx= 0; rep->re_need_reset= 0; rep->re_tx_alive= 0; rep->re_read_s= 0; rep->re_tx_head= 0; rep->re_tx_tail= 0; rep->re_ertxth= RL_TSD_ERTXTH_8; rep->re_stat= empty_stat;}/*===========================================================================* * rl_init_buf * *===========================================================================*/static void rl_init_buf(rep)re_t *rep;{ size_t rx_bufsize, tx_bufsize, tot_bufsize; phys_bytes buf; char *mallocbuf; static struct memory chunk; int fd, s, i, off; /* Allocate receive and transmit buffers */ tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED; if (tx_bufsize % 4) tx_bufsize += 4-(tx_bufsize % 4); /* Align */ rx_bufsize= RX_BUFSIZE; tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize; /* Now try to allocate a kernel memory buffer. */ chunk.size = tot_bufsize;#define BUF_ALIGNMENT (64*1024) if(!(mallocbuf = malloc(BUF_ALIGNMENT + tot_bufsize))) { panic("RTL8139","Couldn't allocate kernel buffer",i); } if(OK != (i = sys_umap(SELF, D, (vir_bytes) mallocbuf, tot_bufsize, &buf))) { panic("RTL8139","Couldn't re-map malloced buffer",i); } /* click-align mallocced buffer. this is what we used to get * from kmalloc() too. */ if((off = buf % BUF_ALIGNMENT)) { mallocbuf += BUF_ALIGNMENT - off; buf += BUF_ALIGNMENT - off; } for (i= 0; i<N_TX_BUF; i++) { rep->re_tx[i].ret_buf= buf; rep->re_tx[i].v_ret_buf= mallocbuf; buf += tx_bufsize; mallocbuf += tx_bufsize; } rep->re_rx_buf= buf; rep->v_re_rx_buf= mallocbuf;}/*===========================================================================* * rl_init_hw * *===========================================================================*/static void rl_init_hw(rep)re_t *rep;{ int s, i; rep->re_flags = REF_EMPTY; rep->re_flags |= REF_ENABLED; /* Set the interrupt handler. The policy is to only send HARD_INT * notifications. Don't reenable interrupts automatically. The id * that is passed back is the interrupt line number. */ rep->re_hook_id = rep->re_irq; if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK) printf("RTL8139: error, couldn't set IRQ policy: %d\n", s); rl_reset_hw(rep); if ((s=sys_irqenable(&rep->re_hook_id)) != OK) printf("RTL8139: error, couldn't enable interrupts: %d\n", s);#if VERBOSE /* stay silent during startup, can always get status later */ if (rep->re_mode) { printf("%s: model %s\n", rep->re_name, rep->re_model); } else { printf("%s: unknown model 0x%08x\n", rep->re_name, rl_inl(rep->re_base_port, RL_TCR) & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM)); }#endif rl_confaddr(rep); if (debug) { printf("%s: Ethernet address ", rep->re_name); for (i= 0; i < 6; i++) { printf("%x%c", rep->re_address.ea_addr[i], i < 5 ? ':' : '\n'); } }}/*===========================================================================* * rl_reset_hw * *===========================================================================*/static void rl_reset_hw(rep)re_t *rep;{ port_t port; u32_t t; phys_bytes bus_buf; int i; clock_t t0,t1; port= rep->re_base_port;#if 0 /* Reset the PHY */ rl_outb(port, RL_BMCR, MII_CTRL_RST); getuptime(&t0); do { if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST)) break; } while (getuptime(&t1)==OK && (t1-t0) < HZ); if (rl_inb(port, RL_BMCR) & MII_CTRL_RST) panic("rtl8139","reset PHY failed to complete", NO_NUM);#endif /* Reset the device */ rl_outb(port, RL_CR, RL_CR_RST); getuptime(&t0); do { if (!(rl_inb(port, RL_CR) & RL_CR_RST)) break; } while (getuptime(&t1)==OK && (t1-t0) < HZ); if (rl_inb(port, RL_CR) & RL_CR_RST) panic("rtl8139","reset failed to complete", NO_NUM); t= rl_inl(port, RL_TCR); switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM)) { case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break; case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break; case RL_TCR_HWVER_RTL8139AG: rep->re_model= "RTL8139A-G / RTL8139C"; break; case RL_TCR_HWVER_RTL8139B: rep->re_model= "RTL8139B / RTL8130"; break; case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break; case RL_TCR_HWVER_RTL8100B: rep->re_model= "RTL8100B/RTL8139D"; break; case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break; case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break; default: rep->re_model= NULL; break; }#if 0 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));#endif /* Intialize Rx */ /* Should init multicast mask */#if 008-0f R/W MAR[0-7] multicast#endif bus_buf= vm_1phys2bus(rep->re_rx_buf); rl_outl(port, RL_RBSTART, bus_buf); /* Initialize Tx */ for (i= 0; i<N_TX_BUF; i++) { rep->re_tx[i].ret_busy= FALSE; bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf); rl_outl(port, RL_TSAD0+i*4, bus_buf); t= rl_inl(port, RL_TSD0+i*4); assert(t & RL_TSD_OWN); }#if 0 dump_phy(rep);#endif t= rl_inw(port, RL_IMR); rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT | RL_IMR_LENCHG)); t= rl_inw(port, RL_IMR); rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN | RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK)); t= rl_inw(port, RL_IMR); rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK)); t= rl_inb(port, RL_CR); rl_outb(port, RL_CR, t | RL_CR_RE); t= rl_inb(port, RL_CR); rl_outb(port, RL_CR, t | RL_CR_TE); rl_outl(port, RL_RCR, RX_BUFBITS); t= rl_inl(port, RL_TCR); rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);}/*===========================================================================* * rl_confaddr * *===========================================================================*/static void rl_confaddr(rep)re_t *rep;{ static char eakey[]= RL_ENVVAR "#_EA"; static char eafmt[]= "x:x:x:x:x:x"; int i; port_t port; u32_t w; long v; /* User defined ethernet address? */ eakey[sizeof(RL_ENVVAR)-1]= '0' + (rep-re_table); port= rep->re_base_port; for (i= 0; i < 6; i++) { if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET) break; rep->re_address.ea_addr[i]= v; } if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */ /* Should update ethernet address in hardware */ if (i == 6) { port= rep->re_base_port; rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG); w= 0; for (i= 0; i<4; i++) w |= (rep->re_address.ea_addr[i] << (i*8)); rl_outl(port, RL_IDR, w); w= 0; for (i= 4; i<6; i++) w |= (rep->re_address.ea_addr[i] << ((i-4)*8)); rl_outl(port, RL_IDR+4, w); rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL); } /* Get ethernet address */ for (i= 0; i<6; i++) rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);}/*===========================================================================* * rl_rec_mode * *===========================================================================*/static void rl_rec_mode(rep)re_t *rep;{ port_t port; u32_t rcr; port= rep->re_base_port; rcr= rl_inl(port, RL_RCR); rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP); if (rep->re_flags & REF_PROMISC) rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP; if (rep->re_flags & REF_BROAD) rcr |= RL_RCR_AB; if (rep->re_flags & REF_MULTI) rcr |= RL_RCR_AM; rcr |= RL_RCR_APM; rl_outl(port, RL_RCR, rcr);}/*===========================================================================* * rl_readv * *===========================================================================*/static void rl_readv(mp, from_int, vectored)message *mp;int from_int;int vectored;{ int i, j, n, o, s, s1, dl_port, re_client, count, size; port_t port; unsigned amount, totlen, packlen; phys_bytes src_phys, dst_phys, iov_src; u16_t d_start, d_end; u32_t l, rxstat = 0x12345678; re_t *rep; iovec_t *iovp; int cps; dl_port = mp->DL_PORT; count = mp->DL_COUNT; if (dl_port < 0 || dl_port >= RE_PORT_NR) panic("rtl8139"," illegal port", dl_port); rep= &re_table[dl_port]; re_client= mp->DL_PROC; rep->re_client= re_client; if (rep->re_clear_rx) goto suspend; /* Buffer overflow */ assert(rep->re_mode == REM_ENABLED); assert(rep->re_flags & REF_ENABLED); port= rep->re_base_port; /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints */ if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE)) { /* Receive buffer is empty, suspend */ goto suspend; } d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF; d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE; if (d_start >= RX_BUFSIZE) { printf("rl_readv: strange value in RL_CAPR: 0x%x\n", rl_inw(port, RL_CAPR)); d_start %= RX_BUFSIZE; } if (d_end > d_start) amount= d_end-d_start; else amount= d_end+RX_BUFSIZE - d_start; rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -