static void pcnet_reset_8390(void) { int i, r; PRINTK("nic base is %lx\n", nic_base); #if 1 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD)); #endif n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); n2k_outb(n2k_inb(nic_base + PCNET_RESET), PCNET_RESET); for (i = 0; i < 100; i++) { if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0) break; PRINTK("got %x in reset\n", r); my_udelay(100); } n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */ if (i == 100) printf("pcnet_reset_8390() did not complete.\n"); } /* pcnet_reset_8390 */
/* * This function is called when a packet has been received. It's job is * to prepare to unload the packet from the hardware. Once the length of * the packet is known, the upper layer of the driver can be told. When * the upper layer is ready to unload the packet, the internal function * 'dp83902a_recv' will be called to actually fetch it from the hardware. */ static void dp83902a_RxEvent(struct nic_priv_data *dp) { u8 rsr; u8 rcv_hdr[4]; int i, len, pkt, cur = 0; rsr = n2k_inb(dp, DP_RSR); if (!(rsr & 0x01)) { return; } while (true) { /* Read incoming packet header */ n2k_outb(dp, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); n2k_outb(dp, DP_P1_CURP, cur); n2k_outb(dp, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); pkt = n2k_inb(dp, DP_BNDRY); pkt += 1; if (pkt == dp->rx_buf_end) pkt = dp->rx_buf_start; if (pkt == cur) { break; } n2k_outb(dp, DP_RBCL, sizeof(rcv_hdr)); n2k_outb(dp, DP_RBCH, 0); n2k_outb(dp, DP_RSAL, 0); n2k_outb(dp, DP_RSAH, pkt); if (dp->rx_next == pkt) { if (cur == dp->rx_buf_start) n2k_outb(dp, DP_BNDRY, dp->rx_buf_end - 1); else n2k_outb(dp, DP_BNDRY, cur - 1); /* Update pointer */ return; } dp->rx_next = pkt; n2k_outb(dp, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ n2k_outb(dp, DP_CR, DP_CR_RDMA | DP_CR_START); /* read header (get data size)*/ for (i = 0; i < sizeof(rcv_hdr);) { DP_IN_DATA(dp->data, rcv_hdr[i++]); } len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); /* FIXME: Tell that data has been read */ push_packet_len(dp, len); if (rcv_hdr[1] == dp->rx_buf_start) n2k_outb(dp, DP_BNDRY, dp->rx_buf_end - 1); else n2k_outb(dp, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ } }
int get_prom(u8* mac_addr, u8* base_addr) { u8 prom[32]; int i, j; struct { u_char value, offset; } program_seq[] = { {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ {0x00, EN0_RCNTLO}, /* Clear the count regs. */ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {32, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; PRINTK ("trying to get MAC via prom reading\n"); pcnet_reset_8390 (base_addr); mdelay (10); for (i = 0; i < sizeof (program_seq) / sizeof (program_seq[0]); i++) n2k_outb (program_seq[i].value, program_seq[i].offset); PRINTK ("PROM:"); for (i = 0; i < 32; i++) { prom[i] = n2k_inb (PCNET_DATAPORT); PRINTK (" %02x", prom[i]); } PRINTK ("\n"); for (i = 0; i < NR_INFO; i++) { if ((prom[0] == hw_info[i].a0) && (prom[2] == hw_info[i].a1) && (prom[4] == hw_info[i].a2)) { PRINTK ("matched board %d\n", i); break; } } if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) { PRINTK ("on exit i is %d/%ld\n", i, NR_INFO); PRINTK ("MAC address is "); for (j = 0; j < 6; j++) { mac_addr[j] = prom[j << 1]; PRINTK ("%02x:", mac_addr[i]); } PRINTK ("\n"); return (i < NR_INFO) ? i : 0; } return 0; }
static void pcnet_reset_8390(struct nic_priv_data *dp) { int i, r; n2k_outb(dp, E8390_CMD, E8390_NODMA + E8390_PAGE0+E8390_STOP); n2k_outb(dp, E8390_CMD, E8390_NODMA+E8390_PAGE1+E8390_STOP); n2k_outb(dp, E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_STOP); n2k_outb(dp, E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD); n2k_outb(dp, PCNET_RESET, n2k_inb(dp, PCNET_RESET)); for (i = 0; i < 100; i++) { if ((r = (n2k_inb(dp, EN0_ISR) & ENISR_RESET)) != 0) break; } n2k_outb(dp, EN0_ISR, ENISR_RESET); /* Ack intr. */ if (i == 100) vmm_printf("pcnet_reset_8390() did not complete.\n"); }
int get_prom(struct nic_priv_data *dp, u8* mac_addr) { u8 prom[32]; int i, j; struct { unsigned char value, offset; } program_seq[] = { {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ {0x00, EN0_RCNTLO}, /* Clear the count regs. */ {0x00, EN0_RCNTHI}, {0x00, EN0_IMR}, /* Mask completion irq. */ {0xFF, EN0_ISR}, {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ {32, EN0_RCNTLO}, {0x00, EN0_RCNTHI}, {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ {0x00, EN0_RSARHI}, {E8390_RREAD+E8390_START, E8390_CMD}, }; pcnet_reset_8390(dp); for (i = 0; i < sizeof (program_seq) / sizeof (program_seq[0]); i++) n2k_outb (dp, program_seq[i].value, program_seq[i].offset); for (i = 0; i < 32; i++) { prom[i] = n2k_inb (dp, PCNET_DATAPORT); } for (i = 0;; i++) { if (hw_info[i].dev_name == NULL) break; if ((prom[0] == hw_info[i].a0) && (prom[2] == hw_info[i].a1) && (prom[4] == hw_info[i].a2)) { vmm_printf("%s detected.\n", hw_info[i].dev_name); break; } } if ((prom[28] == 0x57) && (prom[30] == 0x57)) { vmm_printf ("MAC address is "); for (j = 0; j < 6; j++) { if (j) vmm_printf(":"); mac_addr[j] = prom[j << 1]; vmm_printf ("%02x", mac_addr[j]); } vmm_printf ("\n"); } return VMM_OK; }
static void dp83902a_poll(struct nic_priv_data *dp) { u8 *base = dp->base; volatile u8 isr = 0; DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); while (1) { wait_on_event_running((isr = n2k_inb(dp, DP_ISR)) != 0) /* * The CNT interrupt triggers when the MSB of one of the error * counters is set. We don't much care about these counters, but * we should read their values to reset them. */ if (isr & DP_ISR_CNT) { dp83902a_ClearCounters(dp); } /* * Check for overflow. It's a special case, since there's a * particular procedure that must be followed to get back into * a running state.a */ if (isr & DP_ISR_OFLW) { dp83902a_Overflow(dp); } else { /* * Other kinds of interrupts can be acknowledged simply by * clearing the relevant bits of the ISR. Do that now, then * handle the interrupts we care about. */ DP_OUT(base, DP_ISR, isr); /* Clear set bits */ if (!dp->running) break; /* Is this necessary? */ /* * Check for tx_started on TX event since these may happen * spuriously it seems. */ if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { dp83902a_TxEvent(dp); } if (isr & DP_ISR_RxP) { dp83902a_RxEvent(dp); } } } }
/* * This routine is called to send data to the hardware. It is known a-priori * that there is free buffer space (dp->tx_next). */ static void dp83902a_send(struct nic_priv_data *dp, u8 *data, int total_len, u32 key) { int len, start_page, pkt_len, i; volatile int isr; len = pkt_len = total_len; if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME; start_page = dp->tx_next; if (dp->tx_next == dp->tx_buf1) { dp->tx1 = start_page; dp->tx1_len = pkt_len; dp->tx1_key = key; dp->tx_next = dp->tx_buf2; } else { dp->tx2 = start_page; dp->tx2_len = pkt_len; dp->tx2_key = key; dp->tx_next = dp->tx_buf1; } n2k_outb(dp, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ { /* * Dummy read. The manual sez something slightly different, * but the code is extended a bit to do what Hitachi's monitor * does (i.e., also read data). */ u16 tmp; int len = 1; n2k_outb(dp, DP_RSAL, 0x100 - len); n2k_outb(dp, DP_RSAH, (start_page - 1) & 0xff); n2k_outb(dp, DP_RBCL, len); n2k_outb(dp, DP_RBCH, 0); n2k_outb(dp, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); DP_IN_DATA(dp->data, tmp); } /* Send data to device buffer(s) */ n2k_outb(dp, DP_RSAL, 0); n2k_outb(dp, DP_RSAH, start_page); n2k_outb(dp, DP_RBCL, pkt_len & 0xFF); n2k_outb(dp, DP_RBCH, pkt_len >> 8); n2k_outb(dp, DP_CR, DP_CR_WDMA | DP_CR_START); /* Put data into buffer */ while (len > 0) { DP_OUT_DATA(dp->data, *data++); len--; } if (total_len < pkt_len) { /* Padding to 802.3 length was required */ for (i = total_len; i < pkt_len;) { i++; DP_OUT_DATA(dp->data, 0); } } /* Wait for DMA to complete */ do { isr = n2k_inb(dp, DP_ISR); } while ((isr & DP_ISR_RDC) == 0); /* Then disable DMA */ n2k_outb(dp, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); /* Start transmit if not already going */ if (!dp->tx_started) { if (start_page == dp->tx1) { dp->tx_int = 1; /* Expecting interrupt from BUF1 */ } else { dp->tx_int = 2; /* Expecting interrupt from BUF2 */ } dp83902a_start_xmit(dp, start_page, pkt_len); } }